1 /*
2  *   Print plug-in for the GIMP.
3  *
4  *   Copyright 1997-2000 Michael Sweet (mike@easysw.com) and
5  *	Robert Krawitz (rlk@alum.mit.edu)
6  *   Copyright 2000 Charles Briscoe-Smith <cpbs@debian.org>
7  *
8  *   This program is free software; you can redistribute it and/or modify it
9  *   under the terms of the GNU General Public License as published by the Free
10  *   Software Foundation; either version 2 of the License, or (at your option)
11  *   any later version.
12  *
13  *   This program is distributed in the hope that it will be useful, but
14  *   WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
15  *   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
16  *   for more details.
17  *
18  *   You should have received a copy of the GNU General Public License
19  *   along with this program.  If not, see <https://www.gnu.org/licenses/>.
20  */
21 
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25 #include <string.h>
26 
27 #include "print_gimp.h"
28 
29 #include "print-intl.h"
30 
31 
32 /*
33  * "Image" ADT
34  *
35  * This file defines an abstract data type called "Image".  An Image wraps
36  * a Gimp drawable (or some other application-level image representation)
37  * for presentation to the low-level printer drivers (which do CMYK
38  * separation, dithering and weaving).  The Image ADT has the ability
39  * to perform any combination of flips and rotations on the image,
40  * and then deliver individual rows to the driver code.
41  *
42  * Stuff which might be useful to do in this layer:
43  *
44  * - Scaling, optionally with interpolation/filtering.
45  *
46  * - Colour-adjustment.
47  *
48  * - Multiple-image composition.
49  *
50  * Also useful might be to break off a thin application-dependent
51  * sublayer leaving this layer (which does the interesting stuff)
52  * application-independent.
53  */
54 
55 
56 /* Concrete type to represent image */
57 typedef struct
58 {
59   GimpDrawable *drawable;
60   GimpPixelRgn  rgn;
61 
62   /*
63    * Transformations we can impose on the image.  The transformations
64    * are considered to be performed in the order given here.
65    */
66 
67   /* 1: Transpose the x and y axes (flip image over its leading diagonal) */
68   int columns;		/* Set if returning columns instead of rows. */
69 
70   /* 2: Translate (ox,oy) to the origin */
71   int ox, oy;		/* Origin of image */
72 
73   /* 3: Flip vertically about the x axis */
74   int increment;	/* +1 or -1 for offset of row n+1 from row n. */
75 
76   /* 4: Crop to width w, height h */
77   int w, h;		/* Width and height of output image */
78 
79   /* 5: Flip horizontally about the vertical centre-line of the image */
80   int mirror;		/* Set if mirroring rows end-for-end. */
81 
82   gint32 image_ID;
83   gint32 ncolors;
84   gint32 real_bpp;
85   GimpImageBaseType base_type;
86   guchar *cmap;
87   guchar *alpha_table;
88   guchar *tmp;
89   gint last_printed_percent;
90   gint initialized;
91 } Gimp_Image_t;
92 
93 static const char *Image_get_appname(stp_image_t *image);
94 static void Image_conclude(stp_image_t *image);
95 static stp_image_status_t Image_get_row(stp_image_t *image,
96 					unsigned char *data,
97 					size_t byte_limit, int row);
98 static int Image_height(stp_image_t *image);
99 static int Image_width(stp_image_t *image);
100 static void Image_reset(stp_image_t *image);
101 static void Image_init(stp_image_t *image);
102 
103 static void Image_transpose(stpui_image_t *image);
104 static void Image_hflip(stpui_image_t *image);
105 static void Image_vflip(stpui_image_t *image);
106 static void Image_rotate_ccw(stpui_image_t *image);
107 static void Image_rotate_cw(stpui_image_t *image);
108 static void Image_rotate_180(stpui_image_t *image);
109 static void Image_crop(stpui_image_t *image, int, int, int, int);
110 
111 static stpui_image_t theImage =
112 {
113   {
114     Image_init,
115     Image_reset,
116     Image_width,
117     Image_height,
118     Image_get_row,
119     Image_get_appname,
120     Image_conclude,
121     NULL,
122   },
123   Image_transpose,
124   Image_hflip,
125   Image_vflip,
126   Image_rotate_ccw,
127   Image_rotate_cw,
128   Image_rotate_180,
129   Image_crop
130 };
131 
132 static void
compute_alpha_table(Gimp_Image_t * image)133 compute_alpha_table(Gimp_Image_t *image)
134 {
135   unsigned val, alpha;
136   image->alpha_table = stp_malloc(65536 * sizeof(unsigned char));
137   for (val = 0; val < 256; val++)
138     for (alpha = 0; alpha < 256; alpha++)
139       image->alpha_table[(val * 256) + alpha] =
140 	val * alpha / 255 + 255 - alpha;
141 }
142 
143 static inline unsigned char
alpha_lookup(Gimp_Image_t * image,int val,int alpha)144 alpha_lookup(Gimp_Image_t *image, int val, int alpha)
145 {
146   return image->alpha_table[(val * 256) + alpha];
147 }
148 
149 stpui_image_t *
Image_GimpDrawable_new(GimpDrawable * drawable,gint32 image_ID)150 Image_GimpDrawable_new(GimpDrawable *drawable, gint32 image_ID)
151 {
152   Gimp_Image_t *im = stp_malloc(sizeof(Gimp_Image_t));
153   memset(im, 0, sizeof(Gimp_Image_t));
154   im->drawable = drawable;
155   gimp_pixel_rgn_init(&(im->rgn), drawable, 0, 0,
156                       drawable->width, drawable->height, FALSE, FALSE);
157   im->image_ID = image_ID;
158   im->base_type = gimp_image_base_type(image_ID);
159   im->initialized = 0;
160   theImage.im.rep = im;
161   theImage.im.reset(&(theImage.im));
162   switch (im->base_type)
163     {
164     case GIMP_INDEXED:
165       im->cmap = gimp_image_get_cmap(image_ID, &(im->ncolors));
166       im->real_bpp = 3;
167       break;
168     case GIMP_GRAY:
169       im->real_bpp = 1;
170       break;
171     case GIMP_RGB:
172       im->real_bpp = 3;
173       break;
174     }
175   if (im->drawable->bpp == 2 || im->drawable->bpp == 4)
176     compute_alpha_table(im);
177   return &theImage;
178 }
179 
180 static void
Image_init(stp_image_t * image)181 Image_init(stp_image_t *image)
182 {
183   /* Nothing to do. */
184 }
185 
186 static void
Image_reset(stp_image_t * image)187 Image_reset(stp_image_t *image)
188 {
189   Gimp_Image_t *im = (Gimp_Image_t *) (image->rep);
190   im->columns = FALSE;
191   im->ox = 0;
192   im->oy = 0;
193   im->increment = 1;
194   im->w = im->drawable->width;
195   im->h = im->drawable->height;
196   im->mirror = FALSE;
197 }
198 
199 static int
Image_width(stp_image_t * image)200 Image_width(stp_image_t *image)
201 {
202   Gimp_Image_t *im = (Gimp_Image_t *) (image->rep);
203   return im->w;
204 }
205 
206 static int
Image_height(stp_image_t * image)207 Image_height(stp_image_t *image)
208 {
209   Gimp_Image_t *im = (Gimp_Image_t *) (image->rep);
210   return im->h;
211 }
212 
213 static stp_image_status_t
Image_get_row(stp_image_t * image,unsigned char * data,size_t byte_limit,int row)214 Image_get_row(stp_image_t *image, unsigned char *data, size_t byte_limit,
215 	      int row)
216 {
217   Gimp_Image_t *im = (Gimp_Image_t *) (image->rep);
218   int last_printed_percent;
219   guchar *inter;
220   if (!im->initialized)
221     {
222       gimp_progress_init(_("Printing..."));
223       switch (im->base_type)
224 	{
225 	case GIMP_INDEXED:
226 	  im->tmp = stp_malloc(im->drawable->bpp * im->w);
227 	  break;
228 	case GIMP_GRAY:
229 	  if (im->drawable->bpp == 2)
230 	    im->tmp = stp_malloc(im->drawable->bpp * im->w);
231 	  break;
232 	case GIMP_RGB:
233 	  if (im->drawable->bpp == 4)
234 	    im->tmp = stp_malloc(im->drawable->bpp * im->w);
235 	  break;
236 	}
237       im->initialized = 1;
238     }
239   if (im->tmp)
240     inter = im->tmp;
241   else
242     inter = data;
243   if (im->columns)
244     gimp_pixel_rgn_get_col(&(im->rgn), inter,
245                            im->oy + row * im->increment, im->ox, im->w);
246   else
247     gimp_pixel_rgn_get_row(&(im->rgn), inter,
248                            im->ox, im->oy + row * im->increment, im->w);
249   if (im->cmap)
250     {
251       int i;
252       if (im->alpha_table)
253 	{
254 	  for (i = 0; i < im->w; i++)
255 	    {
256 	      int j;
257 	      for (j = 0; j < 3; j++)
258 		{
259 		  gint32 tval = im->cmap[(3 * inter[2 * i]) + j];
260 		  data[(3 * i) + j] = alpha_lookup(im, tval,
261 						   inter[(2 * i) + 1]);
262 		}
263 
264 	    }
265 	}
266       else
267 	{
268 	  for (i = 0; i < im->w; i++)
269 	    {
270 	      data[(3 * i) + 0] = im->cmap[(3 * inter[i]) + 0];
271 	      data[(3 * i) + 1] = im->cmap[(3 * inter[i]) + 1];
272 	      data[(3 * i) + 2] = im->cmap[(3 * inter[i]) + 2];
273 	    }
274 	}
275     }
276   else if (im->alpha_table)
277     {
278       int i;
279       for (i = 0; i < im->w; i++)
280 	{
281 	  int j;
282 	  for (j = 0; j < im->real_bpp; j++)
283 	    {
284 	      gint32 tval = inter[(i * im->drawable->bpp) + j];
285 	      data[(i * im->real_bpp) + j] =
286 		alpha_lookup(im, tval,
287 			     inter[((i + 1) * im->drawable->bpp) - 1]);
288 	    }
289 
290 	}
291     }
292   if (im->mirror)
293     {
294       /* Flip row -- probably inefficiently */
295       int f;
296       int l;
297       int b = im->real_bpp;
298       for (f = 0, l = im->w - 1; f < l; f++, l--)
299 	{
300 	  int c;
301 	  unsigned char tmp;
302 	  for (c = 0; c < b; c++)
303 	    {
304 	      tmp = data[f*b+c];
305 	      data[f*b+c] = data[l*b+c];
306 	      data[l*b+c] = tmp;
307 	    }
308 	}
309     }
310   last_printed_percent = row * 100 / im->h;
311   if (last_printed_percent > im->last_printed_percent)
312     {
313       gimp_progress_update((double) row / (double) im->h);
314       im->last_printed_percent = last_printed_percent;
315     }
316   return STP_IMAGE_STATUS_OK;
317 }
318 
319 static void
Image_transpose(stpui_image_t * image)320 Image_transpose(stpui_image_t *image)
321 {
322   Gimp_Image_t *im = (Gimp_Image_t *) (image->im.rep);
323   int tmp;
324 
325   if (im->mirror) im->ox += im->w - 1;
326 
327   im->columns = !im->columns;
328 
329   tmp = im->ox;
330   im->ox = im->oy;
331   im->oy = tmp;
332 
333   tmp = im->mirror;
334   im->mirror = im->increment < 0;
335   im->increment = tmp ? -1 : 1;
336 
337   tmp = im->w;
338   im->w = im->h;
339   im->h = tmp;
340 
341   if (im->mirror) im->ox -= im->w - 1;
342 }
343 
344 static void
Image_hflip(stpui_image_t * image)345 Image_hflip(stpui_image_t *image)
346 {
347   Gimp_Image_t *im = (Gimp_Image_t *) (image->im.rep);
348   im->mirror = !im->mirror;
349 }
350 
351 static void
Image_vflip(stpui_image_t * image)352 Image_vflip(stpui_image_t *image)
353 {
354   Gimp_Image_t *im = (Gimp_Image_t *) (image->im.rep);
355   im->oy += (im->h-1) * im->increment;
356   im->increment = -im->increment;
357 }
358 
359 /*
360  * Image_crop:
361  *
362  * Crop the given number of pixels off the LEFT, TOP, RIGHT and BOTTOM
363  * of the image.
364  */
365 
366 static void
Image_crop(stpui_image_t * image,int left,int top,int right,int bottom)367 Image_crop(stpui_image_t *image, int left, int top, int right, int bottom)
368 {
369   Gimp_Image_t *im = (Gimp_Image_t *) (image->im.rep);
370   int xmax = (im->columns ? im->drawable->height : im->drawable->width) - 1;
371   int ymax = (im->columns ? im->drawable->width : im->drawable->height) - 1;
372 
373   int nx = im->ox + im->mirror ? right : left;
374   int ny = im->oy + top * (im->increment);
375 
376   int nw = im->w - left - right;
377   int nh = im->h - top - bottom;
378 
379   int wmax, hmax;
380 
381   if (nx < 0)         nx = 0;
382   else if (nx > xmax) nx = xmax;
383 
384   if (ny < 0)         ny = 0;
385   else if (ny > ymax) ny = ymax;
386 
387   wmax = xmax - nx + 1;
388   hmax = im->increment ? ny + 1 : ymax - ny + 1;
389 
390   if (nw < 1)         nw = 1;
391   else if (nw > wmax) nw = wmax;
392 
393   if (nh < 1)         nh = 1;
394   else if (nh > hmax) nh = hmax;
395 
396   im->ox = nx;
397   im->oy = ny;
398   im->w = nw;
399   im->h = nh;
400 }
401 
402 static void
Image_rotate_ccw(stpui_image_t * image)403 Image_rotate_ccw(stpui_image_t *image)
404 {
405   Image_transpose(image);
406   Image_vflip(image);
407 }
408 
409 static void
Image_rotate_cw(stpui_image_t * image)410 Image_rotate_cw(stpui_image_t *image)
411 {
412   Image_transpose(image);
413   Image_hflip(image);
414 }
415 
416 static void
Image_rotate_180(stpui_image_t * image)417 Image_rotate_180(stpui_image_t *image)
418 {
419   Image_vflip(image);
420   Image_hflip(image);
421 }
422 
423 static void
Image_conclude(stp_image_t * image)424 Image_conclude(stp_image_t *image)
425 {
426   Gimp_Image_t *im = (Gimp_Image_t *) (image->rep);
427   gimp_progress_update(1);
428   if (im->alpha_table)
429     stp_free(im->alpha_table);
430   if (im->tmp)
431     stp_free(im->tmp);
432 }
433 
434 static const char *
Image_get_appname(stp_image_t * image)435 Image_get_appname(stp_image_t *image)
436 {
437   static char pluginname[] = "Print plug-in V" VERSION " - " RELEASE_DATE
438     " for GIMP";
439   return pluginname;
440 }
441