/usr/lib/gimp/2.0/plug-ins/plugin-render-texture.py is in gimp-plugin-registry 7.20140602ubuntu3.
This file is owned by root:root, with mode 0o755.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 | #!/usr/bin/env python
'''
Gimp plugin.
Create new image having texture synthesized from the selection.
Works best if selection is natural (fractal).
Can work with man-made regular texture.
Works worst with man-made, structured but not regular, symbols.
Sometimes called rendering a texture.
Requires resynthesizer plug-in.
Author:
lloyd konneker, lkk, bootch at nc.rr.com
Version:
1.0 lkk 7/15/2010 Initial version
1.1 lkk 4/10/2011 Fixed a bug with layer types impacting greyscale images.
License:
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 2 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.
The GNU Public License is available at
http://www.gnu.org/copyleft/gpl.html
The effect for users:
Similar to "Fill resynthesized pattern" except:
- here the arguments are reversed: you select a texture and create a new image
instead of selecting an area and choosing a pattern.
- here the result is less random (since Fill resynthesized adds noise.)
Different from tiling since:
- seamless and irregular pattern
The continuum of randomness versus speed:
- Filters.Map.Tile is fast but has seams and regular pattern (even if you use "Make Seamless" first.)
- Filter.Render.Texture a tile followed by tiling is seamless but still has regularity.
- Filte.Render.Texture an entire image is slower but seamless and moderately irregular.
- Edit.Fill with resynthesized pattern is slowest but seamless and highly irregular, unpatterned.
This filter is not tiling (instead resynthesizing) but makes
an image that you can then use to tile with especially if
you choose the option to make the edges suitable for tiling.
IN: The selection (or the entire active drawable) is the source of texture and is not changed.
OUT New image, possibly resized canvas, same scale and resolution.
TODO a quality setting
'''
from gimpfu import *
gettext.install("resynthesizer", gimp.locale_directory, unicode=True)
debug = False
def new_resized_image(image, resize_ratio):
# Create new image resized by a ratio from *selection* in the old image
(is_selection, ulx, uly, lrx, lry) = pdb.gimp_selection_bounds(image)
if not is_selection :
# Resynthesizer will use the entire source image as corpus.
# Resize new image in proportion to entire source image.
new_width = int(pdb.gimp_image_width(image) * resize_ratio)
new_height = int(pdb.gimp_image_height(image) * resize_ratio)
new_type = pdb.gimp_image_base_type(image) # same as source
else :
# Resize new image in proportion to selection in source
new_width = int((lrx - ulx) * resize_ratio)
new_height = int((lry - uly) * resize_ratio)
new_basetype = pdb.gimp_image_base_type(image) # same as source
new_layertype = pdb.gimp_drawable_type(pdb.gimp_image_get_active_layer(image))
new_image = pdb.gimp_image_new(new_width, new_height, new_basetype)
# !!! Note that gimp_layer_new wants a layer type, not an image basetype
new_drawable = pdb.gimp_layer_new(new_image, new_width, new_height,
new_layertype, "Texture", 100, NORMAL_MODE)
pdb.gimp_image_add_layer(new_image, new_drawable, 0)
return new_image, new_drawable
def display_image(image):
try:
gimp.Display(image)
except gimp.error:
pass # If runmode is NONINTERACTIVE, expect gimp_display_new() to fail
gimp.displays_flush()
def render_texture(image, drawable, resize_ratio=2, make_tile=0):
'''
Create a randomized texture image from the selection.
The image can be suited for further, seamless tiling.
The image is same scale and resolution but resized from the selection.
Not undoable, no changes to the source (you can just delete the new image.)
A selection in the source image is optional.
If there is no selection, the resynthesizer will use the entire source image.
'''
# Its all or nothing, user must delete new image if not happy.
pdb.gimp_image_undo_disable(image)
'''
Create new image, optionally resized, and display for it.
'''
new_image, new_drawable = new_resized_image(image, resize_ratio)
pdb.gimp_image_undo_disable(new_image)
if not new_drawable:
raise RuntimeError, "Failed create layer."
# If using new resynthesizer with animation for debugging
if debug:
display_image(new_image)
'''
copy original into temp and crop it to the selection to save memory in resynthesizer
'''
temp_image = pdb.gimp_image_duplicate(image)
if not temp_image:
raise RuntimeError, "Failed duplicate image"
# Get bounds, offset of selection
(is_selection, ulx, uly, lrx, lry) = pdb.gimp_selection_bounds(image)
if not is_selection :
# No need to crop. Resynthesizer will use all if no selection.
pass
else :
pdb.gimp_image_crop(temp_image, lrx - ulx, lry - uly, ulx, uly)
# Don't flatten because it turns transparency to background (white usually)
work_layer = pdb.gimp_image_get_active_layer(temp_image)
if not work_layer:
raise RuntimeError, "Failed get active layer"
# Insure the selection is all (not necessary, resynthesizer will use all if no selection.)
pdb.gimp_selection_all(temp_image)
# Settings for making edges suitable for seamless tiling afterwards.
# That is what these settings mean in the resynthesizer:
# wrap context probes in the target so that edges of target will be suitable for seamless tiling.
# I.E. treat the target as a sphere when matching.
if make_tile :
htile = 1
vtile = 1
else :
htile = 0
vtile = 0
# Call resynthesizer
# use_border is moot since there is no context (outside the target) in the newImage.
# The target is the entire new image, the source is the cropped copy of the selection.
#
# 9 neighbors (a 3x3 patch) and 200 tries for speed, since new image is probably large
# and source is probably natural (fractal), where quality is not important.
# For version of resynthesizer with uninverted selection
# !!! Pass -1 for ID of no layer, not None
pdb.plug_in_resynthesizer(new_image, new_drawable, htile, vtile, 0, work_layer.ID, -1, -1, 0.0, 0.117, 9, 200)
display_image(new_image)
# Clean up.
pdb.gimp_image_delete(temp_image)
pdb.gimp_image_undo_enable(image)
pdb.gimp_image_undo_enable(new_image)
return new_image
register(
"python_fu_render_texture",
N_("Create a new image with texture from the current image or selection. Optionally, create image edges suited for further, seamless tiling. "),
"New image is the same scale but seamless and irregular. Use 'Map>Tile' for less randomness. Use 'Edit>Fill resynthesized pattern' for more randomness. Requires separate resynthesizer plugin.",
"Lloyd Konneker",
"Copyright 2010 Lloyd Konneker",
"2010",
N_("_Texture..."),
"RGB*, GRAY*",
[
(PF_IMAGE, "image", "Input image", None),
(PF_DRAWABLE, "drawable", "Input drawable", None),
# Spinner is digital and linear, slider is analog but exponential
(PF_SPINNER, "resize_ratio", _("Ratio of size of new image to source selection"), 2, (0.5, 10, 0.5)),
(PF_TOGGLE, "make_tile", _("Make new image edges suitable for seamless tiling"), 0 )
],
[(PF_IMAGE, "new_image", "New, synthesized texture.")],
render_texture,
menu="<Image>/Filters/Render",
domain=("resynthesizer", gimp.locale_directory)
)
main()
|