1 /* Copyright (C) 1997, 1998, 1999 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: gdevjpeg.c,v 1.10 2005/08/31 15:29:40 ray Exp $ */
18 /* JPEG output driver */
19 #include "stdio_.h" /* for jpeglib.h */
20 #include "jpeglib_.h"
21 #include "gdevprn.h"
22 #include "stream.h"
23 #include "strimpl.h"
24 #include "sdct.h"
25 #include "sjpeg.h"
26
27 /* Structure for the JPEG-writing device. */
28 typedef struct gx_device_jpeg_s {
29 gx_device_common;
30 gx_prn_device_common;
31 /* Additional parameters */
32 int JPEGQ; /* quality on IJG scale */
33 float QFactor; /* quality per DCTEncode conventions */
34 /* JPEGQ overrides QFactor if both are specified. */
35 } gx_device_jpeg;
36
37 /* The device descriptor */
38 private dev_proc_get_params(jpeg_get_params);
39 private dev_proc_put_params(jpeg_put_params);
40 private dev_proc_print_page(jpeg_print_page);
41 private dev_proc_map_color_rgb(jpegcmyk_map_color_rgb);
42 private dev_proc_map_cmyk_color(jpegcmyk_map_cmyk_color);
43
44 /* ------ The device descriptors ------ */
45
46 /* Default X and Y resolution. */
47 #ifndef X_DPI
48 # define X_DPI 72
49 #endif
50 #ifndef Y_DPI
51 # define Y_DPI 72
52 #endif
53
54 /* 24-bit color RGB */
55
56 private const gx_device_procs jpeg_procs =
57 prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
58 gx_default_rgb_map_rgb_color,
59 gx_default_rgb_map_color_rgb,
60 jpeg_get_params, jpeg_put_params);
61
62 const gx_device_jpeg gs_jpeg_device =
63 {prn_device_std_body(gx_device_jpeg, jpeg_procs, "jpeg",
64 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
65 X_DPI, Y_DPI, 0, 0, 0, 0, 24, jpeg_print_page),
66 0, /* JPEGQ: 0 indicates not specified */
67 0.0 /* QFactor: 0 indicates not specified */
68 };
69
70 /* 8-bit gray */
71
72 private const gx_device_procs jpeggray_procs =
73 prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close,
74 gx_default_gray_map_rgb_color,
75 gx_default_gray_map_color_rgb,
76 jpeg_get_params, jpeg_put_params);
77
78 const gx_device_jpeg gs_jpeggray_device =
79 {prn_device_body(gx_device_jpeg, jpeggray_procs, "jpeggray",
80 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
81 X_DPI, Y_DPI, 0, 0, 0, 0,
82 1, 8, 255, 0, 256, 0,
83 jpeg_print_page),
84 0, /* JPEGQ: 0 indicates not specified */
85 0.0 /* QFactor: 0 indicates not specified */
86 };
87
88 /* 32-bit CMYK */
89
90 private const gx_device_procs jpegcmyk_procs =
91 { gdev_prn_open,
92 gx_default_get_initial_matrix,
93 NULL, /* sync_output */
94 gdev_prn_output_page,
95 gdev_prn_close,
96 NULL,
97 jpegcmyk_map_color_rgb,
98 NULL, /* fill_rectangle */
99 NULL, /* tile_rectangle */
100 NULL, /* copy_mono */
101 NULL, /* copy_color */
102 NULL, /* draw_line */
103 NULL, /* get_bits */
104 jpeg_get_params,
105 jpeg_put_params,
106 jpegcmyk_map_cmyk_color,
107 NULL, /* get_xfont_procs */
108 NULL, /* get_xfont_device */
109 NULL, /* map_rgb_alpha_color */
110 gx_page_device_get_page_device /* get_page_device */
111 };
112
113 const gx_device_jpeg gs_jpegcmyk_device =
114 {prn_device_std_body(gx_device_jpeg, jpegcmyk_procs, "jpegcmyk",
115 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
116 X_DPI, Y_DPI, 0, 0, 0, 0, 32, jpeg_print_page),
117 0, /* JPEGQ: 0 indicates not specified */
118 0.0 /* QFactor: 0 indicates not specified */
119 };
120
121
122 /* Apparently Adobe Photoshop and some other applications that */
123 /* accept JPEG CMYK images expect color values to be inverted. */
124 private int
jpegcmyk_map_color_rgb(gx_device * dev,gx_color_index color,gx_color_value prgb[3])125 jpegcmyk_map_color_rgb(gx_device * dev, gx_color_index color,
126 gx_color_value prgb[3])
127 {
128 int
129 not_k = color & 0xff,
130 r = not_k - ~(color >> 24),
131 g = not_k - ~((color >> 16) & 0xff),
132 b = not_k - ~((color >> 8) & 0xff);
133
134 prgb[0] = (r < 0 ? 0 : gx_color_value_from_byte(r));
135 prgb[1] = (g < 0 ? 0 : gx_color_value_from_byte(g));
136 prgb[2] = (b < 0 ? 0 : gx_color_value_from_byte(b));
137 return 0;
138 }
139
140 private gx_color_index
jpegcmyk_map_cmyk_color(gx_device * dev,const gx_color_value cv[])141 jpegcmyk_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
142 {
143 gx_color_index color = ~(
144 gx_color_value_to_byte(cv[3]) +
145 ((uint)gx_color_value_to_byte(cv[2]) << 8) +
146 ((uint)gx_color_value_to_byte(cv[1]) << 16) +
147 ((uint)gx_color_value_to_byte(cv[0]) << 24));
148
149 return (color == gx_no_color_index ? color ^ 1 : color);
150 }
151
152 /* Get parameters. */
153 private int
jpeg_get_params(gx_device * dev,gs_param_list * plist)154 jpeg_get_params(gx_device * dev, gs_param_list * plist)
155 {
156 gx_device_jpeg *jdev = (gx_device_jpeg *) dev;
157 int code = gdev_prn_get_params(dev, plist);
158 int ecode;
159
160 if (code < 0)
161 return code;
162
163 if ((ecode = param_write_int(plist, "JPEGQ", &jdev->JPEGQ)) < 0)
164 code = ecode;
165 if ((ecode = param_write_float(plist, "QFactor", &jdev->QFactor)) < 0)
166 code = ecode;
167
168 return code;
169 }
170
171 /* Put parameters. */
172 private int
jpeg_put_params(gx_device * dev,gs_param_list * plist)173 jpeg_put_params(gx_device * dev, gs_param_list * plist)
174 {
175 gx_device_jpeg *jdev = (gx_device_jpeg *) dev;
176 int ecode = 0;
177 int code;
178 gs_param_name param_name;
179 int jq = jdev->JPEGQ;
180 float qf = jdev->QFactor;
181
182 switch (code = param_read_int(plist, (param_name = "JPEGQ"), &jq)) {
183 case 0:
184 if (jq < 0 || jq > 100)
185 ecode = gs_error_limitcheck;
186 else
187 break;
188 goto jqe;
189 default:
190 ecode = code;
191 jqe:param_signal_error(plist, param_name, ecode);
192 case 1:
193 break;
194 }
195
196 switch (code = param_read_float(plist, (param_name = "QFactor"), &qf)) {
197 case 0:
198 if (qf < 0.0 || qf > 1.0e6)
199 ecode = gs_error_limitcheck;
200 else
201 break;
202 goto qfe;
203 default:
204 ecode = code;
205 qfe:param_signal_error(plist, param_name, ecode);
206 case 1:
207 break;
208 }
209
210 if (ecode < 0)
211 return ecode;
212 code = gdev_prn_put_params(dev, plist);
213 if (code < 0)
214 return code;
215
216 jdev->JPEGQ = jq;
217 jdev->QFactor = qf;
218 return 0;
219 }
220
221 /* Send the page to the file. */
222 private int
jpeg_print_page(gx_device_printer * pdev,FILE * prn_stream)223 jpeg_print_page(gx_device_printer * pdev, FILE * prn_stream)
224 {
225 gx_device_jpeg *jdev = (gx_device_jpeg *) pdev;
226 gs_memory_t *mem = pdev->memory;
227 int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
228 byte *in = gs_alloc_bytes(mem, line_size, "jpeg_print_page(in)");
229 jpeg_compress_data *jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
230 &st_jpeg_compress_data, "jpeg_print_page(jpeg_compress_data)");
231 byte *fbuf = 0;
232 uint fbuf_size;
233 byte *jbuf = 0;
234 uint jbuf_size;
235 int lnum;
236 int code;
237 stream_DCT_state state;
238 stream fstrm, jstrm;
239
240 if (jcdp == 0 || in == 0) {
241 code = gs_note_error(gs_error_VMerror);
242 goto fail;
243 }
244 /* Create the DCT decoder state. */
245 jcdp->template = s_DCTE_template;
246 state.template = &jcdp->template;
247 state.memory = 0;
248 if (state.template->set_defaults)
249 (*state.template->set_defaults) ((stream_state *) & state);
250 state.QFactor = 1.0; /* disable quality adjustment in zfdcte.c */
251 state.ColorTransform = 1; /* default for RGB */
252 /* We insert no markers, allowing the IJG library to emit */
253 /* the format it thinks best. */
254 state.NoMarker = true; /* do not insert our own Adobe marker */
255 state.Markers.data = 0;
256 state.Markers.size = 0;
257 state.data.compress = jcdp;
258 jcdp->memory = state.jpeg_memory = mem;
259 if ((code = gs_jpeg_create_compress(&state)) < 0)
260 goto fail;
261 jcdp->cinfo.image_width = pdev->width;
262 jcdp->cinfo.image_height = pdev->height;
263 switch (pdev->color_info.depth) {
264 case 32:
265 jcdp->cinfo.input_components = 4;
266 jcdp->cinfo.in_color_space = JCS_CMYK;
267 break;
268 case 24:
269 jcdp->cinfo.input_components = 3;
270 jcdp->cinfo.in_color_space = JCS_RGB;
271 break;
272 case 8:
273 jcdp->cinfo.input_components = 1;
274 jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
275 break;
276 }
277 /* Set compression parameters. */
278 if ((code = gs_jpeg_set_defaults(&state)) < 0)
279 goto done;
280 if (jdev->JPEGQ > 0) {
281 code = gs_jpeg_set_quality(&state, jdev->JPEGQ, TRUE);
282 if (code < 0)
283 goto done;
284 } else if (jdev->QFactor > 0.0) {
285 code = gs_jpeg_set_linear_quality(&state,
286 (int)(min(jdev->QFactor, 100.0)
287 * 100.0 + 0.5),
288 TRUE);
289 if (code < 0)
290 goto done;
291 }
292 jcdp->cinfo.restart_interval = 0;
293 jcdp->cinfo.density_unit = 1; /* dots/inch (no #define or enum) */
294 jcdp->cinfo.X_density = (UINT16)pdev->HWResolution[0];
295 jcdp->cinfo.Y_density = (UINT16)pdev->HWResolution[1];
296 /* Create the filter. */
297 /* Make sure we get at least a full scan line of input. */
298 state.scan_line_size = jcdp->cinfo.input_components *
299 jcdp->cinfo.image_width;
300 jcdp->template.min_in_size =
301 max(s_DCTE_template.min_in_size, state.scan_line_size);
302 /* Make sure we can write the user markers in a single go. */
303 jcdp->template.min_out_size =
304 max(s_DCTE_template.min_out_size, state.Markers.size);
305
306 /* Set up the streams. */
307 fbuf_size = max(512 /* arbitrary */ , jcdp->template.min_out_size);
308 jbuf_size = jcdp->template.min_in_size;
309 if ((fbuf = gs_alloc_bytes(mem, fbuf_size, "jpeg_print_page(fbuf)")) == 0 ||
310 (jbuf = gs_alloc_bytes(mem, jbuf_size, "jpeg_print_page(jbuf)")) == 0
311 ) {
312 code = gs_note_error(gs_error_VMerror);
313 goto done;
314 }
315 s_init(&fstrm, mem);
316 swrite_file(&fstrm, prn_stream, fbuf, fbuf_size);
317 s_init(&jstrm, mem);
318 s_std_init(&jstrm, jbuf, jbuf_size, &s_filter_write_procs,
319 s_mode_write);
320 jstrm.state = (stream_state *) & state;
321 jstrm.procs.process = state.template->process;
322 jstrm.strm = &fstrm;
323 if (state.template->init)
324 (*state.template->init) (jstrm.state);
325
326 /* Copy the data to the output. */
327 for (lnum = 0; lnum < pdev->height; ++lnum) {
328 byte *data;
329 uint ignore_used;
330
331 gdev_prn_get_bits(pdev, lnum, in, &data);
332 sputs(&jstrm, data, state.scan_line_size, &ignore_used);
333 }
334
335 /* Wrap up. */
336 sclose(&jstrm);
337 sflush(&fstrm);
338 jcdp = 0;
339 done:
340 gs_free_object(mem, jbuf, "jpeg_print_page(jbuf)");
341 gs_free_object(mem, fbuf, "jpeg_print_page(fbuf)");
342 if (jcdp)
343 gs_jpeg_destroy(&state); /* frees *jcdp */
344 gs_free_object(mem, in, "jpeg_print_page(in)");
345 return code;
346 fail:
347 if (jcdp)
348 gs_free_object(mem, jcdp, "jpeg_print_page(jpeg_compress_data)");
349 gs_free_object(mem, in, "jpeg_print_page(in)");
350 return code;
351 }
352