1
/* Copyright (C) 2001-2006 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied, modified
8
or distributed except as expressly authorized under the terms of that
9
license. Refer to licensing information at http://www.artifex.com/
10
or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11
San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
13
/* $Id: gdevjpeg.c 8250 2007-09-25 13:31:24Z giles $ */
14
/* JPEG output driver */
15
#include "stdio_.h" /* for jpeglib.h */
23
/* Structure for the JPEG-writing device. */
24
typedef struct gx_device_jpeg_s {
27
/* Additional parameters */
28
int JPEGQ; /* quality on IJG scale */
29
float QFactor; /* quality per DCTEncode conventions */
30
/* JPEGQ overrides QFactor if both are specified. */
32
/** 1.0 default 2.0 is twice as big
36
/** translation needs to have scalefactor multiplied in.
42
/* The device descriptor */
43
static dev_proc_get_params(jpeg_get_params);
44
static dev_proc_get_initial_matrix(jpeg_get_initial_matrix);
45
static dev_proc_put_params(jpeg_put_params);
46
static dev_proc_print_page(jpeg_print_page);
47
static dev_proc_map_color_rgb(jpegcmyk_map_color_rgb);
48
static dev_proc_map_cmyk_color(jpegcmyk_map_cmyk_color);
50
/* ------ The device descriptors ------ */
52
/* Default X and Y resolution. */
62
static const gx_device_procs jpeg_procs =
65
jpeg_get_initial_matrix, /* get_initial_matrix */
66
NULL, /* sync_output */
69
gx_default_rgb_map_rgb_color,/* map_rgb_color */
70
gx_default_rgb_map_color_rgb,
71
NULL, /* fill_rectangle */
72
NULL, /* tile_rectangle */
74
NULL, /* copy_color */
80
NULL, /* get_xfont_procs */
81
NULL, /* get_xfont_device */
82
NULL, /* map_rgb_alpha_color */
83
gx_page_device_get_page_device
86
const gx_device_jpeg gs_jpeg_device =
87
{prn_device_std_body(gx_device_jpeg, jpeg_procs, "jpeg",
88
DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
89
X_DPI, Y_DPI, 0, 0, 0, 0, 24, jpeg_print_page),
90
0, /* JPEGQ: 0 indicates not specified */
91
0.0, /* QFactor: 0 indicates not specified */
92
{ 1.0, 1.0 }, /* ViewScale 1 to 1 */
93
{ 0.0, 0.0 } /* translation 0 */
98
static const gx_device_procs jpeggray_procs =
101
jpeg_get_initial_matrix, /* get_initial_matrix */
102
NULL, /* sync_output */
103
gdev_prn_output_page,
105
gx_default_gray_map_rgb_color,/* map_rgb_color */
106
gx_default_gray_map_color_rgb,
107
NULL, /* fill_rectangle */
108
NULL, /* tile_rectangle */
109
NULL, /* copy_mono */
110
NULL, /* copy_color */
111
NULL, /* draw_line */
116
NULL, /* get_xfont_procs */
117
NULL, /* get_xfont_device */
118
NULL, /* map_rgb_alpha_color */
119
gx_page_device_get_page_device
122
const gx_device_jpeg gs_jpeggray_device =
123
{prn_device_body(gx_device_jpeg, jpeggray_procs, "jpeggray",
124
DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
125
X_DPI, Y_DPI, 0, 0, 0, 0,
126
1, 8, 255, 0, 256, 0,
128
0, /* JPEGQ: 0 indicates not specified */
129
0.0, /* QFactor: 0 indicates not specified */
130
{ 1.0, 1.0 }, /* ViewScale 1 to 1 */
131
{ 0.0, 0.0 } /* translation 0 */
135
static const gx_device_procs jpegcmyk_procs =
137
gx_default_get_initial_matrix,
138
NULL, /* sync_output */
139
gdev_prn_output_page,
142
jpegcmyk_map_color_rgb,
143
NULL, /* fill_rectangle */
144
NULL, /* tile_rectangle */
145
NULL, /* copy_mono */
146
NULL, /* copy_color */
147
NULL, /* draw_line */
151
jpegcmyk_map_cmyk_color,
152
NULL, /* get_xfont_procs */
153
NULL, /* get_xfont_device */
154
NULL, /* map_rgb_alpha_color */
155
gx_page_device_get_page_device /* get_page_device */
158
const gx_device_jpeg gs_jpegcmyk_device =
159
{prn_device_std_body(gx_device_jpeg, jpegcmyk_procs, "jpegcmyk",
160
DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
161
X_DPI, Y_DPI, 0, 0, 0, 0, 32, jpeg_print_page),
162
0, /* JPEGQ: 0 indicates not specified */
163
0.0, /* QFactor: 0 indicates not specified */
164
{ 1.0, 1.0 }, /* ViewScale 1 to 1 */
165
{ 0.0, 0.0 } /* translation 0 */
169
/* Apparently Adobe Photoshop and some other applications that */
170
/* accept JPEG CMYK images expect color values to be inverted. */
172
jpegcmyk_map_color_rgb(gx_device * dev, gx_color_index color,
173
gx_color_value prgb[3])
176
not_k = color & 0xff,
177
r = not_k - ~(color >> 24),
178
g = not_k - ~((color >> 16) & 0xff),
179
b = not_k - ~((color >> 8) & 0xff);
181
prgb[0] = (r < 0 ? 0 : gx_color_value_from_byte(r));
182
prgb[1] = (g < 0 ? 0 : gx_color_value_from_byte(g));
183
prgb[2] = (b < 0 ? 0 : gx_color_value_from_byte(b));
187
static gx_color_index
188
jpegcmyk_map_cmyk_color(gx_device * dev, const gx_color_value cv[])
190
gx_color_index color = ~(
191
gx_color_value_to_byte(cv[3]) +
192
((uint)gx_color_value_to_byte(cv[2]) << 8) +
193
((uint)gx_color_value_to_byte(cv[1]) << 16) +
194
((uint)gx_color_value_to_byte(cv[0]) << 24));
196
return (color == gx_no_color_index ? color ^ 1 : color);
199
/* Get parameters. */
201
jpeg_get_params(gx_device * dev, gs_param_list * plist)
203
gx_device_jpeg *jdev = (gx_device_jpeg *) dev;
204
int code = gdev_prn_get_params(dev, plist);
210
if ((ecode = param_write_int(plist, "JPEGQ", &jdev->JPEGQ)) < 0)
212
if ((ecode = param_write_float(plist, "QFactor", &jdev->QFactor)) < 0)
214
float2double = jdev->ViewScale.x;
215
if ((ecode = param_write_float(plist, "ViewScaleX", &float2double)) < 0)
217
float2double = jdev->ViewScale.y;
218
if ((ecode = param_write_float(plist, "ViewScaleY", &float2double)) < 0)
220
float2double = jdev->ViewTrans.x;
221
if ((ecode = param_write_float(plist, "ViewTransX", &float2double)) < 0)
223
float2double = jdev->ViewTrans.y;
224
if ((ecode = param_write_float(plist, "ViewTransY", &float2double)) < 0)
230
/* Put parameters. */
232
jpeg_put_params(gx_device * dev, gs_param_list * plist)
234
gx_device_jpeg *jdev = (gx_device_jpeg *) dev;
237
gs_param_name param_name;
238
int jq = jdev->JPEGQ;
239
float qf = jdev->QFactor;
242
switch (code = param_read_int(plist, (param_name = "JPEGQ"), &jq)) {
244
if (jq < 0 || jq > 100)
245
ecode = gs_error_limitcheck;
251
jqe:param_signal_error(plist, param_name, ecode);
256
switch (code = param_read_float(plist, (param_name = "QFactor"), &qf)) {
258
if (qf < 0.0 || qf > 1.0e6)
259
ecode = gs_error_limitcheck;
265
qfe:param_signal_error(plist, param_name, ecode);
271
code = param_read_float(plist, (param_name = "ViewScaleX"), &fparam);
274
param_signal_error(plist, param_name, gs_error_limitcheck);
276
jdev->ViewScale.x = fparam;
278
else if ( code < 1 ) {
280
param_signal_error(plist, param_name, code);
283
code = param_read_float(plist, (param_name = "ViewScaleY"), &fparam);
286
param_signal_error(plist, param_name, gs_error_limitcheck);
288
jdev->ViewScale.y = fparam;
290
else if ( code < 1 ) {
292
param_signal_error(plist, param_name, code);
295
/* pixels in desired dpi, auto negative ( moves up and left ) */
296
code = param_read_float(plist, (param_name = "ViewTransX"), &fparam);
298
jdev->ViewTrans.x = fparam;
300
else if ( code < 1 ) {
302
param_signal_error(plist, param_name, code);
305
code = param_read_float(plist, (param_name = "ViewTransY"), &fparam);
307
jdev->ViewTrans.y = fparam;
309
else if ( code < 1 ) {
311
param_signal_error(plist, param_name, code);
313
code = gdev_prn_put_params(dev, plist);
325
/******************************************************************
326
This device supports translation and scaling.
331
PPPPPPPP 1 is x1,y1 (2,2)
332
PP1vvvPP 2 is x2,y2 (6,6)
333
PPvvvvPP v is viewport, P is original page
338
Given a view port in pixels starting at x1,y1
339
where x1 < width, y1 < height in pixels
341
ViewScaleX = desired Resolution / HWResolution ; 1.0 default
342
ViewScaleY = desired Resolution / HWResolution
344
HWResolutionX = desired dpi at 1:1 scaling ; 72dpi default
345
HWResolutionY = desired dpi at 1:1 scaling
347
ViewTransX = x1 * ViewScaleX ; 0.0 default
348
ViewTransY = y1 * ViewScaleY
350
if initial matrix multiplies ViewScaleX in then translation is limited to
351
multiples of the HWResolution.
353
***************************************************************************/
356
jpeg_get_initial_matrix(gx_device *dev, gs_matrix *pmat)
358
gx_device_jpeg *pdev = (gx_device_jpeg *)dev;
359
floatp fs_res = (dev->HWResolution[0] / 72.0) * pdev->ViewScale.x;
360
floatp ss_res = (dev->HWResolution[1] / 72.0) * pdev->ViewScale.y;
362
/* NB this device has no paper margins */
364
switch(pdev->LeadingEdge) {
370
pmat->tx = (pdev->width * pdev->ViewScale.x) - pdev->ViewTrans.x;
371
pmat->ty = (pdev->height * pdev->ViewScale.y) - pdev->ViewTrans.y;
378
pmat->tx = (pdev->width * pdev->ViewScale.x) - pdev->ViewTrans.x;
379
pmat->ty = -pdev->ViewTrans.x;
386
pmat->tx = -pdev->ViewTrans.x;
387
pmat->ty = -pdev->ViewTrans.y;
395
pmat->tx = -pdev->ViewTrans.x;
396
pmat->ty = (pdev->height * pdev->ViewScale.y) - pdev->ViewTrans.y;
402
/* Send the page to the file. */
404
jpeg_print_page(gx_device_printer * pdev, FILE * prn_stream)
406
gx_device_jpeg *jdev = (gx_device_jpeg *) pdev;
407
gs_memory_t *mem = pdev->memory;
408
int line_size = gdev_mem_bytes_per_scan_line((gx_device *) pdev);
409
byte *in = gs_alloc_bytes(mem, line_size, "jpeg_print_page(in)");
410
jpeg_compress_data *jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
411
&st_jpeg_compress_data, "jpeg_print_page(jpeg_compress_data)");
418
stream_DCT_state state;
421
if (jcdp == 0 || in == 0) {
422
code = gs_note_error(gs_error_VMerror);
425
/* Create the DCT encoder state. */
426
jcdp->template = s_DCTE_template;
427
s_init_state((stream_state *)&state, &jcdp->template, 0);
428
if (state.template->set_defaults)
429
(*state.template->set_defaults) ((stream_state *) & state);
430
state.QFactor = 1.0; /* disable quality adjustment in zfdcte.c */
431
state.ColorTransform = 1; /* default for RGB */
432
/* We insert no markers, allowing the IJG library to emit */
433
/* the format it thinks best. */
434
state.NoMarker = true; /* do not insert our own Adobe marker */
435
state.Markers.data = 0;
436
state.Markers.size = 0;
437
state.data.compress = jcdp;
438
jcdp->memory = state.jpeg_memory = mem;
439
if ((code = gs_jpeg_create_compress(&state)) < 0)
441
jcdp->cinfo.image_width = pdev->width;
442
jcdp->cinfo.image_height = pdev->height;
443
switch (pdev->color_info.depth) {
445
jcdp->cinfo.input_components = 4;
446
jcdp->cinfo.in_color_space = JCS_CMYK;
449
jcdp->cinfo.input_components = 3;
450
jcdp->cinfo.in_color_space = JCS_RGB;
453
jcdp->cinfo.input_components = 1;
454
jcdp->cinfo.in_color_space = JCS_GRAYSCALE;
457
/* Set compression parameters. */
458
if ((code = gs_jpeg_set_defaults(&state)) < 0)
460
if (jdev->JPEGQ > 0) {
461
code = gs_jpeg_set_quality(&state, jdev->JPEGQ, TRUE);
464
} else if (jdev->QFactor > 0.0) {
465
code = gs_jpeg_set_linear_quality(&state,
466
(int)(min(jdev->QFactor, 100.0)
472
jcdp->cinfo.restart_interval = 0;
473
jcdp->cinfo.density_unit = 1; /* dots/inch (no #define or enum) */
474
jcdp->cinfo.X_density = (UINT16)pdev->HWResolution[0];
475
jcdp->cinfo.Y_density = (UINT16)pdev->HWResolution[1];
476
/* Create the filter. */
477
/* Make sure we get at least a full scan line of input. */
478
state.scan_line_size = jcdp->cinfo.input_components *
479
jcdp->cinfo.image_width;
480
jcdp->template.min_in_size =
481
max(s_DCTE_template.min_in_size, state.scan_line_size);
482
/* Make sure we can write the user markers in a single go. */
483
jcdp->template.min_out_size =
484
max(s_DCTE_template.min_out_size, state.Markers.size);
486
/* Set up the streams. */
487
fbuf_size = max(512 /* arbitrary */ , jcdp->template.min_out_size);
488
jbuf_size = jcdp->template.min_in_size;
489
if ((fbuf = gs_alloc_bytes(mem, fbuf_size, "jpeg_print_page(fbuf)")) == 0 ||
490
(jbuf = gs_alloc_bytes(mem, jbuf_size, "jpeg_print_page(jbuf)")) == 0
492
code = gs_note_error(gs_error_VMerror);
496
swrite_file(&fstrm, prn_stream, fbuf, fbuf_size);
498
s_std_init(&jstrm, jbuf, jbuf_size, &s_filter_write_procs,
500
jstrm.state = (stream_state *) & state;
501
jstrm.procs.process = state.template->process;
503
if (state.template->init)
504
(*state.template->init) (jstrm.state);
506
/* Copy the data to the output. */
507
for (lnum = 0; lnum < pdev->height; ++lnum) {
511
if (jstrm.end_status) {
512
code = gs_note_error(gs_error_ioerror);
515
gdev_prn_get_bits(pdev, lnum, in, &data);
516
sputs(&jstrm, data, state.scan_line_size, &ignore_used);
524
gs_free_object(mem, jbuf, "jpeg_print_page(jbuf)");
525
gs_free_object(mem, fbuf, "jpeg_print_page(fbuf)");
527
gs_jpeg_destroy(&state); /* frees *jcdp */
528
gs_free_object(mem, in, "jpeg_print_page(in)");
532
gs_free_object(mem, jcdp, "jpeg_print_page(jpeg_compress_data)");
533
gs_free_object(mem, in, "jpeg_print_page(in)");