1 /* Copyright (C) 1996, 2000 artofcode LLC.  All rights reserved.
2 
3   This program is free software; you can redistribute it and/or modify it
4   under the terms of the GNU General Public License as published by the
5   Free Software Foundation; either version 2 of the License, or (at your
6   option) any later version.
7 
8   This program is distributed in the hope that it will be useful, but
9   WITHOUT ANY WARRANTY; without even the implied warranty of
10   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11   General Public License for more details.
12 
13   You should have received a copy of the GNU General Public License along
14   with this program; if not, write to the Free Software Foundation, Inc.,
15   59 Temple Place, Suite 330, Boston, MA, 02111-1307.
16 
17 */
18 
19 /*$Id: gdevpdfi.c,v 1.24.2.1.2.1 2003/01/17 00:49:01 giles Exp $ */
20 /* Image handling for PDF-writing driver */
21 #include "gx.h"
22 #include "gserrors.h"
23 #include "gsdevice.h"
24 #include "gsflip.h"
25 #include "gdevpdfx.h"
26 #include "gdevpdfg.h"
27 #include "gdevpdfo.h"		/* for data stream */
28 #include "gxcspace.h"
29 #include "gximage3.h"
30 #include "gximag3x.h"
31 #include "gsiparm4.h"
32 
33 /* Forward references */
34 private image_enum_proc_plane_data(pdf_image_plane_data);
35 private image_enum_proc_end_image(pdf_image_end_image);
36 private image_enum_proc_end_image(pdf_image_end_image_object);
37 private IMAGE3_MAKE_MID_PROC(pdf_image3_make_mid);
38 private IMAGE3_MAKE_MCDE_PROC(pdf_image3_make_mcde);
39 private IMAGE3X_MAKE_MID_PROC(pdf_image3x_make_mid);
40 private IMAGE3X_MAKE_MCDE_PROC(pdf_image3x_make_mcde);
41 
42 private const gx_image_enum_procs_t pdf_image_enum_procs = {
43     pdf_image_plane_data,
44     pdf_image_end_image
45 };
46 private const gx_image_enum_procs_t pdf_image_object_enum_procs = {
47     pdf_image_plane_data,
48     pdf_image_end_image_object
49 };
50 
51 /* ---------------- Driver procedures ---------------- */
52 
53 /* Define the structure for keeping track of progress through an image. */
54 typedef struct pdf_image_enum_s {
55     gx_image_enum_common;
56     gs_memory_t *memory;
57     int width;
58     int bits_per_pixel;		/* bits per pixel (per plane) */
59     int rows_left;
60     pdf_image_writer writer;
61     gs_matrix mat;
62 } pdf_image_enum;
63 gs_private_st_composite(st_pdf_image_enum, pdf_image_enum, "pdf_image_enum",
64   pdf_image_enum_enum_ptrs, pdf_image_enum_reloc_ptrs);
65 /* GC procedures */
66 private ENUM_PTRS_WITH(pdf_image_enum_enum_ptrs, pdf_image_enum *pie)
67     if (index < pdf_image_writer_max_ptrs) {
68 	gs_ptr_type_t ret =
69 	    ENUM_USING(st_pdf_image_writer, &pie->writer, sizeof(pie->writer),
70 		       index);
71 
72 	if (ret == 0)		/* don't stop early */
73 	    ENUM_RETURN(0);
74 	return ret;
75     }
76     return ENUM_USING_PREFIX(st_gx_image_enum_common,
77 			     pdf_image_writer_max_ptrs);
78 ENUM_PTRS_END
RELOC_PTRS_WITH(pdf_image_enum_reloc_ptrs,pdf_image_enum * pie)79 private RELOC_PTRS_WITH(pdf_image_enum_reloc_ptrs, pdf_image_enum *pie)
80 {
81     RELOC_USING(st_pdf_image_writer, &pie->writer, sizeof(pie->writer));
82     RELOC_USING(st_gx_image_enum_common, vptr, size);
83 }
84 RELOC_PTRS_END
85 
86 /*
87  * Test whether we can write an image in-line.  Before PDF 1.2, this is only
88  * allowed for masks, images in built-in color spaces, and images in Indexed
89  * color spaces based on these with a string lookup table.
90  */
91 private bool
can_write_image_in_line(const gx_device_pdf * pdev,const gs_image_t * pim)92 can_write_image_in_line(const gx_device_pdf *pdev, const gs_image_t *pim)
93 {
94     const gs_color_space *pcs;
95 
96     if (pim->ImageMask)
97 	return true;
98     if (pdev->CompatibilityLevel >= 1.2)
99 	return true;
100     pcs = pim->ColorSpace;
101  cs:
102     switch (gs_color_space_get_index(pcs)) {
103     case gs_color_space_index_DeviceGray:
104     case gs_color_space_index_DeviceRGB:
105     case gs_color_space_index_DeviceCMYK:
106 	return true;
107     case gs_color_space_index_Indexed:
108 	if (pcs->params.indexed.use_proc)
109 	    return false;
110 	pcs = (const gs_color_space *)&pcs->params.indexed.base_space;
111 	goto cs;
112     default:
113 	return false;
114     }
115 }
116 
117 /*
118  * Start processing an image.  This procedure takes extra arguments because
119  * it has to do something slightly different for the parts of an ImageType 3
120  * image.
121  */
122 typedef enum {
123     PDF_IMAGE_DEFAULT,
124     PDF_IMAGE_TYPE3_MASK,	/* no in-line, don't render */
125     PDF_IMAGE_TYPE3_DATA	/* no in-line */
126 } pdf_typed_image_context_t;
127 private int
pdf_begin_typed_image(gx_device_pdf * pdev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo,pdf_typed_image_context_t context)128 pdf_begin_typed_image(gx_device_pdf *pdev, const gs_imager_state * pis,
129 		      const gs_matrix *pmat, const gs_image_common_t *pic,
130 		      const gs_int_rect * prect,
131 		      const gx_drawing_color * pdcolor,
132 		      const gx_clip_path * pcpath, gs_memory_t * mem,
133 		      gx_image_enum_common_t ** pinfo,
134 		      pdf_typed_image_context_t context)
135 {
136     const gs_pixel_image_t *pim;
137     int code;
138     pdf_image_enum *pie;
139     gs_image_format_t format;
140     const gs_color_space *pcs;
141     gs_color_space cs_gray_temp;
142     cos_value_t cs_value;
143     int num_components;
144     bool is_mask = false, in_line = false;
145     gs_int_rect rect;
146     /*
147      * We define this union because psdf_setup_image_filters may alter the
148      * gs_pixel_image_t part, but pdf_begin_image_data must also have access
149      * to the type-specific parameters.
150      */
151     union iu_ {
152 	gs_pixel_image_t pixel;	/* we may change some components */
153 	gs_image1_t type1;
154 	gs_image3_t type3;
155 	gs_image3x_t type3x;
156 	gs_image4_t type4;
157     } image;
158     ulong nbytes;
159     int width, height;
160 
161     /* Check for the image types we can handle. */
162     switch (pic->type->index) {
163     case 1: {
164 	const gs_image_t *pim1 = (const gs_image_t *)pic;
165 
166 	if (pim1->Alpha != gs_image_alpha_none)
167 	    goto nyi;
168 	is_mask = pim1->ImageMask;
169 	in_line = context == PDF_IMAGE_DEFAULT &&
170 	    can_write_image_in_line(pdev, pim1);
171 	image.type1 = *pim1;
172 	break;
173     }
174     case 3: {
175 	const gs_image3_t *pim3 = (const gs_image3_t *)pic;
176 
177 	if (pdev->CompatibilityLevel < 1.3)
178 	    goto nyi;
179 	if (prect && !(prect->p.x == 0 && prect->p.y == 0 &&
180 		       prect->q.x == pim3->Width &&
181 		       prect->q.y == pim3->Height))
182 	    goto nyi;
183 	/*
184 	 * We handle ImageType 3 images in a completely different way:
185 	 * the default implementation sets up the enumerator.
186 	 */
187 	return gx_begin_image3_generic((gx_device *)pdev, pis, pmat, pic,
188 				       prect, pdcolor, pcpath, mem,
189 				       pdf_image3_make_mid,
190 				       pdf_image3_make_mcde, pinfo);
191     }
192     case IMAGE3X_IMAGETYPE: {
193 	/* See ImageType3 above for more information. */
194 	const gs_image3x_t *pim3x = (const gs_image3x_t *)pic;
195 
196 	if (pdev->CompatibilityLevel < 1.4)
197 	    goto nyi;
198 	if (prect && !(prect->p.x == 0 && prect->p.y == 0 &&
199 		       prect->q.x == pim3x->Width &&
200 		       prect->q.y == pim3x->Height))
201 	    goto nyi;
202 	return gx_begin_image3x_generic((gx_device *)pdev, pis, pmat, pic,
203 					prect, pdcolor, pcpath, mem,
204 					pdf_image3x_make_mid,
205 					pdf_image3x_make_mcde, pinfo);
206     }
207     case 4:
208 	if (pdev->CompatibilityLevel < 1.3)
209 	    goto nyi;
210 	image.type4 = *(const gs_image4_t *)pic;
211 	break;
212     default:
213 	goto nyi;
214     }
215     pim = (const gs_pixel_image_t *)pic;
216     format = pim->format;
217     switch (format) {
218     case gs_image_format_chunky:
219     case gs_image_format_component_planar:
220 	break;
221     default:
222 	goto nyi;
223     }
224     pcs = pim->ColorSpace;
225     num_components = (is_mask ? 1 : gs_color_space_num_components(pcs));
226 
227     code = pdf_open_page(pdev, PDF_IN_STREAM);
228     if (code < 0)
229 	return code;
230     pdf_put_clip_path(pdev, pcpath);
231     if (context == PDF_IMAGE_TYPE3_MASK) {
232 	/*
233 	 * The soft mask for an ImageType 3x image uses a DevicePixel
234 	 * color space, which pdf_color_space() can't handle.  Patch it
235 	 * to DeviceGray here.
236 	 */
237 	gs_cspace_init_DeviceGray(&cs_gray_temp);
238 	pcs = &cs_gray_temp;
239     } else if (is_mask)
240 	code = pdf_prepare_imagemask(pdev, pis, pdcolor);
241     else
242 	code = pdf_prepare_image(pdev, pis);
243     if (code < 0)
244 	goto nyi;
245     if (prect)
246 	rect = *prect;
247     else {
248 	rect.p.x = rect.p.y = 0;
249 	rect.q.x = pim->Width, rect.q.y = pim->Height;
250     }
251     pie = gs_alloc_struct(mem, pdf_image_enum, &st_pdf_image_enum,
252 			  "pdf_begin_image");
253     if (pie == 0)
254 	return_error(gs_error_VMerror);
255     *pinfo = (gx_image_enum_common_t *) pie;
256     gx_image_enum_common_init(*pinfo, (const gs_data_image_t *) pim,
257 			      (context == PDF_IMAGE_TYPE3_MASK ?
258 			       &pdf_image_object_enum_procs :
259 			       &pdf_image_enum_procs),
260 			      (gx_device *)pdev, num_components, format);
261     pie->memory = mem;
262     width = rect.q.x - rect.p.x;
263     pie->width = width;
264     height = rect.q.y - rect.p.y;
265     pie->bits_per_pixel =
266 	pim->BitsPerComponent * num_components / pie->num_planes;
267     pie->rows_left = height;
268     nbytes = (((ulong) pie->width * pie->bits_per_pixel + 7) >> 3) *
269 	pie->num_planes * pie->rows_left;
270     in_line &= nbytes <= MAX_INLINE_IMAGE_BYTES;
271     if (rect.p.x != 0 || rect.p.y != 0 ||
272 	rect.q.x != pim->Width || rect.q.y != pim->Height ||
273 	(is_mask && pim->CombineWithColor)
274 	/* Color space setup used to be done here: see SRZB comment below. */
275 	) {
276 	gs_free_object(mem, pie, "pdf_begin_image");
277 	goto nyi;
278     }
279     if (pmat == 0)
280 	pmat = &ctm_only(pis);
281     {
282 	gs_matrix mat;
283 	gs_matrix bmat;
284 	int code;
285 
286 	pdf_make_bitmap_matrix(&bmat, -rect.p.x, -rect.p.y,
287 			       pim->Width, pim->Height, height);
288 	if ((code = gs_matrix_invert(&pim->ImageMatrix, &mat)) < 0 ||
289 	    (code = gs_matrix_multiply(&bmat, &mat, &mat)) < 0 ||
290 	    (code = gs_matrix_multiply(&mat, pmat, &pie->mat)) < 0
291 	    ) {
292 	    gs_free_object(mem, pie, "pdf_begin_image");
293 	    return code;
294 	}
295     }
296     if ((code = pdf_begin_write_image(pdev, &pie->writer, gs_no_id, width,
297 				      height, NULL, in_line)) < 0 ||
298 	/*
299 	 * Some regrettable PostScript code (such as LanguageLevel 1 output
300 	 * from Microsoft's PSCRIPT.DLL driver) misuses the transfer
301 	 * function to accomplish the equivalent of indexed color.
302 	 * Downsampling (well, only averaging) or JPEG compression are not
303 	 * compatible with this.  Play it safe by using only lossless
304 	 * filters if the transfer function(s) is/are other than the
305 	 * identity.
306 	 */
307 	(code = (pdev->transfer_not_identity ?
308 		 psdf_setup_lossless_filters((gx_device_psdf *) pdev,
309 					     &pie->writer.binary,
310 					     &image.pixel) :
311 		 psdf_setup_image_filters((gx_device_psdf *) pdev,
312 					  &pie->writer.binary, &image.pixel,
313 					  pmat, pis))) < 0 ||
314 	/* SRZB 2001-04-25/Bl
315 	 * Since psdf_setup_image_filters may change the color space
316 	 * (in case of pdev->params.ConvertCMYKImagesToRGB == true),
317 	 * we postpone the selection of the PDF color space to here:
318 	 */
319 	(!is_mask &&
320 	 (code = pdf_color_space(pdev, &cs_value, image.pixel.ColorSpace,
321 				 (in_line ? &pdf_color_space_names_short :
322 				  &pdf_color_space_names), in_line)) < 0) ||
323 	(code = pdf_begin_image_data(pdev, &pie->writer,
324 				     (const gs_pixel_image_t *)&image,
325 				     &cs_value)) < 0
326 	) {
327 	/****** SHOULD FREE STRUCTURES AND CLEAN UP HERE ******/
328 	goto nyi;		/* fall back to default implementation */
329     }
330     return 0;
331  nyi:
332     return gx_default_begin_typed_image
333 	((gx_device *)pdev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
334 	 pinfo);
335 }
336 int
gdev_pdf_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)337 gdev_pdf_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
338 			   const gs_matrix *pmat, const gs_image_common_t *pic,
339 			   const gs_int_rect * prect,
340 			   const gx_drawing_color * pdcolor,
341 			   const gx_clip_path * pcpath, gs_memory_t * mem,
342 			   gx_image_enum_common_t ** pinfo)
343 {
344     return pdf_begin_typed_image((gx_device_pdf *)dev, pis, pmat, pic, prect,
345 				 pdcolor, pcpath, mem, pinfo,
346 				 PDF_IMAGE_DEFAULT);
347 }
348 
349 /* ---------------- All images ---------------- */
350 
351 /* Process the next piece of an image. */
352 private int
pdf_image_plane_data(gx_image_enum_common_t * info,const gx_image_plane_t * planes,int height,int * rows_used)353 pdf_image_plane_data(gx_image_enum_common_t * info,
354 		     const gx_image_plane_t * planes, int height,
355 		     int *rows_used)
356 {
357     gx_device_pdf *pdev = (gx_device_pdf *)info->dev;
358     pdf_image_enum *pie = (pdf_image_enum *) info;
359     int h = height;
360     int y;
361     /****** DOESN'T HANDLE IMAGES WITH VARYING WIDTH PER PLANE ******/
362     uint width_bits = pie->width * pie->plane_depths[0];
363     /****** DOESN'T HANDLE NON-ZERO data_x CORRECTLY ******/
364     uint bcount = (width_bits + 7) >> 3;
365     uint ignore;
366     int nplanes = pie->num_planes;
367     stream *s = pdev->streams.strm;
368     long pos = stell(s);
369     int code;
370     int status = 0;
371 
372     if (h > pie->rows_left)
373 	h = pie->rows_left;
374     pie->rows_left -= h;
375     for (y = 0; y < h; ++y) {
376 	if (nplanes > 1) {
377 	    /*
378 	     * We flip images in blocks, and each block except the last one
379 	     * must contain an integral number of pixels.  The easiest way
380 	     * to meet this condition is for all blocks except the last to
381 	     * be a multiple of 3 source bytes (guaranteeing an integral
382 	     * number of 1/2/4/8/12-bit samples), i.e., 3*nplanes flipped
383 	     * bytes.  This requires a buffer of at least
384 	     * 3*GS_IMAGE_MAX_COMPONENTS bytes.
385 	     */
386 	    int pi;
387 	    uint count = bcount;
388 	    uint offset = 0;
389 #define ROW_BYTES max(200 /*arbitrary*/, 3 * GS_IMAGE_MAX_COMPONENTS)
390 	    const byte *bit_planes[GS_IMAGE_MAX_COMPONENTS];
391 	    int block_bytes = ROW_BYTES / (3 * nplanes) * 3;
392 	    byte row[ROW_BYTES];
393 
394 	    for (pi = 0; pi < nplanes; ++pi)
395 		bit_planes[pi] = planes[pi].data + planes[pi].raster * y;
396 	    while (count) {
397 		uint flip_count;
398 		uint flipped_count;
399 
400 		if (count >= block_bytes) {
401 		    flip_count = block_bytes;
402 		    flipped_count = block_bytes * nplanes;
403 		} else {
404 		    flip_count = count;
405 		    flipped_count =
406 			(width_bits % (block_bytes * 8) * nplanes + 7) >> 3;
407 		}
408 		image_flip_planes(row, bit_planes, offset, flip_count,
409 				  nplanes, pie->plane_depths[0]);
410 		status = sputs(pie->writer.binary.strm, row, flipped_count,
411 			       &ignore);
412 		if (status < 0)
413 		    break;
414 		offset += flip_count;
415 		count -= flip_count;
416 	    }
417 	} else {
418 	    status = sputs(pie->writer.binary.strm,
419 			   planes[0].data + planes[0].raster * y, bcount,
420 			   &ignore);
421 	}
422 	if (status < 0)
423 	    break;
424     }
425     *rows_used = h;
426     if (status < 0)
427 	return_error(gs_error_ioerror);
428     code = cos_stream_add_since(pie->writer.data, pos);
429     return (code < 0 ? code : !pie->rows_left);
430 #undef ROW_BYTES
431 }
432 
433 /* Clean up by releasing the buffers. */
434 private int
pdf_image_end_image_data(gx_image_enum_common_t * info,bool draw_last,bool do_image)435 pdf_image_end_image_data(gx_image_enum_common_t * info, bool draw_last,
436 			 bool do_image)
437 {
438     gx_device_pdf *pdev = (gx_device_pdf *)info->dev;
439     pdf_image_enum *pie = (pdf_image_enum *)info;
440     int height = pie->writer.height;
441     int data_height = height - pie->rows_left;
442     int code;
443 
444     if (pie->writer.pres)
445 	((pdf_x_object_t *)pie->writer.pres)->data_height = data_height;
446     else
447 	pdf_put_image_matrix(pdev, &pie->mat,
448 			     (height == 0 || data_height == 0 ? 1.0 :
449 			      (double)data_height / height));
450     code = pdf_end_image_binary(pdev, &pie->writer, data_height);
451     if (code < 0)
452 	return code;
453     code = pdf_end_write_image(pdev, &pie->writer);
454     switch (code) {
455     default:
456 	return code;	/* error */
457     case 1:
458 	code = 0;
459 	break;
460     case 0:
461 	if (do_image)
462 	    code = pdf_do_image(pdev, pie->writer.pres, &pie->mat, true);
463     }
464     gs_free_object(pie->memory, pie, "pdf_end_image");
465     return code;
466 }
467 
468 /* End a normal image, drawing it. */
469 private int
pdf_image_end_image(gx_image_enum_common_t * info,bool draw_last)470 pdf_image_end_image(gx_image_enum_common_t * info, bool draw_last)
471 {
472     return pdf_image_end_image_data(info, draw_last, true);
473 }
474 
475 /* ---------------- Type 3/3x images ---------------- */
476 
477 /*
478  * For both types of masked images, we create temporary dummy (null) devices
479  * that forward the begin_typed_image call to the implementation above.
480  */
481 private int
pdf_make_mxd(gx_device ** pmxdev,gx_device * tdev,gs_memory_t * mem)482 pdf_make_mxd(gx_device **pmxdev, gx_device *tdev, gs_memory_t *mem)
483 {
484     gx_device *fdev;
485     int code = gs_copydevice(&fdev, (const gx_device *)&gs_null_device, mem);
486 
487     if (code < 0)
488 	return code;
489     gx_device_set_target((gx_device_forward *)fdev, tdev);
490     *pmxdev = fdev;
491     return 0;
492 }
493 
494 /* End the mask of an ImageType 3 image, not drawing it. */
495 private int
pdf_image_end_image_object(gx_image_enum_common_t * info,bool draw_last)496 pdf_image_end_image_object(gx_image_enum_common_t * info, bool draw_last)
497 {
498     return pdf_image_end_image_data(info, draw_last, false);
499 }
500 
501 /* ---------------- Type 3 images ---------------- */
502 
503 /* Implement the mask image device. */
504 private dev_proc_begin_typed_image(pdf_mid_begin_typed_image);
505 private int
pdf_image3_make_mid(gx_device ** pmidev,gx_device * dev,int width,int height,gs_memory_t * mem)506 pdf_image3_make_mid(gx_device **pmidev, gx_device *dev, int width, int height,
507 		    gs_memory_t *mem)
508 {
509     int code = pdf_make_mxd(pmidev, dev, mem);
510 
511     if (code < 0)
512 	return code;
513     set_dev_proc(*pmidev, begin_typed_image, pdf_mid_begin_typed_image);
514     return 0;
515 }
516 private int
pdf_mid_begin_typed_image(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo)517 pdf_mid_begin_typed_image(gx_device * dev, const gs_imager_state * pis,
518 			  const gs_matrix *pmat, const gs_image_common_t *pic,
519 			  const gs_int_rect * prect,
520 			  const gx_drawing_color * pdcolor,
521 			  const gx_clip_path * pcpath, gs_memory_t * mem,
522 			  gx_image_enum_common_t ** pinfo)
523 {
524     /* The target of the null device is the pdfwrite device. */
525     gx_device_pdf *const pdev = (gx_device_pdf *)
526 	((gx_device_null *)dev)->target;
527     int code = pdf_begin_typed_image
528 	(pdev, pis, pmat, pic, prect, pdcolor, pcpath, mem, pinfo,
529 	 PDF_IMAGE_TYPE3_MASK);
530 
531     if (code < 0)
532 	return code;
533     if ((*pinfo)->procs != &pdf_image_object_enum_procs) {
534 	/* We couldn't handle the mask image.  Bail out. */
535 	/* (This is never supposed to happen.) */
536 	return_error(gs_error_rangecheck);
537     }
538     return code;
539 }
540 
541 /* Implement the mask clip device. */
542 private int
pdf_image3_make_mcde(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo,gx_device ** pmcdev,gx_device * midev,gx_image_enum_common_t * pminfo,const gs_int_point * origin)543 pdf_image3_make_mcde(gx_device *dev, const gs_imager_state *pis,
544 		     const gs_matrix *pmat, const gs_image_common_t *pic,
545 		     const gs_int_rect *prect, const gx_drawing_color *pdcolor,
546 		     const gx_clip_path *pcpath, gs_memory_t *mem,
547 		     gx_image_enum_common_t **pinfo,
548 		     gx_device **pmcdev, gx_device *midev,
549 		     gx_image_enum_common_t *pminfo,
550 		     const gs_int_point *origin)
551 {
552     int code = pdf_make_mxd(pmcdev, midev, mem);
553     pdf_image_enum *pmie;
554     pdf_image_enum *pmce;
555     cos_stream_t *pmcs;
556 
557     if (code < 0)
558 	return code;
559     code = pdf_begin_typed_image
560 	((gx_device_pdf *)dev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
561 	 pinfo, PDF_IMAGE_TYPE3_DATA);
562     if (code < 0)
563 	return code;
564     /* Add the /Mask entry to the image dictionary. */
565     if ((*pinfo)->procs != &pdf_image_enum_procs) {
566 	/* We couldn't handle the image.  Bail out. */
567 	gx_image_end(*pinfo, false);
568 	gs_free_object(mem, *pmcdev, "pdf_image3_make_mcde");
569 	return_error(gs_error_rangecheck);
570     }
571     pmie = (pdf_image_enum *)pminfo;
572     pmce = (pdf_image_enum *)(*pinfo);
573     pmcs = (cos_stream_t *)pmce->writer.pres->object;
574     return cos_dict_put_c_key_object(cos_stream_dict(pmcs), "/Mask",
575 				     pmie->writer.pres->object);
576 }
577 
578 /* ---------------- Type 3x images ---------------- */
579 
580 /* Implement the mask image device. */
581 private int
pdf_image3x_make_mid(gx_device ** pmidev,gx_device * dev,int width,int height,int depth,gs_memory_t * mem)582 pdf_image3x_make_mid(gx_device **pmidev, gx_device *dev, int width, int height,
583 		     int depth, gs_memory_t *mem)
584 {
585     int code = pdf_make_mxd(pmidev, dev, mem);
586 
587     if (code < 0)
588 	return code;
589     set_dev_proc(*pmidev, begin_typed_image, pdf_mid_begin_typed_image);
590     return 0;
591 }
592 
593 /* Implement the mask clip device. */
594 private int
pdf_image3x_make_mcde(gx_device * dev,const gs_imager_state * pis,const gs_matrix * pmat,const gs_image_common_t * pic,const gs_int_rect * prect,const gx_drawing_color * pdcolor,const gx_clip_path * pcpath,gs_memory_t * mem,gx_image_enum_common_t ** pinfo,gx_device ** pmcdev,gx_device * midev[2],gx_image_enum_common_t * pminfo[2],const gs_int_point origin[2],const gs_image3x_t * pim)595 pdf_image3x_make_mcde(gx_device *dev, const gs_imager_state *pis,
596 		      const gs_matrix *pmat, const gs_image_common_t *pic,
597 		      const gs_int_rect *prect,
598 		      const gx_drawing_color *pdcolor,
599 		      const gx_clip_path *pcpath, gs_memory_t *mem,
600 		      gx_image_enum_common_t **pinfo,
601 		      gx_device **pmcdev, gx_device *midev[2],
602 		      gx_image_enum_common_t *pminfo[2],
603 		      const gs_int_point origin[2],
604 		      const gs_image3x_t *pim)
605 {
606     int code;
607     pdf_image_enum *pmie;
608     pdf_image_enum *pmce;
609     cos_stream_t *pmcs;
610     int i;
611     const gs_image3x_mask_t *pixm;
612 
613     if (midev[0]) {
614 	if (midev[1])
615 	    return_error(gs_error_rangecheck);
616 	i = 0, pixm = &pim->Opacity;
617     } else if (midev[1])
618 	i = 1, pixm = &pim->Shape;
619     else
620 	return_error(gs_error_rangecheck);
621     code = pdf_make_mxd(pmcdev, midev[i], mem);
622     if (code < 0)
623 	return code;
624     code = pdf_begin_typed_image
625 	((gx_device_pdf *)dev, pis, pmat, pic, prect, pdcolor, pcpath, mem,
626 	 pinfo, PDF_IMAGE_TYPE3_DATA);
627     if (code < 0)
628 	return code;
629     if ((*pinfo)->procs != &pdf_image_enum_procs) {
630 	/* We couldn't handle the image.  Bail out. */
631 	gx_image_end(*pinfo, false);
632 	gs_free_object(mem, *pmcdev, "pdf_image3x_make_mcde");
633 	return_error(gs_error_rangecheck);
634     }
635     pmie = (pdf_image_enum *)pminfo[i];
636     pmce = (pdf_image_enum *)(*pinfo);
637     pmcs = (cos_stream_t *)pmce->writer.pres->object;
638     /*
639      * Add the SMask entry to the image dictionary, and, if needed,
640      * the Matte entry to the mask dictionary.
641      */
642     if (pixm->has_Matte) {
643 	int num_components =
644 	    gs_color_space_num_components(pim->ColorSpace);
645 
646 	code = cos_dict_put_c_key_floats(
647 				(cos_dict_t *)pmie->writer.pres->object,
648 				"/Matte", pixm->Matte,
649 				num_components);
650 	if (code < 0)
651 	    return code;
652     }
653     return cos_dict_put_c_key_object(cos_stream_dict(pmcs), "/SMask",
654 				     pmie->writer.pres->object);
655 }
656