1 /*
2 The Resynthesizer - A GIMP plug-in for resynthesizing textures
3
4 Copyright (C) 2010 Lloyd Konneker
5 Copyright (C) 2000 2008 Paul Francis Harrison
6 Copyright (C) 2002 Laurent Despeyroux
7 Copyright (C) 2002 David Rodríguez García
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 /*
25 Notes:
26
27 The selection:
28
29 In prior versions, you could pass the same layer as the target and corpus.
30 Since there is only one selection, the selection was the target and the inverse
31 of the selection was the corpus. But if you wanted to pass a different image and layer
32 as the corpus, you needed to invert the selection in that image.
33
34 This feature was a source of confusion for users and programmers.
35 Here, this feature is abolished. The selection in the corpus layer is the corpus,
36 not the inverse of the selection.
37
38 This only eliminates one use: synthesizing a selection from the inverse of the selection
39 in the same drawable. If you need to do that, copy the drawable to another image and
40 create a selection there that is the inverse of the selection in the original.
41 The heal selection plugin does that for you.
42
43 The alpha:
44
45 In prior versions the alpha was treated like a color channel, and matched during resynthesis.
46 Transparent pixels (which Gimp arbitrarily gives the color black in some circumstances)
47 were not distinguished. In certain cases with transparency, transparent pixels were synthesized
48 into the target, as good matches for black.
49
50 Here, we don't match the alpha channel between target and corpus.
51 We don't generate any alpha in the target, instead we leave the target alpha unaltered.
52 We use the alpha to determine what pixels are in the target and corpus,
53 (similar to a selection mask.)
54 Any totally transparent pixel in the target selection IS synthesized,
55 I.E. a color is generated (but since it is totally transparent, you don't see it.)
56 Any partially transparent target pixel is also synthesized, except as stated,
57 the alpha is not matched (so colors from opaque areas of the corpus
58 could be synthesized into partially transparent areas of the target.)
59 Any totally transparent pixel in the corpus is not in the corpus, i.e. never matched.
60 Any partially transparent pixel in the corpus is a candidate for matching.
61 A color from a partially transparent pixel in the corpus could be synthesized
62 into an opaque area of the target.
63 Again, the transparency of the target is retained even as new colors are synthesized.
64
65 Tiling: (see parameters horizontal and vertical tiling)
66 This means we synthesize a target that is *seamlessly* tileable.
67 We treat the target as a sphere, wrapping a coord outside the target around
68 to the opposite side.
69 It doesn't make tiles in the target, it makes a target that is suitable as a tile.
70 */
71
72 //#include "buildSwitches.h" // Affects debug, assertions, use of glib, threading, etc.
73
74 #include "../../config.h" // GNU buildtools local configuration
75 #include "../plugin-intl.h" // i18n macros
76
77 #include <libgimp/gimp.h>
78 #include <glib/gprintf.h>
79
80 /* Shared with resynth-gui plugin, resynthesizer engine plugin. */
81 #include "../resynth-constants.h"
82
83 /*
84 True header files: types, function prototypes, and in-line functions only.
85 No definitions of non in-line functions or data.
86
87 Types, etc. from resynthesizer (image_synth) library
88 */
89 // FIXME need to include glibProxy.h here so everything else uses glibless Map?
90 #ifdef USE_GLIB_PROXY
91 #include "glibProxy.h"
92 #endif
93 #include "imageFormat.h"
94 #include "imageFormatIndicies.h"
95 #include "map.h"
96 #include "engineParams.h"
97 #include "engine.h" // requires map.h
98 #include "imageSynthConstants.h"
99
100 /*
101 Source included, not compiled separately.
102 Is separate to reduce file sizes and later, coupling.
103 */
104
105 #include "mapIndex.h" // from resynthesizer library
106 #include "adaptGimp.h" // requires mapIndex.h
107 #include "../resynth-parameters.h" // requires engine.h
108 #include "adaptParameters.c"
109
110 /* See below for more includes. */
111
112 /*
113 Macro to cleanup for abort.
114 Return value is already PDB_ERROR.
115 Return an error string to Gimp, which will display an alert dialog.
116 Also log message in case engine is called non-interactively.
117 Note this must be used in the scope of nreturn_vals and value, in main().
118 */
119 #define ERROR_RETURN(message) { \
120 detach_drawables(drawable, corpus_drawable, map_in_drawable, map_out_drawable); \
121 *nreturn_vals = 2; \
122 values[1].type = GIMP_PDB_STRING; \
123 values[1].data.d_string = message ; \
124 g_debug(message); \
125 return; \
126 }
127
128 #ifdef ANIMATE
129 /*
130 Use in debugging with DEEP_PROGRESS and ANIMATE.
131 Blacken target, then animate pixels as they are synthesized.
132 */
133
134 GimpDrawable * targetDrawableCopy;
135 Map* targetMapCopy;
136
137 static void
138 post_results_to_gimp(
139 GimpDrawable *drawable,
140 Map targetMap);
141
142 /*
143 Clear target pixels. So see them get synthesized when animated debugging.
144 Note the initial values of the target are never used, but totally synthesized.
145 */
146 static void
clear_target_pixels(guint bpp)147 clear_target_pixels(guint bpp)
148 {
149 guint x;
150 guint y;
151
152 for(y=0;y<targetMapCopy->height;y++)
153 for(x=0;x<targetMapCopy->width;x++)
154 {
155 Coordinates coords = {x,y};
156 if (pixmap_index(targetMapCopy, coords)[MASK_PIXELEL_INDEX] != MASK_UNSELECTED)
157 // if (isSelectedTarget(coords, targetMapCopy))
158 {
159 guint pixelel;
160 Pixelel * pixel = pixmap_index(targetMapCopy, coords);
161 for (pixelel = FIRST_PIXELEL_INDEX; pixelel < bpp; pixelel++) // Color channels only
162 pixel[pixelel] = PIXELEL_BLACK;
163 }
164 }
165 }
166
167 #endif
168
169
170 /*
171 Progress functions.
172 */
173
174 // Called before any real progress is made
175 static void
progressStart(gchar * message)176 progressStart(gchar * message)
177 {
178 gimp_progress_init(message);
179 gimp_progress_update(0.0);
180 #ifdef DEBUG
181 /* To console. On Windows, it annoyingly opens a console.
182 On Unix it dissappears unless console already open.
183 */
184 g_printf(message);
185 g_printf("\n");
186 #endif
187 }
188
189 // Called repeatedly as progress is made
190 void // Not static, in test build, called from inside engine
progressUpdate(int percent,void * contextInfo)191 progressUpdate( int percent, void * contextInfo)
192 {
193 gimp_progress_update((float)percent/100);
194
195 #ifdef ANIMATE
196 post_results_to_gimp(targetDrawableCopy, *targetMapCopy);
197 #endif
198
199 }
200
201
202 /* Return count of color channels, exclude alpha and any other channels. */
203 static guint
count_color_channels(GimpDrawable * drawable)204 count_color_channels(GimpDrawable *drawable)
205 {
206 g_assert(drawable); // Not null
207
208 GimpImageType type = gimp_drawable_type(drawable->drawable_id);
209 switch(type)
210 {
211 case GIMP_RGB_IMAGE:
212 case GIMP_RGBA_IMAGE:
213 return 3;
214 case GIMP_GRAY_IMAGE:
215 case GIMP_GRAYA_IMAGE:
216 return 1;
217 default:
218 g_assert(FALSE);
219 }
220 return 0;
221 }
222
223
224 /*
225 Return whether drawables have the same base type.
226 */
227 static gboolean
equal_basetypes(GimpDrawable * first_drawable,GimpDrawable * second_drawable)228 equal_basetypes(
229 GimpDrawable *first_drawable,
230 GimpDrawable *second_drawable
231 )
232 {
233 /* !!! Not drawable->bpp minus one if alpha, because there might be other channels. */
234 return (count_color_channels(first_drawable) == count_color_channels(second_drawable));
235 }
236
237
238
239 /*
240 Update Gimp image from local pixmap. Canonical postlude for plugins.
241 !!! Called in the postlude but also for debugging: animate results during processing.
242 */
243 static void
post_results_to_gimp(GimpDrawable * drawable,Map targetMap)244 post_results_to_gimp(
245 GimpDrawable *drawable,
246 Map targetMap)
247 {
248 pixmap_to_drawable(targetMap, drawable, FIRST_PIXELEL_INDEX); // our pixels to region
249 gimp_drawable_flush(drawable); // regions back to core
250 gimp_drawable_merge_shadow(drawable->drawable_id,TRUE); // temp buffers merged
251 gimp_drawable_update(drawable->drawable_id,0,0,targetMap.width,targetMap.height);
252 gimp_displays_flush();
253 }
254
255
256
257 static void
detach_drawables(GimpDrawable * out,GimpDrawable * in,GimpDrawable * out_map,GimpDrawable * in_map)258 detach_drawables(
259 GimpDrawable * out,
260 GimpDrawable * in,
261 GimpDrawable * out_map,
262 GimpDrawable * in_map
263 )
264 {
265 if (out)
266 gimp_drawable_detach(out);
267 if (in)
268 gimp_drawable_detach(in);
269 if (out_map)
270 gimp_drawable_detach(out_map);
271 if (in_map)
272 gimp_drawable_detach(in_map);
273 }
274
275 #ifdef ADAPT_SIMPLE
276 #include "imageBuffer.h"
277 #include "adaptSimple.h"
278 #include "adaptGimpSimple.h"
279 #endif
280
281 /*
282 Plugin main.
283 This adapts the texture synthesis engine to a Gimp plugin.
284 */
285
run(const gchar * name,gint nparams,const GimpParam * param,gint * nreturn_vals,GimpParam ** return_vals)286 static void run(
287 const gchar * name,
288 gint nparams,
289 const GimpParam * param,
290 gint * nreturn_vals,
291 GimpParam ** return_vals)
292 {
293 static GimpParam values[2]; /* Gimp return values. !!! Allow 2: status and error message. */
294 TGimpAdapterParameters pluginParameters;
295 TImageSynthParameters engineParameters;
296
297 GimpDrawable *drawable = NULL;
298 GimpDrawable *corpus_drawable = NULL;
299 GimpDrawable *map_in_drawable= NULL;
300 GimpDrawable *map_out_drawable= NULL;
301 gboolean ok, with_map;
302
303 /*
304 Local copies of pixmaps (not using gimp regions.)
305 2-D arrays of Pixel, addressable by Coordinates (Point).
306 c++: static Bitmap<Pixelel>
307 */
308 Map targetMap;
309 Map corpusMap;
310 Map targetMaskMap;
311 Map corpusMaskMap;
312
313 int cancelFlag = 0;
314
315 #ifdef SYNTH_THREADED
316 // This is as early as it can be called. Not sure it needs to be called. See later call to it.
317 // Call it early since calls to gdk, gtk might require this?
318 g_thread_init(NULL);
319 #endif
320
321 #ifdef DEBUG
322 gimp_message_set_handler(1); // To console instead of GUI
323 start_time = clock();
324 #endif
325
326 // internationalization i18n
327 // Note these constants are defined in the build environment.
328 /* Initialize i18n support */
329 #if defined(G_OS_WIN32)
330 bindtextdomain (GETTEXT_PACKAGE, gimp_locale_directory());
331 #else
332 bindtextdomain (GETTEXT_PACKAGE, LOCALEDIR);
333 #endif
334 #ifdef HAVE_BIND_TEXTDOMAIN_CODESET
335 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
336 #endif
337 textdomain (GETTEXT_PACKAGE);
338
339 *nreturn_vals = 1;
340 *return_vals = values;
341 values[0].type = GIMP_PDB_STATUS;
342 values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; /* Unless everything succeeds. */
343
344 drawable = gimp_drawable_get(param[2].data.d_drawable);
345
346 /* Check image type (could be called non-interactive) */
347 if (!gimp_drawable_is_rgb(drawable->drawable_id) &&
348 !gimp_drawable_is_gray(drawable->drawable_id))
349 {
350 ERROR_RETURN(_("Incompatible image mode."));
351 }
352
353
354 /* Deal with run mode */
355 ok = FALSE;
356 switch(param[0].data.d_int32)
357 {
358 case GIMP_RUN_INTERACTIVE :
359 ok = get_last_parameters(&pluginParameters,drawable->drawable_id, RESYNTH_ENGINE_PDB_NAME);
360 gimp_message("Resynthesizer engine should not be called interactively");
361 /* But keep going with last (or default) parameters, really no harm. */
362 break;
363 case GIMP_RUN_NONINTERACTIVE :
364 ok = get_parameters_from_list(&pluginParameters, nparams, param);
365 break;
366 case GIMP_RUN_WITH_LAST_VALS :
367 ok = get_last_parameters(&pluginParameters,drawable->drawable_id, RESYNTH_ENGINE_PDB_NAME);
368 break;
369 }
370
371 if (!ok)
372 {
373 ERROR_RETURN(_("Resynthesizer failed to get parameters."));
374 }
375
376 /* Limit neighbours parameter to size allocated. */
377 if (pluginParameters.neighbours > IMAGE_SYNTH_MAX_NEIGHBORS )
378 pluginParameters.neighbours = IMAGE_SYNTH_MAX_NEIGHBORS;
379
380 corpus_drawable = gimp_drawable_get(pluginParameters.corpus_id);
381
382 /* The target and corpus must have the same base type.
383 In earlier version, they must have the same bpp.
384 But now we don't compare the alphas, so they can differ in presence of alpha.
385 */
386 if (! equal_basetypes(drawable, corpus_drawable) )
387 {
388 ERROR_RETURN(_("The input texture and output image must have the same number of color channels."));
389 }
390
391
392 with_map = (pluginParameters.input_map_id != -1 && pluginParameters.output_map_id != -1);
393 /* If only one map is passed, it is ignored quietly. */
394 map_in_drawable=0;
395 map_out_drawable=0;
396
397 if (with_map)
398 {
399 map_in_drawable = gimp_drawable_get(pluginParameters.input_map_id);
400 map_out_drawable = gimp_drawable_get(pluginParameters.output_map_id);
401 /* All these can be wrong at the same time.
402 Forego userfriendliness for ease of programming: abort on first error
403 */
404 if ( ! equal_basetypes(map_in_drawable, map_out_drawable) )
405 {
406 /* Maps need the same base type. Formerly needed the same bpp. */
407 ERROR_RETURN(_("The input and output maps must have the same mode"));
408 }
409 if (map_in_drawable->width != corpus_drawable->width ||
410 map_in_drawable->height != corpus_drawable->height)
411 {
412 ERROR_RETURN(_("The input map should be the same size as the input texture image"));
413 }
414 if (map_out_drawable->width != drawable->width ||
415 map_out_drawable->height != drawable->height)
416 {
417 ERROR_RETURN(_("The output map should be the same size as the output image"));
418 }
419 }
420
421 /*
422 The engine should not be run interactively so no need to store last values.
423 I.E. the meaning of "last" is "last values set by user interaction".
424 */
425
426 #ifdef ANIMATE
427 // Copy local pointer vars to globals
428 targetDrawableCopy = drawable;
429 targetMapCopy = &targetMap;
430 #endif
431
432 /* Error checks done, initialization work begins. So start progress callbacks. */
433 progressStart("Initializing...");
434
435 /*
436 Set flags for presence of alpha channels.
437 The flag is an optimization. Alternatives:
438 - a function
439 - OR standardize the internal pixmap to ALWAYS have an alpha pixelel
440 initialized to VISIBLE and set from any alpha pixelel.
441 */
442 gboolean is_alpha_image = gimp_drawable_has_alpha(drawable->drawable_id);
443 gboolean is_alpha_corpus = gimp_drawable_has_alpha(corpus_drawable->drawable_id);
444
445 // Image adaption requires format indices
446 // WAS prepareImageFormatIndices(drawable, corpus_drawable, with_map, map_in_drawable);
447 TFormatIndices formatIndices;
448
449 guint map_count = (with_map? count_color_channels(map_in_drawable) : 0 );
450
451 prepareImageFormatIndices(
452 &formatIndices,
453 count_color_channels(drawable),
454 map_count,
455 is_alpha_image,
456 is_alpha_corpus,
457 with_map
458 );
459
460 #ifdef ADAPT_SIMPLE
461 /* Adapt Gimp to an engine with a simpler interface. */
462 setDefaultParams(¶meters);
463 ImageBuffer imageBuffer;
464 ImageBuffer maskBuffer;
465
466 // TODO change to new signature
467 adaptGimpToSimple(drawable, &imageBuffer, &maskBuffer); // From Gimp to simple
468 g_printf("Here3\n");
469 adaptSimpleAPI(&imageBuffer, &maskBuffer); // From simple to existing engine API
470
471 #else
472 g_printf("Gimp adaption\n");
473 /* target/context adaption */
474 fetch_image_mask_map(drawable, &targetMap, formatIndices.total_bpp,
475 &targetMaskMap,
476 MASK_TOTALLY_SELECTED,
477 map_out_drawable, formatIndices.map_start_bip);
478
479 #ifdef ANIMATE
480 clear_target_pixels(formatIndices.colorEndBip); // For debugging, blacken so new colors sparkle
481 #endif
482
483 /* corpus adaption */
484 fetch_image_mask_map(corpus_drawable, &corpusMap, formatIndices.total_bpp,
485 &corpusMaskMap,
486 MASK_TOTALLY_SELECTED,
487 map_in_drawable, formatIndices.map_start_bip);
488
489 // TODO These are artifacts of earlier design, not used.
490 free_map(&corpusMaskMap);
491 free_map(&targetMaskMap);
492
493 adaptPluginToLibraryParameters(&pluginParameters, &engineParameters);
494
495 #endif
496
497 // After possible adaption, check size again
498 g_assert(targetMap.width * targetMap.height); // Image is not empty
499 g_assert(corpusMap.width * corpusMap.height); // Corpus is not empty
500
501 // Done with adaption: now main image data in canonical pixmaps, etc.
502 // Begin real work
503 progressStart("synthesizing...");
504
505 int result = engine(
506 engineParameters,
507 &formatIndices,
508 &targetMap,
509 &corpusMap,
510 progressUpdate,
511 (void *) 0,
512 &cancelFlag
513 );
514
515 if (result == IMAGE_SYNTH_ERROR_EMPTY_CORPUS)
516 {
517 ERROR_RETURN(_("The texture source is empty. Does any selection include non-transparent pixels?"));
518 }
519 else if (result == IMAGE_SYNTH_ERROR_EMPTY_TARGET )
520 {
521 ERROR_RETURN(_("The output layer is empty. Does any selection have visible pixels in the active layer?"));
522 }
523
524 // Normal post-process adaption follows
525
526 /* dump_target_points(); */ /* detailed debugging. */
527 // print_post_stats();
528
529 // Update Gimp image from local pixmap
530 // Note this works even for test harness where ADAPT_SIMPLE
531 // but then it does NOT test returning results in buffer.
532
533 /*
534 We could test antiAdaptImage() here.
535 But antiAdaptImage() has already been tested once on the incoming side.
536 So no compelling need to test it again here.
537 */
538 post_results_to_gimp(drawable, targetMap);
539
540 /* Clean up */
541 // Adapted
542 free_map(&targetMap);
543 free_map(&corpusMap);
544 // GIMP
545 detach_drawables(drawable, corpus_drawable, map_in_drawable, map_out_drawable);
546 gimp_progress_end();
547 values[0].data.d_status = GIMP_PDB_SUCCESS;
548 }
549
550 /* PDB registration and MAIN() */
551 #include "../resynth-pdb.h"
552
553