summaryrefslogtreecommitdiff
path: root/devices/vector/gdevpdfb.c
diff options
context:
space:
mode:
Diffstat (limited to 'devices/vector/gdevpdfb.c')
-rw-r--r--devices/vector/gdevpdfb.c654
1 files changed, 654 insertions, 0 deletions
diff --git a/devices/vector/gdevpdfb.c b/devices/vector/gdevpdfb.c
new file mode 100644
index 000000000..38fdb6d8a
--- /dev/null
+++ b/devices/vector/gdevpdfb.c
@@ -0,0 +1,654 @@
+/* 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.
+*/
+
+
+/* Low-level bitmap image handling for PDF-writing driver */
+#include "string_.h"
+#include "gx.h"
+#include "gserrors.h"
+#include "gdevpdfx.h"
+#include "gdevpdfg.h"
+#include "gdevpdfo.h" /* for data stream */
+#include "gxcspace.h"
+#include "gxdcolor.h"
+#include "gxpcolor.h"
+#include "gxhldevc.h"
+#include "gxchar.h"
+#include "gdevpdtf.h" /* Required to include gdevpdti.h */
+#include "gdevpdti.h" /* For pdf_charproc_x_offset */
+#include "gsptype1.h"
+
+/* We need this color space type for constructing temporary color spaces. */
+extern const gs_color_space_type gs_color_space_type_Indexed;
+
+/* ---------------- Utilities ---------------- */
+
+/* Fill in the image parameters for a bitmap image. */
+static void
+pdf_make_bitmap_image(gs_image_t * pim, int x, int y, int w, int h)
+{
+ pim->Width = w;
+ pim->Height = h;
+ pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h, h);
+}
+
+/* ---------------- Driver procedures ---------------- */
+
+/* Copy a mask bitmap. for_pattern = -1 means put the image in-line, */
+/* 1 means put the image in a resource. */
+static int
+pdf_copy_mask_data(gx_device_pdf * pdev, const byte * base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gs_image_t *pim, pdf_image_writer *piw,
+ int for_pattern)
+{
+ ulong nbytes;
+ int code;
+ const byte *row_base;
+ int row_step;
+ bool in_line;
+
+ gs_image_t_init_mask(pim, true);
+ pdf_make_bitmap_image(pim, x, y, w, h);
+ nbytes = ((ulong)w * h + 7) / 8;
+
+ if (for_pattern) {
+ /*
+ * Patterns must be emitted in order of increasing user Y, i.e.,
+ * the opposite of PDF's standard image order.
+ */
+ row_base = base + (h - 1) * raster;
+ row_step = -raster;
+ in_line = for_pattern < 0;
+ } else {
+ row_base = base;
+ row_step = raster;
+ in_line = nbytes < pdev->MaxInlineImageSize;
+ pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
+ /*
+ * Check whether we've already made an XObject resource for this
+ * image.
+ */
+ if (id != gx_no_bitmap_id) {
+ piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
+ if (piw->pres)
+ return 0;
+ }
+ }
+ /*
+ * We have to be able to control whether to put Pattern images in line,
+ * to avoid trying to create an XObject resource while we're in the
+ * middle of writing a Pattern resource.
+ */
+ if (for_pattern < 0)
+ stream_puts(pdev->strm, "q ");
+ pdf_image_writer_init(piw);
+ pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
+ if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
+ (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
+ &piw->binary[0],
+ (gs_pixel_image_t *)pim, in_line)) < 0 ||
+ (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
+ NULL, 0)) < 0
+ )
+ return code;
+ pdf_copy_mask_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h, 0);
+ pdf_end_image_binary(pdev, piw, piw->height);
+ return pdf_end_write_image(pdev, piw);
+}
+
+static void
+set_image_color(gx_device_pdf *pdev, gx_color_index c)
+{
+ pdf_set_pure_color(pdev, c, &pdev->saved_fill_color,
+ &pdev->fill_used_process_color,
+ &psdf_set_fill_color_commands);
+ if (!pdev->HaveStrokeColor)
+ pdf_set_pure_color(pdev, c, &pdev->saved_stroke_color,
+ &pdev->stroke_used_process_color,
+ &psdf_set_stroke_color_commands);
+}
+
+static int
+pdf_copy_mono(gx_device_pdf *pdev,
+ const byte *base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero,
+ gx_color_index one, const gx_clip_path *pcpath)
+{
+ int code;
+ gs_color_space *pcs = NULL;
+ cos_value_t cs_value;
+ cos_value_t *pcsvalue;
+ byte palette[arch_sizeof_color_index * 2];
+ gs_image_t image;
+ pdf_image_writer writer;
+ pdf_stream_position_t ipos;
+ pdf_resource_t *pres = 0;
+ byte invert = 0;
+ bool in_line = false;
+ gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
+ int x_offset, y_offset;
+ double width;
+
+ /* Update clipping. */
+ if (pdf_must_put_clip_path(pdev, pcpath)) {
+ code = pdf_open_page(pdev, PDF_IN_STREAM);
+ if (code < 0)
+ return code;
+ code = pdf_put_clip_path(pdev, pcpath);
+ if (code < 0)
+ return code;
+ }
+ /* We have 3 cases: mask, inverse mask, and solid. */
+ if (zero == gx_no_color_index) {
+ if (one == gx_no_color_index)
+ return 0;
+ /* If a mask has an id, assume it's a character. */
+ if (id != gx_no_bitmap_id && sourcex == 0 && show_enum) {
+ pdf_char_proc_t *pcp;
+
+ if (show_enum->use_wxy_float)
+ pdev->char_width.x = show_enum->wxy_float.x;
+ else
+ pdev->char_width.x = fixed2float(show_enum->wxy.x);
+ pres = pdf_find_resource_by_gs_id(pdev, resourceCharProc, id);
+ if (pres == 0) { /* Define the character in an embedded font. */
+ gs_image_t_init_mask(&image, false);
+ invert = 0xff;
+ x_offset = x - (int)show_enum->pis->current_point.x;
+ y_offset = y - (int)show_enum->pis->current_point.y;
+ x -= x_offset;
+ y -= y_offset;
+ y -= h;
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ /*
+ * The Y axis of the text matrix is inverted,
+ * so we need to negate the Y offset appropriately.
+ */
+ code = pdf_begin_char_proc(pdev, w, h, 0, y_offset, x_offset, id,
+ &pcp, &ipos);
+ if (code < 0)
+ return code;
+ y_offset = -y_offset;
+ width = psdf_round(pdev->char_width.x, 100, 10); /* See
+ pdf_write_Widths about rounding. We need to provide
+ a compatible data for Tj. */
+ pprintg1(pdev->strm, "%g ", width);
+ pprintd4(pdev->strm, "0 %d %d %d %d d1\n", x_offset, -h + y_offset, w + x_offset, y_offset);
+ pprintd4(pdev->strm, "%d 0 0 %d %d %d cm\n", w, h, x_offset,
+ -h + y_offset);
+ pdf_image_writer_init(&writer);
+ code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, true);
+ if (code < 0)
+ return code;
+ pres = (pdf_resource_t *) pcp;
+ goto wr;
+ } else if (pdev->pte) {
+ /* We're under pdf_text_process. It set a high level color. */
+ } else
+ set_image_color(pdev, one);
+ pcp = (pdf_char_proc_t *) pres;
+ x -= pdf_charproc_x_offset(pcp);
+ y -= pdf_charproc_y_offset(pcp);
+ y -= h;
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ goto rx;
+ }
+ set_image_color(pdev, one);
+ gs_image_t_init_mask(&image, false);
+ invert = 0xff;
+ } else if (one == gx_no_color_index) {
+ gs_image_t_init_mask(&image, false);
+ set_image_color(pdev, zero);
+ } else if (zero == pdev->black && one == pdev->white) {
+ pcs = gs_cspace_new_DeviceGray(pdev->memory);
+ gs_image_t_init(&image, pcs);
+ } else if (zero == pdev->white && one == pdev->black) {
+ pcs = gs_cspace_new_DeviceGray(pdev->memory);
+ gs_image_t_init(&image, pcs);
+ invert = 0xff;
+ } else {
+ /*
+ * We think this code is never executed when interpreting PostScript
+ * or PDF: the library never uses monobit non-mask images
+ * internally, and high-level images don't go through this code.
+ * However, we still want the code to work.
+ */
+ gs_color_space *pcs_base;
+ gx_color_index c[2];
+ int i, j;
+ int ncomp = pdev->color_info.num_components;
+ byte *p;
+
+ code = pdf_cspace_init_Device(pdev->memory, &pcs_base, ncomp);
+ if (code < 0)
+ return code;
+ c[0] = psdf_adjust_color_index((gx_device_vector *)pdev, zero);
+ c[1] = psdf_adjust_color_index((gx_device_vector *)pdev, one);
+ pcs = gs_cspace_alloc(pdev->memory, &gs_color_space_type_Indexed);
+ if (pcs == NULL) {
+ rc_decrement_cs(pcs_base, "pdf_copy_mono");
+ return_error(gs_error_VMerror);
+ }
+ pcs->base_space = pcs_base;
+ pcs->params.indexed.hival = 1;
+ pcs->params.indexed.n_comps = ncomp;
+ p = palette;
+ for (i = 0; i < 2; ++i)
+ for (j = ncomp - 1; j >= 0; --j)
+ *p++ = (byte)(c[i] >> (j * 8));
+ pcs->params.indexed.lookup.table.data = palette;
+ pcs->params.indexed.lookup.table.size = p - palette;
+ pcs->params.indexed.use_proc = false;
+ gs_image_t_init(&image, pcs);
+ image.BitsPerComponent = 1;
+ }
+ pdf_make_bitmap_image(&image, x, y, w, h);
+ {
+ ulong nbytes = (ulong) ((w + 7) >> 3) * h;
+
+ code = pdf_open_page(pdev, PDF_IN_STREAM);
+ if (code < 0)
+ return code;
+ in_line = nbytes < pdev->MaxInlineImageSize;
+ if (in_line)
+ pdf_put_image_matrix(pdev, &image.ImageMatrix, 1.0);
+ pdf_image_writer_init(&writer);
+ code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, in_line);
+ if (code < 0)
+ return code;
+ }
+ wr:
+ if (image.ImageMask)
+ pcsvalue = NULL;
+ else {
+ /*
+ * We don't have to worry about color space scaling: the color
+ * space is always a Device space.
+ */
+ code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs,
+ &writer.pin->color_spaces, in_line, NULL, 0, false);
+ if (code < 0)
+ return code;
+ pcsvalue = &cs_value;
+ }
+ /*
+ * There are 3 different cases at this point:
+ * - Writing an in-line image (pres == 0, writer.pres == 0);
+ * - Writing an XObject image (pres == 0, writer.pres != 0);
+ * - Writing the image for a CharProc (pres != 0).
+ * We handle them with in-line code followed by a switch,
+ * rather than making the shared code into a procedure,
+ * simply because there would be an awful lot of parameters
+ * that would need to be passed.
+ */
+ if (pres) {
+ if (!pdev->NoT3CCITT) {
+ /*
+ * Always use CCITTFax 2-D for character bitmaps. It takes less
+ * space to invert the data with Decode than to set BlackIs1.
+ */
+ float d0 = image.Decode[0];
+
+ image.Decode[0] = image.Decode[1];
+ image.Decode[1] = d0;
+ psdf_CFE_binary(&writer.binary[0], image.Width, image.Height, true);
+ invert ^= 0xff;
+ }
+ } else {
+ /* Use the Distiller compression parameters. */
+ pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
+ psdf_setup_image_filters((gx_device_psdf *) pdev, &writer.binary[0],
+ (gs_pixel_image_t *)&image, NULL, NULL, true, in_line);
+ }
+ pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image,
+ pcsvalue, 0);
+ code = pdf_copy_mask_bits(writer.binary[0].strm, base, sourcex, raster,
+ w, h, invert);
+ if (code < 0)
+ return code;
+ pdf_end_image_binary(pdev, &writer, writer.height);
+ if (!pres) {
+ switch ((code = pdf_end_write_image(pdev, &writer))) {
+ default: /* error */
+ return code;
+ case 1:
+ return 0;
+ case 0:
+ return pdf_do_image(pdev, writer.pres, &image.ImageMatrix,
+ true);
+ }
+ }
+ writer.end_string = ""; /* no Q */
+ switch ((code = pdf_end_write_image(pdev, &writer))) {
+ default: /* error */
+ return code;
+ case 0: /* not possible */
+ return_error(gs_error_Fatal);
+ case 1:
+ break;
+ }
+ code = pdf_end_char_proc(pdev, &ipos);
+ if (code < 0)
+ return code;
+ rx:{
+ gs_matrix imat;
+
+ imat = image.ImageMatrix;
+ imat.xx /= w;
+ imat.xy /= h;
+ imat.yx /= w;
+ imat.yy /= h;
+ return pdf_do_char_image(pdev, (const pdf_char_proc_t *)pres, &imat);
+ }
+}
+int
+gdev_pdf_copy_mono(gx_device * dev,
+ const byte * base, int sourcex, int raster, gx_bitmap_id id,
+ int x, int y, int w, int h, gx_color_index zero,
+ gx_color_index one)
+{
+ gx_device_pdf *pdev = (gx_device_pdf *) dev;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+ return pdf_copy_mono(pdev, base, sourcex, raster, id, x, y, w, h,
+ zero, one, NULL);
+}
+
+/* Copy a color bitmap. for_pattern = -1 means put the image in-line, */
+/* 1 means put the image in a resource, 2 means image is a rasterized shading. */
+int
+pdf_copy_color_data(gx_device_pdf * pdev, const byte * base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h,
+ gs_image_t *pim, pdf_image_writer *piw,
+ int for_pattern)
+{
+ int depth = pdev->color_info.depth;
+ int bytes_per_pixel = depth >> 3;
+ gs_color_space *pcs;
+ cos_value_t cs_value;
+ ulong nbytes;
+ int code = pdf_cspace_init_Device(pdev->memory, &pcs, bytes_per_pixel);
+ const byte *row_base;
+ int row_step;
+ bool in_line;
+
+ if (code < 0)
+ return code; /* can't happen */
+ if (!base)
+ return 1;
+ gs_image_t_init(pim, pcs);
+ pdf_make_bitmap_image(pim, x, y, w, h);
+ pim->BitsPerComponent = 8;
+ nbytes = (ulong)w * bytes_per_pixel * h;
+
+ if (for_pattern == 1) {
+ /*
+ * Patterns must be emitted in order of increasing user Y, i.e.,
+ * the opposite of PDF's standard image order.
+ */
+ row_base = base + (h - 1) * raster;
+ row_step = -raster;
+ in_line = for_pattern < 0;
+ } else {
+ row_base = base;
+ row_step = raster;
+ in_line = nbytes < pdev->MaxInlineImageSize;
+ pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
+ /*
+ * Check whether we've already made an XObject resource for this
+ * image.
+ */
+ if (id != gx_no_bitmap_id) {
+ piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
+ if (piw->pres)
+ return 0;
+ }
+ }
+ /*
+ * We have to be able to control whether to put Pattern images in line,
+ * to avoid trying to create an XObject resource while we're in the
+ * middle of writing a Pattern resource.
+ */
+ if (for_pattern < 0)
+ stream_puts(pdev->strm, "q ");
+ /*
+ * We don't have to worry about color space scaling: the color
+ * space is always a Device space.
+ */
+ pdf_image_writer_init(piw);
+ pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
+ if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
+ (code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs,
+ &piw->pin->color_spaces, in_line, NULL, 0, false)) < 0 ||
+ (for_pattern < 2 || nbytes < 512000 ?
+ (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
+ &piw->binary[0], (gs_pixel_image_t *)pim, false)) :
+ (code = psdf_setup_image_filters((gx_device_psdf *) pdev,
+ &piw->binary[0], (gs_pixel_image_t *)pim, NULL, NULL, false, false))
+ ) < 0 ||
+ (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
+ &cs_value, 0)) < 0
+ )
+ return code;
+ pdf_copy_color_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h,
+ bytes_per_pixel);
+ pdf_end_image_binary(pdev, piw, piw->height);
+ return pdf_end_write_image(pdev, piw);
+}
+
+int
+gdev_pdf_copy_color(gx_device * dev, const byte * base, int sourcex,
+ int raster, gx_bitmap_id id, int x, int y, int w, int h)
+{
+ gx_device_pdf *pdev = (gx_device_pdf *) dev;
+ gs_image_t image;
+ pdf_image_writer writer;
+ int code;
+
+ if (w <= 0 || h <= 0)
+ return 0;
+ code = pdf_open_page(pdev, PDF_IN_STREAM);
+ if (code < 0)
+ return code;
+ /* Make sure we aren't being clipped. */
+ code = pdf_put_clip_path(pdev, NULL);
+ if (code < 0)
+ return code;
+ code = pdf_copy_color_data(pdev, base, sourcex, raster, id, x, y, w, h,
+ &image, &writer, 0);
+ switch (code) {
+ default:
+ return code; /* error */
+ case 1:
+ return 0;
+ case 0:
+ return pdf_do_image(pdev, writer.pres, NULL, true);
+ }
+}
+
+/* Fill a mask. */
+int
+gdev_pdf_fill_mask(gx_device * dev,
+ const byte * data, int data_x, int raster, gx_bitmap_id id,
+ int x, int y, int width, int height,
+ const gx_drawing_color * pdcolor, int depth,
+ gs_logical_operation_t lop, const gx_clip_path * pcpath)
+{
+ gx_device_pdf *pdev = (gx_device_pdf *) dev;
+
+ if (width <= 0 || height <= 0)
+ return 0;
+ if (depth > 1 || (!gx_dc_is_pure(pdcolor) != 0 && !(gx_dc_is_pattern1_color(pdcolor))))
+ return gx_default_fill_mask(dev, data, data_x, raster, id,
+ x, y, width, height, pdcolor, depth, lop,
+ pcpath);
+ return pdf_copy_mono(pdev, data, data_x, raster, id, x, y, width, height,
+ gx_no_color_index, gx_dc_pure_color(pdcolor),
+ pcpath);
+}
+
+/* Tile with a bitmap. This is important for pattern fills. */
+int
+gdev_pdf_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
+ int x, int y, int w, int h,
+ gx_color_index color0, gx_color_index color1,
+ int px, int py)
+{
+ gx_device_pdf *const pdev = (gx_device_pdf *) dev;
+ int tw = tiles->rep_width, th = tiles->rep_height;
+ double xscale = pdev->HWResolution[0] / 72.0,
+ yscale = pdev->HWResolution[1] / 72.0;
+ bool mask;
+ int depth;
+ int (*copy_data)(gx_device_pdf *, const byte *, int, int,
+ gx_bitmap_id, int, int, int, int,
+ gs_image_t *, pdf_image_writer *, int);
+ pdf_resource_t *pres;
+ cos_value_t cs_value;
+ int code;
+
+ if (tiles->id == gx_no_bitmap_id || tiles->shift != 0 ||
+ (w < tw && h < th) ||
+ color0 != gx_no_color_index
+ )
+ goto use_default;
+ if (color1 != gx_no_color_index) {
+ /* This is a mask pattern. */
+ mask = true;
+ depth = 1;
+ copy_data = pdf_copy_mask_data;
+ code = pdf_cs_Pattern_uncolored(pdev, &cs_value);
+ } else {
+ /* This is a colored pattern. */
+ mask = false;
+ depth = pdev->color_info.depth;
+ copy_data = pdf_copy_color_data;
+ code = pdf_cs_Pattern_colored(pdev, &cs_value);
+ }
+ if (code < 0)
+ goto use_default;
+ pres = pdf_find_resource_by_gs_id(pdev, resourcePattern, tiles->id);
+ if (!pres) {
+ /* Create the Pattern resource. */
+ int code;
+ long image_id, length_id;
+ gs_offset_t start, end;
+ stream *s;
+ gs_image_t image;
+ pdf_image_writer writer;
+ long image_bytes = ((long)tw * depth + 7) / 8 * th;
+ bool in_line = image_bytes < pdev->MaxInlineImageSize;
+ ulong tile_id =
+ (tw == tiles->size.x && th == tiles->size.y ? tiles->id :
+ gx_no_bitmap_id);
+
+ if (in_line)
+ image_id = 0;
+ else if (image_bytes > 65500) {
+ /*
+ * Acrobat Reader can't handle image Patterns with more than
+ * 64K of data. :-(
+ */
+ goto use_default;
+ } else {
+ /* Write the image as an XObject resource now. */
+ code = copy_data(pdev, tiles->data, 0, tiles->raster,
+ tile_id, 0, 0, tw, th, &image, &writer, 1);
+ if (code < 0)
+ goto use_default;
+ image_id = pdf_resource_id(writer.pres);
+ }
+ code = pdf_begin_resource(pdev, resourcePattern, tiles->id, &pres);
+ if (code < 0)
+ goto use_default;
+ s = pdev->strm;
+ pprintd1(s, "/PatternType 1/PaintType %d/TilingType 1/Resources<<\n",
+ (mask ? 2 : 1));
+ if (image_id)
+ pprintld2(s, "/XObject<</R%ld %ld 0 R>>", image_id, image_id);
+ pprints1(s, "/ProcSet[/PDF/Image%s]>>\n", (mask ? "B" : "C"));
+ /*
+ * Because of bugs in Acrobat Reader's Print function, we can't use
+ * the natural BBox and Step here: they have to be 1.
+ */
+ pprintg2(s, "/Matrix[%g 0 0 %g 0 0]", tw / xscale, th / yscale);
+ stream_puts(s, "/BBox[0 0 1 1]/XStep 1/YStep 1/Length ");
+ if (image_id) {
+ char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */
+
+ gs_sprintf(buf, "/R%ld Do\n", image_id);
+ pprintd1(s, "%d>>stream\n", strlen(buf));
+ if (pdev->PDFA != 0)
+ pprints1(s, "%s\nendstream\n", buf);
+ else
+ pprints1(s, "%sendstream\n", buf);
+ pdf_end_resource(pdev, resourcePattern);
+ } else {
+ length_id = pdf_obj_ref(pdev);
+ pprintld1(s, "%ld 0 R>>stream\n", length_id);
+ start = pdf_stell(pdev);
+ code = copy_data(pdev, tiles->data, 0, tiles->raster,
+ tile_id, 0, 0, tw, th, &image, &writer, -1);
+ switch (code) {
+ default:
+ return code; /* error */
+ case 1:
+ break;
+ case 0: /* not possible */
+ return_error(gs_error_Fatal);
+ }
+ end = pdf_stell(pdev);
+ stream_puts(s, "\nendstream\n");
+ pdf_end_resource(pdev, resourcePattern);
+ pdf_open_separate(pdev, length_id, resourceNone);
+ pprintld1(pdev->strm, "%ld\n", end - start);
+ pdf_end_separate(pdev, resourceNone);
+ }
+ pres->object->written = true; /* don't write at end of page */
+ }
+ /* Fill the rectangle with the Pattern. */
+ {
+ int code = pdf_open_page(pdev, PDF_IN_STREAM);
+ stream *s;
+
+ if (code < 0)
+ goto use_default;
+ /* Make sure we aren't being clipped. */
+ code = pdf_put_clip_path(pdev, NULL);
+ if (code < 0)
+ return code;
+ s = pdev->strm;
+ /*
+ * Because of bugs in Acrobat Reader's Print function, we can't
+ * leave the CTM alone here: we have to reset it to the default.
+ */
+ pprintg2(s, "q %g 0 0 %g 0 0 cm\n", xscale, yscale);
+ cos_value_write(&cs_value, pdev);
+ stream_puts(s, " cs");
+ if (mask)
+ pprintg3(s, " %g %g %g", (int)(color1 >> 16) / 255.0,
+ (int)((color1 >> 8) & 0xff) / 255.0,
+ (int)(color1 & 0xff) / 255.0);
+ pprintld1(s, "/R%ld scn", pdf_resource_id(pres));
+ pprintg4(s, " %g %g %g %g re f Q\n",
+ x / xscale, y / yscale, w / xscale, h / xscale);
+ }
+ return 0;
+use_default:
+ return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
+ color0, color1, px, py);
+}