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