def prepare_tts(img, _, output_folder): # pylint: disable=R0914 """ Prepare a TTS sheet image. """ gimp.progress_init('Prepare a TTS sheet image...') pdb.gimp_undo_push_group_start(img) try: file_name, _ = _get_filename_backside(img, 'jpg') except Exception: # pylint: disable=W0703 pdb.gimp_undo_push_group_end(img) return parts = file_name.split('_') num = int(parts[-3]) rows = int(parts[-4]) columns = int(parts[-5]) new_width = columns * 750 new_height = rows * 1050 pdb.gimp_image_scale(img, new_width, new_height) json_path = re.sub(r'\.jpg$', '.json', pdb.gimp_image_get_filename(img)) try: with open(json_path, 'r') as fobj: cards = json.load(fobj) except Exception: # pylint: disable=W0703 pdb.gimp_undo_push_group_end(img) return cards = [c['path'] for c in cards] if len(cards) != num: pdb.gimp_undo_push_group_end(img) return card_rows = [ cards[i * columns:(i + 1) * columns] for i in range((len(cards) + columns - 1) // columns) ] if len(card_rows) != rows: pdb.gimp_undo_push_group_end(img) return for i, card_row in enumerate(card_rows): for j, card_path in enumerate(card_row): if not os.path.exists(card_path): pdb.gimp_undo_push_group_end(img) return card_layer = pdb.gimp_file_load_layer(img, card_path) pdb.gimp_image_insert_layer(img, card_layer, None, -1) rotation = _get_rotation(card_layer) if rotation: _rotate(card_layer, True) pdb.gimp_layer_set_offsets(card_layer, j * 750, i * 1050) pdb.gimp_image_merge_down(img, card_layer, 1) pdb.file_jpeg_save(img, img.layers[0], os.path.join(output_folder, file_name), file_name, 1, 0, 1, 0, '', 2, 1, 0, 0) pdb.gimp_undo_push_group_end(img)
def png(image=None): if not image: image = gimp.image_list()[0] prefix = pdb.gimp_image_get_filename(image)[:-4] + "_" gimp.progress_init("Save frames as {}_*.png".format(prefix)) for (layer_index, layer) in enumerate(image.layers): try: filename = "{}{:02d}.png".format(prefix, int(layer.name)) except ValueError: filename = "{}{}.png".format(prefix, layer.name) pdb.file_png_save( image, layer, filename, None, True, # interlace 9, # compression True, # bkgd True, # gama True, # offs True, # phys True, # time ) gimp.progress_update(100 * (layer_index + 1) / len(image.layers)) gimp.message("All frames saved as {}_*.png".format(prefix))
def pythonSaveToPSD(image): # Prep pdb.gimp_image_undo_group_start(image) pdb.gimp_context_push() # Code drawable = pdb.gimp_image_get_active_drawable(image) filename = pdb.gimp_image_get_filename(image) temp = filename.replace("_CLEAN", "") temp2 = temp.replace("_EDIT", "") temp = temp2.replace("_XCF", "") filename = temp.replace("_PSD", "") path = os.path.dirname(filename) path += "_PSD" name = os.path.basename(filename) out_psd = os.path.join(path, name) out_psd = os.path.splitext(out_psd)[0] + '.psd' # Create folder if not os.path.exists(path): os.makedirs(path) # Save in PSD pdb.gimp_file_save(image, drawable, out_psd, out_psd) pdb.gimp_image_clean_all(image) # Finish pdb.gimp_context_pop() pdb.gimp_image_undo_group_end(image) pdb.gimp_displays_flush()
def pythonSaveToClean(image): # Prep pdb.gimp_image_undo_group_start(image) pdb.gimp_context_push() # Code filename_old = pdb.gimp_image_get_filename(image) filename = filename_old.replace("_CLEAN", "") # drawable = pdb.gimp_image_get_active_drawable(image) path = os.path.dirname(filename) path += "_CLEAN" name = os.path.basename(filename) out_file = os.path.join(path, name) # Create CLEAN folder if not os.path.exists(path): os.makedirs(path) # Merge visible layers in new image and export in CLEAN folder new_image = pdb.gimp_image_duplicate(image) layer = pdb.gimp_image_merge_visible_layers(new_image, CLIP_TO_IMAGE) pdb.gimp_file_save(new_image, layer, out_file, out_file) pdb.gimp_image_delete(new_image) pdb.gimp_image_clean_all(image) # Finish pdb.gimp_context_pop() pdb.gimp_image_undo_group_end(image) pdb.gimp_displays_flush()
def pythonSaveToEditJpeg(image): # Prep pdb.gimp_image_undo_group_start(image) pdb.gimp_context_push() # Code # drawable = pdb.gimp_image_get_active_drawable(image) filename = pdb.gimp_image_get_filename(image) temp = filename.replace("_CLEAN", "") temp2 = temp.replace("_EDIT", "") filename = temp2.replace("_XCF", "") path = os.path.dirname(filename) path += "_EDIT" name = os.path.basename(filename) out_file = os.path.join(path, name) out_file = os.path.splitext(out_file)[0] + '.jpg' # Create _EDIT folder if not os.path.exists(path): os.makedirs(path) # Merge visible layers in new image and export in JPEG new_image = pdb.gimp_image_duplicate(image) layer = pdb.gimp_image_merge_visible_layers(new_image, CLIP_TO_IMAGE) pdb.gimp_file_save(new_image, layer, out_file, out_file) pdb.gimp_image_delete(new_image) pdb.gimp_image_clean_all(image) # Finish pdb.gimp_context_pop() pdb.gimp_image_undo_group_end(image) pdb.gimp_displays_flush()
def _get_filename_backside(img, file_type='png'): """ Determine card side and output file name. """ file_name = pdb.gimp_image_get_filename(img) file_name = os.path.split(file_name)[-1] file_name = '.'.join(file_name.split('.')[:-1]) back_side = file_name.endswith('-Back-Face') or file_name.endswith('-2') file_name = file_name + '.' + file_type return (file_name, back_side)
def gif(image=None, suffix=None, fps=24): if not image: image = gimp.image_list()[0] file_path = pdb.gimp_image_get_filename(image)[:-4] if suffix: file_path += "_" + suffix.strip() file_path += ".gif" ms = int(1000.0 / fps) temp_image = False try: gimp.progress_init( "Save animated GIF @ {} fps = {} ms/frame as {}".format( fps, ms, file_path)) if pdb.gimp_image_base_type(image) != 2: temp_image = True image = pdb.gimp_image_duplicate(image) pdb.gimp_image_convert_indexed( image, 0, # dither-type=CONVERT-DITHER-NONE 0, # palette-type=CONVERT-PALETTE-GENERATE 255, # num-cols False, # alpha-dither False, # remove-unused "" # palette ) gimp.progress_update(50) pdb.file_gif_save( image, image.layers[0], file_path, file_path, True, # interlace True, # loop ms, # default-delay 2 # default-dispose ) gimp.progress_update(100) gimp.message("Saved animated GIF @ {} fps = {} ms/frame as {}".format( fps, ms, file_path)) finally: if temp_image: pdb.gimp_image_delete(image)
def sheet(image=None, cols=0): if not image: image = gimp.image_list()[0] if not cols: best = (1, 10000000) for cols in range(1, len(image.layers) + 1): rows = (len(image.layers) + (cols - 1)) // cols (sheet_width, sheet_height) = (cols * image.width, rows * image.height) sheet_aspect_ratio = sheet_width / sheet_height if sheet_width > sheet_height else sheet_height / sheet_width if sheet_aspect_ratio < best[1]: best = (cols, sheet_aspect_ratio) cols = best[0] file_path = "{}_sheet_{}_frames_{}_columns_{}x{}.png".format( pdb.gimp_image_get_filename(image)[:-4], len(image.layers), cols, image.width, image.height) gimp.progress_init("Save sheet as {}".format(file_path)) rows = (len(image.layers) + (cols - 1)) // cols sheet = pdb.gimp_image_new(image.width * cols, image.height * rows, 0) try: sheet_layer = pdb.gimp_layer_new( sheet, sheet.width, sheet.height, 1, # type = RGBA-IMAGE "sprite sheet", 100, # opacity = 100 % 0 # mode = LAYER-MODE-NORMAL-LEGACY ) pdb.gimp_image_insert_layer(sheet, sheet_layer, None, 0) (row, col) = (0, 0) for (layer_index, layer) in enumerate(image.layers): pdb.gimp_selection_none(image) pdb.gimp_layer_resize_to_image_size(layer) pdb.gimp_edit_copy(layer) floating = pdb.gimp_edit_paste(sheet_layer, True) (left, top) = floating.offsets pdb.gimp_layer_translate(floating, col * image.width - left, row * image.height - top) pdb.gimp_floating_sel_anchor(floating) col += 1 if col >= cols: col = 0 row += 1 gimp.progress_update(100 * (layer_index + 1) / len(image.layers)) pdb.file_png_save( sheet, sheet_layer, file_path, None, True, # interlace 9, # compression True, # bkgd True, # gama True, # offs True, # phys True, # time ) gimp.message("All frames saved as {}".format(file_path)) finally: pdb.gimp_image_delete(sheet)
def cutter_single_image( image, drawable, limit, sl_thresh, sz_thresh, bg_manual, bg_color, bg_corner, bg_x, bg_y, padding, deskew, sq_crop, autoclose, save_same, save_dir, save_ftype, save_dpi, jpg_qual, save_suffix ): img_width = pdb.gimp_image_width(image) img_height = pdb.gimp_image_height(image) img_fullpath = pdb.gimp_image_get_filename(image) img_filename = os.path.basename(img_fullpath) img_name = '.'.join(img_filename.split('.')[:-1]) img_ext = save_ftype or img_filename.split('.')[-1].lower() new_filename_tpl = ''.join([ img_name, '-', save_suffix, '-', '%0', str(len(str(int(limit + 1)))), 'd', '.', img_ext ]) new_fullpath_tpl = os.path.join( os.path.dirname(img_fullpath) if save_same else save_dir, new_filename_tpl ) # gimp.message(new_fullpath_tpl) # function code goes here... gimp.context_push() pdb.gimp_image_undo_disable(image) # If the background wasn't manually defined, pick the colour from one of the four corners # (using radius 5 average) if not bg_manual: if bg_corner in (1, 3): bg_x = img_width - bg_x if bg_corner in (2, 3): bg_y = img_height - bg_y bg_color = pdb.gimp_image_pick_color(image, drawable, bg_x, bg_y, True, True, 5) pdb.gimp_context_set_defaults() pdb.gimp_context_set_antialias(True) pdb.gimp_context_set_sample_transparent(True) pdb.gimp_context_set_sample_threshold_int(sl_thresh) pdb.gimp_context_set_feather(True) fr = min(img_width, img_height) / 100.0 # NOTE why??? pdb.gimp_context_set_feather_radius(fr, fr) pdb.gimp_context_set_background(bg_color) pdb.gimp_image_select_color(image, gimpfu.CHANNEL_OP_REPLACE, drawable, bg_color) # convert inverted copy of the background selection to a path pdb.gimp_selection_sharpen(image) pdb.gimp_selection_invert(image) # _, before = pdb.gimp_image_get_vectors(image) pdb.plug_in_sel2path(image, drawable) # _, after = pdb.gimp_image_get_vectors(image) # newpath_id = list(set(after) - set(before))[0] # newpath = gimp.Vectors.from_id(newpath_id) # looks like newly created vector is always active, so this should be sufficent newpath = pdb.gimp_image_get_active_vectors(image) pdb.gimp_context_set_feather(False) _, strokes = pdb.gimp_vectors_get_strokes(newpath) extracted = 0 for stroke_id in strokes: stroke_points = pdb.gimp_vectors_stroke_get_points(newpath, stroke_id) # skip not closed paths if not stroke_points[3]: continue temp_vector = pdb.gimp_vectors_new(image, '-temp-') pdb.gimp_image_insert_vectors(image, temp_vector, None, -1) pdb.gimp_vectors_stroke_new_from_points(temp_vector, *stroke_points) pdb.gimp_image_select_item(image, gimpfu.CHANNEL_OP_REPLACE, temp_vector) pdb.gimp_image_remove_vectors(image, temp_vector) # check for minimum size bounds = pdb.gimp_selection_bounds(image) sizex = bounds[3] - bounds[1] sizey = bounds[4] - bounds[2] if (min(sizex, sizey) < sz_thresh or sizex >= img_width or sizey >= img_height): continue buffname = "dsibuff" if deskew and pdb.gimp_procedural_db_proc_exists('gimp_deskew_plugin'): pdb.gimp_progress_set_text('Running deskew plugin...') pdb.gimp_image_select_rectangle( image, gimpfu.CHANNEL_OP_REPLACE, bounds[1], bounds[2], sizex, sizey ) buffname = pdb.gimp_edit_named_copy(drawable, buffname) temp_image = pdb.gimp_edit_named_paste_as_new(buffname) temp_layer = pdb.gimp_image_get_active_layer(temp_image) pdb.gimp_image_undo_disable(temp_image) pdb.gimp_layer_flatten(temp_layer) # RUN_NONINTERACTIVE causes 'calling error' exception pdb.gimp_deskew_plugin(temp_image, temp_layer, 0, 0, 0, 0, True, run_mode=gimpfu.RUN_INTERACTIVE) pdb.gimp_image_resize_to_layers(temp_image) pdb.gimp_layer_flatten(temp_layer) pdb.gimp_image_select_contiguous_color( temp_image, gimpfu.CHANNEL_OP_REPLACE, temp_layer, 0, 0 ) pdb.gimp_selection_invert(temp_image) bounds = pdb.gimp_selection_bounds(temp_image) sizex = bounds[3] - bounds[1] sizey = bounds[4] - bounds[2] pdb.gimp_selection_none(temp_image) pdb.gimp_image_crop(temp_image, sizex, sizey, bounds[1], bounds[2]) if (sq_crop and sizex != sizey and pdb.gimp_procedural_db_proc_exists('script_fu_addborder')): if sizex > sizey: dx = 0 dy = (sizex - sizey) * 0.5 else: dx = (sizey - sizex) * 0.5 dy = 0 pdb.script_fu_addborder(temp_image, temp_layer, dx, dy, bg_color, 0) pdb.gimp_image_raise_item_to_top(temp_image, temp_layer) pdb.gimp_image_merge_visible_layers(temp_image, gimpfu.EXPAND_AS_NECESSARY) temp_layer = pdb.gimp_image_get_active_layer(temp_image) else: temp_image = image pdb.gimp_image_undo_disable(temp_image) temp_layer = pdb.gimp_image_get_active_layer(temp_image) if sq_crop: c_x = 0.5 * (bounds[1] + bounds[3]) c_y = 0.5 * (bounds[2] + bounds[4]) hl = padding + max(sizex, sizey) * 0.5 sel_x = c_x - hl sel_y = c_y - hl sel_w = sel_h = 2 * hl else: sel_x = bounds[1] sel_y = bounds[2] sel_w = sizex sel_h = sizey pdb.gimp_image_select_rectangle( temp_image, gimpfu.CHANNEL_OP_REPLACE, sel_x, sel_y, sel_w, sel_h ) buffname = pdb.gimp_edit_named_copy(drawable, buffname) temp_image = pdb.gimp_edit_named_paste_as_new(buffname) temp_layer = pdb.gimp_image_get_active_layer(temp_image) if padding and pdb.gimp_procedural_db_proc_exists('script_fu_addborder'): pdb.script_fu_addborder(temp_image, temp_layer, padding, padding, bg_color, 0) pdb.gimp_image_merge_visible_layers(temp_image, gimpfu.EXPAND_AS_NECESSARY) temp_layer = pdb.gimp_image_get_active_layer(temp_image) pdb.gimp_image_undo_enable(temp_image) temp_display = pdb.gimp_display_new(temp_image) extracted += 1 filename = new_fullpath_tpl % (extracted, ) pdb.gimp_image_set_resolution(temp_image, save_dpi, save_dpi) if img_ext == 'jpg': pdb.file_jpeg_save( temp_image, temp_layer, filename, filename, jpg_qual, 0.1, 1, 1, '', 2, 0, 0, 1 ) else: pdb.gimp_file_save(temp_image, temp_layer, filename, filename) if autoclose: pdb.gimp_display_delete(temp_display) if extracted >= limit: break pdb.gimp_progress_set_text('Extracted %d images' % (extracted, )) pdb.gimp_image_remove_vectors(image, newpath) pdb.gimp_selection_none(image) pdb.gimp_image_undo_enable(image) pdb.gimp_progress_end() pdb.gimp_displays_flush() gimp.context_pop() return extracted