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