diff options
author | Henry Stiles <henry.stiles@artifex.com> | 1998-07-26 07:36:41 +0000 |
---|---|---|
committer | Henry Stiles <henry.stiles@artifex.com> | 1998-07-26 07:36:41 +0000 |
commit | eec0ef527f18c5978c4476c9490f4de4c4249628 (patch) | |
tree | 5588d5e1300a245186594893c930949a19bcbbce /gs/src/gdevjpeg.c | |
parent | d4bdba93ef34f68d27148e1b31088d1d3e786e8c (diff) | |
download | ghostpdl-eec0ef527f18c5978c4476c9490f4de4c4249628.tar.gz |
Initial revision
git-svn-id: http://svn.ghostscript.com/ghostpcl/trunk/ghostpcl@246 06663e23-700e-0410-b217-a244a6096597
Diffstat (limited to 'gs/src/gdevjpeg.c')
-rw-r--r-- | gs/src/gdevjpeg.c | 288 |
1 files changed, 288 insertions, 0 deletions
diff --git a/gs/src/gdevjpeg.c b/gs/src/gdevjpeg.c new file mode 100644 index 000000000..96883f0c3 --- /dev/null +++ b/gs/src/gdevjpeg.c @@ -0,0 +1,288 @@ +/* Copyright (C) 1997 Aladdin Enterprises. All rights reserved. + + This file is part of Aladdin Ghostscript. + + Aladdin Ghostscript is distributed with NO WARRANTY OF ANY KIND. No author + or distributor accepts any responsibility for the consequences of using it, + or for whether it serves any particular purpose or works at all, unless he + or she says so in writing. Refer to the Aladdin Ghostscript Free Public + License (the "License") for full details. + + Every copy of Aladdin Ghostscript must include a copy of the License, + normally in a plain ASCII text file named PUBLIC. The License grants you + the right to copy, modify and redistribute Aladdin Ghostscript, but only + under certain conditions described in the License. Among other things, the + License requires that the copyright notice and this notice be preserved on + all copies. +*/ + +/* gdevjpeg.c */ +/* JPEG output driver */ +#include "stdio_.h" /* for jpeglib.h */ +#include "jpeglib.h" +#include "gdevprn.h" +#include "stream.h" +#include "strimpl.h" +#include "sdct.h" +#include "sjpeg.h" + +/* Structure for the JPEG-writing device. */ +typedef struct gx_device_jpeg_s { + gx_device_common; + gx_prn_device_common; + /* Additional parameters */ + int JPEGQ; /* quality on IJG scale */ + float QFactor; /* quality per DCTEncode conventions */ + /* JPEGQ overrides QFactor if both are specified. */ +} gx_device_jpeg; + +/* The device descriptor */ +private dev_proc_get_params(jpeg_get_params); +private dev_proc_put_params(jpeg_put_params); +private dev_proc_print_page(jpeg_print_page); + +/* ------ The device descriptors ------ */ + +/* Default X and Y resolution. */ +#ifndef X_DPI +# define X_DPI 72 +#endif +#ifndef Y_DPI +# define Y_DPI 72 +#endif + +/* 24-bit color */ + +private const gx_device_procs jpeg_procs = + prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close, + gx_default_rgb_map_rgb_color, + gx_default_rgb_map_color_rgb, + jpeg_get_params, jpeg_put_params); + +gx_device_jpeg far_data gs_jpeg_device = +{ prn_device_std_body(gx_device_jpeg, jpeg_procs, "jpeg", + DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, + X_DPI, Y_DPI, 0,0,0,0, 24, jpeg_print_page), + 0, /* JPEGQ: 0 indicates not specified */ + 0.0 /* QFactor: 0 indicates not specified */ +}; + +/* 8-bit gray */ + +private const gx_device_procs jpeggray_procs = + prn_color_params_procs(gdev_prn_open, gdev_prn_output_page, gdev_prn_close, + gx_default_gray_map_rgb_color, + gx_default_gray_map_color_rgb, + jpeg_get_params, jpeg_put_params); + +gx_device_jpeg far_data gs_jpeggray_device = +{ prn_device_body(gx_device_jpeg, jpeggray_procs, "jpeggray", + DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS, + X_DPI, Y_DPI, 0,0,0,0, + 1,8,255,0,256,0, + jpeg_print_page), + 0, /* JPEGQ: 0 indicates not specified */ + 0.0 /* QFactor: 0 indicates not specified */ +}; + +/* Get parameters. */ +private int +jpeg_get_params(gx_device *dev, gs_param_list *plist) +{ gx_device_jpeg *jdev = (gx_device_jpeg *)dev; + int code = gdev_prn_get_params(dev, plist); + int ecode; + + if ( code < 0 ) + return code; + + if ((ecode = param_write_int(plist, "JPEGQ", &jdev->JPEGQ)) < 0) + code = ecode; + if ((ecode = param_write_float(plist, "QFactor", &jdev->QFactor)) < 0) + code = ecode; + + return code; +} + +/* Put parameters. */ +private int +jpeg_put_params(gx_device *dev, gs_param_list *plist) +{ gx_device_jpeg *jdev = (gx_device_jpeg *)dev; + int ecode = 0; + int code; + gs_param_name param_name; + int jq = jdev->JPEGQ; + float qf = jdev->QFactor; + + switch ( code = param_read_int(plist, (param_name = "JPEGQ"), &jq) ) + { + case 0: + if ( jq < 0 || jq > 100 ) + ecode = gs_error_limitcheck; + else + break; + goto jqe; + default: + ecode = code; +jqe: param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + switch ( code = param_read_float(plist, (param_name = "QFactor"), &qf) ) + { + case 0: + if ( qf < 0.0 || qf > 1.0e6 ) + ecode = gs_error_limitcheck; + else + break; + goto qfe; + default: + ecode = code; +qfe: param_signal_error(plist, param_name, ecode); + case 1: + break; + } + + if ( ecode < 0 ) + return ecode; + code = gdev_prn_put_params(dev, plist); + if ( code < 0 ) + return code; + + jdev->JPEGQ = jq; + jdev->QFactor = qf; + return 0; +} + +/* Send the page to the file. */ +private int +jpeg_print_page(gx_device_printer *pdev, FILE *prn_stream) +{ gx_device_jpeg *jdev = (gx_device_jpeg *)pdev; + gs_memory_t *mem = pdev->memory; + int line_size = gdev_mem_bytes_per_scan_line((gx_device *)pdev); + byte *in = gs_alloc_bytes(mem, line_size, "jpeg_print_page(in)"); + /* The current implementation of the DCTE filter */ + /* requires that we allocate this with gs_malloc! */ + jpeg_compress_data *jcdp = + gs_malloc(1, sizeof(*jcdp), "jpeg_print_page(jpeg_compress_data)"); + byte *fbuf = 0; + uint fbuf_size; + byte *jbuf = 0; + uint jbuf_size; + int lnum; + int code; + stream_DCT_state state; + stream fstrm, jstrm; + + static const stream_procs filter_write_procs = + { s_std_noavailable, s_std_noseek, s_std_write_reset, + s_std_write_flush, s_filter_close + }; + + if ( jcdp == 0 || in == 0 ) + { code = gs_note_error(gs_error_VMerror); + goto fail; + } + /* Create the DCT decoder state. */ + state.template = &jcdp->template; + state.memory = 0; + state.QFactor = 1.0; /* disable quality adjustment in zfdcte.c */ + state.ColorTransform = 1; /* default for RGB */ + /* We insert no markers, allowing the IJG library to emit */ + /* the format it thinks best. */ + state.NoMarker = true; /* do not insert our own Adobe marker */ + state.Markers.data = 0; + state.Markers.size = 0; + state.data.compress = jcdp; + if ( (code = gs_jpeg_create_compress(&state)) < 0 ) + goto fail; + jcdp->cinfo.image_width = pdev->width; + jcdp->cinfo.image_height = pdev->height; + switch (pdev->color_info.depth) { + case 24: + jcdp->cinfo.input_components = 3; + jcdp->cinfo.in_color_space = JCS_RGB; + break; + case 8: + jcdp->cinfo.input_components = 1; + jcdp->cinfo.in_color_space = JCS_GRAYSCALE; + break; + } + /* Set compression parameters. */ + if ( (code = gs_jpeg_set_defaults(&state)) < 0 ) + goto done; + if (jdev->JPEGQ > 0) + { code = gs_jpeg_set_quality(&state, jdev->JPEGQ, TRUE); + if ( code < 0 ) + goto done; + } + else if (jdev->QFactor > 0.0) + { code = gs_jpeg_set_linear_quality(&state, + (int) (min(jdev->QFactor, 100.0) + * 100.0 + 0.5), + TRUE); + if ( code < 0 ) + goto done; + } + jcdp->cinfo.restart_interval = 0; + jcdp->cinfo.density_unit = 1; /* dots/inch (no #define or enum) */ + jcdp->cinfo.X_density = pdev->HWResolution[0]; + jcdp->cinfo.Y_density = pdev->HWResolution[1]; + /* Create the filter. */ + jcdp->template = s_DCTE_template; + /* Make sure we get at least a full scan line of input. */ + state.scan_line_size = jcdp->cinfo.input_components * + jcdp->cinfo.image_width; + jcdp->template.min_in_size = + max(s_DCTE_template.min_in_size, state.scan_line_size); + /* Make sure we can write the user markers in a single go. */ + jcdp->template.min_out_size = + max(s_DCTE_template.min_out_size, state.Markers.size); + + /* Set up the streams. */ + fbuf_size = max(512 /* arbitrary */, jcdp->template.min_out_size); + jbuf_size = jcdp->template.min_in_size; + if ( (fbuf = gs_alloc_bytes(mem, fbuf_size, "jpeg_print_page(fbuf)")) == 0 || + (jbuf = gs_alloc_bytes(mem, jbuf_size, "jpeg_print_page(jbuf)")) == 0 + ) + { code = gs_note_error(gs_error_VMerror); + goto done; + } + swrite_file(&fstrm, prn_stream, fbuf, fbuf_size); + s_std_init(&jstrm, jbuf, jbuf_size, &filter_write_procs, + s_mode_write); + jstrm.memory = mem; + jstrm.state = (stream_state *)&state; + jstrm.procs.process = state.template->process; + jstrm.strm = &fstrm; + if ( state.template->init ) + (*state.template->init)(jstrm.state); + + /* Copy the data to the output. */ + for ( lnum = 0; lnum < pdev->height; ++lnum ) + { byte *data; + uint ignore_used; + + gdev_prn_get_bits(pdev, lnum, in, &data); + sputs(&jstrm, data, state.scan_line_size, &ignore_used); + } + + /* Wrap up. */ + sclose(&jstrm); + sflush(&fstrm); + jcdp = 0; +done: + gs_free_object(mem, jbuf, "jpeg_print_page(jbuf)"); + gs_free_object(mem, fbuf, "jpeg_print_page(fbuf)"); + if ( jcdp ) + gs_jpeg_destroy(&state); /* frees *jcdp */ + gs_free_object(mem, in, "jpeg_print_page(in)"); + return code; +fail: + if ( jcdp ) + gs_free(jcdp, 1, sizeof(*jcdp), + "jpeg_print_page(jpeg_compress_data)"); + gs_free_object(mem, in, "jpeg_print_page(in)"); + return code; +#undef jcdp +} |