Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
237 changes: 129 additions & 108 deletions core.py
Original file line number Diff line number Diff line change
Expand Up @@ -66,138 +66,159 @@ def download_image(file, id, name, token, out=None, frame=None):
def parse_file(file, token, download_images=True, out=None):
output = []
result = get_file(file, token)

if isinstance(result, tuple):
return []

try:
frames = result['document']['children'][0]['children']
frame_count = 1 if len(frames) > 1 else 0

def parse_frame(frame, frame_count):
nonlocal output
parsed = []
def parse_node(i, frame, frame_count):
image_count = 0
entry_placeholder = False
text_placeholder = False

for i in frame['children']:
if 'absoluteBoundingBox' in i:
bounds = i['absoluteBoundingBox']
else:
bounds = i['absoluteRenderBounds']

items = ["image", "button", "label", "scale", "listbox", "textbox", "textarea", "rectangle", "spinbox", "circle", "oval", "line"]
type = i['name'].split(' ', 1)[0].lower()
type = type if type in items else "text"

i['type'] = type
i['x'] = abs(int(frame['absoluteBoundingBox']['x']) - int(bounds['x']))
i['y'] = abs(int(frame['absoluteBoundingBox']['y']) - int(bounds['y']))
i['width'] = int(bounds['width'])
i['height'] = int(bounds['height'])
i['background'] = None

bg_color = i.get('backgroundColor') or \
(i.get('background', [{}])[0].get('color') if i.get('background') else None) or \
(i.get('fills', [{}])[0].get('color') if i.get('fills') else "#000000")

if bg_color and bg_color != "#000000":
i['background'] = rgb_to_hex(bg_color['r'], bg_color['g'], bg_color['b'])
fg = get_foreground_color(bg_color['r'], bg_color['g'], bg_color['b'])

if fg == i['background']:
i['foreground'] = '#ffffff' if fg == '#000000' else '#000000' if fg == '#ffffff' else fg
else:
i['foreground'] = fg
else:
i['background'] = "#000000"
i['foreground'] = "#FFFFFF"

def download(name):
nonlocal i
image = download_image(file, i['id'], name, token, out, frame_count) if frame_count > 0 else download_image(file, i['id'], name, token, out)

if image:
i['image'] = image
if 'absoluteBoundingBox' in i:
bounds = i['absoluteBoundingBox']
else:
bounds = i['absoluteRenderBounds']

items = [
"image", "button", "label", "scale", "listbox",
"textbox", "textarea", "rectangle", "spinbox",
"circle", "oval", "line"
]

type_ = i['name'].split(' ', 1)[0].lower()
type_ = type_ if type_ in items else "text"

i['type'] = type_
i['x'] = abs(int(frame['absoluteBoundingBox']['x']) - int(bounds['x']))
i['y'] = abs(int(frame['absoluteBoundingBox']['y']) - int(bounds['y']))
i['width'] = int(bounds['width'])
i['height'] = int(bounds['height'])
i['background'] = None

bg_color = (
i.get('backgroundColor') or
(i.get('background', [{}])[0].get('color') if i.get('background') else None) or
(i.get('fills', [{}])[0].get('color') if i.get('fills') else None)
)

if bg_color:
i['background'] = rgb_to_hex(bg_color['r'], bg_color['g'], bg_color['b'])
fg = get_foreground_color(bg_color['r'], bg_color['g'], bg_color['b'])
i['foreground'] = fg
else:
i['background'] = "#000000"
i['foreground'] = "#FFFFFF"

def download(name):
image = (
download_image(file, i['id'], name, token, out, frame_count)
if frame_count > 0 else
download_image(file, i['id'], name, token, out)
)
i['image'] = image if image else None

if i.get('strokes'):
stroke_color = i['strokes'][0].get('color')
if stroke_color:
i['stroke_color'] = rgb_to_hex(
stroke_color['r'],
stroke_color['g'],
stroke_color['b']
)

if type_ in ['text', 'label']:
i['text'] = i.get('characters', '').replace('\n', '\\n')
style = i.get('style', {})
i['font'] = style.get('fontFamily', 'Default Font')
i['font_size'] = int(style.get('fontSize', 12))

