1 /* Copyright (C) 1996, 1997, 1998, 1999, 2000 Aladdin Enterprises. All rights reserved.
2
3 This software is provided AS-IS with no warranty, either express or
4 implied.
5
6 This software is distributed under license and may not be copied,
7 modified or distributed except as expressly authorized under the terms
8 of the license contained in the file LICENSE in this distribution.
9
10 For more information about licensing, please refer to
11 http://www.ghostscript.com/licensing/. For information on
12 commercial licensing, go to http://www.artifex.com/licensing/ or
13 contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14 San Rafael, CA 94903, U.S.A., +1(415)492-9861.
15 */
16
17 /* $Id: gsimage.c,v 1.15 2005/06/21 16:50:50 igor Exp $ */
18 /* Image setup procedures for Ghostscript library */
19 #include "memory_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gsstruct.h"
23 #include "gscspace.h"
24 #include "gsmatrix.h" /* for gsiparam.h */
25 #include "gsimage.h"
26 #include "gxarith.h" /* for igcd */
27 #include "gxdevice.h"
28 #include "gxiparam.h"
29 #include "gxpath.h" /* for gx_effective_clip_path */
30 #include "gzstate.h"
31
32
33 /*
34 The main internal invariant for the gs_image machinery is
35 straightforward. The state consists primarily of N plane buffers
36 (planes[]).
37 */
38 typedef struct image_enum_plane_s {
39 /*
40 The state of each plane consists of:
41
42 - A row buffer, aligned and (logically) large enough to hold one scan line
43 for that plane. (It may have to be reallocated if the plane width or
44 depth changes.) A row buffer is "full" if it holds exactly a full scan
45 line.
46 */
47 gs_string row;
48 /*
49 - A position within the row buffer, indicating how many initial bytes are
50 occupied.
51 */
52 uint pos;
53 /*
54 - A (retained) source string, which may be empty (size = 0).
55 */
56 gs_const_string source;
57 } image_enum_plane_t;
58 /*
59 The possible states for each plane do not depend on the state of any other
60 plane. Either:
61
62 - pos = 0, source.size = 0.
63
64 - If the underlying image processor says the plane is currently wanted,
65 either:
66
67 - pos = 0, source.size >= one full row of data for this plane. This
68 case allows us to avoid copying the data from the source string to the
69 row buffer if the client is providing data in blocks of at least one
70 scan line.
71
72 - pos = full, source.size may have any value.
73
74 - pos > 0, pos < full, source.size = 0;
75
76 - If the underlying image processor says the plane is not currently
77 wanted:
78
79 - pos = 0, source.size may have any value.
80
81 This invariant holds at the beginning and end of each call on
82 gs_image_next_planes. Note that for each plane, the "plane wanted" status
83 and size of a full row may change after each call of plane_data. As
84 documented in gxiparam.h, we assume that a call of plane_data can only
85 change a plane's status from "wanted" to "not wanted", or change the width
86 or depth of a wanted plane, if data for that plane was actually supplied
87 (and used).
88 */
89
90 /* Define the enumeration state for this interface layer. */
91 /*typedef struct gs_image_enum_s gs_image_enum; *//* in gsimage.h */
92 struct gs_image_enum_s {
93 /* The following are set at initialization time. */
94 gs_memory_t *memory;
95 gx_device *dev; /* if 0, just skip over the data */
96 gx_image_enum_common_t *info; /* driver bookkeeping structure */
97 int num_planes;
98 int height;
99 bool wanted_varies;
100 /* The following are updated dynamically. */
101 int plane_index; /* index of next plane of data, */
102 /* only needed for gs_image_next */
103 int y;
104 bool error;
105 byte wanted[gs_image_max_planes]; /* cache gx_image_planes_wanted */
106 byte client_wanted[gs_image_max_planes]; /* see gsimage.h */
107 image_enum_plane_t planes[gs_image_max_planes]; /* see above */
108 /*
109 * To reduce setup for transferring complete rows, we maintain a
110 * partially initialized parameter array for gx_image_plane_data_rows.
111 * The data member is always set just before calling
112 * gx_image_plane_data_rows; the data_x and raster members are reset
113 * when needed.
114 */
115 gx_image_plane_t image_planes[gs_image_max_planes];
116 };
117
118 gs_private_st_composite(st_gs_image_enum, gs_image_enum, "gs_image_enum",
119 gs_image_enum_enum_ptrs, gs_image_enum_reloc_ptrs);
120 #define gs_image_enum_num_ptrs 2
121
122 /* GC procedures */
123 private
ENUM_PTRS_WITH(gs_image_enum_enum_ptrs,gs_image_enum * eptr)124 ENUM_PTRS_WITH(gs_image_enum_enum_ptrs, gs_image_enum *eptr)
125 {
126 /* Enumerate the data planes. */
127 index -= gs_image_enum_num_ptrs;
128 if (index < eptr->num_planes)
129 ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].source);
130 index -= eptr->num_planes;
131 if (index < eptr->num_planes)
132 ENUM_RETURN_STRING_PTR(gs_image_enum, planes[index].row);
133 return 0;
134 }
135 ENUM_PTR(0, gs_image_enum, dev);
136 ENUM_PTR(1, gs_image_enum, info);
137 ENUM_PTRS_END
RELOC_PTRS_WITH(gs_image_enum_reloc_ptrs,gs_image_enum * eptr)138 private RELOC_PTRS_WITH(gs_image_enum_reloc_ptrs, gs_image_enum *eptr)
139 {
140 int i;
141
142 RELOC_PTR(gs_image_enum, dev);
143 RELOC_PTR(gs_image_enum, info);
144 for (i = 0; i < eptr->num_planes; i++)
145 RELOC_CONST_STRING_PTR(gs_image_enum, planes[i].source);
146 for (i = 0; i < eptr->num_planes; i++)
147 RELOC_STRING_PTR(gs_image_enum, planes[i].row);
148 }
149 RELOC_PTRS_END
150
151 /* Create an image enumerator given image parameters and a graphics state. */
152 int
gs_image_begin_typed(const gs_image_common_t * pic,gs_state * pgs,bool uses_color,gx_image_enum_common_t ** ppie)153 gs_image_begin_typed(const gs_image_common_t * pic, gs_state * pgs,
154 bool uses_color, gx_image_enum_common_t ** ppie)
155 {
156 gx_device *dev = gs_currentdevice(pgs);
157 gx_clip_path *pcpath;
158 int code = gx_effective_clip_path(pgs, &pcpath);
159
160 if (code < 0)
161 return code;
162 if (uses_color) {
163 gx_set_dev_color(pgs);
164 code = gs_state_color_load(pgs);
165 if (code < 0)
166 return code;
167 }
168 return gx_device_begin_typed_image(dev, (const gs_imager_state *)pgs,
169 NULL, pic, NULL, pgs->dev_color, pcpath, pgs->memory, ppie);
170 }
171
172 /* Allocate an image enumerator. */
173 private void
image_enum_init(gs_image_enum * penum)174 image_enum_init(gs_image_enum * penum)
175 {
176 /* Clean pointers for GC. */
177 penum->info = 0;
178 penum->dev = 0;
179 penum->plane_index = 0;
180 penum->num_planes = 0;
181 }
182 gs_image_enum *
gs_image_enum_alloc(gs_memory_t * mem,client_name_t cname)183 gs_image_enum_alloc(gs_memory_t * mem, client_name_t cname)
184 {
185 gs_image_enum *penum =
186 gs_alloc_struct(mem, gs_image_enum, &st_gs_image_enum, cname);
187
188 if (penum != 0) {
189 penum->memory = mem;
190 image_enum_init(penum);
191 }
192 return penum;
193 }
194
195 /* Start processing an ImageType 1 image. */
196 int
gs_image_init(gs_image_enum * penum,const gs_image_t * pim,bool multi,gs_state * pgs)197 gs_image_init(gs_image_enum * penum, const gs_image_t * pim, bool multi,
198 gs_state * pgs)
199 {
200 gs_image_t image;
201 gx_image_enum_common_t *pie;
202 int code;
203
204 image = *pim;
205 if (image.ImageMask) {
206 image.ColorSpace = NULL;
207 if (pgs->in_cachedevice <= 1)
208 image.adjust = false;
209 } else {
210 if (pgs->in_cachedevice)
211 return_error(gs_error_undefined);
212 if (image.ColorSpace == NULL) {
213 /* parameterless color space - no re-entrancy problems */
214 static gs_color_space cs;
215
216 /*
217 * Mutiple initialization of a DeviceGray color space is
218 * not harmful, as the space has no parameters. Use of a
219 * non-current color space is potentially incorrect, but
220 * it appears this case doesn't arise.
221 */
222 gs_cspace_init_DeviceGray(pgs->memory, &cs);
223 image.ColorSpace = &cs;
224 }
225 }
226 code = gs_image_begin_typed((const gs_image_common_t *)&image, pgs,
227 image.ImageMask | image.CombineWithColor,
228 &pie);
229 if (code < 0)
230 return code;
231 return gs_image_enum_init(penum, pie, (const gs_data_image_t *)&image,
232 pgs);
233 }
234
235 /*
236 * Return the number of bytes of data per row for a given plane.
237 */
238 inline uint
gs_image_bytes_per_plane_row(const gs_image_enum * penum,int plane)239 gs_image_bytes_per_plane_row(const gs_image_enum * penum, int plane)
240 {
241 const gx_image_enum_common_t *pie = penum->info;
242
243 return (pie->plane_widths[plane] * pie->plane_depths[plane] + 7) >> 3;
244 }
245
246 /* Cache information when initializing, or after transferring plane data. */
247 private void
cache_planes(gs_image_enum * penum)248 cache_planes(gs_image_enum *penum)
249 {
250 int i;
251
252 if (penum->wanted_varies) {
253 penum->wanted_varies =
254 !gx_image_planes_wanted(penum->info, penum->wanted);
255 for (i = 0; i < penum->num_planes; ++i)
256 if (penum->wanted[i])
257 penum->image_planes[i].raster =
258 gs_image_bytes_per_plane_row(penum, i);
259 else
260 penum->image_planes[i].data = 0;
261 }
262 }
263 /* Advance to the next wanted plane. */
264 private void
next_plane(gs_image_enum * penum)265 next_plane(gs_image_enum *penum)
266 {
267 int px = penum->plane_index;
268
269 do {
270 if (++px == penum->num_planes)
271 px = 0;
272 } while (!penum->wanted[px]);
273 penum->plane_index = px;
274 }
275 /*
276 * Initialize plane_index and (if appropriate) wanted and
277 * wanted_varies at the beginning of a group of planes.
278 */
279 private void
begin_planes(gs_image_enum * penum)280 begin_planes(gs_image_enum *penum)
281 {
282 cache_planes(penum);
283 penum->plane_index = -1;
284 next_plane(penum);
285 }
286
287 static int
gs_image_common_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gx_device * dev)288 gs_image_common_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
289 const gs_data_image_t * pim, gx_device * dev)
290 {
291 /*
292 * HACK : For a compatibility with gs_image_cleanup_and_free_enum,
293 * penum->memory must be initialized in advance
294 * with the memory heap that owns *penum.
295 */
296 int i;
297
298 if (pim->Width == 0 || pim->Height == 0) {
299 gx_image_end(pie, false);
300 return 1;
301 }
302 image_enum_init(penum);
303 penum->dev = dev;
304 penum->info = pie;
305 penum->num_planes = pie->num_planes;
306 /*
307 * Note that for ImageType 3 InterleaveType 2, penum->height (the
308 * expected number of data rows) differs from pim->Height (the height
309 * of the source image in scan lines). This doesn't normally cause
310 * any problems, because penum->height is not used to determine when
311 * all the data has been processed: that is up to the plane_data
312 * procedure for the specific image type.
313 */
314 penum->height = pim->Height;
315 for (i = 0; i < pie->num_planes; ++i) {
316 penum->planes[i].pos = 0;
317 penum->planes[i].source.size = 0; /* for gs_image_next_planes */
318 penum->planes[i].row.data = 0; /* for GC */
319 penum->planes[i].row.size = 0; /* ditto */
320 penum->image_planes[i].data_x = 0; /* just init once, never changes */
321 }
322 /* Initialize the dynamic part of the state. */
323 penum->y = 0;
324 penum->error = false;
325 penum->wanted_varies = true;
326 begin_planes(penum);
327 return 0;
328 }
329
330 /* Initialize an enumerator for a general image.
331 penum->memory must be initialized in advance.
332 */
333 int
gs_image_enum_init(gs_image_enum * penum,gx_image_enum_common_t * pie,const gs_data_image_t * pim,gs_state * pgs)334 gs_image_enum_init(gs_image_enum * penum, gx_image_enum_common_t * pie,
335 const gs_data_image_t * pim, gs_state *pgs)
336 {
337 return gs_image_common_init(penum, pie, pim,
338 (pgs->in_charpath ? NULL :
339 gs_currentdevice_inline(pgs)));
340 }
341
342 /* Return the set of planes wanted. */
343 const byte *
gs_image_planes_wanted(gs_image_enum * penum)344 gs_image_planes_wanted(gs_image_enum *penum)
345 {
346 int i;
347
348 /*
349 * A plane is wanted at this interface if it is wanted by the
350 * underlying machinery and has no buffered or retained data.
351 */
352 for (i = 0; i < penum->num_planes; ++i)
353 penum->client_wanted[i] =
354 (penum->wanted[i] &&
355 penum->planes[i].pos + penum->planes[i].source.size <
356 penum->image_planes[i].raster);
357 return penum->client_wanted;
358 }
359
360 /*
361 * Return the enumerator memory used for allocating the row buffers.
362 * Because some PostScript files use save/restore within an image data
363 * reading procedure, this must be a stable allocator.
364 */
365 private gs_memory_t *
gs_image_row_memory(const gs_image_enum * penum)366 gs_image_row_memory(const gs_image_enum *penum)
367 {
368 return gs_memory_stable(penum->memory);
369 }
370
371 /* Free the row buffers when cleaning up. */
372 private void
free_row_buffers(gs_image_enum * penum,int num_planes,client_name_t cname)373 free_row_buffers(gs_image_enum *penum, int num_planes, client_name_t cname)
374 {
375 int i;
376
377 for (i = num_planes - 1; i >= 0; --i) {
378 if_debug3('b', "[b]free plane %d row (0x%lx,%u)\n",
379 i, (ulong)penum->planes[i].row.data,
380 penum->planes[i].row.size);
381 gs_free_string(gs_image_row_memory(penum), penum->planes[i].row.data,
382 penum->planes[i].row.size, cname);
383 penum->planes[i].row.data = 0;
384 penum->planes[i].row.size = 0;
385 }
386 }
387
388 /* Process the next piece of an image. */
389 int
gs_image_next(gs_image_enum * penum,const byte * dbytes,uint dsize,uint * pused)390 gs_image_next(gs_image_enum * penum, const byte * dbytes, uint dsize,
391 uint * pused)
392 {
393 int px = penum->plane_index;
394 int num_planes = penum->num_planes;
395 int i, code;
396 uint used[gs_image_max_planes];
397 gs_const_string plane_data[gs_image_max_planes];
398
399 if (penum->planes[px].source.size != 0)
400 return_error(gs_error_rangecheck);
401 for (i = 0; i < num_planes; i++)
402 plane_data[i].size = 0;
403 plane_data[px].data = dbytes;
404 plane_data[px].size = dsize;
405 penum->error = false;
406 code = gs_image_next_planes(penum, plane_data, used);
407 *pused = used[px];
408 if (code >= 0)
409 next_plane(penum);
410 return code;
411 }
412
413 int
gs_image_next_planes(gs_image_enum * penum,gs_const_string * plane_data,uint * used)414 gs_image_next_planes(gs_image_enum * penum,
415 gs_const_string *plane_data /*[num_planes]*/,
416 uint *used /*[num_planes]*/)
417 {
418 const int num_planes = penum->num_planes;
419 int i;
420 int code = 0;
421
422 #ifdef DEBUG
423 if (gs_debug_c('b')) {
424 int pi;
425
426 for (pi = 0; pi < num_planes; ++pi)
427 dprintf6("[b]plane %d source=0x%lx,%u pos=%u data=0x%lx,%u\n",
428 pi, (ulong)penum->planes[pi].source.data,
429 penum->planes[pi].source.size, penum->planes[pi].pos,
430 (ulong)plane_data[pi].data, plane_data[pi].size);
431 }
432 #endif
433 for (i = 0; i < num_planes; ++i) {
434 used[i] = 0;
435 if (penum->wanted[i] && plane_data[i].size != 0) {
436 penum->planes[i].source.size = plane_data[i].size;
437 penum->planes[i].source.data = plane_data[i].data;
438 }
439 }
440 for (;;) {
441 /* If wanted can vary, only transfer 1 row at a time. */
442 int h = (penum->wanted_varies ? 1 : max_int);
443
444 /* Move partial rows from source[] to row[]. */
445 for (i = 0; i < num_planes; ++i) {
446 int pos, size;
447 uint raster;
448
449 if (!penum->wanted[i])
450 continue; /* skip unwanted planes */
451 pos = penum->planes[i].pos;
452 size = penum->planes[i].source.size;
453 raster = penum->image_planes[i].raster;
454 if (size > 0) {
455 if (pos < raster && (pos != 0 || size < raster)) {
456 /* Buffer a partial row. */
457 int copy = min(size, raster - pos);
458 uint old_size = penum->planes[i].row.size;
459
460 /* Make sure the row buffer is fully allocated. */
461 if (raster > old_size) {
462 gs_memory_t *mem = gs_image_row_memory(penum);
463 byte *old_data = penum->planes[i].row.data;
464 byte *row =
465 (old_data == 0 ?
466 gs_alloc_string(mem, raster,
467 "gs_image_next(row)") :
468 gs_resize_string(mem, old_data, old_size, raster,
469 "gs_image_next(row)"));
470
471 if_debug5('b', "[b]plane %d row (0x%lx,%u) => (0x%lx,%u)\n",
472 i, (ulong)old_data, old_size,
473 (ulong)row, raster);
474 if (row == 0) {
475 code = gs_note_error(gs_error_VMerror);
476 free_row_buffers(penum, i, "gs_image_next(row)");
477 break;
478 }
479 penum->planes[i].row.data = row;
480 penum->planes[i].row.size = raster;
481 }
482 memcpy(penum->planes[i].row.data + pos,
483 penum->planes[i].source.data, copy);
484 penum->planes[i].source.data += copy;
485 penum->planes[i].source.size = size -= copy;
486 penum->planes[i].pos = pos += copy;
487 used[i] += copy;
488 }
489 }
490 if (h == 0)
491 continue; /* can't transfer any data this cycle */
492 if (pos == raster) {
493 /*
494 * This plane will be transferred from the row buffer,
495 * so we can only transfer one row.
496 */
497 h = min(h, 1);
498 penum->image_planes[i].data = penum->planes[i].row.data;
499 } else if (pos == 0 && size >= raster) {
500 /* We can transfer 1 or more planes from the source. */
501 h = min(h, size / raster);
502 penum->image_planes[i].data = penum->planes[i].source.data;
503 } else
504 h = 0; /* not enough data in this plane */
505 }
506 if (h == 0 || code != 0)
507 break;
508 /* Pass rows to the device. */
509 if (penum->dev == 0) {
510 /*
511 * ****** NOTE: THE FOLLOWING IS NOT CORRECT FOR ImageType 3
512 * ****** InterleaveType 2, SINCE MASK HEIGHT AND IMAGE HEIGHT
513 * ****** MAY DIFFER (BY AN INTEGER FACTOR). ALSO, plane_depths[0]
514 * ****** AND plane_widths[0] ARE NOT UPDATED.
515 */
516 if (penum->y + h < penum->height)
517 code = 0;
518 else
519 h = penum->height - penum->y, code = 1;
520 } else {
521 code = gx_image_plane_data_rows(penum->info, penum->image_planes,
522 h, &h);
523 if_debug2('b', "[b]used %d, code=%d\n", h, code);
524 penum->error = code < 0;
525 }
526 penum->y += h;
527 /* Update positions and sizes. */
528 if (h == 0)
529 break;
530 for (i = 0; i < num_planes; ++i) {
531 int count;
532
533 if (!penum->wanted[i])
534 continue;
535 count = penum->image_planes[i].raster * h;
536 if (penum->planes[i].pos) {
537 /* We transferred the row from the row buffer. */
538 penum->planes[i].pos = 0;
539 } else {
540 /* We transferred the row(s) from the source. */
541 penum->planes[i].source.data += count;
542 penum->planes[i].source.size -= count;
543 used[i] += count;
544 }
545 }
546 cache_planes(penum);
547 if (code > 0)
548 break;
549 }
550 /* Return the retained data pointers. */
551 for (i = 0; i < num_planes; ++i)
552 plane_data[i] = penum->planes[i].source;
553 return code;
554 }
555
556 /* Clean up after processing an image. */
557 int
gs_image_cleanup(gs_image_enum * penum)558 gs_image_cleanup(gs_image_enum * penum)
559 {
560 int code = 0;
561
562 free_row_buffers(penum, penum->num_planes, "gs_image_cleanup(row)");
563 if (penum->info != 0)
564 code = gx_image_end(penum->info, !penum->error);
565 /* Don't free the local enumerator -- the client does that. */
566 return code;
567 }
568
569 /* Clean up after processing an image and free the enumerator. */
570 int
gs_image_cleanup_and_free_enum(gs_image_enum * penum)571 gs_image_cleanup_and_free_enum(gs_image_enum * penum)
572 {
573 int code = gs_image_cleanup(penum);
574
575 gs_free_object(penum->memory, penum, "gs_image_cleanup_and_free_enum");
576 return code;
577 }
578