xref: /plan9/sys/src/cmd/gs/src/gdevpdfb.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
1 /* Copyright (C) 2000 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: gdevpdfb.c,v 1.34 2005/10/10 19:09:30 leonardo Exp $ */
18 /* Low-level bitmap image handling for PDF-writing driver */
19 #include "string_.h"
20 #include "gx.h"
21 #include "gserrors.h"
22 #include "gdevpdfx.h"
23 #include "gdevpdfg.h"
24 #include "gdevpdfo.h"		/* for data stream */
25 #include "gxcspace.h"
26 #include "gxdcolor.h"
27 #include "gxpcolor.h"
28 #include "gxhldevc.h"
29 
30 /* We need this color space type for constructing temporary color spaces. */
31 extern const gs_color_space_type gs_color_space_type_Indexed;
32 
33 /* ---------------- Utilities ---------------- */
34 
35 /* Fill in the image parameters for a bitmap image. */
36 private void
pdf_make_bitmap_image(gs_image_t * pim,int x,int y,int w,int h)37 pdf_make_bitmap_image(gs_image_t * pim, int x, int y, int w, int h)
38 {
39     pim->Width = w;
40     pim->Height = h;
41     pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h, h);
42 }
43 
44 /* ---------------- Driver procedures ---------------- */
45 
46 /* Copy a mask bitmap.  for_pattern = -1 means put the image in-line, */
47 /* 1 means put the image in a resource. */
48 private 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)49 pdf_copy_mask_data(gx_device_pdf * pdev, const byte * base, int sourcex,
50 		   int raster, gx_bitmap_id id, int x, int y, int w, int h,
51 		   gs_image_t *pim, pdf_image_writer *piw,
52 		   int for_pattern)
53 {
54     ulong nbytes;
55     int code;
56     const byte *row_base;
57     int row_step;
58     bool in_line;
59 
60     gs_image_t_init_mask(pim, true);
61     pdf_make_bitmap_image(pim, x, y, w, h);
62     nbytes = ((ulong)w * h + 7) / 8;
63 
64     if (for_pattern) {
65 	/*
66 	 * Patterns must be emitted in order of increasing user Y, i.e.,
67 	 * the opposite of PDF's standard image order.
68 	 */
69 	row_base = base + (h - 1) * raster;
70 	row_step = -raster;
71 	in_line = for_pattern < 0;
72     } else {
73 	row_base = base;
74 	row_step = raster;
75 	in_line = nbytes < pdev->MaxInlineImageSize;
76 	pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
77 	/*
78 	 * Check whether we've already made an XObject resource for this
79 	 * image.
80 	 */
81 	if (id != gx_no_bitmap_id) {
82 	    piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
83 	    if (piw->pres)
84 		return 0;
85 	}
86     }
87     /*
88      * We have to be able to control whether to put Pattern images in line,
89      * to avoid trying to create an XObject resource while we're in the
90      * middle of writing a Pattern resource.
91      */
92     if (for_pattern < 0)
93 	stream_puts(pdev->strm, "q ");
94     pdf_image_writer_init(piw);
95     if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
96 	(code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
97 					    &piw->binary[0],
98 					    (gs_pixel_image_t *)pim)) < 0 ||
99 	(code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
100 				     NULL, 0)) < 0
101 	)
102 	return code;
103     pdf_copy_mask_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h, 0);
104     pdf_end_image_binary(pdev, piw, piw->height);
105     return pdf_end_write_image(pdev, piw);
106 }
107 
108 private void
set_image_color(gx_device_pdf * pdev,gx_color_index c)109 set_image_color(gx_device_pdf *pdev, gx_color_index c)
110 {
111     pdf_set_pure_color(pdev, c, &pdev->saved_fill_color,
112 			&pdev->fill_used_process_color,
113 			&psdf_set_fill_color_commands);
114     if (!pdev->HaveStrokeColor)
115 	pdf_set_pure_color(pdev, c, &pdev->saved_stroke_color,
116 			    &pdev->stroke_used_process_color,
117 			    &psdf_set_stroke_color_commands);
118 }
119 
120 /* Copy a monochrome bitmap or mask. */
121 private 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)122 pdf_copy_mono(gx_device_pdf *pdev,
123 	      const byte *base, int sourcex, int raster, gx_bitmap_id id,
124 	      int x, int y, int w, int h, gx_color_index zero,
125 	      gx_color_index one, const gx_clip_path *pcpath)
126 {
127     int code;
128     gs_color_space cs;
129     cos_value_t cs_value;
130     cos_value_t *pcsvalue;
131     byte palette[arch_sizeof_color_index * 2];
132     gs_image_t image;
133     pdf_image_writer writer;
134     pdf_stream_position_t ipos;
135     pdf_resource_t *pres = 0;
136     byte invert = 0;
137     bool in_line = false;
138 
139     /* Update clipping. */
140     if (pdf_must_put_clip_path(pdev, pcpath)) {
141 	code = pdf_open_page(pdev, PDF_IN_STREAM);
142 	if (code < 0)
143 	    return code;
144 	code = pdf_put_clip_path(pdev, pcpath);
145 	if (code < 0)
146 	    return code;
147     }
148     /* We have 3 cases: mask, inverse mask, and solid. */
149     if (zero == gx_no_color_index) {
150 	if (one == gx_no_color_index)
151 	    return 0;
152 	/* If a mask has an id, assume it's a character. */
153 	if (id != gx_no_bitmap_id && sourcex == 0) {
154 	    pres = pdf_find_resource_by_gs_id(pdev, resourceCharProc, id);
155 	    if (pres == 0) {	/* Define the character in an embedded font. */
156 		pdf_char_proc_t *pcp;
157 		double x_offset;
158 		int y_offset;
159 
160 		gs_image_t_init_mask(&image, false);
161 		invert = 0xff;
162 		pdf_make_bitmap_image(&image, x, y, w, h);
163 		y_offset = pdf_char_image_y_offset(pdev, x, y, h);
164 		/*
165 		 * The Y axis of the text matrix is inverted,
166 		 * so we need to negate the Y offset appropriately.
167 		 */
168 		code = pdf_begin_char_proc(pdev, w, h, 0, y_offset, id,
169 					   &pcp, &ipos);
170 		if (code < 0)
171 		    return code;
172 		y_offset = -y_offset;
173 		x_offset = psdf_round(pdev->char_width.x, 100, 10); /* See
174 			pdf_write_Widths about rounding. We need to provide
175 			a compatible data for Tj. */
176 		pprintg1(pdev->strm, "%g ", x_offset);
177 		pprintd3(pdev->strm, "0 0 %d %d %d d1\n", y_offset, w, h + y_offset);
178 		pprintd3(pdev->strm, "%d 0 0 %d 0 %d cm\n", w, h,
179 			 y_offset);
180 		pdf_image_writer_init(&writer);
181 		code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, true);
182 		if (code < 0)
183 		    return code;
184 		pres = (pdf_resource_t *) pcp;
185 		goto wr;
186 	    } else if (pdev->pte) {
187 		/* We're under pdf_text_process. It set a high level color. */
188 	    } else
189 		set_image_color(pdev, one);
190 	    pdf_make_bitmap_matrix(&image.ImageMatrix, x, y, w, h, h);
191 	    goto rx;
192 	}
193 	set_image_color(pdev, one);
194 	gs_image_t_init_mask(&image, false);
195 	invert = 0xff;
196     } else if (one == gx_no_color_index) {
197 	gs_image_t_init_mask(&image, false);
198 	set_image_color(pdev, zero);
199     } else if (zero == pdev->black && one == pdev->white) {
200 	gs_cspace_init_DeviceGray(pdev->memory, &cs);
201 	gs_image_t_init(&image, &cs);
202     } else if (zero == pdev->white && one == pdev->black) {
203 	gs_cspace_init_DeviceGray(pdev->memory, &cs);
204 	gs_image_t_init(&image, &cs);
205 	invert = 0xff;
206     } else {
207 	/*
208 	 * We think this code is never executed when interpreting PostScript
209 	 * or PDF: the library never uses monobit non-mask images
210 	 * internally, and high-level images don't go through this code.
211 	 * However, we still want the code to work.
212 	 */
213 	gs_color_space cs_base;
214 	gx_color_index c[2];
215 	int i, j;
216 	int ncomp = pdev->color_info.num_components;
217 	byte *p;
218 
219 	code = pdf_cspace_init_Device(pdev->memory, &cs_base, ncomp);
220 	if (code < 0)
221 	    return code;
222 	c[0] = psdf_adjust_color_index((gx_device_vector *)pdev, zero);
223 	c[1] = psdf_adjust_color_index((gx_device_vector *)pdev, one);
224 	gs_cspace_init(&cs, &gs_color_space_type_Indexed, pdev->memory, false);
225 	cs.params.indexed.base_space = *(gs_direct_color_space *)&cs_base;
226 	cs.params.indexed.hival = 1;
227 	p = palette;
228 	for (i = 0; i < 2; ++i)
229 	    for (j = ncomp - 1; j >= 0; --j)
230 		*p++ = (byte)(c[i] >> (j * 8));
231 	cs.params.indexed.lookup.table.data = palette;
232 	cs.params.indexed.lookup.table.size = p - palette;
233 	cs.params.indexed.use_proc = false;
234 	gs_image_t_init(&image, &cs);
235 	image.BitsPerComponent = 1;
236     }
237     pdf_make_bitmap_image(&image, x, y, w, h);
238     {
239 	ulong nbytes = (ulong) ((w + 7) >> 3) * h;
240 
241 	in_line = nbytes < pdev->MaxInlineImageSize;
242 	if (in_line)
243 	    pdf_put_image_matrix(pdev, &image.ImageMatrix, 1.0);
244 	code = pdf_open_page(pdev, PDF_IN_STREAM);
245 	if (code < 0)
246 	    return code;
247 	pdf_image_writer_init(&writer);
248 	code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, in_line);
249 	if (code < 0)
250 	    return code;
251     }
252   wr:
253     if (image.ImageMask)
254 	pcsvalue = NULL;
255     else {
256 	/*
257 	 * We don't have to worry about color space scaling: the color
258 	 * space is always a Device space.
259 	 */
260 	code = pdf_color_space(pdev, &cs_value, NULL, &cs,
261 			       &writer.pin->color_spaces, in_line);
262 	if (code < 0)
263 	    return code;
264 	pcsvalue = &cs_value;
265     }
266     /*
267      * There are 3 different cases at this point:
268      *      - Writing an in-line image (pres == 0, writer.pres == 0);
269      *      - Writing an XObject image (pres == 0, writer.pres != 0);
270      *      - Writing the image for a CharProc (pres != 0).
271      * We handle them with in-line code followed by a switch,
272      * rather than making the shared code into a procedure,
273      * simply because there would be an awful lot of parameters
274      * that would need to be passed.
275      */
276     if (pres) {
277 	/*
278 	 * Always use CCITTFax 2-D for character bitmaps.  It takes less
279 	 * space to invert the data with Decode than to set BlackIs1.
280 	 */
281 	float d0 = image.Decode[0];
282 
283 	image.Decode[0] = image.Decode[1];
284 	image.Decode[1] = d0;
285 	psdf_CFE_binary(&writer.binary[0], image.Width, image.Height, true);
286 	invert ^= 0xff;
287     } else {
288 	/* Use the Distiller compression parameters. */
289 	psdf_setup_image_filters((gx_device_psdf *) pdev, &writer.binary[0],
290 				 (gs_pixel_image_t *)&image, NULL, NULL, true);
291     }
292     pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image,
293 			 pcsvalue, 0);
294     code = pdf_copy_mask_bits(writer.binary[0].strm, base, sourcex, raster,
295 			      w, h, invert);
296     if (code < 0)
297 	return code;
298     pdf_end_image_binary(pdev, &writer, writer.height);
299     if (!pres) {
300 	switch ((code = pdf_end_write_image(pdev, &writer))) {
301 	    default:		/* error */
302 		return code;
303 	    case 1:
304 		return 0;
305 	    case 0:
306 		return pdf_do_image(pdev, writer.pres, &image.ImageMatrix,
307 				    true);
308 	}
309     }
310     writer.end_string = "";	/* no Q */
311     switch ((code = pdf_end_write_image(pdev, &writer))) {
312     default:		/* error */
313 	return code;
314     case 0:			/* not possible */
315 	return_error(gs_error_Fatal);
316     case 1:
317 	break;
318     }
319     code = pdf_end_char_proc(pdev, &ipos);
320     if (code < 0)
321 	return code;
322   rx:{
323 	gs_matrix imat;
324 
325 	imat = image.ImageMatrix;
326 	imat.xx /= w;
327 	imat.xy /= h;
328 	imat.yx /= w;
329 	imat.yy /= h;
330 	return pdf_do_char_image(pdev, (const pdf_char_proc_t *)pres, &imat);
331     }
332 }
333 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)334 gdev_pdf_copy_mono(gx_device * dev,
335 		   const byte * base, int sourcex, int raster, gx_bitmap_id id,
336 		   int x, int y, int w, int h, gx_color_index zero,
337 		   gx_color_index one)
338 {
339     gx_device_pdf *pdev = (gx_device_pdf *) dev;
340 
341     if (w <= 0 || h <= 0)
342 	return 0;
343     return pdf_copy_mono(pdev, base, sourcex, raster, id, x, y, w, h,
344 			 zero, one, NULL);
345 }
346 
347 /* Copy a color bitmap.  for_pattern = -1 means put the image in-line, */
348 /* 1 means put the image in a resource, 2 means image is a rasterized shading. */
349 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)350 pdf_copy_color_data(gx_device_pdf * pdev, const byte * base, int sourcex,
351 		    int raster, gx_bitmap_id id, int x, int y, int w, int h,
352 		    gs_image_t *pim, pdf_image_writer *piw,
353 		    int for_pattern)
354 {
355     int depth = pdev->color_info.depth;
356     int bytes_per_pixel = depth >> 3;
357     gs_color_space cs;
358     cos_value_t cs_value;
359     ulong nbytes;
360     int code = pdf_cspace_init_Device(pdev->memory, &cs, bytes_per_pixel);
361     const byte *row_base;
362     int row_step;
363     bool in_line;
364 
365     if (code < 0)
366 	return code;		/* can't happen */
367     gs_image_t_init(pim, &cs);
368     pdf_make_bitmap_image(pim, x, y, w, h);
369     pim->BitsPerComponent = 8;
370     nbytes = (ulong)w * bytes_per_pixel * h;
371 
372     if (for_pattern == 1) {
373 	/*
374 	 * Patterns must be emitted in order of increasing user Y, i.e.,
375 	 * the opposite of PDF's standard image order.
376 	 */
377 	row_base = base + (h - 1) * raster;
378 	row_step = -raster;
379 	in_line = for_pattern < 0;
380     } else {
381 	row_base = base;
382 	row_step = raster;
383 	in_line = nbytes < pdev->MaxInlineImageSize;
384 	pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
385 	/*
386 	 * Check whether we've already made an XObject resource for this
387 	 * image.
388 	 */
389 	if (id != gx_no_bitmap_id) {
390 	    piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
391 	    if (piw->pres)
392 		return 0;
393 	}
394     }
395     /*
396      * We have to be able to control whether to put Pattern images in line,
397      * to avoid trying to create an XObject resource while we're in the
398      * middle of writing a Pattern resource.
399      */
400     if (for_pattern < 0)
401 	stream_puts(pdev->strm, "q ");
402     /*
403      * We don't have to worry about color space scaling: the color
404      * space is always a Device space.
405      */
406     pdf_image_writer_init(piw);
407     if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
408 	(code = pdf_color_space(pdev, &cs_value, NULL, &cs,
409 				&piw->pin->color_spaces, in_line)) < 0 ||
410 	(for_pattern < 2 || nbytes < 512000 ?
411 	    (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
412 			&piw->binary[0], (gs_pixel_image_t *)pim)) :
413 	    (code = psdf_setup_image_filters((gx_device_psdf *) pdev,
414 			&piw->binary[0], (gs_pixel_image_t *)pim, NULL, NULL, false))
415 	) < 0 ||
416 	(code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
417 				     &cs_value, 0)) < 0
418 	)
419 	return code;
420     pdf_copy_color_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h,
421 			bytes_per_pixel);
422     pdf_end_image_binary(pdev, piw, piw->height);
423     return pdf_end_write_image(pdev, piw);
424 }
425 
426 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)427 gdev_pdf_copy_color(gx_device * dev, const byte * base, int sourcex,
428 		    int raster, gx_bitmap_id id, int x, int y, int w, int h)
429 {
430     gx_device_pdf *pdev = (gx_device_pdf *) dev;
431     gs_image_t image;
432     pdf_image_writer writer;
433     int code;
434 
435     if (w <= 0 || h <= 0)
436 	return 0;
437     code = pdf_open_page(pdev, PDF_IN_STREAM);
438     if (code < 0)
439 	return code;
440     /* Make sure we aren't being clipped. */
441     code = pdf_put_clip_path(pdev, NULL);
442     if (code < 0)
443 	return code;
444     code = pdf_copy_color_data(pdev, base, sourcex, raster, id, x, y, w, h,
445 			       &image, &writer, 0);
446     switch (code) {
447 	default:
448 	    return code;	/* error */
449 	case 1:
450 	    return 0;
451 	case 0:
452 	    return pdf_do_image(pdev, writer.pres, NULL, true);
453     }
454 }
455 
456 /* Fill a mask. */
457 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)458 gdev_pdf_fill_mask(gx_device * dev,
459 		 const byte * data, int data_x, int raster, gx_bitmap_id id,
460 		   int x, int y, int width, int height,
461 		   const gx_drawing_color * pdcolor, int depth,
462 		   gs_logical_operation_t lop, const gx_clip_path * pcpath)
463 {
464     gx_device_pdf *pdev = (gx_device_pdf *) dev;
465 
466     if (width <= 0 || height <= 0)
467 	return 0;
468     if (depth > 1 || (!gx_dc_is_pure(pdcolor) != 0 && pdcolor->type != &gx_dc_pattern))
469 	return gx_default_fill_mask(dev, data, data_x, raster, id,
470 				    x, y, width, height, pdcolor, depth, lop,
471 				    pcpath);
472     return pdf_copy_mono(pdev, data, data_x, raster, id, x, y, width, height,
473 			 gx_no_color_index, gx_dc_pure_color(pdcolor),
474 			 pcpath);
475 }
476 
477 /* Tile with a bitmap.  This is important for pattern fills. */
478 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)479 gdev_pdf_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
480 			      int x, int y, int w, int h,
481 			      gx_color_index color0, gx_color_index color1,
482 			      int px, int py)
483 {
484     gx_device_pdf *const pdev = (gx_device_pdf *) dev;
485     int tw = tiles->rep_width, th = tiles->rep_height;
486     double xscale = pdev->HWResolution[0] / 72.0,
487 	yscale = pdev->HWResolution[1] / 72.0;
488     bool mask;
489     int depth;
490     int (*copy_data)(gx_device_pdf *, const byte *, int, int,
491 		     gx_bitmap_id, int, int, int, int,
492 		     gs_image_t *, pdf_image_writer *, int);
493     pdf_resource_t *pres;
494     cos_value_t cs_value;
495     int code;
496 
497     if (tiles->id == gx_no_bitmap_id || tiles->shift != 0 ||
498 	(w < tw && h < th) ||
499 	color0 != gx_no_color_index
500 	)
501 	goto use_default;
502     if (color1 != gx_no_color_index) {
503 	/* This is a mask pattern. */
504 	mask = true;
505 	depth = 1;
506 	copy_data = pdf_copy_mask_data;
507 	code = pdf_cs_Pattern_uncolored(pdev, &cs_value);
508     } else {
509 	/* This is a colored pattern. */
510 	mask = false;
511 	depth = pdev->color_info.depth;
512 	copy_data = pdf_copy_color_data;
513 	code = pdf_cs_Pattern_colored(pdev, &cs_value);
514     }
515     if (code < 0)
516 	goto use_default;
517     pres = pdf_find_resource_by_gs_id(pdev, resourcePattern, tiles->id);
518     if (!pres) {
519 	/* Create the Pattern resource. */
520 	int code;
521 	long image_id, length_id, start, end;
522 	stream *s;
523 	gs_image_t image;
524 	pdf_image_writer writer;
525 	long image_bytes = ((long)tw * depth + 7) / 8 * th;
526 	bool in_line = image_bytes < pdev->MaxInlineImageSize;
527 	ulong tile_id =
528 	    (tw == tiles->size.x && th == tiles->size.y ? tiles->id :
529 	     gx_no_bitmap_id);
530 
531 	if (in_line)
532 	    image_id = 0;
533 	else if (image_bytes > 65500) {
534 	    /*
535 	     * Acrobat Reader can't handle image Patterns with more than
536 	     * 64K of data.  :-(
537 	     */
538 	    goto use_default;
539 	} else {
540 	    /* Write the image as an XObject resource now. */
541 	    code = copy_data(pdev, tiles->data, 0, tiles->raster,
542 			     tile_id, 0, 0, tw, th, &image, &writer, 1);
543 	    if (code < 0)
544 		goto use_default;
545 	    image_id = pdf_resource_id(writer.pres);
546 	}
547 	code = pdf_begin_resource(pdev, resourcePattern, tiles->id, &pres);
548 	if (code < 0)
549 	    goto use_default;
550 	s = pdev->strm;
551 	pprintd1(s, "/PatternType 1/PaintType %d/TilingType 1/Resources<<\n",
552 		 (mask ? 2 : 1));
553 	if (image_id)
554 	    pprintld2(s, "/XObject<</R%ld %ld 0 R>>", image_id, image_id);
555 	pprints1(s, "/ProcSet[/PDF/Image%s]>>\n", (mask ? "B" : "C"));
556 	/*
557 	 * Because of bugs in Acrobat Reader's Print function, we can't use
558 	 * the natural BBox and Step here: they have to be 1.
559 	 */
560 	pprintg2(s, "/Matrix[%g 0 0 %g 0 0]", tw / xscale, th / yscale);
561 	stream_puts(s, "/BBox[0 0 1 1]/XStep 1/YStep 1/Length ");
562 	if (image_id) {
563 	    char buf[MAX_REF_CHARS + 6 + 1]; /* +6 for /R# Do\n */
564 
565 	    sprintf(buf, "/R%ld Do\n", image_id);
566 	    pprintd1(s, "%d>>stream\n", strlen(buf));
567 	    pprints1(s, "%sendstream\n", buf);
568 	    pdf_end_resource(pdev);
569 	} else {
570 	    length_id = pdf_obj_ref(pdev);
571 	    pprintld1(s, "%ld 0 R>>stream\n", length_id);
572 	    start = pdf_stell(pdev);
573 	    code = copy_data(pdev, tiles->data, 0, tiles->raster,
574 			     tile_id, 0, 0, tw, th, &image, &writer, -1);
575 	    switch (code) {
576 	    default:
577 		return code;	/* error */
578 	    case 1:
579 		break;
580 	    case 0:			/* not possible */
581 		return_error(gs_error_Fatal);
582 	    }
583 	    end = pdf_stell(pdev);
584 	    stream_puts(s, "\nendstream\n");
585 	    pdf_end_resource(pdev);
586 	    pdf_open_separate(pdev, length_id);
587 	    pprintld1(pdev->strm, "%ld\n", end - start);
588 	    pdf_end_separate(pdev);
589 	}
590 	pres->object->written = true; /* don't write at end of page */
591     }
592     /* Fill the rectangle with the Pattern. */
593     {
594 	int code = pdf_open_page(pdev, PDF_IN_STREAM);
595 	stream *s;
596 
597 	if (code < 0)
598 	    goto use_default;
599 	/* Make sure we aren't being clipped. */
600 	code = pdf_put_clip_path(pdev, NULL);
601 	if (code < 0)
602 	    return code;
603 	s = pdev->strm;
604 	/*
605 	 * Because of bugs in Acrobat Reader's Print function, we can't
606 	 * leave the CTM alone here: we have to reset it to the default.
607 	 */
608 	pprintg2(s, "q %g 0 0 %g 0 0 cm\n", xscale, yscale);
609 	cos_value_write(&cs_value, pdev);
610 	stream_puts(s, " cs");
611 	if (mask)
612 	    pprintg3(s, " %g %g %g", (int)(color1 >> 16) / 255.0,
613 		     (int)((color1 >> 8) & 0xff) / 255.0,
614 		     (int)(color1 & 0xff) / 255.0);
615 	pprintld1(s, "/R%ld scn", pdf_resource_id(pres));
616 	pprintg4(s, " %g %g %g %g re f Q\n",
617 		 x / xscale, y / yscale, w / xscale, h / xscale);
618     }
619     return 0;
620 use_default:
621     return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
622 					   color0, color1, px, py);
623 }
624