elif type_ == 'image':
parts = i['name'].split(' ')
name = " ".join(parts[1:])
image_count += 1
download(name if name.strip() else str(image_count))

elif type_ == 'scale':
scale = i['name'].split(' ')
i['from'] = int(scale[1])
i['to'] = int(scale[2])
i['orient'] = scale[3] if len(scale) > 3 else "HORIZONTAL"

elif type_ in ['textbox', 'textarea']:
parts = i['name'].split(' ')
placeholder = " ".join(parts[1:])
if placeholder.strip():
i['placeholder'] = placeholder
if type_ == 'textbox':
entry_placeholder = True
else:
i['image'] = None
text_placeholder = True

if (i.get('strokes') and not i.get('strokes') == []):
stroke_color = i.get('strokes', [{}])[0].get('color')
i['stroke_color'] = rgb_to_hex(stroke_color['r'], stroke_color['g'], stroke_color['b'])
elif type_ == 'button' and download_images:
image_count += 1
download(str(image_count))

if type in ['text', 'label']:
i['text'] = i.get('characters', '').replace('\n', '\\n')
style = i.get('style', {})
i['font'] = style.get('fontFamily', 'Default Font')
i['font_size'] = int(style.get('fontSize', 12))

elif type == 'image':
parts = i['name'].split(' ')
name = " ".join(parts[1:])
if not name.replace(' ', '') == '':
download(name)
else:
image_count += 1
download(str(image_count))

elif type == 'scale':
scale = i['name'].split(' ')
i['from'] = int(scale[1])
i['to'] = int(scale[2])
i['orient'] = scale[3] if len(scale) > 3 else "HORIZONTAL"

elif type in ['textbox', 'textarea']:
parts = i['name'].split(' ')
placeholder = " ".join(parts[1:])
return i, entry_placeholder, text_placeholder

if not placeholder.replace(' ', '') == '':
i['placeholder'] = placeholder

if type == 'textbox':
entry_placeholder = True

elif type == 'textarea':
text_placeholder = True

elif type == 'button' and download_images:
image_count += 1
download(image_count)

parsed.append(i)

frame_bg = frame.get('backgroundColor') or \
(frame.get('background', [{}])[0].get('color') if frame.get('background') else None) or \
(frame.get('fills', [{}])[0].get('color') if frame.get('fills') else None)
def parse_frame(frame, frame_count):
parsed = []
entry_placeholder = False
text_placeholder = False

if frame_bg:
frame_bg = rgb_to_hex(frame_bg['r'], frame_bg['g'], frame_bg['b'])
else:
frame_bg = "No background color specified"

output.append([parsed, [
int(frame['absoluteBoundingBox']['width']),
int(frame['absoluteBoundingBox']['height']),
frame_bg,
result['name'].replace('\n', '\\n'),
frame_count,
entry_placeholder,
text_placeholder
]])
for child in frame.get('children', []):
if child['type'] == 'FRAME':
parse_frame(child, frame_count)
else:
node, ep, tp = parse_node(child, frame, frame_count)
entry_placeholder |= ep
text_placeholder |= tp
parsed.append(node)

frame_bg = (
frame.get('backgroundColor') or
(frame.get('background', [{}])[0].get('color') if frame.get('background') else None) or
(frame.get('fills', [{}])[0].get('color') if frame.get('fills') else None)
)

frame_bg = (
rgb_to_hex(frame_bg['r'], frame_bg['g'], frame_bg['b'])
if frame_bg else "No background color specified"
)

output.append([
parsed,
[
int(frame['absoluteBoundingBox']['width']),
int(frame['absoluteBoundingBox']['height']),
frame_bg,
result['name'].replace('\n', '\\n'),
frame_count,
entry_placeholder,
text_placeholder
]
])

threads = []
for frame in frames:
if frame["type"] == "FRAME":
thread = threading.Thread(target=parse_frame, args=(frame, frame_count,))
if frame['type'] == 'FRAME':
thread = threading.Thread(
target=parse_frame,
args=(frame, frame_count)
)
threads.append(thread)
thread.start()
frame_count = frame_count + 1;
frame_count += 1

for thread in threads:
thread.join()

except KeyError as e:
print(f"KeyError: {str(e)} - likely due to missing keys in JSON response")

return output