Tile Layer

Header image for Tile Layer

Tile a layer in a single direction.

7 minute reading time of 1488 words (inc code) Code available at github.com

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

Reply via email