#!/usr/bin/env python # sprite_gutter_remove # Version 1.1 # Copyright 2012 David 'The Visible Man' Braun # GIMP plugin to remove padding/spacing from 2D Spritesheets # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # See for a copy of the GNU General Public License from gimpfu import * import os gettext.install("gimp20-python", gimp.locale_directory, unicode=True) def python_sprite_gutter_remove(img, tdrawable, padding=1, spacing=0, tile_width=32, tile_height=32, \ resize=1, padding_edge=True, spacing_edge=False, preserve_undo=True): old_width = img.width old_height = img.height tile_width = int(tile_width) tile_height = int(tile_height) padding = int(padding) spacing = int(spacing) if img.width>0 and img.height>0 and tile_width>0 and tile_height>0 and (padding>0 or spacing>0): new_width = old_width new_height = old_height if spacing_edge: # Remove spacing along image edges new_width -= spacing*2 new_height -= spacing*2 if not padding_edge: # Offset edge padding assumption in equation new_width += padding*2 new_height += padding*2 columns = (new_width+spacing) / (tile_width + padding*2 + spacing) rows = (new_height+spacing) / (tile_height + padding*2 + spacing) new_width = columns*tile_width new_height = rows*tile_height if resize == 1: # Multiple of four new_width = (new_width + 3) & ~0x03 new_height = (new_height + 3) & ~0x03 elif resize == 2: # Power of two new_width-=1 new_width |= new_width >> 1 new_width |= new_width >> 2 new_width |= new_width >> 4 new_width |= new_width >> 8 new_width |= new_width >> 16 new_width+=1 new_height-=1 new_height |= new_height >> 1 new_height |= new_height >> 2 new_height |= new_height >> 4 new_height |= new_height >> 8 new_height |= new_height >> 16 new_height+=1 if preserve_undo: # Start undo group pdb.gimp_image_undo_group_start(img) else: # Don't track specific undo history for this next section pdb.gimp_image_undo_disable(img) # Make sure feather isn't enabled pdb.gimp_context_set_feather(FALSE) # We use the active layer as the source layer source_layer = img.active_layer # Work on a new layer placed above active layer dest_layer = pdb.gimp_layer_copy(source_layer, True) pdb.gimp_image_insert_layer(img, dest_layer, None, -1) dest_layer.fill(TRANSPARENT_FILL) # Compress rows offset = ((padding_edge and padding) or 0) + ((spacing_edge and spacing) or 0) multiplier = (tile_height + padding*2 + spacing) right_edge = old_width - offset # Don't want to copy any padding on right edge, or we'd have to go back and clean it for row in range(rows): pos = row*multiplier + offset # Copy original pdb.gimp_image_select_rectangle(img, 2, 0, pos, right_edge, tile_height) success = pdb.gimp_edit_copy(source_layer) # Paste in destination pdb.gimp_image_select_rectangle(img, 2, 0, (row*tile_height), right_edge, tile_height) floating_sel = pdb.gimp_edit_paste(dest_layer, FALSE) pdb.gimp_floating_sel_anchor(floating_sel) # Compress columns multiplier = (tile_width + padding*2 + spacing) for col in range(columns): pos = col*multiplier + offset # Cut from destination pdb.gimp_image_select_rectangle(img, 2, pos, 0, tile_width, new_height) success = pdb.gimp_edit_cut(dest_layer) # Paste in destination pdb.gimp_image_select_rectangle(img, 2, (col*tile_width), 0, tile_width, new_height) if dest_layer.has_alpha: pdb.gimp_edit_clear(dest_layer) # Prevent spacing between columns from affecting tiles floating_sel = pdb.gimp_edit_paste(dest_layer, FALSE) pdb.gimp_floating_sel_anchor(floating_sel) # Resize the image to fit the new dimensions img.resize(new_width, new_height,0,0) #Resize our resulting layer pdb.gimp_layer_resize_to_image_size(dest_layer) # Hide the old layer source_layer.visible = False if preserve_undo: # End undo group pdb.gimp_image_undo_group_end(img) else: # Re-enable undo history pdb.gimp_image_undo_enable(img) register( proc_name=("python_fu_sprite_gutter_remove"), blurb=("Removes padding and spacing from a 2D Spritesheet. \n\ Padding is applied on all four sides of each tile. \n\ Spacing is applied between each tile. \n\ Disable undo history to improve performance."), help=("Removes padding/gutter from spritesheets"), author=("The Visible Man"), copyright=("GPLv3, David 'The Visible Man' Braun"), date=("2012"), label=("Remove Gutter"), imagetypes=("*"), params=[ (PF_IMAGE, "img", "Image", None), (PF_DRAWABLE, "tdrawable", "Drawable", None), (PF_SPINNER, "padding", "Padding:", 1, (0, 32, 1)), (PF_SPINNER, "spacing", "Spacing:", 0, (0, 32, 1)), (PF_SPINNER, "tile_width", "Tile Width:", 32, (1, 1024, 1)), (PF_SPINNER, "tile_height", "Tile Height:", 32, (1, 1024, 1)), (PF_OPTION, "resize", "Resize:", 1, ["Minimum", "Multiple of four", "Power of two"]), (PF_TOGGLE, "padding_edge", "Padding at image edge:", True), (PF_TOGGLE, "spacing_edge", "Spacing at image edge:", False), (PF_TOGGLE, "preserve_undo", "Preserve Undo History:", True), ], results=[], function=(python_sprite_gutter_remove), menu=("/Filters/Sprite Sheet"), domain=("gimp20-python", gimp.locale_directory), ) main()