]> git.ipfire.org Git - thirdparty/cups.git/blob - pstoraster/gdevpsdi.c
Copyright update...
[thirdparty/cups.git] / pstoraster / gdevpsdi.c
1 /*
2 Copyright 1993-2002 by Easy Software Products.
3 Copyright 1997, 1998 Aladdin Enterprises. All rights reserved.
4
5 This file is part of GNU Ghostscript.
6
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.
12
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
19 copies.
20
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.
25 */
26
27 /*$Id: gdevpsdi.c,v 1.5 2002/01/02 17:59:10 mike Exp $ */
28 /* Image compression for PostScript and PDF writers */
29 #include "math_.h"
30 #include "gx.h"
31 #include "gserrors.h"
32 #include "gscspace.h"
33 #include "gdevpsdf.h"
34 #include "gdevpsds.h"
35 #include "strimpl.h"
36 #include "scfx.h"
37 #include <config.h>
38 #ifdef HAVE_LIBJPEG
39 #include "jpeglib.h" /* for sdct.h */
40 #include "sdct.h"
41 #endif /* HAVE_LIBJPEG */
42 #include "slzwx.h"
43 #include "spngpx.h"
44 #include "srlx.h"
45 #ifdef HAVE_LIBZ
46 #include "szlibx.h"
47 #endif /* HAVE_LIBZ */
48
49 /* ---------------- Image compression ---------------- */
50
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. */
53 private int
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 *template;
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[5] =
66 {
67 0, &s_1_8_template, &s_2_8_template, 0, &s_4_8_template
68 };
69
70 template = exts[bpc_in];
71 } else {
72 static const stream_template *const rets[5] =
73 {
74 0, &s_8_1_template, &s_8_2_template, 0, &s_8_4_template
75 };
76
77 template = rets[bpc_out];
78 }
79 st = (stream_1248_state *)
80 s_alloc_state(mem, template->stype, "pixel_resize state");
81 if (st == 0)
82 return_error(gs_error_VMerror);
83 code = psdf_encode_binary(pbw, template, (stream_state *) st);
84 if (code < 0) {
85 gs_free_object(mem, st, "pixel_resize state");
86 return code;
87 }
88 s_1248_init(st, width, num_components);
89 return 0;
90 }
91
92 /* Add the appropriate image compression filter, if any. */
93 private int
94 setup_image_compression(psdf_binary_writer * pbw, const psdf_image_params * pdip,
95 const gs_image_t * pim)
96 {
97 gx_device_psdf *pdev = pbw->dev;
98 const stream_template *template = pdip->filter_template;
99 stream_state *st;
100
101 if (pdip->AutoFilter) {
102 /****** AutoFilter IS NYI ******/
103 /*
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.
107 */
108 #ifdef HAVE_LIBZ
109 template =
110 (pdev->params.UseFlateCompression &&
111 pdev->version >= psdf_version_ll3 ?
112 &s_zlibE_template : &s_LZWE_template);
113 #else
114 template = &s_LZWE_template;
115 #endif /* HAVE_LIBZ */
116 }
117 if (!pdip->Encode || template == 0) /* no compression */
118 return 0;
119 #ifdef HAVE_LIBJPEG
120 /* Only use DCTE for 8-bit data. */
121 if (template == &s_DCTE_template &&
122 !(pdip->Downsample ?
123 pdip->Depth == 8 ||
124 (pdip->Depth == -1 && pim->BitsPerComponent == 8) :
125 pim->BitsPerComponent == 8)
126 ) {
127 /* Use LZW instead. */
128 template = &s_LZWE_template;
129 }
130 #endif /* HAVE_LIBJPEG */
131 st = s_alloc_state(pdev->v_memory, template->stype,
132 "setup_image_compression");
133 if (st == 0)
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;
139
140 if (pdip->Dict != 0 && pdip->Dict->template == &s_CFE_template) {
141 stream_state common;
142
143 common = *st; /* save generic info */
144 *ss = *(const stream_CFE_state *)pdip->Dict;
145 *st = common;
146 } else {
147 ss->K = -1;
148 ss->BlackIs1 = true;
149 }
150 ss->Columns = pim->Width;
151 ss->Rows = (ss->EndOfBlock ? 0 : pim->Height);
152 #ifdef HAVE_LIBZ
153 } else if (template == &s_LZWE_template ||
154 template == &s_zlibE_template) {
155 #else
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);
160
161 if (code < 0) {
162 gs_free_object(pdev->v_memory, st, "setup_image_compression");
163 return code;
164 }
165 template = &s_PNGPE_template;
166 st = s_alloc_state(pdev->v_memory, template->stype,
167 "setup_image_compression");
168 if (st == 0)
169 return_error(gs_error_VMerror);
170 if (template->set_defaults)
171 (*template->set_defaults) (st);
172 {
173 stream_PNGP_state *const ss = (stream_PNGP_state *) st;
174
175 ss->Colors = gs_color_space_num_components(pim->ColorSpace);
176 ss->Columns = pim->Width;
177 }
178 #ifdef HAVE_LIBJPEG
179 } else if (template == &s_DCTE_template) {
180 /****** ADD PARAMETERS FROM pdip->Dict ******/
181 #endif /* HAVE_LIBJPEG */
182 } {
183 int code = psdf_encode_binary(pbw, template, st);
184
185 if (code < 0) {
186 gs_free_object(pdev->v_memory, st, "setup_image_compression");
187 return code;
188 }
189 }
190 return 0;
191 }
192
193 /* Add downsampling, antialiasing, and compression filters. */
194 /* Uses AntiAlias, Depth, DownsampleType, Resolution. */
195 private int
196 setup_downsampling(psdf_binary_writer * pbw, const psdf_image_params * pdip,
197 gs_image_t * pim, floatp resolution)
198 {
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;
207 stream_state *st;
208 int code;
209
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");
214 if (st == 0)
215 return_error(gs_error_VMerror);
216 if (template->set_defaults)
217 (*template->set_defaults) (st);
218 {
219 stream_Downsample_state *const ss = (stream_Downsample_state *) st;
220
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;
225 if (template->init)
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,
232 &pim->ImageMatrix);
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,
239 orig_bpc, 8)) < 0
240 ) {
241 gs_free_object(pdev->v_memory, st, "setup_image_compression");
242 return code;
243 }
244 }
245 return 0;
246 }
247
248 /* Set up compression and downsampling filters for an image. */
249 /* Note that this may modify the image parameters. */
250 int
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)
254 { /*
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.
258 *
259 * The control structure is a little tricky, because filter
260 * pipelines must be constructed back-to-front.
261 */
262 int code = 0;
263 psdf_image_params params;
264
265 if (pim->ImageMask) {
266 params = pdev->params.MonoImage;
267 params.Depth = 1;
268 } else {
269 int ncomp = gs_color_space_num_components(pim->ColorSpace);
270 int bpc = pim->BitsPerComponent;
271
272 /*
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.
276 */
277 double resolution;
278
279 if (pctm == 0)
280 resolution = -1;
281 else {
282 gs_point pt;
283
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]);
289 }
290 if (ncomp == 1) {
291 /* Monochrome or gray */
292 if (bpc == 1)
293 params = pdev->params.MonoImage;
294 else
295 params = pdev->params.GrayImage;
296 if (params.Depth == -1)
297 params.Depth = bpc;
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;
305 } else {
306 params.Filter = pdev->params.GrayImage.Filter;
307 params.filter_template = pdev->params.GrayImage.filter_template;
308 params.Dict = pdev->params.GrayImage.Dict;
309 }
310 code = setup_downsampling(pbw, &params, pim, resolution);
311 } else {
312 code = setup_image_compression(pbw, &params, pim);
313 }
314 } else {
315 /* Color */
316 bool cmyk_to_rgb =
317 pdev->params.ConvertCMYKImagesToRGB &&
318 pis != 0 &&
319 gs_color_space_get_index(pim->ColorSpace) ==
320 gs_color_space_index_DeviceCMYK;
321
322 if (cmyk_to_rgb)
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, &params, pim, resolution);
329 } else {
330 code = setup_image_compression(pbw, &params, pim);
331 }
332 if (cmyk_to_rgb) {
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);
337
338 if (code < 0 ||
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
342 )
343 return code;
344 s_C2R_init(ss, pis);
345 }
346 }
347 }
348 return code;
349 }