/src/ghostpdl/base/gxidata.c
Line | Count | Source |
1 | | /* Copyright (C) 2001-2026 Artifex Software, Inc. |
2 | | All Rights Reserved. |
3 | | |
4 | | This software is provided AS-IS with no warranty, either express or |
5 | | implied. |
6 | | |
7 | | This software is distributed under license and may not be copied, |
8 | | modified or distributed except as expressly authorized under the terms |
9 | | of the license contained in the file LICENSE in this distribution. |
10 | | |
11 | | Refer to licensing information at http://www.artifex.com or contact |
12 | | Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco, |
13 | | CA 94129, USA, for further information. |
14 | | */ |
15 | | |
16 | | |
17 | | /* Generic image enumeration and cleanup */ |
18 | | #include "gx.h" |
19 | | #include "memory_.h" |
20 | | #include "gserrors.h" |
21 | | #include "gxdevice.h" |
22 | | #include "gxcpath.h" |
23 | | #include "gximage.h" |
24 | | #include "gsicc_cache.h" |
25 | | #include "gxgstate.h" |
26 | | |
27 | | #ifdef WITH_CAL |
28 | | #include "cal.h" |
29 | | #endif |
30 | | |
31 | | /* Forward declarations */ |
32 | | static void update_strip(gx_image_enum *penum); |
33 | | static void repack_bit_planes(const gx_image_plane_t *src_planes, |
34 | | const ulong *offsets, int num_planes, |
35 | | byte *buffer, int width, |
36 | | const sample_lookup_t * ptab, int spread); |
37 | | static gx_device *setup_image_device(const gx_image_enum *penum); |
38 | | |
39 | | /* Process the next piece of an ImageType 1 image. */ |
40 | | int |
41 | | gx_image1_plane_data(gx_image_enum_common_t * info, |
42 | | const gx_image_plane_t * planes, int height, |
43 | | int *rows_used) |
44 | 37.5M | { |
45 | 37.5M | gx_image_enum *penum = (gx_image_enum *) info; |
46 | 37.5M | gx_device *dev; |
47 | 37.5M | const int y = penum->y; |
48 | 37.5M | int y_end = min(y + height, penum->rect.h); |
49 | 37.5M | int width_spp; |
50 | 37.5M | int num_planes = penum->num_planes; |
51 | 37.5M | int num_components_per_plane = 1; |
52 | | |
53 | 37.5M | #define BCOUNT(plane) /* bytes per data row */\ |
54 | 37.5M | (((penum->rect.w + (plane).data_x) * penum->spp * penum->bps / num_planes\ |
55 | 33.5M | + 7) >> 3) |
56 | | |
57 | 37.5M | fixed adjust = penum->adjust; |
58 | 37.5M | ulong offsets[GS_IMAGE_MAX_COMPONENTS]; |
59 | 37.5M | int ignore_data_x; |
60 | 37.5M | bool bit_planar = penum->num_planes > penum->spp; |
61 | 37.5M | int code; |
62 | | |
63 | | /* Sanity check */ |
64 | 37.5M | if (penum->pgs != NULL && penum->pgs->level < penum->pgs_level) { |
65 | 1 | code = gs_note_error(gs_error_undefinedresult); |
66 | 1 | goto out; |
67 | 1 | } |
68 | 37.5M | if (height == 0) { |
69 | 0 | *rows_used = 0; |
70 | 0 | return 0; |
71 | 0 | } |
72 | | |
73 | | /* width_spp is an 'int' and is passed in various places as an int (or sometimes uint) data type. Since this could |
74 | | * be (usually is) a 32-bit type we need to ensure we do not overflow an int. We specifically test against 'int' |
75 | | * rather than '32-bit' in case int isn't 32-bit on this system. |
76 | | */ |
77 | 37.5M | if (check_int_multiply(penum->rect.w, penum->spp, &width_spp) != 0) |
78 | 0 | return gs_note_error(gs_error_undefinedresult); |
79 | | |
80 | 37.5M | dev = setup_image_device(penum); |
81 | | |
82 | | /* Now render complete rows. */ |
83 | | |
84 | 37.5M | if (penum->used.y) { |
85 | | /* |
86 | | * Processing was interrupted by an error. Skip over rows |
87 | | * already processed. |
88 | | */ |
89 | 0 | int px; |
90 | |
|
91 | 0 | for (px = 0; px < num_planes; ++px) |
92 | 0 | offsets[px] = (size_t)planes[px].raster * penum->used.y; |
93 | 0 | penum->used.y = 0; |
94 | 0 | } else |
95 | 37.5M | memset(offsets, 0, num_planes * sizeof(offsets[0])); |
96 | 37.5M | if (num_planes == 1 && penum->plane_depths[0] != penum->bps) { |
97 | | /* A single plane with multiple components. */ |
98 | 7.24M | num_components_per_plane = penum->plane_depths[0] / penum->bps; |
99 | 7.24M | } |
100 | 82.8M | for (; penum->y < y_end; penum->y++) { |
101 | 45.3M | int px; |
102 | 45.3M | const byte *buffer; |
103 | 45.3M | int sourcex; |
104 | 45.3M | int x_used = penum->used.x; |
105 | 45.3M | int skip = 0; |
106 | | |
107 | | /* Bump DDA's if it doesn't cause overflow */ |
108 | 45.3M | penum->cur.x = dda_current(penum->dda.row.x); |
109 | 45.3M | if (max_int - any_abs(penum->dda.row.x.step.dQ) > any_abs(penum->cur.x)) |
110 | 45.3M | dda_next(penum->dda.row.x); |
111 | 45.3M | penum->cur.y = dda_current(penum->dda.row.y); |
112 | 45.3M | if (max_int - any_abs(penum->dda.row.y.step.dQ) > any_abs(penum->cur.y)) |
113 | 45.3M | dda_next(penum->dda.row.y); |
114 | | |
115 | 45.3M | if (penum->interpolate == interp_off && penum->skip_next_line && penum->skip_next_line(penum, dev)) { |
116 | 19.4k | goto mt; |
117 | 45.2M | } else if (penum->skip_next_line == NULL) { |
118 | | /* Previously we skipped these calculations if we were interpolating. |
119 | | * Bug 706881 shows us that we can't skip this in all cases, because |
120 | | * the values are needed when halftoning for landscape files at least. |
121 | | * Easiest to always perform the calculations. */ |
122 | 44.2M | switch (penum->posture) { |
123 | 39.3M | case image_portrait: |
124 | 39.3M | { /* Precompute integer y and height, */ |
125 | | /* and check for clipping. */ |
126 | 39.3M | fixed yc = penum->cur.y, |
127 | 39.3M | yn = dda_current(penum->dda.row.y); |
128 | | |
129 | 39.3M | if (yn < yc) { |
130 | 1.04M | fixed temp = yn; |
131 | | |
132 | 1.04M | yn = yc; |
133 | 1.04M | yc = temp; |
134 | 1.04M | } |
135 | 39.3M | yc -= adjust; |
136 | 39.3M | yn += adjust; |
137 | 39.3M | if (penum->interpolate == interp_off) |
138 | 39.3M | { |
139 | 39.3M | if (yc >= penum->clip_outer.q.y) |
140 | 8.00M | goto mt; |
141 | 31.3M | if (yn <= penum->clip_outer.p.y) |
142 | 1.69M | goto mt; |
143 | 31.3M | } |
144 | 29.6M | penum->yci = fixed2int_pixround_perfect(yc); |
145 | 29.6M | penum->hci = fixed2int_pixround_perfect(yn) - penum->yci; |
146 | 29.6M | if (penum->interpolate == interp_off && penum->hci == 0) |
147 | 2.57M | goto mt; |
148 | 29.6M | if_debug2m('b', penum->memory, "[b]yci=%d, hci=%d\n", |
149 | 27.1M | penum->yci, penum->hci); |
150 | 27.1M | } |
151 | 0 | break; |
152 | 1.43M | case image_landscape: |
153 | 1.43M | { /* Check for no pixel centers in x. */ |
154 | 1.43M | fixed xc = penum->cur.x, |
155 | 1.43M | xn = dda_current(penum->dda.row.x); |
156 | | |
157 | 1.43M | if (xn < xc) { |
158 | 2.54k | fixed temp = xn; |
159 | | |
160 | 2.54k | xn = xc; |
161 | 2.54k | xc = temp; |
162 | 2.54k | } |
163 | 1.43M | xc -= adjust; |
164 | 1.43M | xn += adjust; |
165 | 1.43M | if (penum->interpolate == interp_off) |
166 | 1.43M | { |
167 | 1.43M | if (xc >= penum->clip_outer.q.x) |
168 | 2.80k | goto mt; |
169 | 1.43M | if (xn <= penum->clip_outer.p.x) |
170 | 82.7k | goto mt; |
171 | 1.43M | } |
172 | 1.35M | penum->xci = fixed2int_pixround_perfect(xc); |
173 | 1.35M | penum->wci = fixed2int_pixround_perfect(xn) - penum->xci; |
174 | 1.35M | if (penum->interpolate == interp_off && penum->wci == 0) |
175 | 16.8k | goto mt; |
176 | 1.35M | if_debug2m('b', penum->memory, "[b]xci=%d, wci=%d\n", |
177 | 1.33M | penum->xci, penum->wci); |
178 | 1.33M | } |
179 | 0 | break; |
180 | 3.42M | case image_skewed: |
181 | 3.42M | ; |
182 | 44.2M | } |
183 | 44.2M | } |
184 | 32.9M | if (0) |
185 | 0 | { |
186 | 12.4M | mt: |
187 | 12.4M | skip = 1; |
188 | 12.4M | } |
189 | 45.3M | if (bit_planar) { |
190 | | /* Repack the bit planes into byte-wide samples. */ |
191 | |
|
192 | 0 | buffer = penum->buffer; |
193 | 0 | sourcex = 0; |
194 | 0 | if (!skip) |
195 | 0 | for (px = 0; px < num_planes; px += penum->bps) |
196 | 0 | repack_bit_planes(planes, offsets, penum->bps, penum->buffer, |
197 | 0 | penum->rect.w, &penum->map[px].table, |
198 | 0 | penum->spread); |
199 | 0 | for (px = 0; px < num_planes; ++px) |
200 | 0 | offsets[px] += planes[px].raster; |
201 | 45.3M | } else { |
202 | | /* |
203 | | * Normally, we unpack the data into the buffer, but if |
204 | | * there is only one plane and we don't need to expand the |
205 | | * input samples, we may use the data directly. |
206 | | */ |
207 | 45.3M | sourcex = planes[0].data_x; |
208 | 45.3M | if (!skip) |
209 | 32.9M | buffer = |
210 | 32.9M | (*penum->unpack)(penum->buffer, &sourcex, |
211 | 32.9M | planes[0].data + offsets[0], |
212 | 32.9M | planes[0].data_x, BCOUNT(planes[0]), |
213 | 32.9M | &penum->map[0], penum->spread, num_components_per_plane); |
214 | 12.4M | else |
215 | 12.4M | buffer = NULL; |
216 | | |
217 | 45.3M | offsets[0] += planes[0].raster; |
218 | 45.9M | for (px = 1; px < num_planes; ++px) { |
219 | 667k | if (!skip) |
220 | 667k | (*penum->unpack)(penum->buffer + (px << penum->log2_xbytes), |
221 | 667k | &ignore_data_x, |
222 | 667k | planes[px].data + offsets[px], |
223 | 667k | planes[px].data_x, BCOUNT(planes[px]), |
224 | 667k | &penum->map[px], penum->spread, 1); |
225 | 667k | offsets[px] += planes[px].raster; |
226 | 667k | } |
227 | 45.3M | } |
228 | | #ifdef DEBUG |
229 | | if (gs_debug_c('b')) |
230 | | dmprintf1(dev->memory, "[b]image1 y=%d\n", y); |
231 | | if (gs_debug_c('B')) { |
232 | | int i, n = width_spp; |
233 | | byte *buftemp = (buffer == NULL) ? penum->buffer : (byte *)buffer; |
234 | | |
235 | | if (penum->bps > 8) |
236 | | n *= 2; |
237 | | else if (penum->bps == 1 && penum->unpack_bps == 8) |
238 | | n = (n + 7) / 8; |
239 | | dmlputs(dev->memory, "[B]row:"); |
240 | | for (i = 0; i < n; i++) |
241 | | dmprintf1(dev->memory, " %02x", buftemp[i]); |
242 | | dmputs(dev->memory, "\n"); |
243 | | } |
244 | | #endif |
245 | 45.3M | if (!skip) |
246 | 32.9M | { |
247 | 32.9M | update_strip(penum); |
248 | 32.9M | if (x_used) { |
249 | | /* |
250 | | * Processing was interrupted by an error. Skip over pixels |
251 | | * already processed. |
252 | | */ |
253 | 0 | dda_advance(penum->dda.pixel0.x, x_used); |
254 | 0 | dda_advance(penum->dda.pixel0.y, x_used); |
255 | 0 | penum->used.x = 0; |
256 | 0 | } |
257 | 32.9M | if_debug2m('b', penum->memory, "[b]pixel0 x=%g, y=%g\n", |
258 | 32.9M | fixed2float(dda_current(penum->dda.pixel0.x)), |
259 | 32.9M | fixed2float(dda_current(penum->dda.pixel0.y))); |
260 | 32.9M | code = (*penum->render)(penum, buffer, sourcex + x_used, |
261 | 32.9M | width_spp - x_used * penum->spp, 1, dev); |
262 | 32.9M | if (code < 0) { |
263 | | /* Error or interrupt, restore original state. */ |
264 | 0 | penum->used.x += x_used; |
265 | 0 | if (!penum->used.y) { |
266 | 0 | dda_previous(penum->dda.row.x); |
267 | 0 | dda_previous(penum->dda.row.y); |
268 | 0 | dda_translate(penum->dda.strip.x, |
269 | 0 | penum->prev.x - penum->cur.x); |
270 | 0 | dda_translate(penum->dda.strip.y, |
271 | 0 | penum->prev.y - penum->cur.y); |
272 | 0 | } |
273 | 0 | goto out; |
274 | 0 | } |
275 | 32.9M | penum->prev = penum->cur; |
276 | 32.9M | } |
277 | 45.3M | } |
278 | 37.5M | if (penum->y < penum->rect.h) { |
279 | 35.9M | code = 0; |
280 | 35.9M | } else { |
281 | | /* End of input data. Render any left-over buffered data. */ |
282 | 1.56M | code = gx_image1_flush(info); |
283 | 1.56M | if (code >= 0) |
284 | 1.56M | code = 1; |
285 | 1.56M | } |
286 | 37.5M | out: |
287 | | /* Note that caller must call end_image */ |
288 | | /* for both error and normal termination. */ |
289 | 37.5M | *rows_used = penum->y - y; |
290 | 37.5M | return code; |
291 | 37.5M | } |
292 | | |
293 | | /* Flush any buffered data. */ |
294 | | int |
295 | | gx_image1_flush(gx_image_enum_common_t * info) |
296 | 3.22M | { |
297 | 3.22M | gx_image_enum *penum = (gx_image_enum *)info; |
298 | 3.22M | int width_spp = penum->rect.w * penum->spp; |
299 | 3.22M | fixed adjust = penum->adjust; |
300 | | |
301 | 3.22M | penum->cur.x = dda_current(penum->dda.row.x); |
302 | 3.22M | penum->cur.y = dda_current(penum->dda.row.y); |
303 | 3.22M | switch (penum->posture) { |
304 | 2.75M | case image_portrait: |
305 | 2.75M | { |
306 | 2.75M | fixed yc = penum->cur.y; |
307 | | |
308 | 2.75M | penum->yci = fixed2int_rounded(yc - adjust); |
309 | 2.75M | penum->hci = fixed2int_rounded(yc + adjust) - penum->yci; |
310 | 2.75M | } |
311 | 2.75M | break; |
312 | 266k | case image_landscape: |
313 | 266k | { |
314 | 266k | fixed xc = penum->cur.x; |
315 | | |
316 | 266k | penum->xci = fixed2int_rounded(xc - adjust); |
317 | 266k | penum->wci = fixed2int_rounded(xc + adjust) - penum->xci; |
318 | 266k | } |
319 | 266k | break; |
320 | 198k | case image_skewed: /* pacify compilers */ |
321 | 198k | ; |
322 | 3.22M | } |
323 | 3.22M | update_strip(penum); |
324 | 3.22M | penum->prev = penum->cur; |
325 | 3.22M | return (*penum->render)(penum, NULL, 0, width_spp, 0, |
326 | 3.22M | setup_image_device(penum)); |
327 | 3.22M | } |
328 | | |
329 | | /* Update the strip DDA when moving to a new row. */ |
330 | | static void |
331 | | update_strip(gx_image_enum *penum) |
332 | 36.1M | { |
333 | | |
334 | 36.1M | #if 1 |
335 | | /* Old code. */ |
336 | 36.1M | dda_translate(penum->dda.strip.x, penum->cur.x - penum->prev.x); |
337 | 36.1M | dda_translate(penum->dda.strip.y, penum->cur.y - penum->prev.y); |
338 | 36.1M | penum->dda.pixel0 = penum->dda.strip; |
339 | | #else |
340 | | /* A better precision with stromng dda_advance - |
341 | | doesn't work becauae gx_image1_plane_data |
342 | | doesn't call it at each step. */ |
343 | | gx_dda_fixed_point temp; |
344 | | |
345 | | temp.x.state = penum->dda.strip.x.state; |
346 | | temp.y.state = penum->dda.strip.y.state; |
347 | | temp.x.step = penum->dda.row.x.step; |
348 | | temp.y.step = penum->dda.row.y.step; |
349 | | dda_next(temp.x); |
350 | | dda_next(temp.y); |
351 | | penum->dda.strip.x.state = temp.x.state; |
352 | | penum->dda.strip.y.state = temp.y.state; |
353 | | penum->dda.pixel0 = penum->dda.strip; |
354 | | #endif |
355 | 36.1M | } |
356 | | |
357 | | /* |
358 | | * Repack 1 to 8 individual bit planes into 8-bit samples. |
359 | | * buffer is aligned, and includes padding to an 8-byte boundary. |
360 | | * This procedure repacks one row, so the only relevant members of |
361 | | * src_planes are data and data_x (not raster). |
362 | | */ |
363 | | static void |
364 | | repack_bit_planes(const gx_image_plane_t *src_planes, const ulong *offsets, |
365 | | int num_planes, byte *buffer, int width, |
366 | | const sample_lookup_t * ptab, int spread) |
367 | 0 | { |
368 | 0 | gx_image_plane_t planes[8]; |
369 | 0 | byte *zeros = 0; |
370 | 0 | byte *dest = buffer; |
371 | 0 | int any_data_x = 0; |
372 | 0 | bool direct = (spread == 1 && ptab->lookup8[0] == 0 && |
373 | 0 | ptab->lookup8[255] == 255); |
374 | 0 | int pi, x; |
375 | 0 | gx_image_plane_t *pp; |
376 | | |
377 | | /* |
378 | | * Set up the row pointers, taking data_x and null planes into account. |
379 | | * If there are any null rows, we need to create a block of zeros in |
380 | | * order to avoid tests in the loop. |
381 | | */ |
382 | 0 | for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) |
383 | 0 | if (src_planes[pi].data == 0) { |
384 | 0 | if (!zeros) { |
385 | 0 | zeros = buffer + width - ((width + 7) >> 3); |
386 | 0 | } |
387 | 0 | pp->data = zeros; |
388 | 0 | pp->data_x = 0; |
389 | 0 | } else { |
390 | 0 | int dx = src_planes[pi].data_x; |
391 | |
|
392 | 0 | pp->data = src_planes[pi].data + (dx >> 3) + offsets[pi]; |
393 | 0 | any_data_x |= (pp->data_x = dx & 7); |
394 | 0 | } |
395 | 0 | if (zeros) |
396 | 0 | memset(zeros, 0, buffer + width - zeros); |
397 | | |
398 | | /* |
399 | | * Now process the data, in blocks of one input byte column |
400 | | * (8 output bytes). |
401 | | */ |
402 | 0 | for (x = 0; x < width; x += 8) { |
403 | 0 | bits32 w0 = 0, w1 = 0; |
404 | | #if ARCH_IS_BIG_ENDIAN |
405 | | static const bits32 expand[16] = { |
406 | | 0x00000000, 0x00000001, 0x00000100, 0x00000101, |
407 | | 0x00010000, 0x00010001, 0x00010100, 0x00010101, |
408 | | 0x01000000, 0x01000001, 0x01000100, 0x01000101, |
409 | | 0x01010000, 0x01010001, 0x01010100, 0x01010101 |
410 | | }; |
411 | | #else |
412 | 0 | static const bits32 expand[16] = { |
413 | 0 | 0x00000000, 0x01000000, 0x00010000, 0x01010000, |
414 | 0 | 0x00000100, 0x01000100, 0x00010100, 0x01010100, |
415 | 0 | 0x00000001, 0x01000001, 0x00010001, 0x01010001, |
416 | 0 | 0x00000101, 0x01000101, 0x00010101, 0x01010101 |
417 | 0 | }; |
418 | 0 | #endif |
419 | |
|
420 | 0 | if (any_data_x) { |
421 | 0 | for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) { |
422 | 0 | uint b = *(pp->data++); |
423 | 0 | int dx = pp->data_x; |
424 | |
|
425 | 0 | if (dx) { |
426 | 0 | b <<= dx; |
427 | 0 | if (x + 8 - dx < width) |
428 | 0 | b += *pp->data >> (8 - dx); |
429 | 0 | } |
430 | 0 | w0 = (w0 << 1) | expand[b >> 4]; |
431 | 0 | w1 = (w1 << 1) | expand[b & 0xf]; |
432 | 0 | } |
433 | 0 | } else { |
434 | 0 | for (pi = 0, pp = planes; pi < num_planes; ++pi, ++pp) { |
435 | 0 | uint b = *(pp->data++); |
436 | |
|
437 | 0 | w0 = (w0 << 1) | expand[b >> 4]; |
438 | 0 | w1 = (w1 << 1) | expand[b & 0xf]; |
439 | 0 | } |
440 | 0 | } |
441 | | /* |
442 | | * We optimize spread == 1 and identity ptab together, although |
443 | | * we could subdivide these 2 cases into 4 if we wanted. |
444 | | */ |
445 | 0 | if (direct) { |
446 | 0 | ((bits32 *)dest)[0] = w0; |
447 | 0 | ((bits32 *)dest)[1] = w1; |
448 | 0 | dest += 8; |
449 | 0 | } else { |
450 | 0 | #define MAP_BYTE(v) (ptab->lookup8[(byte)(v)]) |
451 | 0 | dest[0] = MAP_BYTE(w0 >> 24); dest += spread; |
452 | 0 | dest[1] = MAP_BYTE(w0 >> 16); dest += spread; |
453 | 0 | dest[2] = MAP_BYTE(w0 >> 8); dest += spread; |
454 | 0 | dest[3] = MAP_BYTE(w0); dest += spread; |
455 | 0 | dest[4] = MAP_BYTE(w1 >> 24); dest += spread; |
456 | 0 | dest[5] = MAP_BYTE(w1 >> 16); dest += spread; |
457 | 0 | dest[6] = MAP_BYTE(w1 >> 8); dest += spread; |
458 | 0 | dest[7] = MAP_BYTE(w1); dest += spread; |
459 | 0 | #undef MAP_BYTE |
460 | 0 | } |
461 | 0 | } |
462 | 0 | } |
463 | | |
464 | | /* Set up the device for drawing an image. */ |
465 | | static gx_device * |
466 | | setup_image_device(const gx_image_enum *penum) |
467 | 40.7M | { |
468 | 40.7M | gx_device *dev = penum->dev; |
469 | | |
470 | 40.7M | if (penum->clip_dev) { |
471 | 27.4M | gx_device_clip *cdev = penum->clip_dev; |
472 | | |
473 | 27.4M | gx_device_set_target((gx_device_forward *)cdev, dev); |
474 | 27.4M | dev = (gx_device *) cdev; |
475 | 27.4M | } |
476 | 40.7M | if (penum->rop_dev) { |
477 | 0 | gx_device_rop_texture *rtdev = penum->rop_dev; |
478 | |
|
479 | 0 | gx_device_set_target((gx_device_forward *)rtdev, dev); |
480 | 0 | dev = (gx_device *) rtdev; |
481 | 0 | } |
482 | 40.7M | return dev; |
483 | 40.7M | } |
484 | | |
485 | | /* Clean up by releasing the buffers. */ |
486 | | /* Currently we ignore draw_last. */ |
487 | | int |
488 | | gx_image1_end_image(gx_image_enum_common_t * info, bool draw_last) |
489 | 1.58M | { |
490 | 1.58M | gx_image_enum *penum = (gx_image_enum *) info; |
491 | 1.58M | gs_memory_t *mem = penum->memory; |
492 | 1.58M | stream_image_scale_state *scaler = penum->scaler; |
493 | | |
494 | 1.58M | if_debug2m('b', penum->memory, "[b]%send_image, y=%d\n", |
495 | 1.58M | (penum->y < penum->rect.h ? "premature " : ""), penum->y); |
496 | 1.58M | if (draw_last) { |
497 | 1.58M | int code = gx_image_flush(info); |
498 | | |
499 | 1.58M | if (code < 0) |
500 | 0 | return code; |
501 | 1.58M | } |
502 | | |
503 | 1.58M | if (penum->tpr_state != NULL) { |
504 | 63.6k | transform_pixel_region_data data; |
505 | 63.6k | gx_device *dev = penum->dev; |
506 | 63.6k | if (penum->clip_dev) |
507 | 8.94k | dev = (gx_device *)penum->clip_dev; |
508 | 63.6k | if (penum->rop_dev) |
509 | 0 | dev = (gx_device *)penum->rop_dev; |
510 | 63.6k | data.state = penum->tpr_state; |
511 | 63.6k | dev_proc(dev, transform_pixel_region)(dev, transform_pixel_region_end, &data); |
512 | 63.6k | } |
513 | | /* release the reference to the target */ |
514 | 1.58M | if ( penum->rop_dev ) |
515 | 0 | gx_device_set_target((gx_device_forward *)penum->rop_dev, NULL); |
516 | | /* it is not clear (to me) why these are freed explicitly instead |
517 | | of using reference counting */ |
518 | 1.58M | gs_free_object(mem, penum->rop_dev, "image RasterOp"); |
519 | | |
520 | | /* We do now reference count the clip device, see bug #706771 */ |
521 | 1.58M | rc_decrement(penum->clip_dev, "gx_image1_end_image"); |
522 | 1.58M | penum->clip_dev = NULL; |
523 | | |
524 | 1.58M | if (scaler != 0) { |
525 | 0 | (*scaler->templat->release) ((stream_state *) scaler); |
526 | 0 | gs_free_object(mem, scaler, "image scaler state"); |
527 | 0 | } |
528 | 1.58M | if (penum->icc_link != NULL) { |
529 | 800k | gsicc_release_link(penum->icc_link); |
530 | 800k | } |
531 | 1.58M | if (penum->color_cache != NULL) { |
532 | 1.77k | gs_free_object(mem, penum->color_cache->device_contone, |
533 | 1.77k | "device_contone"); |
534 | 1.77k | gs_free_object(mem, penum->color_cache->is_transparent, |
535 | 1.77k | "image is_transparent"); |
536 | 1.77k | gs_free_object(mem, penum->color_cache, "image color cache"); |
537 | 1.77k | } |
538 | 1.58M | if (penum->thresh_buffer != NULL) { |
539 | 139k | gs_free_object(mem, penum->thresh_buffer, "image thresh_buffer"); |
540 | 139k | } |
541 | 1.58M | if (penum->ht_buffer != NULL) { |
542 | 139k | gs_free_object(mem, penum->ht_buffer, "image ht_buffer"); |
543 | 139k | } |
544 | 1.58M | if (penum->clues != NULL) { |
545 | 864k | gs_free_object(mem,penum->clues, "image clues"); |
546 | 864k | } |
547 | | |
548 | | /* decrement this ref that was incremented in gx_image_enum_begin() */ |
549 | 1.58M | rc_decrement_only(penum->pcs, "pcs"); |
550 | 1.58M | penum->pcs = NULL; |
551 | | |
552 | 1.58M | gs_free_object(mem, penum->line, "image line"); |
553 | 1.58M | gs_free_object(mem, penum->buffer, "image buffer"); |
554 | | |
555 | | #ifdef WITH_CAL |
556 | | if (penum->cal_ht != NULL) { |
557 | | cal_halftone_fin(penum->cal_ht, mem->non_gc_memory); |
558 | | } |
559 | | #endif |
560 | 1.58M | gx_image_free_enum(&info); |
561 | 1.58M | return 0; |
562 | 1.58M | } |