Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/planix-v0/sys/src/cmd/gs/src/gdevpsdi.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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
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
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 
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
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, &param, 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
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
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
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
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(&params, 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, &params, pim, pis, resolution, lossless);
499
	} else {
500
	    code = setup_image_compression(pbw, &params, 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(&params, pim, resolution)) {
521
	    code = setup_downsampling(pbw, &params, pim, pis, resolution, lossless);
522
	} else {
523
	    code = setup_image_compression(pbw, &params, 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
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
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
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
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
}