import os from art_export import ArtExporter from image_export import export_still_image from ui_dialog import UIDialog, Field from ui_art_dialog import ExportOptionsDialog from renderable import LAYER_VIS_FULL, LAYER_VIS_NONE FILE_EXTENSION = 'png' DEFAULT_SCALE = 1 DEFAULT_CRT = False def get_full_filename(in_filename, frame, layer_name, use_frame, use_layer, forbidden_chars): "Returns properly mutated filename for given frame/layer data" # strip out path and extension from filename as we mutate it dirname = os.path.dirname(in_filename) base_filename = os.path.basename(in_filename) base_filename = os.path.splitext(base_filename)[0] fn = base_filename if use_frame: fn += '_%s' % (str(frame).rjust(4, '0')) if use_layer: fn += '_%s' % layer_name # strip unfriendly chars from output filename for forbidden_char in ['\\', '/', '*', ':']: fn = fn.replace(forbidden_char, '') # add path and extension for final mutated filename return '%s/%s.%s' % (dirname, fn, FILE_EXTENSION) class PNGSetExportOptionsDialog(ExportOptionsDialog): title = 'PNG set export options' tile_width = 60 # extra width for filename preview field0_label = 'Scale factor (%s pixels)' field1_label = 'CRT filter' field2_label = 'Export frames' field3_label = 'Export layers' field4_label = 'First filename (in set of %s):' field5_label = ' %s' fields = [ Field(label=field0_label, type=int, width=6, oneline=False), Field(label=field1_label, type=bool, width=0, oneline=True), Field(label=field2_label, type=bool, width=0, oneline=True), Field(label=field3_label, type=bool, width=0, oneline=True), Field(label=field4_label, type=None, width=0, oneline=True), Field(label=field5_label, type=None, width=0, oneline=True) ] # redraw dynamic labels always_redraw_labels = True invalid_scale_error = 'Scale must be greater than 0' def get_initial_field_text(self, field_number): art = self.ui.active_art if field_number == 0: return str(DEFAULT_SCALE) elif field_number == 1: return [' ', UIDialog.true_field_text][DEFAULT_CRT] elif field_number == 2: # default false if only one frame return [' ', UIDialog.true_field_text][art.frames > 1] elif field_number == 3: # default false if only one layer return [' ', UIDialog.true_field_text][art.layers > 1] def get_field_label(self, field_index): label = self.fields[field_index].label if field_index == 0: valid,_ = self.is_input_valid() if not valid: label %= '???' else: # calculate exported image size art = self.ui.active_art scale = int(self.field_texts[0]) width = art.charset.char_width * art.width * scale height = art.charset.char_height * art.height * scale label %= '%s x %s' % (width, height) # show how many images exported set will be elif field_index == 4: export_frames = bool(self.field_texts[2].strip()) export_layers = bool(self.field_texts[3].strip()) art = self.ui.active_art if export_frames and export_layers: label %= str(art.frames * art.layers) elif export_frames: label %= str(art.frames) elif export_layers: label %= str(art.layers) else: label %= '1' # preview frame + layer filename mutations based on current settings elif field_index == 5: export_frames = bool(self.field_texts[2].strip()) export_layers = bool(self.field_texts[3].strip()) art = self.ui.active_art fn = get_full_filename(self.filename, 0, art.layer_names[0], export_frames, export_layers, self.ui.app.forbidden_filename_chars) fn = os.path.basename(fn) label %= fn return label def is_input_valid(self): # scale factor: >0 int try: int(self.field_texts[0]) except: return False, self.invalid_scale_error if int(self.field_texts[0]) <= 0: return False, self.invalid_scale_error return True, None def confirm_pressed(self): valid, reason = self.is_input_valid() if not valid: return self.dismiss() # compile options for importer options = { 'scale': int(self.field_texts[0]), 'crt': bool(self.field_texts[1].strip()), 'frames': bool(self.field_texts[2].strip()), 'layers': bool(self.field_texts[3].strip()) } ExportOptionsDialog.do_export(self.ui.app, self.filename, options) class PNGSetExporter(ArtExporter): format_name = 'PNG image set' format_description = """ PNG image set for each frame and/or layer. """ file_extension = FILE_EXTENSION options_dialog_class = PNGSetExportOptionsDialog def run_export(self, out_filename, options): export_frames = options['frames'] export_layers = options['layers'] art = self.app.ui.active_art # remember user's active frame/layer/viz settings so we # can set em back when done start_frame = art.active_frame start_layer = art.active_layer start_onion = self.app.onion_frames_visible start_layer_viz = self.app.inactive_layer_visibility self.app.onion_frames_visible = False # if multi-player, only show active layer self.app.inactive_layer_visibility = LAYER_VIS_NONE if export_layers else LAYER_VIS_FULL success = True for frame in range(art.frames): # if exporting layers but not frames, only export active frame if not export_frames and frame != art.active_frame: continue art.set_active_frame(frame) for layer in range(art.layers): art.set_active_layer(layer) full_filename = get_full_filename(out_filename, frame, art.layer_names[layer], export_frames, export_layers, self.app.forbidden_filename_chars) if not export_still_image(self.app, art, full_filename, crt=options.get('crt', DEFAULT_CRT), scale=options.get('scale', DEFAULT_SCALE)): success = False # put everything back how user left it art.set_active_frame(start_frame) art.set_active_layer(start_layer) self.app.onion_frames_visible = start_onion self.app.inactive_layer_visibility = start_layer_viz return success