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