def cree_background(inLayer, inLayerF, Img): """Add background to inLayer""" newlayer = pdb.gimp_layer_copy(inLayer, True) newfond = pdb.gimp_layer_copy(inLayerF, True) layername = pdb.gimp_item_get_name(inLayer) pdb.gimp_item_set_visible(newlayer, True) pdb.gimp_image_insert_layer(Img, newlayer, None, 0) pdb.gimp_image_set_active_layer(Img, inLayer) pdb.gimp_image_insert_layer(Img, newfond, None, -1) pdb.gimp_image_lower_item(Img, newfond) pdb.gimp_item_set_visible(newfond, 1) pdb.gimp_context_set_sample_transparent(True) pdb.gimp_image_select_contiguous_color(Img, CHANNEL_OP_REPLACE, newlayer, 10, 10) pdb.gimp_edit_clear(newfond) pdb.gimp_item_set_visible(inLayer, True) clipped_layer = pdb.gimp_image_merge_down(Img, inLayer, CLIP_TO_IMAGE) pdb.gimp_item_set_name(clipped_layer, layername) pdb.gimp_selection_invert(Img) pdb.gimp_context_set_foreground((117, 117, 154)) pdb.gimp_edit_fill(newlayer, FILL_FOREGROUND) floating_sel = pdb.gimp_edit_paste(newlayer, 0) pdb.gimp_layer_set_opacity(floating_sel, 70) pdb.gimp_floating_sel_anchor(floating_sel) pdb.gimp_layer_set_opacity(newlayer, 85) pdb.gimp_selection_none(Img) layerfinal = pdb.gimp_image_get_layer_by_name(Img, layername) pdb.gimp_item_set_visible(layerfinal, False)
def caches(inImg, inNameLayerFleche, inNameLayerFond): path_cadenas = GRAPH_PATH + "images/cadenas.png" imagecadenas = pdb.gimp_file_load(path_cadenas, path_cadenas) layercadenas = pdb.gimp_image_get_active_layer(imagecadenas) pdb.gimp_selection_all(imagecadenas) pdb.gimp_edit_copy(layercadenas) pdb.gimp_image_delete(imagecadenas) layerfond = pdb.gimp_image_get_layer_by_name(inImg, inNameLayerFond) layerfleche = pdb.gimp_image_get_layer_by_name(inImg, inNameLayerFleche) _, alayers = pdb.gimp_image_get_layers(inImg) for layercurrent in alayers: pdb.gimp_selection_none(inImg) layercurrent = gimp.Item.from_id(layercurrent) pdb.script_fu_add_bevel(inImg, layercurrent, 5, 0, 0) pdb.gimp_item_set_visible(layercurrent, False) layername = pdb.gimp_item_get_name(layercurrent) if not (layername == inNameLayerFleche or layername == inNameLayerFond): cree_background(layercurrent, layerfond, inImg) cache = pdb.gimp_image_merge_visible_layers(inImg, CLIP_TO_IMAGE) pdb.script_fu_add_bevel(inImg, cache, 5, 0, 0) pdb.gimp_item_set_name(cache, "cache.png") pdb.gimp_image_lower_item_to_bottom(inImg, layerfleche) pdb.gimp_image_lower_item_to_bottom(inImg, cache) pdb.gimp_image_lower_item_to_bottom(inImg, layerfond)
def load_caches(args): inColorFondR, inColorFondG, inColorFondB, outDir = args.split(" ") inDir, inNameLayerFleche = GRAPH_PATH + "layers/", "layer_fleche-1.png" inColorFondR, inColorFondG, inColorFondB = int(inColorFondR), int( inColorFondG), int(inColorFondB) nb, listimg = pdb.file_glob(inDir + "*.png", 1) baseimage = pdb.gimp_image_new(10, 10, RGB) fondcolor = (inColorFondR, inColorFondG, inColorFondB) for filename in listimg: layer = pdb.gimp_file_load_layer(baseimage, filename) pdb.gimp_image_insert_layer(baseimage, layer, None, 0) pdb.gimp_image_resize_to_layers(baseimage) pdb.gimp_message("Layers chargés") pdb.gimp_selection_all(baseimage) layerfond = pdb.gimp_image_get_layers(baseimage)[1][0] layerfond = gimp.Item.from_id(layerfond) fond = pdb.gimp_layer_copy(layerfond, 1) _, _, _, xmax, ymax = pdb.gimp_selection_bounds(baseimage) pdb.gimp_item_set_name(fond, "layer_fond.png") pdb.gimp_image_insert_layer(baseimage, fond, None, 0) pdb.gimp_edit_clear(fond) pdb.gimp_image_select_round_rectangle(baseimage, CHANNEL_OP_REPLACE, 0, 0, xmax, ymax, 35, 35) pdb.gimp_selection_shrink(baseimage, 3) pdb.gimp_selection_feather(baseimage, 20) pdb.gimp_context_set_foreground(fondcolor) pdb.gimp_edit_fill(fond, FILL_FOREGROUND) pdb.gimp_image_lower_item_to_bottom(baseimage, fond) pdb.plug_in_hsv_noise(baseimage, fond, 5, 38, 63, 74) pdb.gimp_selection_none(baseimage) pdb.gimp_message("Fond créé") caches(baseimage, inNameLayerFleche, "layer_fond.png") pdb.gimp_message("Cache créé") layercache = pdb.gimp_image_get_layer_by_name(baseimage, "cache.png") layerfond = pdb.gimp_image_get_layer_by_name(baseimage, "layer_fond.png") layerfleche = pdb.gimp_image_get_layer_by_name(baseimage, inNameLayerFleche) pdb.gimp_item_set_visible(layerfond, True) pdb.gimp_image_merge_down(baseimage, layercache, CLIP_TO_IMAGE) pdb.gimp_item_set_visible(layerfleche, True) pdb.gimp_image_merge_down(baseimage, layerfleche, CLIP_TO_IMAGE) pdb.gimp_image_scale(baseimage, 900, 550) # drawable = pdb.gimp_image_get_active_drawable(baseimage) pdb.script_fu_multiple_layer_actions(baseimage, None, 0, 0, (0, 0, 0), 4, 0, 0, 0, 0, 0) pdb.gimp_message("Taille de l'image ajustée") pdb.script_fu_export_layers(baseimage, None, outDir, "~l") pdb.gimp_message("Layers enregistrés")
def stack(target=None): for image in gimp.image_list(): pdb.gimp_selection_none(image) if image.layers: if not target: target = image elif image != target: for layer in image.layers: pdb.gimp_edit_cut(layer) floating = pdb.gimp_edit_paste(target.layers[0], True) pdb.gimp_floating_sel_to_layer(floating)
def cookie_cutter_letter(img, substrate, right, font, letter): '''Cut text shaped like letter out of the given layer.''' temp_layer = gpdb.gimp_text_fontname(img, substrate, right, 0, letter, 1, False, FONT_HEIGHT, PIXELS, font) gpdb.gimp_selection_layer_alpha(temp_layer) angle = random.uniform(*ANGLE_RANGE) xaxis = right yaxis = 15 # srcX = float(xaxis) # dstX = float(srcX + random.uniform(0, 25)) # srcY = float(yaxis) # dstY = float(srcY + random.uniform(0, 25)) # scaleX = scaleY = float(100) # We need to save the selection as a channel so we can mess with # the letter form. shape = gpdb.gimp_selection_save(img) gpdb.gimp_selection_none(img) gpdb.gimp_floating_sel_remove(temp_layer) # Distort the form of the individual letter: shape = gpdb.gimp_item_transform_rotate(shape, angle, 0, xaxis, yaxis) # We aren't doing any letter warping now, but if we were, this is the # point where it should be done. We want to warp the shape of textLayer, # which later serves as a cutout for the dark noise layer. If we warp the # dark noise layer directly we will end up with warped dots. # # gpdb.gimp_context_set_transform_resize(TRANSFORM_RESIZE_CROP) # shape = gpdb.gimp_item_transform_2d(shape, srcX, srcY, angle, # scaleX, scaleY, dstX, dstY) gpdb.gimp_selection_load(shape) img.remove_channel(shape) # Note the bounding box of the letter form so we can figure out # where the next one should go. bounds = gpdb.gimp_selection_bounds(img) new_right = bounds[3] + LETTER_SPACING # Actually cut the letter form out of the substate. gpdb.gimp_selection_invert(img) gpdb.gimp_edit_clear(substrate) gpdb.gimp_selection_none(img) return new_right
def mirror(image=None): if not image: image = gimp.image_list()[0] max_layer = 0 for layer in image.layers: try: if int(layer.name) > max_layer: max_layer = int(layer.name) except ValueError: pass layers_to_reverse = image.layers[1:] pdb.gimp_selection_none(image) for layer in layers_to_reverse: pdb.gimp_edit_copy(layer) floating = pdb.gimp_edit_paste(image.layers[0], True) pdb.gimp_floating_sel_to_layer(floating) max_layer += 1 floating.name = str(max_layer)
def draw_mark( image, # type: gimp.Image directions, x0, # type: int y0, # type: int size, # type: int distance # type: int ): # type: (...) -> None """Draws a mark at position where one must cut or fold the paper.""" x, y, width, height = 0, 0, 0, 0 # type: int, int, int, int for direction in directions: # type: Direction if direction == Direction.UP: x = x0 - 1 y = y0 - distance - size width = 2 height = size elif direction == Direction.DOWN: x = x0 - 1 y = y0 + distance width = 2 height = size elif direction == Direction.LEFT: x = x0 - distance - size y = y0 - 1 width = size height = 2 elif direction == Direction.RIGHT: x = x0 + distance y = y0 - 1 width = size height = 2 else: gimp.message("Invalid direction %s" % repr(direction)) return pdb.gimp_image_select_rectangle(image, gimpfu.CHANNEL_OP_REPLACE, x, y, width, height) pdb.gimp_edit_fill(image.active_layer, gimpfu.FOREGROUND_FILL) pdb.gimp_selection_none(image)
def effet_texte(inColor, inImg): layer = pdb.gimp_image_get_active_layer(inImg) pdb.gimp_context_set_sample_transparent(True) pdb.gimp_image_select_contiguous_color(inImg, CHANNEL_OP_REPLACE, layer, 1, 1) pdb.gimp_selection_invert(inImg) _, x, _, x2, y2 = pdb.gimp_selection_bounds(inImg) xmiddle = x + (x2 - x) // 2 y = y2 - 1 keep = True while keep: if y < 0: print("Error in effet_texte for img {} : y < 0 !".format(inImg)) return if (not _is_transparent(inImg, layer, xmiddle, y)) and _is_black(inImg, layer, xmiddle, y): keep = False pdb.gimp_context_set_sample_transparent(False) pdb.gimp_image_select_contiguous_color(inImg, CHANNEL_OP_REPLACE, layer, xmiddle, y) pdb.gimp_edit_clear(layer) y -= 1 _, x1, y1, x2, y2 = pdb.gimp_selection_bounds(inImg) newlayer = pdb.gimp_layer_copy(layer, True) pdb.gimp_image_select_rectangle(inImg, CHANNEL_OP_REPLACE, x1, y1, x2-x1, y2-y1) pdb.gimp_context_set_sample_transparent(True) pdb.gimp_image_select_contiguous_color(inImg, CHANNEL_OP_SUBTRACT, layer, x1, y1) pdb.gimp_edit_clear(layer) pdb.gimp_selection_invert(inImg) pdb.gimp_image_insert_layer(inImg, newlayer, None, 0) pdb.gimp_edit_clear(newlayer) pdb.script_fu_layerfx_outer_glow(inImg, newlayer, inColor, 75, 0, 0, 0, 0, 5, 0, 1) pdb.gimp_image_merge_visible_layers(inImg, CLIP_TO_IMAGE) pdb.gimp_selection_none(inImg) pdb.gimp_displays_flush()
def copy_and_rotate_rectangle( src_image, # type: gimp.Image src_x, # type: int src_y, # type: int src_width, # type: int src_height, # type: int dst_layer, # type: gimp.Layer dst_x, # type: int dst_y, # type: int dst_corner, # type: Corner angle # type: int ): # type: (...) -> None """Copies a rectangular region from one image to another while also rotating it. """ pdb.gimp_image_select_rectangle(src_image, gimpfu.CHANNEL_OP_REPLACE, src_x, src_y, src_width, src_height) pdb.gimp_edit_copy_visible(src_image) pdb.gimp_selection_none(src_image) # Paste into dst as a floating selection floating = pdb.gimp_edit_paste(dst_layer, gimpfu.TRUE) # type: gimp.Layer # Rotate floating selection if needed angles = { 90: gimpfu.ROTATE_90, 180: gimpfu.ROTATE_180, 270: gimpfu.ROTATE_270 } # type: int if angle in angles: rotation = angles[angle] # type: int pdb.gimp_drawable_transform_rotate_simple(floating, rotation, gimpfu.FALSE, 0, 0, gimpfu.FALSE) # Move floating selection into position and anchor it move_drawable_to(floating, dst_corner, dst_x, dst_y) pdb.gimp_floating_sel_anchor(floating)
def texte(inR,inG,inB,inFichier,highlight_text,change_numero): print("\tLoading image {}".format(inFichier)) image = pdb.gimp_file_load(inFichier,inFichier) color = (inR,inG,inB) # pdb.gimp_display_new(image) if highlight_text: print("\t\tHighlighting text...") effet_texte(color, image) if change_numero > 0: print("\t\tChanging number...") change_num(image, change_numero) pdb.gimp_selection_none(image) layer_id = pdb.gimp_image_get_layers(image)[1][0] layer = gimp.Item.from_id(layer_id) pdb.script_fu_add_bevel(image, layer, 5, False, False) drawable = pdb.gimp_image_get_active_drawable(image) pdb.file_png_save(image, drawable, inFichier, inFichier, 0,5,0,0,0,0,0) pdb.gimp_image_delete(image)
def make_captcha(sx, sy, font_height, letter_spacing, left_margin, angle_range, fonts, answer): """Generate a captcha consisting of the letters in answer. :rtype: :class:`gimp.Image` :returns: The CAPTCHA as a gimp-python image object. """ img = gimp.Image(sx, sy, RGB_IMAGE) img.disable_undo() light_noise_layer = gimp.Layer(img, 'light noise', sx, sy, RGB_IMAGE, 100, NORMAL_MODE) img.add_layer(light_noise_layer, 0) gpdb.gimp_selection_none(img) gpdb.gimp_drawable_fill(light_noise_layer, WHITE_FILL) # plug_in_randomize_hurl at 1% 1 time is vastly superior to # scatter_rgb here, but has a bug where it creates an artifact at # the top of the image when invoked in a scripting context like # this. # # Future experiment: dial down the amount of noise generated by # scatter, then run it through levels to darken it, then # blur. This should be equivalent to hurl + blur. #gpdb.plug_in_randomize_hurl(img, light_noise_layer, 1, 1, 0, 0) gpdb.plug_in_scatter_hsv(img, light_noise_layer, 1, 25, 200, 180) gpdb.plug_in_gauss_iir(img, light_noise_layer, 1, 1, 1) gpdb.gimp_desaturate(light_noise_layer) # Next make pure black layer which we will copy repeatedly as a # place to cut out letters. blackLayer = gimp.Layer(img, 'black', sx, sy, RGB_IMAGE, 100, NORMAL_MODE) img.add_layer(blackLayer, 0) blackLayer.add_alpha() gpdb.gimp_layer_add_alpha(blackLayer) gpdb.gimp_drawable_fill(blackLayer, WHITE_FILL) gpdb.gimp_invert(blackLayer) # Loop through each letter, making it a separate black layer. right = left_margin last_substrate = None for letter in answer: font = random.choice(FONTS) substrate = blackLayer.copy() img.add_layer(substrate, 0) new_right = cookie_cutter_letter(img, substrate, right, font, letter) # look out for really narrow letters if new_right - right < 20: new_right += 5 right = new_right img.remove_layer(blackLayer) # Hide the light noise layer, then collapse all the remaining # layers (all letters) into a single layer. light_noise_layer.visible = False textLayer = gpdb.gimp_image_merge_visible_layers(img, CLIP_TO_IMAGE) light_noise_layer.visible = True # Create a layer of dark noise which will display the letters. dark_noise_layer = gimp.Layer(img, 'dark noise', sx, sy, RGB_IMAGE, 100, MULTIPLY_MODE) img.add_layer(dark_noise_layer, 1) gpdb.gimp_drawable_fill(dark_noise_layer, WHITE_FILL) gpdb.plug_in_randomize_hurl(img, dark_noise_layer, 25, 1, 0, 0) gpdb.gimp_desaturate(dark_noise_layer) # These next operations are ordered carefully. Changing the order # dramatically affects how the output looks. # Here's where we do the cutout operation. gpdb.gimp_selection_layer_alpha(textLayer) gpdb.gimp_selection_invert(img) gpdb.gimp_edit_clear(dark_noise_layer) gpdb.gimp_selection_none(img) # After the cutout, blur the dark noise layer and then darken it: gpdb.plug_in_gauss_iir(img, dark_noise_layer, 1, 1, 1) gpdb.gimp_levels(dark_noise_layer, HISTOGRAM_VALUE, 127, 255, 0.25, 0, 255) textLayer.visible = False # If you start gimp without --no-interface with an X server, this # line will let you see the image looks like at this point in the # script, layers and all. It should be fine to move this line to # any problematic part of the script for debugging. # # gimp.Display(gpdb.gimp_image_duplicate(img)) final = img.flatten() gpdb.gimp_image_clean_all(img) img.enable_undo() return img, final
def stickerify_bordure(image, current_layer, black_grow=3, white_grow=12, shadow=True, canvas_increase=0, resize=False): def duplicate_layer(): copy = current_layer.copy() image.add_layer(copy) # copy is added above so we want to go down a bit image.active_layer = current_layer return copy def fill_black(): pdb.gimp_edit_bucket_fill(current_layer, 1, 0, 100, 255, 0, 0, 0) def fill_white(): pdb.gimp_edit_bucket_fill(current_layer, 0, 0, 100, 255, 0, 0, 0) def set_colors(): pdb.gimp_context_set_foreground((255, 255, 255)) pdb.gimp_context_set_background((0, 0, 0)) pdb.gimp_context_push() pdb.gimp_image_undo_group_start(image) # clean selection to avoid bugs pdb.gimp_selection_none(image) set_colors() # resize early to avoid compressing the bordure if resize: width, height = image.width, image.height if width == height: new_width, new_height = 512, 512 elif width > height: new_width, new_height = 512, int(height * (512.0 / width)) elif width < height: new_width, new_height = int(width * (512.0 / height)), 512 pdb.gimp_image_scale(image, new_width, new_height) if canvas_increase: width, height = image.width, image.height width_increase = int(width * (canvas_increase / 100)) height_increase = int(height * (canvas_increase / 100)) pdb.gimp_image_resize(image, width + width_increase, height + height_increase, int(width_increase / 2), int(height_increase / 2)) pdb.gimp_layer_resize_to_image_size(current_layer) duplicate_layer() # alpha to selection pdb.gimp_image_select_item(image, 0, current_layer) pdb.gimp_selection_grow(image, black_grow) fill_black() second_layer = duplicate_layer() pdb.gimp_selection_grow(image, white_grow) fill_white() if shadow: duplicate_layer() fill_black() current_layer.translate(8, 8) pdb.gimp_selection_all(image) pdb.plug_in_gauss(image, current_layer, 20, 20, 0) pdb.gimp_layer_set_opacity(current_layer, 70) pdb.gimp_image_merge_down(image, second_layer, 0) if shadow: pdb.gimp_image_merge_down(image, image.active_layer, 0) pdb.gimp_layer_set_name(image.active_layer, "Sticker bordure") pdb.gimp_selection_none(image) pdb.gimp_image_undo_group_end(image) pdb.gimp_context_pop() pdb.gimp_displays_flush()
def draw(dst_image, copy_and_rotate_definitions): """Copies regions from the input image to a wrap image.""" dst_layer = gimp.Layer(dst_image, "Wrap", dst_image_width, dst_image_height, gimpfu.RGB_IMAGE, 100, gimpfu.NORMAL_MODE) # type: gimp.Layer dst_layer.fill(gimpfu.WHITE_FILL) dst_image.add_layer(dst_layer, 0) # Add guides for x in dst_xs: # type: int dst_image.add_vguide(x) for y in dst_ys: # type: int dst_image.add_hguide(y) # Take the layers from the template and move and rotate them # into position for d in copy_and_rotate_definitions: pdb.gimp_progress_pulse() copy_and_rotate_rectangle( src_image, # src_image d[0], # src_x d[1], # src_y d[2], # src_width d[3], # src_height dst_layer, # dst_layer d[4], # dst_x d[5], # dst_y d[6], # dst_corner d[7]) # rotation_angle # Copy strips from the sides to create the flaps on the front # and the back pdb.gimp_progress_pulse() copy_and_rotate_rectangle(dst_image, dst_xs[1], dst_ys[4], half_box_height_plus_extra, flap_size, dst_layer, dst_xs[5], dst_ys[4], Corner.BOTTOM_RIGHT, 90) pdb.gimp_progress_pulse() copy_and_rotate_rectangle(dst_image, dst_xs[1], dst_ys[6], half_box_height_plus_extra, flap_size, dst_layer, dst_xs[5], dst_ys[7], Corner.TOP_RIGHT, 270) pdb.gimp_progress_pulse() copy_and_rotate_rectangle(dst_image, dst_xs[6], dst_ys[4], half_box_height_plus_extra, flap_size, dst_layer, dst_xs[6], dst_ys[4], Corner.BOTTOM_LEFT, 270) pdb.gimp_progress_pulse() copy_and_rotate_rectangle(dst_image, dst_xs[6], dst_ys[6], half_box_height_plus_extra, flap_size, dst_layer, dst_xs[6], dst_ys[7], Corner.TOP_LEFT, 90) # Marks for cutting and folding draw_mark(dst_image, (Direction.UP, Direction.LEFT), dst_xs[4], dst_ys[1], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.UP, ), dst_xs[5], dst_ys[1], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.UP, ), dst_xs[6], dst_ys[1], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.UP, Direction.RIGHT), dst_xs[7], dst_ys[1], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.UP, Direction.LEFT), dst_xs[1], dst_ys[4], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.UP, Direction.RIGHT), dst_xs[10], dst_ys[4], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, Direction.LEFT), dst_xs[1], dst_ys[7], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, Direction.RIGHT), dst_xs[10], dst_ys[7], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, Direction.LEFT), dst_xs[4], dst_ys[10], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, ), dst_xs[5], dst_ys[10], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, ), dst_xs[6], dst_ys[10], crop_mark_size, crop_mark_distance) draw_mark(dst_image, (Direction.DOWN, Direction.RIGHT), dst_xs[7], dst_ys[10], crop_mark_size, crop_mark_distance) pdb.gimp_selection_none(dst_image)
def create_template( box_width_mm, # type: float box_height_mm, # type: float box_depth_mm # type: float ): # type: (...) -> None """Creates an empty template image given the box size.""" with DefaultContext(): box_width = mm_to_px(box_width_mm) # type: int box_height = mm_to_px(box_height_mm) # type: int box_depth = mm_to_px(box_depth_mm) # type: int xs, ys = template_coordinates(box_width, box_height, box_depth) image_width = xs[-1] - xs[0] # type: int image_height = ys[-1] - ys[0] # type: int # Create a template image with one transparent layer image = gimp.Image(image_width, image_height) # type: gimp.Image with PausedUndo(image): layer = gimp.Layer(image, "Template", image_width, image_height, gimpfu.RGBA_IMAGE, 100, gimpfu.NORMAL_MODE) # type: gimp.Layer image.add_layer(layer, 0) # Create guides for x in xs: # type: int image.add_vguide(x) for y in ys: # type: int image.add_hguide(y) # Fill the areas where the graphics go with white pdb.gimp_selection_none(image) pdb.gimp_progress_pulse() pdb.gimp_image_select_rectangle(image, gimpfu.CHANNEL_OP_ADD, xs[0], ys[1], image_width, ys[3] - ys[1]) pdb.gimp_progress_pulse() pdb.gimp_image_select_rectangle(image, gimpfu.CHANNEL_OP_ADD, xs[1], ys[0], xs[2] - xs[1], image_height) pdb.gimp_edit_fill(layer, gimpfu.WHITE_FILL) pdb.gimp_selection_none(image) def put_text(text, left, right, top, bottom): """Puts some text in the center of a rectangle.""" pdb.gimp_progress_pulse() text_size = DPI / 4 # type: int text_layer = pdb.gimp_text_layer_new( image, text, "sans-serif", text_size, gimpfu.PIXELS) # type: gimp.Layer image.add_layer(text_layer, 0) move_drawable_to(text_layer, Corner.CENTER, (left + right) // 2, (top + bottom) // 2) pdb.gimp_image_merge_down(image, text_layer, gimpfu.CLIP_TO_BOTTOM_LAYER) put_text("TOP", xs[1], xs[2], ys[0], ys[1]) put_text("LEFT", xs[0], xs[1], ys[1], ys[3]) put_text("FRONT", xs[1], xs[2], ys[1], ys[3]) put_text("RIGHT", xs[2], xs[3], ys[1], ys[3]) put_text("BACK", xs[3], xs[4], ys[1], ys[3]) put_text("BOTTOM", xs[1], xs[2], ys[3], ys[4]) put_text( "Box width: %dmm (%dpx)\n" "Box height: %dmm (%dpx)\n" "Box depth: %dmm (%dpx)" % (box_width_mm, box_width, box_height_mm, box_height, box_depth_mm, box_depth), xs[0], xs[1], ys[0], ys[1]) gimp.Display(image) gimp.displays_flush()
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