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