Tile Layer
Tile a layer in a single direction.
Intro
For one project, I wanted a seamless horizontal background - and the default “Tile Seamless” filter forced both directions at once, which wasn’t the effect I was after.
So I’ve automated the steps in this instructables.com guide to tile a layer in a single direction. It leaves the original image untouched, and optionally will demo the finished effect or leave the newly created layers separate for you to fine-tune manually.
def __init__(self, args):
self.image, layer, args = args
if not pdb.gimp_drawable_is_layer(layer):
layer = pdb.gimp_image_get_active_layer(self.image)
if not layer:
raise MyError("Please select a layer")
pdb.gimp_context_set_defaults()
# work on a copy of the layer
self.layer = pdb.gimp_layer_copy(layer, True)
pdb.gimp_image_insert_layer(self.image, self.layer, None, pdb.gimp_image_get_item_position(self.image, layer) - 1)
self.layer.name = layer.name + ' (Tileable)'
# get our dimensions
self.width, self.height = self.layer.width, self.layer.height
# including if the layer is not the same size as the image
self.offx, self.offy = self.layer.offsets
self.direction = args['direction']
if self.direction == 0:
aslice = (self.width/100) * args['size']
names = [ 'Right', 'Left', 'Demo Tiles' ]
resize = [ self.width - aslice, self.height, -aslice/2, 0 ]
translate = [ self.width - aslice, 0, -self.width + aslice, 0 ]
else:
aslice = (self.height/100) * args['size']
names = [ 'Bottom', 'Top', 'Demo Tiles' ]
resize = [ self.width, self.height - aslice, 0, -aslice/2 ]
translate = [ 0, self.height - aslice, 0, -self.height + aslice ]
# do one side of the image
layer1 = self.copy_chunk(aslice)
layer1.name = 'Tiling: '+names[0]+' Blend'
# and then the other
layer2 = self.copy_chunk(-aslice)
layer2.name = 'Tiling: '+names[1]+' Blend'
# crop the layer edges
pdb.gimp_layer_resize(self.layer, resize[0], resize[1], resize[2], resize[3])
pdb.gimp_layer_resize(layer1, resize[0], resize[1], resize[2], resize[3])
pdb.gimp_layer_resize(layer2, resize[0], resize[1], resize[2], resize[3])
# combine the edge/masks
if args['merge']:
merged = pdb.gimp_image_merge_down(self.image, layer1, CLIP_TO_BOTTOM_LAYER)
merged = pdb.gimp_image_merge_down(self.image, merged, CLIP_TO_BOTTOM_LAYER)
# demo the tiling
if args['merge'] and args['demo']:
for i in range(2):
demo = pdb.gimp_layer_copy(merged, True)
pdb.gimp_image_insert_layer(self.image, demo, None, pdb.gimp_image_get_item_position(self.image, merged) - (i+1))
pdb.gimp_layer_translate(demo, translate[i*2], translate[(i*2)+1])
demo = pdb.gimp_image_merge_down(self.image, demo, CLIP_TO_IMAGE)
demo.name = names[2]
pass
def copy_chunk(self, aslice):
if self.direction == 0:
x0 = 0 if aslice >= 0 else self.width + aslice
x1 = self.width - aslice if aslice >= 0 else 0
select = [ x0 + self.offx, self.offy, (x0 + abs(aslice) + self.offx), self.height ]
translate = [ x1 - x0, 0 ]
resize = [ x1, 0 ]
gradient = [ (x1 - min(0, aslice)), self.offy, (x1 - min(0, aslice)) + aslice, self.offy ]
else:
y0 = 0 if aslice >= 0 else self.height + aslice
y1 = self.height - aslice if aslice >= 0 else 0
select = [ self.offx, y0 + self.offy, self.width, (y0 + abs(aslice) + self.offy) ]
translate = [ 0, y1 - y0 ]
resize = [ 0, y1 ]
gradient = [ self.offx, (y1 - min(0, aslice)), self.offx, (y1 - min(0, aslice)) + aslice ]
# copy one bit of the base layer
pdb.gimp_image_select_rectangle(self.image, CHANNEL_OP_REPLACE, select[0],select[1], select[2],select[3])
pdb.gimp_edit_copy(self.layer)
layer_id = pdb.gimp_edit_paste(self.layer, False)
# move it to the other side
pdb.gimp_layer_translate(layer_id, translate[0],translate[1])
# stop floating and resize it to the base dimensions
pdb.gimp_floating_sel_to_layer(layer_id)
pdb.gimp_layer_resize(layer_id, self.width, self.height, resize[0],resize[1])
# add the layer mask which does the actual blending
mask_id = pdb.gimp_layer_create_mask(layer_id, ADD_WHITE_MASK)
pdb.gimp_layer_add_mask(layer_id, mask_id)
pdb.gimp_drawable_edit_gradient_fill(mask_id, GRADIENT_LINEAR, 0, False,0,0.0, False, gradient[0],gradient[1], gradient[2],gradient[3])
return layer_id
pass