def generate_static_theme_preview(theme_manifest, version_pk): tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') file_ = File.objects.filter(version_id=version_pk).first() if not file_: return context = _build_static_theme_preview_context(theme_manifest, file_) sizes = sorted( amo.THEME_PREVIEW_SIZES.values(), lambda x, y: x['position'] - y['position']) for size in sizes: # Create a Preview for this size. preview = VersionPreview.objects.create( version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image( preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) preview_sizes = {} preview_sizes['image'] = size['full'] preview_sizes['thumbnail'] = size['thumbnail'] preview.update(sizes=preview_sizes) addon_id = Version.objects.values_list( 'addon_id', flat=True).get(id=version_pk) index_addons.delay([addon_id])
def generate_static_theme_preview(theme_manifest, version_pk): tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') file_ = File.objects.filter(version_id=version_pk).first() if not file_: return context = _build_static_theme_preview_context(theme_manifest, file_) sizes = sorted(amo.THEME_PREVIEW_SIZES.values(), lambda x, y: x['position'] - y['position']) for size in sizes: # Create a Preview for this size. preview = VersionPreview.objects.create(version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image(preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) preview_sizes = {} preview_sizes['image'] = size['full'] preview_sizes['thumbnail'] = size['thumbnail'] preview.update(sizes=preview_sizes) addon_id = Version.objects.values_list('addon_id', flat=True).get(id=version_pk) index_addons.delay([addon_id])
def render_to_svg(template, context, preview, thumbnail_dimensions, theme_manifest): tmp_args = { 'dir': settings.TMP_PATH, 'mode': 'wb', 'delete': not settings.DEBUG, 'suffix': '.png', } # first stage - just the images image_only_svg = template.render(context).encode('utf-8') with BytesIO() as background_blob: # write the image only background to a file and back to a blob with tempfile.NamedTemporaryFile(**tmp_args) as background_png: if not write_svg_to_png(image_only_svg, background_png.name): return # TODO: improvement - only re-encode jpg backgrounds as jpg? Image.open(background_png.name).convert('RGB').save( background_blob, 'JPEG', quality=80 ) # and encode the image in base64 to use in the context try: header_src, _, _ = encode_header(background_blob.getvalue(), 'jpg') except Exception as exc: log.info('Exception during svg preview generation %s', exc) return # then rebuild a context with it and render with_ui_context = { **dict( process_color_value(prop, color) for prop, color in theme_manifest.get('colors', {}).items() ), 'amo': amo, 'header_src': header_src, 'svg_render_size': context['svg_render_size'], 'header_src_height': context['svg_render_size'].height, 'header_width': context['svg_render_size'].width, } finished_svg = template.render(with_ui_context).encode('utf-8') # and write that svg to preview.image_path with storage.open(preview.image_path, 'wb') as image_path: image_path.write(finished_svg) # then also write a fully rendered svg and resize for the thumbnails with tempfile.NamedTemporaryFile(**tmp_args) as complete_preview_as_png: if convert_svg_to_png(preview.image_path, complete_preview_as_png.name): resize_image( complete_preview_as_png.name, preview.thumbnail_path, thumbnail_dimensions, format=preview.get_format('thumbnail'), quality=35, # It's ignored for png format, so it's fine to always set. ) return True
def render_to_png(template, context, preview, thumbnail_dimensions): svg = template.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image( preview.image_path, preview.thumbnail_path, thumbnail_dimensions, format=preview.get_format('thumbnail'), quality=35, # It's ignored for png format, so it's fine to always set. ) pngcrush_image(preview.image_path) return True
def generate_static_theme_preview(theme_manifest, version_pk): # Make sure we import `index_addons` late in the game to avoid having # a "copy" of it here that won't get mocked by our ESTestCase from olympia.addons.tasks import index_addons tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') file_ = File.objects.filter(version_id=version_pk).first() if not file_: return context = _build_static_theme_preview_context(theme_manifest, file_) renderings = sorted(amo.THEME_PREVIEW_RENDERINGS.values(), key=operator.itemgetter('position')) colors = None for rendering in renderings: # Create a Preview for this size. preview = VersionPreview.objects.create( version_id=version_pk, position=rendering['position'], sizes={'thumbnail_format': rendering['thumbnail_format']}, ) # Add the size to the context and render context.update(svg_render_size=rendering['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image( preview.image_path, preview.thumbnail_path, rendering['thumbnail'], format=rendering['thumbnail_format'], quality= 35, # It's ignored for png format, so it's fine to always set. ) pngcrush_image(preview.image_path) # Extract colors once and store it for all previews. # Use the thumbnail for extra speed, we don't need to be super accurate. if colors is None: colors = extract_colors_from_image(preview.thumbnail_path) data = { 'sizes': { 'image': rendering['full'], 'thumbnail': rendering['thumbnail'], 'thumbnail_format': rendering['thumbnail_format'], }, 'colors': colors, } preview.update(**data) addon_id = Version.objects.values_list('addon_id', flat=True).get(id=version_pk) index_addons.delay([addon_id])
def generate_static_theme_preview(theme_manifest, header_root, version_pk): tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') context = _build_static_theme_preview_context(theme_manifest, header_root) for size in sorted(amo.THEME_PREVIEW_SIZES.values()): # Create a Preview for this size. preview = VersionPreview.objects.create( version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image( preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) preview_sizes = {} preview_sizes['image'] = size['full'] preview_sizes['thumbnail'] = size['thumbnail'] preview.update(sizes=preview_sizes)
def generate_static_theme_preview(theme_manifest, header_root, version_pk): tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') context = _build_static_theme_preview_context(theme_manifest, header_root) for size in sorted(amo.THEME_PREVIEW_SIZES.values()): # Create a Preview for this size. preview = VersionPreview.objects.create(version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image(preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) preview_sizes = {} preview_sizes['image'] = size['full'] preview_sizes['thumbnail'] = size['thumbnail'] preview.update(sizes=preview_sizes)
def generate_static_theme_preview(theme_manifest, version_pk): # Make sure we import `index_addons` late in the game to avoid having # a "copy" of it here that won't get mocked by our ESTestCase from olympia.addons.tasks import index_addons tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') file_ = File.objects.filter(version_id=version_pk).first() if not file_: return context = _build_static_theme_preview_context(theme_manifest, file_) sizes = sorted( amo.THEME_PREVIEW_SIZES.values(), key=operator.itemgetter('position')) colors = None for size in sizes: # Create a Preview for this size. preview = VersionPreview.objects.create( version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image( preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) # Extract colors once and store it for all previews. # Use the thumbnail for extra speed, we don't need to be super # accurate. if colors is None: colors = extract_colors_from_image(preview.thumbnail_path) data = { 'sizes': { 'image': size['full'], 'thumbnail': size['thumbnail'], }, 'colors': colors, } preview.update(**data) addon_id = Version.objects.values_list( 'addon_id', flat=True).get(id=version_pk) index_addons.delay([addon_id])
def generate_static_theme_preview(theme_manifest, version_pk): tmpl = loader.get_template( 'devhub/addons/includes/static_theme_preview_svg.xml') file_ = File.objects.filter(version_id=version_pk).first() if not file_: return context = _build_static_theme_preview_context(theme_manifest, file_) sizes = sorted(amo.THEME_PREVIEW_SIZES.values(), lambda x, y: x['position'] - y['position']) colors = None for size in sizes: # Create a Preview for this size. preview = VersionPreview.objects.create(version_id=version_pk, position=size['position']) # Add the size to the context and render context.update(svg_render_size=size['full']) svg = tmpl.render(context).encode('utf-8') if write_svg_to_png(svg, preview.image_path): resize_image(preview.image_path, preview.thumbnail_path, size['thumbnail']) pngcrush_image(preview.image_path) # Extract colors once and store it for all previews. # Use the thumbnail for extra speed, we don't need to be super # accurate. if colors is None: colors = extract_colors_from_image(preview.thumbnail_path) data = { 'sizes': { 'image': size['full'], 'thumbnail': size['thumbnail'], }, 'colors': colors, } preview.update(**data) addon_id = Version.objects.values_list('addon_id', flat=True).get(id=version_pk) index_addons.delay([addon_id])
def recreate_theme_previews(addon_ids, **kw): log.info( '[%s@%s] Recreating previews for themes starting at id: %s...' % (len(addon_ids), recreate_theme_previews.rate_limit, addon_ids[0])) version_ids = Addon.objects.filter( pk__in=addon_ids).values_list('_current_version') versions = Version.objects.filter(pk__in=version_ids) only_missing = kw.get('only_missing', False) renders = {(render['full'], render['image_format']): { 'thumb_size': render['thumbnail'], 'thumb_format': render['thumbnail_format'], } for render in amo.THEME_PREVIEW_RENDERINGS.values()} for version in versions: try: if only_missing: existing_full_sizes = { (tuple(size.get('image', ())), size.get('image_format', 'png')) for size in VersionPreview.objects.filter( version=version).values_list('sizes', flat=True) } all_full_sizes_present = not set( renders.keys()) - existing_full_sizes if all_full_sizes_present: # i.e. we have all renders log.info('Resizing thumbnails for theme: %s' % version.addon_id) for preview in list( VersionPreview.objects.filter(version=version)): # so check the thumbnail size/format for each preview preview_dimension_format = ( tuple(preview.image_dimensions), preview.get_format('image'), ) render = renders.get(preview_dimension_format) if render and (render['thumb_size'] != tuple( preview.thumbnail_dimensions) or render['thumb_format'] != preview.get_format('thumbnail')): preview.sizes['thumbnail_format'] = render[ 'thumb_format'] preview.sizes['thumbnail'] = render['thumb_size'] resize_image( preview.image_path, preview.thumbnail_path, render['thumb_size'], format=render['thumb_format'], quality=35, ) preview.save() continue # else carry on with a full preview generation log.info('Recreating previews for theme: %s' % version.addon_id) xpi = get_filepath(version.all_files[0]) theme_data = parse_addon(xpi, minimal=True).get('theme', {}) generate_static_theme_preview.apply_async(args=(theme_data, version.id), queue='adhoc') except IOError: pass index_addons.delay(addon_ids)