116 lines
4.3 KiB
Python
116 lines
4.3 KiB
Python
|
|
# "convert folder of images to animation"
|
|
# heavy lifting still done by ImageConverter, this mainly coordinates
|
|
# conversion of multiple frames
|
|
|
|
import os, time
|
|
|
|
import image_convert
|
|
import formats.in_bitmap as bm
|
|
|
|
class ImageSequenceConverter:
|
|
|
|
def __init__(self, app, image_filenames, art, bicubic_scale):
|
|
self.init_success = False
|
|
self.app = app
|
|
self.start_time = time.time()
|
|
self.image_filenames = image_filenames
|
|
# App.update_window_title uses image_filename for titlebar
|
|
self.image_filename = ''
|
|
# common name of sequence
|
|
self.image_name = os.path.splitext(self.image_filename)[0]
|
|
self.art = art
|
|
self.bicubic_scale = bicubic_scale
|
|
# queue up first frame
|
|
self.next_image(first=True)
|
|
self.init_success = True
|
|
|
|
def next_image(self, first=False):
|
|
# pop last image off stack
|
|
if not first:
|
|
self.image_filenames.pop(0)
|
|
# done?
|
|
if len(self.image_filenames) == 0:
|
|
self.finish()
|
|
return
|
|
# next frame
|
|
self.art.set_active_frame(self.art.active_frame + 1)
|
|
try:
|
|
self.current_frame_converter = image_convert.ImageConverter(self.app,
|
|
self.image_filenames[0],
|
|
self.art,
|
|
self.bicubic_scale, self)
|
|
except:
|
|
self.fail()
|
|
return
|
|
if not self.current_frame_converter.init_success:
|
|
self.fail()
|
|
return
|
|
self.image_filename = self.image_filenames[0]
|
|
self.preview_sprite = self.current_frame_converter.preview_sprite
|
|
self.app.update_window_title()
|
|
|
|
def fail(self):
|
|
self.app.log('Bad frame %s' % self.image_filenames[0], error=True)
|
|
self.finish(True)
|
|
|
|
def update(self):
|
|
# create converter for new frame if current one is done,
|
|
# else update current one
|
|
if self.current_frame_converter.finished:
|
|
self.next_image()
|
|
else:
|
|
self.current_frame_converter.update()
|
|
|
|
def finish(self, cancelled=False):
|
|
time_taken = time.time() - self.start_time
|
|
(verb, error) = ('cancelled', True) if cancelled else ('finished', False)
|
|
self.app.log('Conversion of image sequence %s %s after %.3f seconds' % (self.image_name, verb, time_taken), error)
|
|
self.app.converter = None
|
|
self.app.update_window_title()
|
|
|
|
|
|
class ConvertImageSequenceChooserDialog(bm.ConvertImageChooserDialog):
|
|
title = 'Convert folder'
|
|
confirm_caption = 'Choose First Image'
|
|
|
|
|
|
class BitmapImageSequenceImporter(bm.BitmapImageImporter):
|
|
format_name = 'Bitmap image folder'
|
|
format_description = """
|
|
Converts a folder of Bitmap images (PNG, JPEG, or BMP)
|
|
into an animation. Dimensions will be based on first
|
|
image chosen.
|
|
"""
|
|
file_chooser_dialog_class = ConvertImageSequenceChooserDialog
|
|
#options_dialog_class = bm.ConvertImageOptionsDialog
|
|
|
|
def run_import(self, in_filename, options={}):
|
|
palette = self.app.load_palette(options['palette'])
|
|
self.art.set_palette(palette)
|
|
width, height = options['art_width'], options['art_height']
|
|
self.art.resize(width, height) # Importer.init will adjust UI
|
|
bicubic_scale = options['bicubic_scale']
|
|
# get dir listing with full pathname
|
|
in_dir = os.path.dirname(in_filename)
|
|
in_files = ['%s/%s' % (in_dir, f) for f in os.listdir(in_dir)]
|
|
in_files.sort()
|
|
# assume numeric sequence starts from chosen file
|
|
in_files = in_files[in_files.index(in_filename):]
|
|
# remove files from end of list if they don't end in a number
|
|
while not os.path.splitext(in_files[-1])[0][-1].isdecimal() and \
|
|
len(in_files) > 0:
|
|
in_files.pop()
|
|
# add frames to art as needed
|
|
while self.art.frames < len(in_files):
|
|
self.art.add_frame_to_end(log=False)
|
|
self.art.set_active_frame(0)
|
|
# create converter
|
|
isc = ImageSequenceConverter(self.app, in_files, self.art,
|
|
bicubic_scale)
|
|
# bail on early failure
|
|
if not isc.init_success:
|
|
return False
|
|
self.app.converter = isc
|
|
self.app.update_window_title()
|
|
return True
|