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(&parameters);
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