2 Copyright 1993-2002 by Easy Software Products.
3 Copyright 1997, 1998 Aladdin Enterprises. All rights reserved.
5 This file is part of GNU Ghostscript.
7 GNU Ghostscript is distributed in the hope that it will be useful, but
8 WITHOUT ANY WARRANTY. No author or distributor accepts responsibility
9 to anyone for the consequences of using it or for whether it serves any
10 particular purpose or works at all, unless he says so in writing. Refer
11 to the GNU General Public License for full details.
13 Everyone is granted permission to copy, modify and redistribute GNU
14 Ghostscript, but only under the conditions described in the GNU General
15 Public License. A copy of this license is supposed to have been given
16 to you along with GNU Ghostscript so you can know your rights and
17 responsibilities. It should be in a file named COPYING. Among other
18 things, the copyright notice and this notice must be preserved on all
21 Aladdin Enterprises supports the work of the GNU Project, but is not
22 affiliated with the Free Software Foundation or the GNU Project. GNU
23 Ghostscript, as distributed by Aladdin Enterprises, does not require any
24 GNU software to build or run it.
27 /*$Id: gdevpsdi.c,v 1.5 2002/01/02 17:59:10 mike Exp $ */
28 /* Image compression for PostScript and PDF writers */
39 #include "jpeglib.h" /* for sdct.h */
41 #endif /* HAVE_LIBJPEG */
47 #endif /* HAVE_LIBZ */
49 /* ---------------- Image compression ---------------- */
51 /* Add a filter to expand or reduce the pixel width if needed. */
52 /* At least one of bpc_in and bpc_out is 8; the other is 1, 2, 4, or 8. */
54 pixel_resize(psdf_binary_writer
* pbw
, int width
, int num_components
,
55 int bpc_in
, int bpc_out
)
57 gs_memory_t
*mem
= pbw
->dev
->v_memory
;
58 const stream_template
*template;
59 stream_1248_state
*st
;
62 if (bpc_out
== bpc_in
)
65 static const stream_template
*const exts
[5] =
67 0, &s_1_8_template
, &s_2_8_template
, 0, &s_4_8_template
70 template = exts
[bpc_in
];
72 static const stream_template
*const rets
[5] =
74 0, &s_8_1_template
, &s_8_2_template
, 0, &s_8_4_template
77 template = rets
[bpc_out
];
79 st
= (stream_1248_state
*)
80 s_alloc_state(mem
, template->stype
, "pixel_resize state");
82 return_error(gs_error_VMerror
);
83 code
= psdf_encode_binary(pbw
, template, (stream_state
*) st
);
85 gs_free_object(mem
, st
, "pixel_resize state");
88 s_1248_init(st
, width
, num_components
);
92 /* Add the appropriate image compression filter, if any. */
94 setup_image_compression(psdf_binary_writer
* pbw
, const psdf_image_params
* pdip
,
95 const gs_image_t
* pim
)
97 gx_device_psdf
*pdev
= pbw
->dev
;
98 const stream_template
*template = pdip
->filter_template
;
101 if (pdip
->AutoFilter
) {
102 /****** AutoFilter IS NYI ******/
104 * Even though this isn't obvious from the Adobe Tech Note,
105 * it appears that if UseFlateCompression is true, the default
106 * compressor for AutoFilter is FlateEncode, not LZWEncode.
110 (pdev
->params
.UseFlateCompression
&&
111 pdev
->version
>= psdf_version_ll3
?
112 &s_zlibE_template
: &s_LZWE_template
);
114 template = &s_LZWE_template
;
115 #endif /* HAVE_LIBZ */
117 if (!pdip
->Encode
|| template == 0) /* no compression */
120 /* Only use DCTE for 8-bit data. */
121 if (template == &s_DCTE_template
&&
124 (pdip
->Depth
== -1 && pim
->BitsPerComponent
== 8) :
125 pim
->BitsPerComponent
== 8)
127 /* Use LZW instead. */
128 template = &s_LZWE_template
;
130 #endif /* HAVE_LIBJPEG */
131 st
= s_alloc_state(pdev
->v_memory
, template->stype
,
132 "setup_image_compression");
134 return_error(gs_error_VMerror
);
135 if (template->set_defaults
)
136 (*template->set_defaults
) (st
);
137 if (template == &s_CFE_template
) {
138 stream_CFE_state
*const ss
= (stream_CFE_state
*) st
;
140 if (pdip
->Dict
!= 0 && pdip
->Dict
->template == &s_CFE_template
) {
143 common
= *st
; /* save generic info */
144 *ss
= *(const stream_CFE_state
*)pdip
->Dict
;
150 ss
->Columns
= pim
->Width
;
151 ss
->Rows
= (ss
->EndOfBlock
? 0 : pim
->Height
);
153 } else if (template == &s_LZWE_template
||
154 template == &s_zlibE_template
) {
156 } else if (template == &s_LZWE_template
) {
157 #endif /* HAVE_LIBZ */
158 /* Add a PNGPredictor filter. */
159 int code
= psdf_encode_binary(pbw
, template, st
);
162 gs_free_object(pdev
->v_memory
, st
, "setup_image_compression");
165 template = &s_PNGPE_template
;
166 st
= s_alloc_state(pdev
->v_memory
, template->stype
,
167 "setup_image_compression");
169 return_error(gs_error_VMerror
);
170 if (template->set_defaults
)
171 (*template->set_defaults
) (st
);
173 stream_PNGP_state
*const ss
= (stream_PNGP_state
*) st
;
175 ss
->Colors
= gs_color_space_num_components(pim
->ColorSpace
);
176 ss
->Columns
= pim
->Width
;
179 } else if (template == &s_DCTE_template
) {
180 /****** ADD PARAMETERS FROM pdip->Dict ******/
181 #endif /* HAVE_LIBJPEG */
183 int code
= psdf_encode_binary(pbw
, template, st
);
186 gs_free_object(pdev
->v_memory
, st
, "setup_image_compression");
193 /* Add downsampling, antialiasing, and compression filters. */
194 /* Uses AntiAlias, Depth, DownsampleType, Resolution. */
196 setup_downsampling(psdf_binary_writer
* pbw
, const psdf_image_params
* pdip
,
197 gs_image_t
* pim
, floatp resolution
)
199 gx_device_psdf
*pdev
= pbw
->dev
;
200 const stream_template
*template =
201 (pdip
->DownsampleType
== ds_Average
?
202 &s_Average_template
: &s_Subsample_template
);
203 int factor
= (int)(resolution
/ pdip
->Resolution
);
204 int orig_bpc
= pim
->BitsPerComponent
;
205 int orig_width
= pim
->Width
;
206 int orig_height
= pim
->Height
;
210 if (factor
<= 1 || pim
->Width
< factor
|| pim
->Height
< factor
)
211 return setup_image_compression(pbw
, pdip
, pim
); /* no downsampling */
212 st
= s_alloc_state(pdev
->v_memory
, template->stype
,
213 "setup_downsampling");
215 return_error(gs_error_VMerror
);
216 if (template->set_defaults
)
217 (*template->set_defaults
) (st
);
219 stream_Downsample_state
*const ss
= (stream_Downsample_state
*) st
;
221 ss
->Colors
= gs_color_space_num_components(pim
->ColorSpace
);
222 ss
->Columns
= pim
->Width
;
223 ss
->XFactor
= ss
->YFactor
= factor
;
224 ss
->AntiAlias
= pdip
->AntiAlias
;
226 (*template->init
) (st
);
227 pim
->Width
/= factor
;
228 pim
->Height
/= factor
;
229 pim
->BitsPerComponent
= pdip
->Depth
;
230 gs_matrix_scale(&pim
->ImageMatrix
, (double)pim
->Width
/ orig_width
,
231 (double)pim
->Height
/ orig_height
,
233 /****** NO ANTI-ALIASING YET ******/
234 if ((code
= setup_image_compression(pbw
, pdip
, pim
)) < 0 ||
235 (code
= pixel_resize(pbw
, pim
->Width
, ss
->Colors
,
236 8, pdip
->Depth
)) < 0 ||
237 (code
= psdf_encode_binary(pbw
, template, st
)) < 0 ||
238 (code
= pixel_resize(pbw
, orig_width
, ss
->Colors
,
241 gs_free_object(pdev
->v_memory
, st
, "setup_image_compression");
248 /* Set up compression and downsampling filters for an image. */
249 /* Note that this may modify the image parameters. */
251 psdf_setup_image_filters(gx_device_psdf
* pdev
, psdf_binary_writer
* pbw
,
252 gs_image_t
* pim
, const gs_matrix
* pctm
,
253 const gs_imager_state
* pis
)
255 * The following algorithms are per Adobe Tech Note # 5151,
256 * "Acrobat Distiller Parameters", revised 16 September 1996
257 * for Acrobat(TM) Distiller(TM) 3.0.
259 * The control structure is a little tricky, because filter
260 * pipelines must be constructed back-to-front.
263 psdf_image_params params
;
265 if (pim
->ImageMask
) {
266 params
= pdev
->params
.MonoImage
;
269 int ncomp
= gs_color_space_num_components(pim
->ColorSpace
);
270 int bpc
= pim
->BitsPerComponent
;
273 * We can compute the image resolution by:
274 * W / (W * ImageMatrix^-1 * CTM / HWResolution).
275 * We can replace W by 1 to simplify the computation.
284 /* We could do both X and Y, but why bother? */
285 gs_distance_transform_inverse(1.0, 0.0, &pim
->ImageMatrix
, &pt
);
286 gs_distance_transform(pt
.x
, pt
.y
, pctm
, &pt
);
287 resolution
= 1.0 / hypot(pt
.x
/ pdev
->HWResolution
[0],
288 pt
.y
/ pdev
->HWResolution
[1]);
291 /* Monochrome or gray */
293 params
= pdev
->params
.MonoImage
;
295 params
= pdev
->params
.GrayImage
;
296 if (params
.Depth
== -1)
298 /* Check for downsampling. */
299 if (params
.Downsample
&& params
.Resolution
<= resolution
/ 2) {
300 /* Use the downsampled depth, not the original data depth. */
301 if (params
.Depth
== 1) {
302 params
.Filter
= pdev
->params
.MonoImage
.Filter
;
303 params
.filter_template
= pdev
->params
.MonoImage
.filter_template
;
304 params
.Dict
= pdev
->params
.MonoImage
.Dict
;
306 params
.Filter
= pdev
->params
.GrayImage
.Filter
;
307 params
.filter_template
= pdev
->params
.GrayImage
.filter_template
;
308 params
.Dict
= pdev
->params
.GrayImage
.Dict
;
310 code
= setup_downsampling(pbw
, ¶ms
, pim
, resolution
);
312 code
= setup_image_compression(pbw
, ¶ms
, pim
);
317 pdev
->params
.ConvertCMYKImagesToRGB
&&
319 gs_color_space_get_index(pim
->ColorSpace
) ==
320 gs_color_space_index_DeviceCMYK
;
323 pim
->ColorSpace
= gs_cspace_DeviceRGB(pis
);
324 params
= pdev
->params
.ColorImage
;
325 if (params
.Depth
== -1)
326 params
.Depth
= (cmyk_to_rgb
? 8 : bpc
);
327 if (params
.Downsample
&& params
.Resolution
<= resolution
/ 2) {
328 code
= setup_downsampling(pbw
, ¶ms
, pim
, resolution
);
330 code
= setup_image_compression(pbw
, ¶ms
, pim
);
333 gs_memory_t
*mem
= pdev
->v_memory
;
334 stream_C2R_state
*ss
= (stream_C2R_state
*)
335 s_alloc_state(mem
, s_C2R_template
.stype
, "C2R state");
336 int code
= pixel_resize(pbw
, pim
->Width
, 3, 8, bpc
);
339 (code
= psdf_encode_binary(pbw
, &s_C2R_template
,
340 (stream_state
*) ss
)) < 0 ||
341 (code
= pixel_resize(pbw
, pim
->Width
, 4, bpc
, 8)) < 0