summaryrefslogtreecommitdiff
path: root/devices/vector/gdevpsdu.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/vector/gdevpsdu.c')
-rw-r--r--devices/vector/gdevpsdu.c520
1 files changed, 520 insertions, 0 deletions
diff --git a/devices/vector/gdevpsdu.c b/devices/vector/gdevpsdu.c
new file mode 100644
index 000000000..7e331bf8f
--- /dev/null
+++ b/devices/vector/gdevpsdu.c
@@ -0,0 +1,520 @@
+/* Copyright (C) 2001-2012 Artifex Software, Inc.
+ All Rights Reserved.
+
+ This software is provided AS-IS with no warranty, either express or
+ implied.
+
+ This software is distributed under license and may not be copied,
+ modified or distributed except as expressly authorized under the terms
+ of the license contained in the file LICENSE in this distribution.
+
+ Refer to licensing information at http://www.artifex.com or contact
+ Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
+ CA 94903, U.S.A., +1(415)492-9861, for further information.
+*/
+
+
+/* Common utilities for PostScript and PDF writers */
+#include "stdio_.h" /* for FILE for jpeglib.h */
+#include "jpeglib_.h" /* for sdct.h */
+#include "memory_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gdevpsdf.h"
+#include "strimpl.h"
+#include "sa85x.h"
+#include "scfx.h"
+#include "sdct.h"
+#include "sjpeg.h"
+#include "spprint.h"
+#include "gsovrc.h"
+#include "gsicc_cache.h"
+
+/* Structure descriptors */
+public_st_device_psdf();
+public_st_psdf_binary_writer();
+
+/* Standard color command names. */
+const psdf_set_color_commands_t psdf_set_fill_color_commands = {
+ "g", "rg", "k", "cs", "sc", "scn"
+};
+const psdf_set_color_commands_t psdf_set_stroke_color_commands = {
+ "G", "RG", "K", "CS", "SC", "SCN"
+};
+
+/* Define parameter-setting procedures. */
+extern stream_state_proc_put_params(s_DCTE_put_params, stream_DCT_state);
+
+/* ---------------- Vector implementation procedures ---------------- */
+
+int
+psdf_setlinewidth(gx_device_vector * vdev, double width)
+{
+ pprintg1(gdev_vector_stream(vdev), "%g w\n", width);
+ return 0;
+}
+
+int
+psdf_setlinecap(gx_device_vector * vdev, gs_line_cap cap)
+{
+ switch (cap) {
+ case gs_cap_butt:
+ case gs_cap_round:
+ case gs_cap_square:
+ pprintd1(gdev_vector_stream(vdev), "%d J\n", cap);
+ break;
+ case gs_cap_triangle:
+ /* If we get a PCL triangle cap, substitute with a round cap */
+ pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_round);
+ break;
+ default:
+ /* Ensure we don't write a broken file if we don't recognise the cap */
+ emprintf1(vdev->memory,
+ "Unknown line cap enumerator %d, substituting butt\n",
+ cap);
+ pprintd1(gdev_vector_stream(vdev), "%d J\n", gs_cap_butt);
+ break;
+ }
+ return 0;
+}
+
+int
+psdf_setlinejoin(gx_device_vector * vdev, gs_line_join join)
+{
+ switch (join) {
+ case gs_join_miter:
+ case gs_join_round:
+ case gs_join_bevel:
+ pprintd1(gdev_vector_stream(vdev), "%d j\n", join);
+ break;
+ case gs_join_none:
+ /* If we get a PCL triangle join, substitute with a bevel join */
+ pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_bevel);
+ break;
+ case gs_join_triangle:
+ /* If we get a PCL triangle join, substitute with a miter join */
+ pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter);
+ break;
+ default:
+ /* Ensure we don't write a broken file if we don't recognise the join */
+ emprintf1(vdev->memory,
+ "Unknown line join enumerator %d, substituting miter\n",
+ join);
+ pprintd1(gdev_vector_stream(vdev), "%d j\n", gs_join_miter);
+ break;
+ }
+ return 0;
+}
+
+int
+psdf_setmiterlimit(gx_device_vector * vdev, double limit)
+{
+ pprintg1(gdev_vector_stream(vdev), "%g M\n", limit);
+ return 0;
+}
+
+int
+psdf_setdash(gx_device_vector * vdev, const float *pattern, uint count,
+ double offset)
+{
+ stream *s = gdev_vector_stream(vdev);
+ int i;
+
+ stream_puts(s, "[ ");
+ for (i = 0; i < count; ++i)
+ pprintg1(s, "%g ", pattern[i]);
+ pprintg1(s, "] %g d\n", offset);
+ return 0;
+}
+
+int
+psdf_setflat(gx_device_vector * vdev, double flatness)
+{
+ pprintg1(gdev_vector_stream(vdev), "%g i\n", flatness);
+ return 0;
+}
+
+int
+psdf_setlogop(gx_device_vector * vdev, gs_logical_operation_t lop,
+ gs_logical_operation_t diff)
+{
+/****** SHOULD AT LEAST DETECT SET-0 & SET-1 ******/
+ return 0;
+}
+
+int
+psdf_dorect(gx_device_vector * vdev, fixed x0, fixed y0, fixed x1, fixed y1,
+ gx_path_type_t type)
+{
+ int code = (*vdev_proc(vdev, beginpath)) (vdev, type);
+
+ if (code < 0)
+ return code;
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g re\n",
+ fixed2float(x0), fixed2float(y0),
+ fixed2float(x1 - x0), fixed2float(y1 - y0));
+ return (*vdev_proc(vdev, endpath)) (vdev, type);
+}
+
+int
+psdf_beginpath(gx_device_vector * vdev, gx_path_type_t type)
+{
+ return 0;
+}
+
+int
+psdf_moveto(gx_device_vector * vdev, double x0, double y0, double x, double y,
+ gx_path_type_t type)
+{
+ pprintg2(gdev_vector_stream(vdev), "%g %g m\n", x, y);
+ return 0;
+}
+
+int
+psdf_lineto(gx_device_vector * vdev, double x0, double y0, double x, double y,
+ gx_path_type_t type)
+{
+ pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x, y);
+ return 0;
+}
+
+int
+psdf_curveto(gx_device_vector * vdev, double x0, double y0,
+ double x1, double y1, double x2, double y2, double x3, double y3,
+ gx_path_type_t type)
+{
+ if (x1 == x0 && y1 == y0 && x2 == x3 && y2 == y3)
+ pprintg2(gdev_vector_stream(vdev), "%g %g l\n", x3, y3);
+ else if (x1 == x0 && y1 == y0)
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g v\n",
+ x2, y2, x3, y3);
+ else if (x3 == x2 && y3 == y2)
+ pprintg4(gdev_vector_stream(vdev), "%g %g %g %g y\n",
+ x1, y1, x2, y2);
+ else
+ pprintg6(gdev_vector_stream(vdev), "%g %g %g %g %g %g c\n",
+ x1, y1, x2, y2, x3, y3);
+ return 0;
+}
+
+int
+psdf_closepath(gx_device_vector * vdev, double x0, double y0,
+ double x_start, double y_start, gx_path_type_t type)
+{
+ stream_puts(gdev_vector_stream(vdev), "h\n");
+ return 0;
+}
+
+/* endpath is deliberately omitted. */
+
+/* ---------------- Utilities ---------------- */
+
+gx_color_index
+psdf_adjust_color_index(gx_device_vector *vdev, gx_color_index color)
+{
+ /*
+ * Since gx_no_color_index is all 1's, we can't represent
+ * a CMYK color consisting of full ink in all 4 components.
+ * However, this color must be available for registration marks.
+ * gxcmap.c fudges this by changing the K component to 254;
+ * undo this fudge here.
+ */
+ return (color == (gx_no_color_index ^ 1) ? gx_no_color_index : color);
+}
+
+/* Round a double value to a specified precision. */
+double
+psdf_round(double v, int precision, int radix)
+{
+ double mul = 1;
+ double w = v;
+
+ if (w <= 0)
+ return w;
+ while (w < precision) {
+ w *= radix;
+ mul *= radix;
+ }
+ return (int)(w + 0.5) / mul;
+}
+
+/*
+ * Since we only have 8 bits of color to start with, round the
+ * values to 3 digits for more compact output.
+ */
+static inline double
+round_byte_color(gx_color_index cv)
+{
+ return (int)((uint)cv * (1000.0 / 255.0) + 0.5) / 1000.0;
+}
+int
+psdf_set_color(gx_device_vector * vdev, const gx_drawing_color * pdc,
+ const psdf_set_color_commands_t *ppscc, bool UseOldColor)
+{
+ const char *setcolor;
+ int num_des_comps, code;
+ cmm_dev_profile_t *dev_profile;
+
+ if (UseOldColor) {
+ num_des_comps = vdev->color_info.num_components;
+ } else {
+ code = dev_proc((gx_device *)vdev, get_profile)((gx_device *)vdev, &dev_profile);
+ if (code < 0)
+ return code;
+ num_des_comps = gsicc_get_device_profile_comps(dev_profile);
+ }
+ if (!gx_dc_is_pure(pdc))
+ return_error(gs_error_rangecheck);
+ {
+ stream *s = gdev_vector_stream(vdev);
+ gx_color_index color =
+ psdf_adjust_color_index(vdev, gx_dc_pure_color(pdc));
+ /*
+ * Normally we would precompute all of v0 .. v3, but gcc 2.7.2.3
+ * generates incorrect code for Intel CPUs if we do this. The code
+ * below is longer, but does less computation in some cases.
+ */
+ double v3 = round_byte_color(color & 0xff);
+
+ switch (num_des_comps) {
+ case 4:
+ /* if (v0 == 0 && v1 == 0 && v2 == 0 && ...) */
+ if ((color & 0xffffff00) == 0 && ppscc->setgray != 0) {
+ v3 = 1.0 - v3;
+ goto g;
+ }
+ pprintg4(s, "%g %g %g %g", round_byte_color(color >> 24),
+ round_byte_color((color >> 16) & 0xff),
+ round_byte_color((color >> 8) & 0xff), v3);
+ setcolor = ppscc->setcmykcolor;
+ break;
+ case 3:
+ /* if (v1 == v2 && v2 == v3 && ...) */
+ if (!((color ^ (color >> 8)) & 0xffff) && ppscc->setgray != 0)
+ goto g;
+ pprintg3(s, "%g %g %g", round_byte_color((color >> 16) & 0xff),
+ round_byte_color((color >> 8) & 0xff), v3);
+ setcolor = ppscc->setrgbcolor;
+ break;
+ case 1:
+ g:
+ pprintg1(s, "%g", v3);
+ setcolor = ppscc->setgray;
+ break;
+ default: /* can't happen */
+ return_error(gs_error_rangecheck);
+ }
+ if (setcolor)
+ pprints1(s, " %s\n", setcolor);
+ }
+ return 0;
+}
+
+/* ---------------- Binary data writing ---------------- */
+
+/* Begin writing binary data. */
+int
+psdf_begin_binary(gx_device_psdf * pdev, psdf_binary_writer * pbw)
+{
+ gs_memory_t *mem = pbw->memory = pdev->v_memory;
+
+ pbw->target = pdev->strm;
+ pbw->dev = pdev;
+ pbw->strm = 0; /* for GC in case of failure */
+ /* If not binary, set up the encoding stream. */
+ if (!pdev->binary_ok) {
+#define BUF_SIZE 100 /* arbitrary */
+ byte *buf = gs_alloc_bytes(mem, BUF_SIZE, "psdf_begin_binary(buf)");
+ stream_A85E_state *ss = (stream_A85E_state *)
+ s_alloc_state(mem, s_A85E_template.stype,
+ "psdf_begin_binary(stream_state)");
+ stream *s = s_alloc(mem, "psdf_begin_binary(stream)");
+
+ if (buf == 0 || ss == 0 || s == 0) {
+ gs_free_object(mem, s, "psdf_begin_binary(stream)");
+ gs_free_object(mem, ss, "psdf_begin_binary(stream_state)");
+ gs_free_object(mem, buf, "psdf_begin_binary(buf)");
+ return_error(gs_error_VMerror);
+ }
+ ss->templat = &s_A85E_template;
+ s_init_filter(s, (stream_state *)ss, buf, BUF_SIZE, pdev->strm);
+#undef BUF_SIZE
+ pbw->strm = s;
+ } else {
+ pbw->strm = pdev->strm;
+ }
+ return 0;
+}
+
+/* Add an encoding filter. The client must have allocated the stream state, */
+/* if any, using pdev->v_memory. */
+int
+psdf_encode_binary(psdf_binary_writer * pbw, const stream_template * templat,
+ stream_state * ss)
+{
+ return (s_add_filter(&pbw->strm, templat, ss, pbw->memory) == 0 ?
+ gs_note_error(gs_error_VMerror) : 0);
+}
+
+/*
+ * Acquire parameters, and optionally set up the filter for, a DCTEncode
+ * filter. This is a separate procedure so it can be used to validate
+ * filter parameters when they are set, rather than waiting until they are
+ * used. pbw = NULL means just set up the stream state.
+ */
+int
+psdf_DCT_filter(gs_param_list *plist /* may be NULL */,
+ stream_state /*stream_DCTE_state*/ *st,
+ int Columns, int Rows, int Colors,
+ psdf_binary_writer *pbw /* may be NULL */)
+{
+ stream_DCT_state *const ss = (stream_DCT_state *) st;
+ gs_memory_t *mem = st->memory;
+ jpeg_compress_data *jcdp;
+ gs_c_param_list rcc_list;
+ int code;
+
+ /*
+ * "Wrap" the actual Dict or ACSDict parameter list in one that
+ * sets Rows, Columns, and Colors.
+ */
+ gs_c_param_list_write(&rcc_list, mem);
+ if ((code = param_write_int((gs_param_list *)&rcc_list, "Rows",
+ &Rows)) < 0 ||
+ (code = param_write_int((gs_param_list *)&rcc_list, "Columns",
+ &Columns)) < 0 ||
+ (code = param_write_int((gs_param_list *)&rcc_list, "Colors",
+ &Colors)) < 0
+ ) {
+ goto rcc_fail;
+ }
+ gs_c_param_list_read(&rcc_list);
+ if (plist)
+ gs_c_param_list_set_target(&rcc_list, plist);
+ /* Allocate space for IJG parameters. */
+ jcdp = gs_alloc_struct_immovable(mem, jpeg_compress_data,
+ &st_jpeg_compress_data, "zDCTE");
+ if (jcdp == 0)
+ return_error(gs_error_VMerror);
+ ss->data.compress = jcdp;
+ jcdp->memory = ss->jpeg_memory = mem; /* set now for allocation */
+ if ((code = gs_jpeg_create_compress(ss)) < 0)
+ goto dcte_fail; /* correct to do jpeg_destroy here */
+ /* Read parameters from dictionary */
+ code = s_DCTE_put_params((gs_param_list *)&rcc_list, ss);
+ if (code < 0)
+ return code;
+ /* Create the filter. */
+ jcdp->templat = s_DCTE_template;
+ /* Make sure we get at least a full scan line of input. */
+ ss->scan_line_size = jcdp->cinfo.input_components *
+ jcdp->cinfo.image_width;
+ /* Profile not used in pdfwrite output */
+ ss->icc_profile = NULL;
+ jcdp->templat.min_in_size =
+ max(s_DCTE_template.min_in_size, ss->scan_line_size);
+ /* Make sure we can write the user markers in a single go. */
+ jcdp->templat.min_out_size =
+ max(s_DCTE_template.min_out_size, ss->Markers.size);
+ if (pbw)
+ code = psdf_encode_binary(pbw, &jcdp->templat, st);
+ if (code >= 0) {
+ gs_c_param_list_release(&rcc_list);
+ return 0;
+ }
+ dcte_fail:
+ gs_jpeg_destroy(ss);
+ gs_free_object(mem, jcdp, "setup_image_compression");
+ ss->data.compress = NULL; /* Avoid problems with double frees later */
+ rcc_fail:
+ gs_c_param_list_release(&rcc_list);
+ return code;
+}
+
+/* Add a 2-D CCITTFax encoding filter. */
+/* Set EndOfBlock iff the stream is not ASCII85 encoded. */
+int
+psdf_CFE_binary(psdf_binary_writer * pbw, int w, int h, bool invert)
+{
+ gs_memory_t *mem = pbw->memory;
+ const stream_template *templat = &s_CFE_template;
+ stream_CFE_state *st =
+ gs_alloc_struct(mem, stream_CFE_state, templat->stype,
+ "psdf_CFE_binary");
+ int code;
+
+ if (st == 0)
+ return_error(gs_error_VMerror);
+ (*templat->set_defaults) ((stream_state *) st);
+ st->K = -1;
+ st->Columns = w;
+ st->Rows = 0;
+ st->BlackIs1 = !invert;
+ st->EndOfBlock = pbw->strm->state->templat != &s_A85E_template;
+ code = psdf_encode_binary(pbw, templat, (stream_state *) st);
+ if (code < 0)
+ gs_free_object(mem, st, "psdf_CFE_binary");
+ return code;
+}
+
+/* Finish writing binary data. */
+int
+psdf_end_binary(psdf_binary_writer * pbw)
+{
+ int status = s_close_filters(&pbw->strm, pbw->target);
+
+ return (status >= 0 ? 0 : gs_note_error(gs_error_ioerror));
+}
+
+/* ---------------- Overprint, Get Bits ---------------- */
+
+/*
+ * High level devices cannot perform get_bits or get_bits_rectangle
+ * operations, for obvious reasons.
+ */
+int
+psdf_get_bits(gx_device * dev, int y, byte * data, byte ** actual_data)
+{
+ if (dev_proc(dev, get_alpha_bits)(dev, go_graphics) > 1)
+ emprintf1(dev->memory,
+ "Can't set GraphicsAlphaBits > 1 with a vector device %s.\n",
+ dev->dname);
+ return_error(gs_error_unregistered);
+}
+
+int
+psdf_get_bits_rectangle(
+ gx_device * dev,
+ const gs_int_rect * prect,
+ gs_get_bits_params_t * params,
+ gs_int_rect ** unread )
+{
+ return_error(gs_error_unregistered);
+}
+
+/*
+ * Create compositor procedure for PostScript/PDF writer. Since these
+ * devices directly support overprint (and have access to the imager
+ * state), no compositor is required for overprint support. Hence, this
+ * routine just recognizes and discards invocations of the overprint
+ * compositor.
+ */
+int
+psdf_create_compositor(
+ gx_device * dev,
+ gx_device ** pcdev,
+ const gs_composite_t * pct,
+ gs_imager_state * pis,
+ gs_memory_t * mem,
+ gx_device * cdev)
+{
+ if (gs_is_overprint_compositor(pct)) {
+ *pcdev = dev;
+ return 0;
+ } else {
+ if (dev->parent)
+ return gx_default_create_compositor(dev->parent, pcdev, pct, pis, mem, cdev);
+ else
+ return gx_default_create_compositor(dev, pcdev, pct, pis, mem, cdev);
+ }
+}