1 /* Copyright (C) 1997, 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: gdevpsdi.c,v 1.45 2005/09/29 18:35:18 leonardo Exp $ */
18 /* Image compression for PostScript and PDF writers */
19 #include "stdio_.h" /* for jpeglib.h */
20 #include "jpeglib_.h" /* for sdct.h */
21 #include "math_.h"
22 #include "gx.h"
23 #include "gserrors.h"
24 #include "gscspace.h"
25 #include "gdevpsdf.h"
26 #include "gdevpsds.h"
27 #include "gxdevmem.h"
28 #include "gxcspace.h"
29 #include "gsparamx.h"
30 #include "strimpl.h"
31 #include "scfx.h"
32 #include "sdct.h"
33 #include "sjpeg.h"
34 #include "slzwx.h"
35 #include "spngpx.h"
36 #include "srlx.h"
37 #include "szlibx.h"
38
39 /* Define parameter-setting procedures. */
40 extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
41
42 /* ---------------- Image compression ---------------- */
43
44 /*
45 * Add a filter to expand or reduce the pixel width if needed.
46 * At least one of bpc_in and bpc_out is 8; the other is 1, 2, 4, or 8,
47 * except if bpc_out is 8, bpc_in may be 12.
48 */
49 private int
pixel_resize(psdf_binary_writer * pbw,int width,int num_components,int bpc_in,int bpc_out)50 pixel_resize(psdf_binary_writer * pbw, int width, int num_components,
51 int bpc_in, int bpc_out)
52 {
53 gs_memory_t *mem = pbw->dev->v_memory;
54 const stream_template *template;
55 stream_1248_state *st;
56 int code;
57
58 if (bpc_out == bpc_in)
59 return 0;
60 if (bpc_in != 8) {
61 static const stream_template *const exts[13] = {
62 0, &s_1_8_template, &s_2_8_template, 0, &s_4_8_template,
63 0, 0, 0, 0, 0, 0, 0, &s_12_8_template
64 };
65
66 template = exts[bpc_in];
67 } else {
68 static const stream_template *const rets[5] = {
69 0, &s_8_1_template, &s_8_2_template, 0, &s_8_4_template
70 };
71
72 template = rets[bpc_out];
73 }
74 st = (stream_1248_state *)
75 s_alloc_state(mem, template->stype, "pixel_resize state");
76 if (st == 0)
77 return_error(gs_error_VMerror);
78 code = psdf_encode_binary(pbw, template, (stream_state *) st);
79 if (code < 0) {
80 gs_free_object(mem, st, "pixel_resize state");
81 return code;
82 }
83 s_1248_init(st, width, num_components);
84 return 0;
85 }
86
87 private int
convert_color(gx_device * pdev,const gs_color_space * pcs,const gs_imager_state * pis,gs_client_color * cc,float c[3])88 convert_color(gx_device *pdev, const gs_color_space *pcs, const gs_imager_state * pis,
89 gs_client_color *cc, float c[3])
90 {
91 int code;
92 gx_device_color dc;
93
94 cs_restrict_color(cc, pcs);
95 code = pcs->type->remap_color(cc, pcs, &dc, pis, pdev, gs_color_select_texture);
96 if (code < 0)
97 return code;
98 c[0] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[0]) & ((1 << pdev->color_info.comp_bits[0]) - 1));
99 c[1] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[1]) & ((1 << pdev->color_info.comp_bits[1]) - 1));
100 c[2] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[2]) & ((1 << pdev->color_info.comp_bits[2]) - 1));
101 return 0;
102 }
103
104 /* A hewristic choice of DCT compression parameters - see bug 687174. */
105 private int
choose_DCT_params(gx_device * pdev,const gs_color_space * pcs,const gs_imager_state * pis,gs_c_param_list * list,gs_c_param_list ** param,stream_state * st)106 choose_DCT_params(gx_device *pdev, const gs_color_space *pcs,
107 const gs_imager_state * pis,
108 gs_c_param_list *list, gs_c_param_list **param,
109 stream_state *st)
110 {
111 gx_device_memory mdev;
112 gs_client_color cc;
113 int code;
114 float c[4][3];
115 const float MIN_FLOAT = - MAX_FLOAT;
116 const float domination = (float)0.25;
117 const int one = 1, zero = 0;
118
119 if (pcs->type->num_components(pcs) != 3)
120 return 0;
121 /* Make a copy of the parameter list since we will modify it. */
122 code = param_list_copy((gs_param_list *)list, (gs_param_list *)*param);
123 if (code < 0)
124 return code;
125 *param = list;
126
127 /* Create a local memory device for transforming colors to DeviceRGB. */
128 gs_make_mem_device(&mdev, gdev_mem_device_for_bits(24), pdev->memory, 0, NULL);
129 gx_device_retain((gx_device *)&mdev, true); /* prevent freeing */
130 set_linear_color_bits_mask_shift((gx_device *)&mdev);
131 mdev.color_info.separable_and_linear = GX_CINFO_SEP_LIN;
132
133 /* Check for an RGB-like color space.
134 To recognize that we make a matrix as it were a linear operator,
135 suppress an ununiformity by subtracting the image of {0,0,0},
136 and then check for giagonal domination. */
137 cc.paint.values[0] = cc.paint.values[1] = cc.paint.values[2] = MIN_FLOAT;
138 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[3]);
139 cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MIN_FLOAT;
140 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[0]);
141 cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MAX_FLOAT; cc.paint.values[2] = MIN_FLOAT;
142 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[1]);
143 cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MAX_FLOAT;
144 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[2]);
145 c[0][0] -= c[3][0]; c[0][1] -= c[3][1]; c[0][2] -= c[3][2];
146 c[1][0] -= c[3][0]; c[1][1] -= c[3][1]; c[1][2] -= c[3][2];
147 c[2][0] -= c[3][0]; c[2][1] -= c[3][1]; c[2][2] -= c[3][2];
148 c[0][0] = any_abs(c[0][0]); c[0][1] = any_abs(c[0][1]); c[0][2] = any_abs(c[0][2]);
149 c[1][0] = any_abs(c[1][0]); c[1][1] = any_abs(c[1][1]); c[1][2] = any_abs(c[1][2]);
150 c[2][0] = any_abs(c[2][0]); c[2][1] = any_abs(c[2][1]); c[2][2] = any_abs(c[2][2]);
151 if (c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
152 c[1][1] * domination > c[1][0] && c[1][1] * domination > c[1][2] &&
153 c[2][2] * domination > c[2][0] && c[2][2] * domination > c[2][1]) {
154 /* Yes, it looks like an RGB color space.
155 Replace ColorTransform with 1. */
156 code = param_write_int((gs_param_list *)list, "ColorTransform", &one);
157 if (code < 0)
158 return code;
159 goto done;
160 }
161
162 /* Check for a Lab-like color space.
163 Colors {v,0,0} should map to grays. */
164 cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = cc.paint.values[2] = 0;
165 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[0]);
166 cc.paint.values[0] /= 2;
167 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[1]);
168 cc.paint.values[0] /= 2;
169 convert_color((gx_device *)&mdev, pcs, pis, &cc, c[2]);
170 c[0][1] -= c[0][0]; c[0][2] -= c[0][0];
171 c[1][1] -= c[1][0]; c[1][2] -= c[1][0];
172 c[2][1] -= c[2][0]; c[2][2] -= c[2][0];
173 c[0][1] = any_abs(c[0][1]); c[0][2] = any_abs(c[0][2]);
174 c[1][1] = any_abs(c[1][1]); c[1][2] = any_abs(c[1][2]);
175 c[2][1] = any_abs(c[2][1]); c[2][2] = any_abs(c[2][2]);
176 if (c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
177 c[1][0] * domination > c[1][1] && c[1][0] * domination > c[1][2] &&
178 c[2][0] * domination > c[2][1] && c[2][0] * domination > c[2][2]) {
179 /* Yes, it looks like an Lab color space.
180 Replace ColorTransform with 0. */
181 code = param_write_int((gs_param_list *)list, "ColorTransform", &zero);
182 if (code < 0)
183 return code;
184 } else {
185 /* Unknown color space type.
186 Replace /HSamples [1 1 1 1] /VSamples [1 1 1 1] to avoid quality degradation. */
187 gs_param_string a;
188 static const byte v[4] = {1, 1, 1, 1};
189
190 a.data = v;
191 a.size = 4;
192 a.persistent = true;
193 code = param_write_string((gs_param_list *)list, "HSamples", &a);
194 if (code < 0)
195 return code;
196 code = param_write_string((gs_param_list *)list, "VSamples", &a);
197 if (code < 0)
198 return code;
199 }
200 done:
201 gs_c_param_list_read(list);
202 return 0;
203 }
204
205 /* Add the appropriate image compression filter, if any. */
206 private int
setup_image_compression(psdf_binary_writer * pbw,const psdf_image_params * pdip,const gs_pixel_image_t * pim,const gs_imager_state * pis,bool lossless)207 setup_image_compression(psdf_binary_writer *pbw, const psdf_image_params *pdip,
208 const gs_pixel_image_t * pim, const gs_imager_state * pis,
209 bool lossless)
210 {
211 gx_device_psdf *pdev = pbw->dev;
212 gs_memory_t *mem = pdev->v_memory;
213 const stream_template *template = pdip->filter_template;
214 const stream_template *orig_template = template;
215 const stream_template *lossless_template =
216 (pdev->params.UseFlateCompression &&
217 pdev->version >= psdf_version_ll3 ?
218 &s_zlibE_template : &s_LZWE_template);
219 const gs_color_space *pcs = pim->ColorSpace; /* null if mask */
220 int Colors = (pcs ? gs_color_space_num_components(pcs) : 1);
221 bool Indexed =
222 (pcs != 0 &&
223 gs_color_space_get_index(pcs) == gs_color_space_index_Indexed);
224 gs_c_param_list *dict = pdip->Dict;
225 stream_state *st;
226 int code;
227
228 if (!pdip->Encode) /* no compression */
229 return 0;
230 if (pdip->AutoFilter) {
231 /*
232 * Disregard the requested filter. What we should do at this point
233 * is analyze the image to decide whether to use JPEG encoding
234 * (DCTEncode with ACSDict) or the lossless filter. However, since
235 * we don't buffer the entire image, we'll make the choice on-fly,
236 * forking the image data into 3 streams : (1) JPEG, (2) lossless,
237 * (3) the compression chooser. In this case this function is
238 * called 2 times with different values of the 'lossless' argument.
239 */
240 if (lossless) {
241 orig_template = template = lossless_template;
242 } else {
243 orig_template = template = &s_DCTE_template;
244 }
245 dict = pdip->ACSDict;
246 } else if (!lossless)
247 return gs_error_rangecheck; /* Reject the alternative stream. */
248 if (pdev->version < psdf_version_ll3 && template == &s_zlibE_template)
249 orig_template = template = lossless_template;
250 if (dict) /* NB: rather than dereference NULL lets continue on without a dict */
251 gs_c_param_list_read(dict); /* ensure param list is in read mode */
252 if (template == 0) /* no compression */
253 return 0;
254 if (pim->Width < 200 && pim->Height < 200) /* Prevent a fixed overflow. */
255 if (pim->Width * pim->Height * Colors * pim->BitsPerComponent <= 160)
256 return 0; /* not worth compressing */
257 /* Only use DCTE for 8-bit, non-Indexed data. */
258 if (template == &s_DCTE_template) {
259 if (Indexed ||
260 !(pdip->Downsample ?
261 pdip->Depth == 8 ||
262 (pdip->Depth == -1 && pim->BitsPerComponent == 8) :
263 pim->BitsPerComponent == 8)
264 ) {
265 /* Use LZW/Flate instead. */
266 template = lossless_template;
267 }
268 }
269 st = s_alloc_state(mem, template->stype, "setup_image_compression");
270 if (st == 0)
271 return_error(gs_error_VMerror);
272 if (template->set_defaults)
273 (*template->set_defaults) (st);
274 if (template == &s_CFE_template) {
275 stream_CFE_state *const ss = (stream_CFE_state *) st;
276
277 if (pdip->Dict != 0 && pdip->filter_template == template) {
278 s_CF_put_params((gs_param_list *)pdip->Dict,
279 (stream_CF_state *)ss); /* ignore errors */
280 } else {
281 ss->K = -1;
282 ss->BlackIs1 = true;
283 }
284 ss->Columns = pim->Width;
285 ss->Rows = (ss->EndOfBlock ? 0 : pim->Height);
286 } else if ((template == &s_LZWE_template ||
287 template == &s_zlibE_template) &&
288 pdev->version >= psdf_version_ll3) {
289 /* If not Indexed, add a PNGPredictor filter. */
290 if (!Indexed) {
291 code = psdf_encode_binary(pbw, template, st);
292 if (code < 0)
293 goto fail;
294 template = &s_PNGPE_template;
295 st = s_alloc_state(mem, template->stype, "setup_image_compression");
296 if (st == 0) {
297 code = gs_note_error(gs_error_VMerror);
298 goto fail;
299 }
300 if (template->set_defaults)
301 (*template->set_defaults) (st);
302 {
303 stream_PNGP_state *const ss = (stream_PNGP_state *) st;
304
305 ss->Colors = Colors;
306 ss->Columns = pim->Width;
307 }
308 }
309 } else if (template == &s_DCTE_template) {
310 gs_c_param_list list, *param = dict;
311
312 gs_c_param_list_write(&list, mem);
313 code = choose_DCT_params((gx_device *)pbw->dev, pcs, pis, &list, ¶m, st);
314 if (code < 0) {
315 gs_c_param_list_release(&list);
316 return code;
317 }
318 code = psdf_DCT_filter((gs_param_list *)param,
319 st, pim->Width, pim->Height, Colors, pbw);
320 gs_c_param_list_release(&list);
321 if (code < 0)
322 goto fail;
323 /* psdf_DCT_filter already did the psdf_encode_binary. */
324 return 0;
325 } else if (template == &s_LZWE_template) {
326 if (template->set_defaults)
327 (*template->set_defaults) (st);
328 }
329 code = psdf_encode_binary(pbw, template, st);
330 if (code >= 0)
331 return 0;
332 fail:
333 gs_free_object(mem, st, "setup_image_compression");
334 return code;
335 }
336
337 /* Determine whether an image should be downsampled. */
338 private bool
do_downsample(const psdf_image_params * pdip,const gs_pixel_image_t * pim,floatp resolution)339 do_downsample(const psdf_image_params *pdip, const gs_pixel_image_t *pim,
340 floatp resolution)
341 {
342 floatp factor = (int)(resolution / pdip->Resolution);
343
344 return (pdip->Downsample && factor >= pdip->DownsampleThreshold &&
345 factor <= pim->Width && factor <= pim->Height);
346 }
347
348 /* Add downsampling, antialiasing, and compression filters. */
349 /* Uses AntiAlias, Depth, DownsampleThreshold, DownsampleType, Resolution. */
350 /* Assumes do_downsampling() is true. */
351 private int
setup_downsampling(psdf_binary_writer * pbw,const psdf_image_params * pdip,gs_pixel_image_t * pim,const gs_imager_state * pis,floatp resolution,bool lossless)352 setup_downsampling(psdf_binary_writer * pbw, const psdf_image_params * pdip,
353 gs_pixel_image_t * pim, const gs_imager_state * pis,
354 floatp resolution, bool lossless)
355 {
356 gx_device_psdf *pdev = pbw->dev;
357 /* Note: Bicubic is currently interpreted as Average. */
358 const stream_template *template =
359 (pdip->DownsampleType == ds_Subsample ?
360 &s_Subsample_template : &s_Average_template);
361 int factor = (int)(resolution / pdip->Resolution);
362 int orig_bpc = pim->BitsPerComponent;
363 int orig_width = pim->Width;
364 int orig_height = pim->Height;
365 stream_state *st;
366 int code;
367
368 st = s_alloc_state(pdev->v_memory, template->stype,
369 "setup_downsampling");
370 if (st == 0)
371 return_error(gs_error_VMerror);
372 if (template->set_defaults)
373 template->set_defaults(st);
374 {
375 stream_Downsample_state *const ss = (stream_Downsample_state *) st;
376
377 ss->Colors =
378 (pim->ColorSpace == 0 ? 1 /*mask*/ :
379 gs_color_space_num_components(pim->ColorSpace));
380 ss->WidthIn = pim->Width;
381 ss->HeightIn = pim->Height;
382 ss->XFactor = ss->YFactor = factor;
383 ss->AntiAlias = pdip->AntiAlias;
384 ss->padX = ss->padY = false; /* should be true */
385 if (template->init)
386 template->init(st);
387 pim->Width = s_Downsample_size_out(pim->Width, factor, ss->padX);
388 pim->Height = s_Downsample_size_out(pim->Height, factor, ss->padY);
389 pim->BitsPerComponent = pdip->Depth;
390 gs_matrix_scale(&pim->ImageMatrix, (double)pim->Width / orig_width,
391 (double)pim->Height / orig_height,
392 &pim->ImageMatrix);
393 /****** NO ANTI-ALIASING YET ******/
394 if ((code = setup_image_compression(pbw, pdip, pim, pis, lossless)) < 0 ||
395 (code = pixel_resize(pbw, pim->Width, ss->Colors,
396 8, pdip->Depth)) < 0 ||
397 (code = psdf_encode_binary(pbw, template, st)) < 0 ||
398 (code = pixel_resize(pbw, orig_width, ss->Colors,
399 orig_bpc, 8)) < 0
400 ) {
401 gs_free_object(pdev->v_memory, st, "setup_image_compression");
402 return code;
403 }
404 }
405 return 0;
406 }
407
408 /* Decive whether to convert an image to RGB. */
409 bool
psdf_is_converting_image_to_RGB(const gx_device_psdf * pdev,const gs_imager_state * pis,const gs_pixel_image_t * pim)410 psdf_is_converting_image_to_RGB(const gx_device_psdf * pdev,
411 const gs_imager_state * pis, const gs_pixel_image_t * pim)
412 {
413 return pdev->params.ConvertCMYKImagesToRGB &&
414 pis != 0 &&
415 gs_color_space_get_index(pim->ColorSpace) ==
416 gs_color_space_index_DeviceCMYK;
417 }
418
419 /* Set up compression and downsampling filters for an image. */
420 /* Note that this may modify the image parameters. */
421 int
psdf_setup_image_filters(gx_device_psdf * pdev,psdf_binary_writer * pbw,gs_pixel_image_t * pim,const gs_matrix * pctm,const gs_imager_state * pis,bool lossless)422 psdf_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw,
423 gs_pixel_image_t * pim, const gs_matrix * pctm,
424 const gs_imager_state * pis, bool lossless)
425 {
426 /*
427 * The following algorithms are per Adobe Tech Note # 5151,
428 * "Acrobat Distiller Parameters", revised 16 September 1996
429 * for Acrobat(TM) Distiller(TM) 3.0.
430 *
431 * The control structure is a little tricky, because filter
432 * pipelines must be constructed back-to-front.
433 */
434 int code = 0;
435 psdf_image_params params;
436 int bpc = pim->BitsPerComponent;
437 int bpc_out = pim->BitsPerComponent = min(bpc, 8);
438 int ncomp;
439 double resolution;
440
441 /*
442 * The Adobe documentation doesn't say this, but mask images are
443 * compressed on the same basis as 1-bit-deep monochrome images,
444 * except that anti-aliasing (resolution/depth tradeoff) is not
445 * allowed.
446 */
447 if (pim->ColorSpace == NULL) { /* mask image */
448 params = pdev->params.MonoImage;
449 params.Depth = 1;
450 ncomp = 1;
451 } else {
452 ncomp = gs_color_space_num_components(pim->ColorSpace);
453 if (ncomp == 1) {
454 if (bpc == 1)
455 params = pdev->params.MonoImage;
456 else
457 params = pdev->params.GrayImage;
458 if (params.Depth == -1)
459 params.Depth = bpc;
460 } else {
461 params = pdev->params.ColorImage;
462 /* params.Depth is reset below */
463 }
464 }
465
466 /*
467 * We can compute the image resolution by:
468 * W / (W * ImageMatrix^-1 * CTM / HWResolution).
469 * We can replace W by 1 to simplify the computation.
470 */
471 if (pctm == 0)
472 resolution = -1;
473 else {
474 gs_point pt;
475
476 /* We could do both X and Y, but why bother? */
477 code = gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt);
478 if (code < 0)
479 return code;
480 gs_distance_transform(pt.x, pt.y, pctm, &pt);
481 resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0],
482 pt.y / pdev->HWResolution[1]);
483 }
484 if (ncomp == 1) {
485 /* Monochrome, gray, or mask */
486 /* Check for downsampling. */
487 if (do_downsample(¶ms, pim, resolution)) {
488 /* Use the downsampled depth, not the original data depth. */
489 if (params.Depth == 1) {
490 params.Filter = pdev->params.MonoImage.Filter;
491 params.filter_template = pdev->params.MonoImage.filter_template;
492 params.Dict = pdev->params.MonoImage.Dict;
493 } else {
494 params.Filter = pdev->params.GrayImage.Filter;
495 params.filter_template = pdev->params.GrayImage.filter_template;
496 params.Dict = pdev->params.GrayImage.Dict;
497 }
498 code = setup_downsampling(pbw, ¶ms, pim, pis, resolution, lossless);
499 } else {
500 code = setup_image_compression(pbw, ¶ms, pim, pis, lossless);
501 }
502 if (code < 0)
503 return code;
504 code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
505 } else {
506 /* Color */
507 bool cmyk_to_rgb = psdf_is_converting_image_to_RGB(pdev, pis, pim);
508
509 if (cmyk_to_rgb) {
510 extern_st(st_color_space);
511 gs_memory_t *mem = pdev->v_memory;
512 gs_color_space *rgb_cs = gs_alloc_struct(mem,
513 gs_color_space, &st_color_space, "psdf_setup_image_filters");
514
515 gs_cspace_init_DeviceRGB(mem, rgb_cs); /* idempotent initialization */
516 pim->ColorSpace = rgb_cs;
517 }
518 if (params.Depth == -1)
519 params.Depth = (cmyk_to_rgb ? 8 : bpc_out);
520 if (do_downsample(¶ms, pim, resolution)) {
521 code = setup_downsampling(pbw, ¶ms, pim, pis, resolution, lossless);
522 } else {
523 code = setup_image_compression(pbw, ¶ms, pim, pis, lossless);
524 }
525 if (code < 0)
526 return code;
527 if (cmyk_to_rgb) {
528 gs_memory_t *mem = pdev->v_memory;
529 stream_C2R_state *ss = (stream_C2R_state *)
530 s_alloc_state(mem, s_C2R_template.stype, "C2R state");
531 int code = pixel_resize(pbw, pim->Width, 3, 8, bpc_out);
532
533 if (code < 0 ||
534 (code = psdf_encode_binary(pbw, &s_C2R_template,
535 (stream_state *) ss)) < 0 ||
536 (code = pixel_resize(pbw, pim->Width, 4, bpc, 8)) < 0
537 )
538 return code;
539 s_C2R_init(ss, pis);
540 } else {
541 code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
542 if (code < 0)
543 return code;
544 }
545 }
546 return code;
547 }
548
549 /* Set up compression filters for a lossless image, with no downsampling, */
550 /* no color space conversion, and only lossless filters. */
551 /* Note that this may modify the image parameters. */
552 int
psdf_setup_lossless_filters(gx_device_psdf * pdev,psdf_binary_writer * pbw,gs_pixel_image_t * pim)553 psdf_setup_lossless_filters(gx_device_psdf *pdev, psdf_binary_writer *pbw,
554 gs_pixel_image_t *pim)
555 {
556 /*
557 * Set up a device with modified parameters for computing the image
558 * compression filters. Don't allow downsampling or lossy compression.
559 */
560 gx_device_psdf ipdev;
561
562 ipdev = *pdev;
563 ipdev.params.ColorImage.AutoFilter = false;
564 ipdev.params.ColorImage.Downsample = false;
565 ipdev.params.ColorImage.Filter = "FlateEncode";
566 ipdev.params.ColorImage.filter_template = &s_zlibE_template;
567 ipdev.params.ConvertCMYKImagesToRGB = false;
568 ipdev.params.GrayImage.AutoFilter = false;
569 ipdev.params.GrayImage.Downsample = false;
570 ipdev.params.GrayImage.Filter = "FlateEncode";
571 ipdev.params.GrayImage.filter_template = &s_zlibE_template;
572 return psdf_setup_image_filters(&ipdev, pbw, pim, NULL, NULL, true);
573 }
574
575 /* Set up image compression chooser. */
576 int
psdf_setup_compression_chooser(psdf_binary_writer * pbw,gx_device_psdf * pdev,int width,int height,int depth,int bits_per_sample)577 psdf_setup_compression_chooser(psdf_binary_writer *pbw, gx_device_psdf *pdev,
578 int width, int height, int depth, int bits_per_sample)
579 {
580 int code;
581 stream_state *ss = s_alloc_state(pdev->memory, s_compr_chooser_template.stype,
582 "psdf_setup_compression_chooser");
583
584 if (ss == 0)
585 return_error(gs_error_VMerror);
586 pbw->memory = pdev->memory;
587 pbw->strm = pdev->strm; /* just a stub - will not write to it. */
588 pbw->dev = pdev;
589 pbw->target = pbw->strm; /* Since s_add_filter may insert NullEncode to comply buffering,
590 will need to close a chain of filetrs. */
591 code = psdf_encode_binary(pbw, &s_compr_chooser_template, ss);
592 if (code < 0)
593 return code;
594 code = s_compr_chooser_set_dimensions((stream_compr_chooser_state *)ss,
595 width, height, depth, bits_per_sample);
596 return code;
597 }
598
599 /* Set up an "image to mask" filter. */
600 int
psdf_setup_image_to_mask_filter(psdf_binary_writer * pbw,gx_device_psdf * pdev,int width,int height,int depth,int bits_per_sample,uint * MaskColor)601 psdf_setup_image_to_mask_filter(psdf_binary_writer *pbw, gx_device_psdf *pdev,
602 int width, int height, int depth, int bits_per_sample, uint *MaskColor)
603 {
604 int code;
605 stream_state *ss = s_alloc_state(pdev->memory, s__image_colors_template.stype,
606 "psdf_setup_image_colors_filter");
607
608 if (ss == 0)
609 return_error(gs_error_VMerror);
610 pbw->memory = pdev->memory;
611 pbw->dev = pdev;
612 code = psdf_encode_binary(pbw, &s__image_colors_template, ss);
613 if (code < 0)
614 return code;
615 s_image_colors_set_dimensions((stream_image_colors_state *)ss,
616 width, height, depth, bits_per_sample);
617 s_image_colors_set_mask_colors((stream_image_colors_state *)ss, MaskColor);
618 return 0;
619 }
620
621 /* Set up an image colors filter. */
622 int
psdf_setup_image_colors_filter(psdf_binary_writer * pbw,gx_device_psdf * pdev,gs_pixel_image_t * pim,const gs_imager_state * pis,gs_color_space_index output_cspace_index)623 psdf_setup_image_colors_filter(psdf_binary_writer *pbw,
624 gx_device_psdf *pdev, gs_pixel_image_t * pim,
625 const gs_imager_state *pis,
626 gs_color_space_index output_cspace_index)
627 { /* fixme: currently it's a stub convertion to mask. */
628 int code;
629 extern_st(st_color_space);
630 gs_memory_t *mem = pdev->v_memory;
631 stream_state *ss = s_alloc_state(pdev->memory, s__image_colors_template.stype,
632 "psdf_setup_image_colors_filter");
633 gs_color_space *cs;
634 int i;
635
636 if (ss == 0)
637 return_error(gs_error_VMerror);
638 pbw->memory = pdev->memory;
639 pbw->dev = pdev;
640 code = psdf_encode_binary(pbw, &s__image_colors_template, ss);
641 if (code < 0)
642 return code;
643 cs = gs_alloc_struct(mem, gs_color_space, &st_color_space,
644 "psdf_setup_image_colors_filter");
645 if (cs == NULL)
646 return_error(gs_error_VMerror);
647 s_image_colors_set_dimensions((stream_image_colors_state *)ss,
648 pim->Width, pim->Height,
649 gs_color_space_num_components(pim->ColorSpace),
650 pim->BitsPerComponent);
651 s_image_colors_set_color_space((stream_image_colors_state *)ss,
652 (gx_device *)pdev, pim->ColorSpace, pis, pim->Decode);
653 pim->BitsPerComponent = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
654 for (i = 0; i < pdev->color_info.num_components; i++) {
655 pim->Decode[i * 2 + 0] = 0;
656 pim->Decode[i * 2 + 1] = 1;
657 }
658 switch (output_cspace_index) {
659 case gs_color_space_index_DeviceGray:
660 gs_cspace_init_DeviceGray(mem, cs);
661 break;
662 case gs_color_space_index_DeviceRGB:
663 gs_cspace_init_DeviceRGB(mem, cs);
664 break;
665 case gs_color_space_index_DeviceCMYK:
666 gs_cspace_init_DeviceCMYK(mem, cs);
667 break;
668 default:
669 /* Notify the user and terminate.
670 Don't emit rangecheck becuause it would fall back
671 to a default implementation (rasterisation).
672 */
673 eprintf("Unsupported ProcessColorModel");
674 return_error(gs_error_undefined);
675 }
676 pim->ColorSpace = cs;
677 return 0;
678 }
679