diff --git a/core.py b/core.py index a6f217a..10f7ec8 100644 --- a/core.py +++ b/core.py @@ -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 +