File indexing completed on 2025-02-02 04:10:04

0001 # SPDX-FileCopyrightText: 2019-2023 Mattia Basaglia <dev@dragon.best>
0002 # SPDX-License-Identifier: GPL-3.0-or-later
0003 import os
0004 from PIL import Image
0005 from PIL import features
0006 
0007 
0008 def _png_gif_prepare(image):
0009     if image.mode not in ["RGBA", "RGBa"]:
0010         image = image.convert("RGBA")
0011     alpha = image.getchannel("A")
0012     image = image.convert("RGB").convert('P', palette=Image.ADAPTIVE, colors=255)
0013     mask = Image.eval(alpha, lambda a: 255 if a <= 128 else 0)
0014     image.paste(255, mask=mask)
0015     return image
0016 
0017 
0018 def save_gif(window, document, comp, file, name, import_export, settings):
0019     skip_frames = 1
0020     start = int(comp.animation.first_frame)
0021     end = int(comp.animation.last_frame)
0022 
0023     import_export.progress_max_changed(end-start)
0024 
0025     frames = []
0026     for i in range(start, end+1, skip_frames):
0027         import_export.progress(i-start)
0028         frames.append(_png_gif_prepare(comp.render_image(i)))
0029 
0030     duration = int(round(1000 / comp.fps * skip_frames / 10)) * 10
0031     frames[0].save(
0032         file,
0033         format='GIF',
0034         append_images=frames[1:],
0035         save_all=True,
0036         duration=duration,
0037         loop=0,
0038         transparency=255,
0039         disposal=2,
0040     )
0041 
0042 
0043 def save_webp(window, document, comp, file, name, import_export, settings):
0044     if not features.check("webp_anim"):
0045         window.warning("WebP animations not supported in this system")
0046         return
0047 
0048     skip_frames = settings["skip_frames"]
0049     dpi = 96
0050 
0051     start = int(comp.animation.first_frame)
0052     end = int(comp.animation.last_frame)
0053     import_export.progress_max_changed(end-start)
0054 
0055     frames = []
0056     for i in range(start, end+1, skip_frames):
0057         import_export.progress(i-start)
0058         frames.append(comp.render_image(i))
0059 
0060     duration = int(round(1000 / comp.fps * skip_frames))
0061     frames[0].save(
0062         file,
0063         format='WebP',
0064         append_images=frames[1:],
0065         save_all=True,
0066         duration=duration,
0067         loop=0,
0068         background=(0, 0, 0, 0),
0069         lossless=settings["lossless"],
0070         quality=settings["quality"],
0071         method=settings["method"]
0072     )
0073 
0074 
0075 def open_image(window, document, file, name, import_export, settings):
0076     raster = Image.open(file)
0077     comp = document.assets.compositions.values[0]
0078     comp.width = raster.width
0079     comp.height = raster.height
0080 
0081     if not hasattr(raster, "is_animated"):
0082         raster.n_frames = 1
0083         raster.seek = lambda x: None
0084 
0085     parent_layer = comp.add_shape("Layer")
0086     parent_layer.name = comp.name = os.path.basename(name)
0087     time = 0
0088 
0089     for frame in range(raster.n_frames):
0090         layer = parent_layer.add_shape("Layer")
0091         layer.name = "Frame %s Layer" % frame
0092         layer.animation.first_frame = time
0093 
0094         raster.seek(frame)
0095 
0096         if "duration" in raster.info:
0097             time += raster.info.get("duration") / 1000 * comp.fps
0098         else:
0099             time += 1
0100         layer.animation.last_frame = time
0101 
0102         asset = document.assets.add_image(raster)
0103 
0104         shape = layer.add_shape("Image")
0105         shape.image = asset
0106         shape.name = "Frame %s" % frame
0107 
0108     comp.animation.last_frame = parent_layer.animation.last_frame = time