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