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