xref: /plan9/sys/src/cmd/gs/src/gdevpdfj.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
13ff48bf5SDavid du Colombier /* Copyright (C) 2000 Aladdin Enterprises.  All rights reserved.
23ff48bf5SDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
53ff48bf5SDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
93ff48bf5SDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
153ff48bf5SDavid du Colombier */
163ff48bf5SDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: gdevpdfj.c,v 1.49 2005/09/06 13:47:10 leonardo Exp $ */
183ff48bf5SDavid du Colombier /* Image-writing utilities for pdfwrite driver */
193ff48bf5SDavid du Colombier #include "memory_.h"
203ff48bf5SDavid du Colombier #include "string_.h"
213ff48bf5SDavid du Colombier #include "gx.h"
223ff48bf5SDavid du Colombier #include "gserrors.h"
233ff48bf5SDavid du Colombier #include "gdevpdfx.h"
243ff48bf5SDavid du Colombier #include "gdevpdfg.h"
253ff48bf5SDavid du Colombier #include "gdevpdfo.h"
263ff48bf5SDavid du Colombier #include "gxcspace.h"
273ff48bf5SDavid du Colombier #include "gsiparm4.h"
28*593dc095SDavid du Colombier #include "gdevpsds.h"
29*593dc095SDavid du Colombier #include "spngpx.h"
303ff48bf5SDavid du Colombier 
313ff48bf5SDavid du Colombier #define CHECK(expr)\
323ff48bf5SDavid du Colombier   BEGIN if ((code = (expr)) < 0) return code; END
333ff48bf5SDavid du Colombier 
343ff48bf5SDavid du Colombier /* GC descriptors */
353ff48bf5SDavid du Colombier public_st_pdf_image_writer();
36*593dc095SDavid du Colombier private ENUM_PTRS_WITH(pdf_image_writer_enum_ptrs, pdf_image_writer *piw)
37*593dc095SDavid du Colombier      index -= 4;
38*593dc095SDavid du Colombier      if (index < psdf_binary_writer_max_ptrs * piw->alt_writer_count) {
39*593dc095SDavid du Colombier 	 gs_ptr_type_t ret =
40*593dc095SDavid du Colombier 	     ENUM_USING(st_psdf_binary_writer, &piw->binary[index / psdf_binary_writer_max_ptrs],
41*593dc095SDavid du Colombier 			sizeof(psdf_binary_writer), index % psdf_binary_writer_max_ptrs);
42*593dc095SDavid du Colombier 
43*593dc095SDavid du Colombier 	 if (ret == 0)		/* don't stop early */
44*593dc095SDavid du Colombier 	     ENUM_RETURN(0);
45*593dc095SDavid du Colombier 	 return ret;
46*593dc095SDavid du Colombier     }
47*593dc095SDavid du Colombier     return 0;
48*593dc095SDavid du Colombier case 0: ENUM_RETURN(piw->pres);
49*593dc095SDavid du Colombier case 1: ENUM_RETURN(piw->data);
50*593dc095SDavid du Colombier case 2: ENUM_RETURN(piw->named);
51*593dc095SDavid du Colombier case 3: ENUM_RETURN(piw->pres_mask);
52*593dc095SDavid du Colombier ENUM_PTRS_END
RELOC_PTRS_WITH(pdf_image_writer_reloc_ptrs,pdf_image_writer * piw)53*593dc095SDavid du Colombier private RELOC_PTRS_WITH(pdf_image_writer_reloc_ptrs, pdf_image_writer *piw)
54*593dc095SDavid du Colombier {
55*593dc095SDavid du Colombier     int i;
56*593dc095SDavid du Colombier 
57*593dc095SDavid du Colombier     for (i = 0; i < piw->alt_writer_count; ++i)
58*593dc095SDavid du Colombier 	RELOC_USING(st_psdf_binary_writer, &piw->binary[i],
59*593dc095SDavid du Colombier 		    sizeof(psdf_binary_writer));
60*593dc095SDavid du Colombier     RELOC_VAR(piw->pres);
61*593dc095SDavid du Colombier     RELOC_VAR(piw->data);
62*593dc095SDavid du Colombier     RELOC_VAR(piw->named);
63*593dc095SDavid du Colombier     RELOC_VAR(piw->pres_mask);
64*593dc095SDavid du Colombier }
65*593dc095SDavid du Colombier RELOC_PTRS_END
663ff48bf5SDavid du Colombier 
673ff48bf5SDavid du Colombier /* ---------------- Image stream dictionaries ---------------- */
683ff48bf5SDavid du Colombier 
693ff48bf5SDavid du Colombier const pdf_image_names_t pdf_image_names_full = {
703ff48bf5SDavid du Colombier     { PDF_COLOR_SPACE_NAMES },
713ff48bf5SDavid du Colombier     { PDF_FILTER_NAMES },
723ff48bf5SDavid du Colombier     PDF_IMAGE_PARAM_NAMES
733ff48bf5SDavid du Colombier };
743ff48bf5SDavid du Colombier const pdf_image_names_t pdf_image_names_short = {
753ff48bf5SDavid du Colombier     { PDF_COLOR_SPACE_NAMES_SHORT },
763ff48bf5SDavid du Colombier     { PDF_FILTER_NAMES_SHORT },
773ff48bf5SDavid du Colombier     PDF_IMAGE_PARAM_NAMES_SHORT
783ff48bf5SDavid du Colombier };
793ff48bf5SDavid du Colombier 
803ff48bf5SDavid du Colombier /* Store the values of image parameters other than filters. */
813ff48bf5SDavid du Colombier /* pdev is used only for updating procsets. */
823ff48bf5SDavid du Colombier /* pcsvalue is not used for masks. */
833ff48bf5SDavid du Colombier private int
pdf_put_pixel_image_values(cos_dict_t * pcd,gx_device_pdf * pdev,const gs_pixel_image_t * pim,const gs_color_space * pcs,const pdf_image_names_t * pin,const cos_value_t * pcsvalue)843ff48bf5SDavid du Colombier pdf_put_pixel_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
853ff48bf5SDavid du Colombier 			   const gs_pixel_image_t *pim,
863ff48bf5SDavid du Colombier 			   const gs_color_space *pcs,
873ff48bf5SDavid du Colombier 			   const pdf_image_names_t *pin,
883ff48bf5SDavid du Colombier 			   const cos_value_t *pcsvalue)
893ff48bf5SDavid du Colombier {
903ff48bf5SDavid du Colombier     int num_components;
913ff48bf5SDavid du Colombier     float indexed_decode[2];
923ff48bf5SDavid du Colombier     const float *default_decode = NULL;
933ff48bf5SDavid du Colombier     int code;
943ff48bf5SDavid du Colombier 
953ff48bf5SDavid du Colombier     if (pcs) {
963ff48bf5SDavid du Colombier 	CHECK(cos_dict_put_c_key(pcd, pin->ColorSpace, pcsvalue));
973ff48bf5SDavid du Colombier 	pdf_color_space_procsets(pdev, pcs);
983ff48bf5SDavid du Colombier 	num_components = gs_color_space_num_components(pcs);
993ff48bf5SDavid du Colombier 	if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
1003ff48bf5SDavid du Colombier 	    indexed_decode[0] = 0;
101*593dc095SDavid du Colombier 	    indexed_decode[1] = (float)((1 << pim->BitsPerComponent) - 1);
1023ff48bf5SDavid du Colombier 	    default_decode = indexed_decode;
1033ff48bf5SDavid du Colombier 	}
1043ff48bf5SDavid du Colombier     } else
1053ff48bf5SDavid du Colombier 	num_components = 1;
1063ff48bf5SDavid du Colombier     CHECK(cos_dict_put_c_key_int(pcd, pin->Width, pim->Width));
1073ff48bf5SDavid du Colombier     CHECK(cos_dict_put_c_key_int(pcd, pin->Height, pim->Height));
1083ff48bf5SDavid du Colombier     CHECK(cos_dict_put_c_key_int(pcd, pin->BitsPerComponent,
1093ff48bf5SDavid du Colombier 				 pim->BitsPerComponent));
1103ff48bf5SDavid du Colombier     {
1113ff48bf5SDavid du Colombier 	int i;
1123ff48bf5SDavid du Colombier 
113*593dc095SDavid du Colombier 	for (i = 0; i < num_components * 2; ++i) {
1143ff48bf5SDavid du Colombier 	    if (pim->Decode[i] !=
1153ff48bf5SDavid du Colombier 		(default_decode ? default_decode[i] : i & 1)
1163ff48bf5SDavid du Colombier 		)
1173ff48bf5SDavid du Colombier 		break;
118*593dc095SDavid du Colombier 	}
1193ff48bf5SDavid du Colombier 	if (i < num_components * 2) {
1203ff48bf5SDavid du Colombier 	    cos_array_t *pca =
1213ff48bf5SDavid du Colombier 		cos_array_alloc(pdev, "pdf_put_pixel_image_values(decode)");
1223ff48bf5SDavid du Colombier 
1233ff48bf5SDavid du Colombier 	    if (pca == 0)
1243ff48bf5SDavid du Colombier 		return_error(gs_error_VMerror);
125*593dc095SDavid du Colombier 	    if (pcs == NULL) {
126*593dc095SDavid du Colombier 		/* 269-01.ps sets /Decode[0 100] with a mask image. */
127*593dc095SDavid du Colombier 		for (i = 0; i < num_components * 2; ++i)
128*593dc095SDavid du Colombier 		    CHECK(cos_array_add_real(pca, min(pim->Decode[i], 1)));
129*593dc095SDavid du Colombier 	    } else {
1303ff48bf5SDavid du Colombier 		for (i = 0; i < num_components * 2; ++i)
1313ff48bf5SDavid du Colombier 		    CHECK(cos_array_add_real(pca, pim->Decode[i]));
132*593dc095SDavid du Colombier 	    }
1333ff48bf5SDavid du Colombier 	    CHECK(cos_dict_put_c_key_object(pcd, pin->Decode,
1343ff48bf5SDavid du Colombier 					    COS_OBJECT(pca)));
1353ff48bf5SDavid du Colombier 	}
1363ff48bf5SDavid du Colombier     }
1373ff48bf5SDavid du Colombier     if (pim->Interpolate)
1383ff48bf5SDavid du Colombier 	CHECK(cos_dict_put_c_strings(pcd, pin->Interpolate, "true"));
1393ff48bf5SDavid du Colombier     return 0;
1403ff48bf5SDavid du Colombier }
1413ff48bf5SDavid du Colombier int
pdf_put_image_values(cos_dict_t * pcd,gx_device_pdf * pdev,const gs_pixel_image_t * pic,const pdf_image_names_t * pin,const cos_value_t * pcsvalue)1423ff48bf5SDavid du Colombier pdf_put_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
1433ff48bf5SDavid du Colombier 		     const gs_pixel_image_t *pic,
1443ff48bf5SDavid du Colombier 		     const pdf_image_names_t *pin,
1453ff48bf5SDavid du Colombier 		     const cos_value_t *pcsvalue)
1463ff48bf5SDavid du Colombier {
1473ff48bf5SDavid du Colombier     const gs_color_space *pcs = pic->ColorSpace;
1483ff48bf5SDavid du Colombier     int code;
1493ff48bf5SDavid du Colombier 
1503ff48bf5SDavid du Colombier     switch (pic->type->index) {
1513ff48bf5SDavid du Colombier     case 1: {
1523ff48bf5SDavid du Colombier 	const gs_image1_t *pim = (const gs_image1_t *)pic;
1533ff48bf5SDavid du Colombier 
1543ff48bf5SDavid du Colombier 	if (pim->ImageMask) {
1553ff48bf5SDavid du Colombier 	    CHECK(cos_dict_put_c_strings(pcd, pin->ImageMask, "true"));
1563ff48bf5SDavid du Colombier 	    pdev->procsets |= ImageB;
1573ff48bf5SDavid du Colombier 	    pcs = NULL;
1583ff48bf5SDavid du Colombier 	}
1593ff48bf5SDavid du Colombier     }
1603ff48bf5SDavid du Colombier 	break;
1613ff48bf5SDavid du Colombier     case 3: {
1623ff48bf5SDavid du Colombier 	/*
1633ff48bf5SDavid du Colombier 	 * Clients must treat this as a special case: they must call
1643ff48bf5SDavid du Colombier 	 * pdf_put_image_values for the MaskDict separately, and must
1653ff48bf5SDavid du Colombier 	 * add the Mask entry to the main image stream (dictionary).
1663ff48bf5SDavid du Colombier 	 */
1673ff48bf5SDavid du Colombier 	/*const gs_image3_t *pim = (const gs_image3_t *)pic;*/
1683ff48bf5SDavid du Colombier 
1693ff48bf5SDavid du Colombier 	/* Masked images are only supported starting in PDF 1.3. */
1703ff48bf5SDavid du Colombier 	if (pdev->CompatibilityLevel < 1.3)
1713ff48bf5SDavid du Colombier 	    return_error(gs_error_rangecheck);
1723ff48bf5SDavid du Colombier     }
1733ff48bf5SDavid du Colombier 	break;
1743ff48bf5SDavid du Colombier     case 4: {
1753ff48bf5SDavid du Colombier 	const gs_image4_t *pim = (const gs_image4_t *)pic;
1763ff48bf5SDavid du Colombier 	int num_components = gs_color_space_num_components(pcs);
1773ff48bf5SDavid du Colombier 	cos_array_t *pca;
1783ff48bf5SDavid du Colombier 	int i;
1793ff48bf5SDavid du Colombier 
1803ff48bf5SDavid du Colombier 	/* Masked images are only supported starting in PDF 1.3. */
1813ff48bf5SDavid du Colombier 	if (pdev->CompatibilityLevel < 1.3)
182*593dc095SDavid du Colombier 	    break; /* Will convert into an imagemask with a pattern color. */
1833ff48bf5SDavid du Colombier 	pca = cos_array_alloc(pdev, "pdf_put_image_values(mask)");
1843ff48bf5SDavid du Colombier 	if (pca == 0)
1853ff48bf5SDavid du Colombier 	    return_error(gs_error_VMerror);
1863ff48bf5SDavid du Colombier 	for (i = 0; i < num_components; ++i) {
1873ff48bf5SDavid du Colombier 	    int lo, hi;
1883ff48bf5SDavid du Colombier 
1893ff48bf5SDavid du Colombier 	    if (pim->MaskColor_is_range)
1903ff48bf5SDavid du Colombier 		lo = pim->MaskColor[i * 2], hi = pim->MaskColor[i * 2 + 1];
1913ff48bf5SDavid du Colombier 	    else
1923ff48bf5SDavid du Colombier 		lo = hi = pim->MaskColor[i];
1933ff48bf5SDavid du Colombier 	    CHECK(cos_array_add_int(pca, lo));
1943ff48bf5SDavid du Colombier 	    CHECK(cos_array_add_int(pca, hi));
1953ff48bf5SDavid du Colombier 	}
1963ff48bf5SDavid du Colombier 	CHECK(cos_dict_put_c_key_object(pcd, "/Mask", COS_OBJECT(pca)));
1973ff48bf5SDavid du Colombier     }
1983ff48bf5SDavid du Colombier 	break;
1993ff48bf5SDavid du Colombier     default:
2003ff48bf5SDavid du Colombier 	return_error(gs_error_rangecheck);
2013ff48bf5SDavid du Colombier     }
2023ff48bf5SDavid du Colombier     return pdf_put_pixel_image_values(pcd, pdev, pic, pcs, pin, pcsvalue);
2033ff48bf5SDavid du Colombier }
2043ff48bf5SDavid du Colombier 
2053ff48bf5SDavid du Colombier /* Store filters for an image. */
2063ff48bf5SDavid du Colombier /* Currently this only saves parameters for CCITTFaxDecode. */
2073ff48bf5SDavid du Colombier int
pdf_put_image_filters(cos_dict_t * pcd,gx_device_pdf * pdev,const psdf_binary_writer * pbw,const pdf_image_names_t * pin)2083ff48bf5SDavid du Colombier pdf_put_image_filters(cos_dict_t *pcd, gx_device_pdf *pdev,
2093ff48bf5SDavid du Colombier 		      const psdf_binary_writer * pbw,
2103ff48bf5SDavid du Colombier 		      const pdf_image_names_t *pin)
2113ff48bf5SDavid du Colombier {
2123ff48bf5SDavid du Colombier     return pdf_put_filters(pcd, pdev, pbw->strm, &pin->filter_names);
2133ff48bf5SDavid du Colombier }
2143ff48bf5SDavid du Colombier 
2153ff48bf5SDavid du Colombier /* ---------------- Image writing ---------------- */
2163ff48bf5SDavid du Colombier 
2173ff48bf5SDavid du Colombier /*
2183ff48bf5SDavid du Colombier  * Fill in the image parameters for a device space bitmap.
2193ff48bf5SDavid du Colombier  * PDF images are always specified top-to-bottom.
2203ff48bf5SDavid du Colombier  * data_h is the actual number of data rows, which may be less than h.
2213ff48bf5SDavid du Colombier  */
2223ff48bf5SDavid du Colombier void
pdf_make_bitmap_matrix(gs_matrix * pmat,int x,int y,int w,int h,int h_actual)2233ff48bf5SDavid du Colombier pdf_make_bitmap_matrix(gs_matrix * pmat, int x, int y, int w, int h,
2243ff48bf5SDavid du Colombier 		       int h_actual)
2253ff48bf5SDavid du Colombier {
226*593dc095SDavid du Colombier     pmat->xx = (float)w;
2273ff48bf5SDavid du Colombier     pmat->xy = 0;
2283ff48bf5SDavid du Colombier     pmat->yx = 0;
229*593dc095SDavid du Colombier     pmat->yy = (float)(-h_actual);
230*593dc095SDavid du Colombier     pmat->tx = (float)x;
231*593dc095SDavid du Colombier     pmat->ty = (float)(y + h);
2323ff48bf5SDavid du Colombier }
2333ff48bf5SDavid du Colombier 
2343ff48bf5SDavid du Colombier /*
2353ff48bf5SDavid du Colombier  * Put out the gsave and matrix for an image.  y_scale adjusts the matrix
2363ff48bf5SDavid du Colombier  * for images that end prematurely.
2373ff48bf5SDavid du Colombier  */
2383ff48bf5SDavid du Colombier void
pdf_put_image_matrix(gx_device_pdf * pdev,const gs_matrix * pmat,floatp y_scale)2393ff48bf5SDavid du Colombier pdf_put_image_matrix(gx_device_pdf * pdev, const gs_matrix * pmat,
2403ff48bf5SDavid du Colombier 		     floatp y_scale)
2413ff48bf5SDavid du Colombier {
2423ff48bf5SDavid du Colombier     gs_matrix imat;
2433ff48bf5SDavid du Colombier 
2443ff48bf5SDavid du Colombier     gs_matrix_translate(pmat, 0.0, 1.0 - y_scale, &imat);
2453ff48bf5SDavid du Colombier     gs_matrix_scale(&imat, 1.0, y_scale, &imat);
2463ff48bf5SDavid du Colombier     pdf_put_matrix(pdev, "q ", &imat, "cm\n");
2473ff48bf5SDavid du Colombier }
2483ff48bf5SDavid du Colombier 
2493ff48bf5SDavid du Colombier /* Put out a reference to an image resource. */
2503ff48bf5SDavid du Colombier int
pdf_do_image_by_id(gx_device_pdf * pdev,double scale,const gs_matrix * pimat,bool in_contents,gs_id id)251*593dc095SDavid du Colombier pdf_do_image_by_id(gx_device_pdf * pdev, double scale,
252*593dc095SDavid du Colombier 	     const gs_matrix * pimat, bool in_contents, gs_id id)
2533ff48bf5SDavid du Colombier {
254*593dc095SDavid du Colombier     /* fixme : in_contents is always true (there are no calls with false). */
2553ff48bf5SDavid du Colombier     if (in_contents) {
2563ff48bf5SDavid du Colombier 	int code = pdf_open_contents(pdev, PDF_IN_STREAM);
2573ff48bf5SDavid du Colombier 
2583ff48bf5SDavid du Colombier 	if (code < 0)
2593ff48bf5SDavid du Colombier 	    return code;
2603ff48bf5SDavid du Colombier     }
261*593dc095SDavid du Colombier     if (pimat)
262*593dc095SDavid du Colombier 	pdf_put_image_matrix(pdev, pimat, scale);
263*593dc095SDavid du Colombier     pprintld1(pdev->strm, "/R%ld Do\nQ\n", id);
264*593dc095SDavid du Colombier     return pdf_register_charproc_resource(pdev, id, resourceXObject);
265*593dc095SDavid du Colombier }
266*593dc095SDavid du Colombier int
pdf_do_image(gx_device_pdf * pdev,const pdf_resource_t * pres,const gs_matrix * pimat,bool in_contents)267*593dc095SDavid du Colombier pdf_do_image(gx_device_pdf * pdev, const pdf_resource_t * pres,
268*593dc095SDavid du Colombier 	     const gs_matrix * pimat, bool in_contents)
269*593dc095SDavid du Colombier {
270*593dc095SDavid du Colombier     /* fixme : call pdf_do_image_by_id when pimam == NULL. */
271*593dc095SDavid du Colombier     double scale = 1;
272*593dc095SDavid du Colombier 
2733ff48bf5SDavid du Colombier     if (pimat) {
2743ff48bf5SDavid du Colombier 	/* Adjust the matrix to account for short images. */
2753ff48bf5SDavid du Colombier 	const pdf_x_object_t *const pxo = (const pdf_x_object_t *)pres;
276*593dc095SDavid du Colombier 	scale = (double)pxo->data_height / pxo->height;
2773ff48bf5SDavid du Colombier     }
278*593dc095SDavid du Colombier     return pdf_do_image_by_id(pdev, scale, pimat, in_contents, pdf_resource_id(pres));
2793ff48bf5SDavid du Colombier }
2803ff48bf5SDavid du Colombier 
2813ff48bf5SDavid du Colombier /* ------ Begin / finish ------ */
2823ff48bf5SDavid du Colombier 
283*593dc095SDavid du Colombier /* Initialize image writer. */
284*593dc095SDavid du Colombier void
pdf_image_writer_init(pdf_image_writer * piw)285*593dc095SDavid du Colombier pdf_image_writer_init(pdf_image_writer * piw)
286*593dc095SDavid du Colombier {
287*593dc095SDavid du Colombier     memset(piw, 0, sizeof(*piw));
288*593dc095SDavid du Colombier     piw->alt_writer_count = 1; /* Default. */
289*593dc095SDavid du Colombier }
290*593dc095SDavid du Colombier 
2913ff48bf5SDavid du Colombier /*
292*593dc095SDavid du Colombier  * Begin writing an image, creating the resource if not in-line, and setting
293*593dc095SDavid du Colombier  * up the binary writer.  If pnamed != 0, it is a stream object created by a
294*593dc095SDavid du Colombier  * NI pdfmark.
2953ff48bf5SDavid du Colombier  */
2963ff48bf5SDavid du Colombier int
pdf_begin_write_image(gx_device_pdf * pdev,pdf_image_writer * piw,gx_bitmap_id id,int w,int h,cos_dict_t * named,bool in_line)2973ff48bf5SDavid du Colombier pdf_begin_write_image(gx_device_pdf * pdev, pdf_image_writer * piw,
298*593dc095SDavid du Colombier 		      gx_bitmap_id id, int w, int h, cos_dict_t *named,
2993ff48bf5SDavid du Colombier 		      bool in_line)
3003ff48bf5SDavid du Colombier {
3013ff48bf5SDavid du Colombier     /* Patch pdev->strm so the right stream gets into the writer. */
3023ff48bf5SDavid du Colombier     stream *save_strm = pdev->strm;
303*593dc095SDavid du Colombier     cos_stream_t *data;
304*593dc095SDavid du Colombier     bool mask = (piw->data != NULL);
305*593dc095SDavid du Colombier     int alt_stream_index = (!mask ? 0 : piw->alt_writer_count);
3063ff48bf5SDavid du Colombier     int code;
3073ff48bf5SDavid du Colombier 
3083ff48bf5SDavid du Colombier     if (in_line) {
3093ff48bf5SDavid du Colombier 	piw->pres = 0;
3103ff48bf5SDavid du Colombier 	piw->pin = &pdf_image_names_short;
311*593dc095SDavid du Colombier 	data = cos_stream_alloc(pdev, "pdf_begin_image_data");
312*593dc095SDavid du Colombier 	if (data == 0)
3133ff48bf5SDavid du Colombier 	    return_error(gs_error_VMerror);
3143ff48bf5SDavid du Colombier 	piw->end_string = " Q";
315*593dc095SDavid du Colombier 	piw->named = 0;		/* must have named == 0 */
3163ff48bf5SDavid du Colombier     } else {
3173ff48bf5SDavid du Colombier 	pdf_x_object_t *pxo;
3183ff48bf5SDavid du Colombier 	cos_stream_t *pcos;
319*593dc095SDavid du Colombier 	pdf_resource_t *pres;
3203ff48bf5SDavid du Colombier 
321*593dc095SDavid du Colombier 	/*
322*593dc095SDavid du Colombier 	 * Note that if named != 0, there are two objects with the same id
323*593dc095SDavid du Colombier 	 * while the image is being accumulated: named, and pres->object.
324*593dc095SDavid du Colombier 	 */
325*593dc095SDavid du Colombier 	code = pdf_alloc_resource(pdev, resourceXObject, id, &pres,
326*593dc095SDavid du Colombier 				  (named ? named->id : -1L));
3273ff48bf5SDavid du Colombier 	if (code < 0)
3283ff48bf5SDavid du Colombier 	    return code;
329*593dc095SDavid du Colombier 	*(mask ? &piw->pres_mask : &piw->pres) = pres;
330*593dc095SDavid du Colombier 	cos_become(pres->object, cos_type_stream);
331*593dc095SDavid du Colombier 	pres->rid = id;
3323ff48bf5SDavid du Colombier 	piw->pin = &pdf_image_names_full;
333*593dc095SDavid du Colombier 	pxo = (pdf_x_object_t *)pres;
3343ff48bf5SDavid du Colombier 	pcos = (cos_stream_t *)pxo->object;
3353ff48bf5SDavid du Colombier 	CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype",
3363ff48bf5SDavid du Colombier 				     "/Image"));
3373ff48bf5SDavid du Colombier 	pxo->width = w;
3383ff48bf5SDavid du Colombier 	pxo->height = h;
3393ff48bf5SDavid du Colombier 	/* Initialize data_height for the benefit of copy_{mono,color}. */
3403ff48bf5SDavid du Colombier 	pxo->data_height = h;
341*593dc095SDavid du Colombier 	data = pcos;
342*593dc095SDavid du Colombier 	if (!mask)
343*593dc095SDavid du Colombier 	    piw->named = named;
3443ff48bf5SDavid du Colombier     }
3453ff48bf5SDavid du Colombier     pdev->strm = pdev->streams.strm;
346*593dc095SDavid du Colombier     pdev->strm = cos_write_stream_alloc(data, pdev, "pdf_begin_write_image");
347*593dc095SDavid du Colombier     if (pdev->strm == 0)
348*593dc095SDavid du Colombier 	return_error(gs_error_VMerror);
349*593dc095SDavid du Colombier     if (!mask)
350*593dc095SDavid du Colombier 	piw->data = data;
351*593dc095SDavid du Colombier     piw->height = h;
352*593dc095SDavid du Colombier     code = psdf_begin_binary((gx_device_psdf *) pdev, &piw->binary[alt_stream_index]);
353*593dc095SDavid du Colombier     piw->binary[alt_stream_index].target = NULL; /* We don't need target with cos_write_stream. */
3543ff48bf5SDavid du Colombier     pdev->strm = save_strm;
3553ff48bf5SDavid du Colombier     return code;
3563ff48bf5SDavid du Colombier }
3573ff48bf5SDavid du Colombier 
358*593dc095SDavid du Colombier /*
359*593dc095SDavid du Colombier  *  Make alternative stream for image compression choice.
360*593dc095SDavid du Colombier  */
361*593dc095SDavid du Colombier int
pdf_make_alt_stream(gx_device_pdf * pdev,psdf_binary_writer * pbw)362*593dc095SDavid du Colombier pdf_make_alt_stream(gx_device_pdf * pdev, psdf_binary_writer * pbw)
363*593dc095SDavid du Colombier {
364*593dc095SDavid du Colombier     stream *save_strm = pdev->strm;
365*593dc095SDavid du Colombier     cos_stream_t *pcos = cos_stream_alloc(pdev, "pdf_make_alt_stream");
366*593dc095SDavid du Colombier     int code;
367*593dc095SDavid du Colombier 
368*593dc095SDavid du Colombier     if (pcos == 0)
369*593dc095SDavid du Colombier         return_error(gs_error_VMerror);
370*593dc095SDavid du Colombier     pcos->id = 0;
371*593dc095SDavid du Colombier     CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype", "/Image"));
372*593dc095SDavid du Colombier     pbw->strm = cos_write_stream_alloc(pcos, pdev, "pdf_make_alt_stream");
373*593dc095SDavid du Colombier     if (pbw->strm == 0)
374*593dc095SDavid du Colombier         return_error(gs_error_VMerror);
375*593dc095SDavid du Colombier     pbw->dev = (gx_device_psdf *)pdev;
376*593dc095SDavid du Colombier     pbw->memory = pdev->pdf_memory;
377*593dc095SDavid du Colombier     pdev->strm = pbw->strm;
378*593dc095SDavid du Colombier     code = psdf_begin_binary((gx_device_psdf *) pdev, pbw);
379*593dc095SDavid du Colombier     pdev->strm = save_strm;
380*593dc095SDavid du Colombier     pbw->target = NULL; /* We don't need target with cos_write_stream. */
381*593dc095SDavid du Colombier     return code;
382*593dc095SDavid du Colombier }
383*593dc095SDavid du Colombier 
3843ff48bf5SDavid du Colombier /* Begin writing the image data, setting up the dictionary and filters. */
3853ff48bf5SDavid du Colombier int
pdf_begin_image_data(gx_device_pdf * pdev,pdf_image_writer * piw,const gs_pixel_image_t * pim,const cos_value_t * pcsvalue,int alt_writer_index)3863ff48bf5SDavid du Colombier pdf_begin_image_data(gx_device_pdf * pdev, pdf_image_writer * piw,
387*593dc095SDavid du Colombier 		     const gs_pixel_image_t * pim, const cos_value_t *pcsvalue,
388*593dc095SDavid du Colombier 		     int alt_writer_index)
3893ff48bf5SDavid du Colombier {
390*593dc095SDavid du Colombier 
391*593dc095SDavid du Colombier     cos_stream_t *s = cos_stream_from_pipeline(piw->binary[alt_writer_index].strm);
392*593dc095SDavid du Colombier     cos_dict_t *pcd = cos_stream_dict(s);
3933ff48bf5SDavid du Colombier     int code = pdf_put_image_values(pcd, pdev, pim, piw->pin, pcsvalue);
3943ff48bf5SDavid du Colombier 
3953ff48bf5SDavid du Colombier     if (code >= 0)
396*593dc095SDavid du Colombier 	code = pdf_put_image_filters(pcd, pdev, &piw->binary[alt_writer_index], piw->pin);
3973ff48bf5SDavid du Colombier     if (code < 0) {
3983ff48bf5SDavid du Colombier 	if (!piw->pres)
3993ff48bf5SDavid du Colombier 	    COS_FREE(piw->data, "pdf_begin_image_data");
4003ff48bf5SDavid du Colombier 	piw->data = 0;
4013ff48bf5SDavid du Colombier     }
4023ff48bf5SDavid du Colombier     return code;
4033ff48bf5SDavid du Colombier }
4043ff48bf5SDavid du Colombier 
405*593dc095SDavid du Colombier /* Complete image data. */
406*593dc095SDavid du Colombier int
pdf_complete_image_data(gx_device_pdf * pdev,pdf_image_writer * piw,int data_h,int width,int bits_per_pixel)407*593dc095SDavid du Colombier pdf_complete_image_data(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h,
408*593dc095SDavid du Colombier 			int width, int bits_per_pixel)
409*593dc095SDavid du Colombier {
410*593dc095SDavid du Colombier     if (data_h != piw->height) {
411*593dc095SDavid du Colombier 	if (piw->binary[0].strm->procs.process == s_DCTE_template.process ||
412*593dc095SDavid du Colombier 	    piw->binary[0].strm->procs.process == s_PNGPE_template.process ) {
413*593dc095SDavid du Colombier 	    /* 	Since DCTE and PNGPE can't safely close with incomplete data,
414*593dc095SDavid du Colombier 		we add stub data to complete the stream.
415*593dc095SDavid du Colombier 	    */
416*593dc095SDavid du Colombier 	    int bytes_per_line = (width * bits_per_pixel + 7) / 8;
417*593dc095SDavid du Colombier 	    int lines_left = piw->height - data_h;
418*593dc095SDavid du Colombier 	    byte buf[256];
419*593dc095SDavid du Colombier 	    const uint lb = sizeof(buf);
420*593dc095SDavid du Colombier 	    int i, l, status;
421*593dc095SDavid du Colombier 	    uint ignore;
422*593dc095SDavid du Colombier 
423*593dc095SDavid du Colombier 	    memset(buf, 128, lb);
424*593dc095SDavid du Colombier 	    for (; lines_left; lines_left--)
425*593dc095SDavid du Colombier 		for (i = 0; i < piw->alt_writer_count; i++) {
426*593dc095SDavid du Colombier 		    for (l = bytes_per_line; l > 0; l -= lb)
427*593dc095SDavid du Colombier 			if ((status = sputs(piw->binary[i].strm, buf, min(l, lb),
428*593dc095SDavid du Colombier 					    &ignore)) < 0)
429*593dc095SDavid du Colombier 			    return_error(gs_error_ioerror);
430*593dc095SDavid du Colombier 		}
431*593dc095SDavid du Colombier 	}
432*593dc095SDavid du Colombier     }
433*593dc095SDavid du Colombier     return 0;
434*593dc095SDavid du Colombier }
435*593dc095SDavid du Colombier 
4363ff48bf5SDavid du Colombier /* Finish writing the binary image data. */
4373ff48bf5SDavid du Colombier int
pdf_end_image_binary(gx_device_pdf * pdev,pdf_image_writer * piw,int data_h)4383ff48bf5SDavid du Colombier pdf_end_image_binary(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h)
4393ff48bf5SDavid du Colombier {
440*593dc095SDavid du Colombier     int code, code1 = 0;
4413ff48bf5SDavid du Colombier 
442*593dc095SDavid du Colombier     if (piw->alt_writer_count > 2)
443*593dc095SDavid du Colombier 	code = pdf_choose_compression(piw, true);
444*593dc095SDavid du Colombier     else
445*593dc095SDavid du Colombier 	code = psdf_end_binary(&piw->binary[0]);
4463ff48bf5SDavid du Colombier     /* If the image ended prematurely, update the Height. */
4473ff48bf5SDavid du Colombier     if (data_h != piw->height)
448*593dc095SDavid du Colombier 	code1 = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
4493ff48bf5SDavid du Colombier 				      piw->pin->Height, data_h);
450*593dc095SDavid du Colombier     return code < 0 ? code : code1;
4513ff48bf5SDavid du Colombier }
4523ff48bf5SDavid du Colombier 
4533ff48bf5SDavid du Colombier /*
4543ff48bf5SDavid du Colombier  * Finish writing an image.  If in-line, write the BI/dict/ID/data/EI and
4553ff48bf5SDavid du Colombier  * return 1; if a resource, write the resource definition and return 0.
4563ff48bf5SDavid du Colombier  */
4573ff48bf5SDavid du Colombier int
pdf_end_write_image(gx_device_pdf * pdev,pdf_image_writer * piw)4583ff48bf5SDavid du Colombier pdf_end_write_image(gx_device_pdf * pdev, pdf_image_writer * piw)
4593ff48bf5SDavid du Colombier {
4603ff48bf5SDavid du Colombier     pdf_resource_t *pres = piw->pres;
4613ff48bf5SDavid du Colombier 
4623ff48bf5SDavid du Colombier     if (pres) {			/* image resource */
463*593dc095SDavid du Colombier 	cos_object_t *const pco = pres->object;
464*593dc095SDavid du Colombier 	cos_stream_t *const pcs = (cos_stream_t *)pco;
465*593dc095SDavid du Colombier 	cos_dict_t *named = piw->named;
466*593dc095SDavid du Colombier 	int code;
467*593dc095SDavid du Colombier 
468*593dc095SDavid du Colombier 	if (named) {
469*593dc095SDavid du Colombier 	    if (pdev->ForOPDFRead) {
470*593dc095SDavid du Colombier 		code = cos_dict_put_c_key_bool(named, "/.Global", true);
471*593dc095SDavid du Colombier 		if (code < 0)
472*593dc095SDavid du Colombier 		    return code;
4733ff48bf5SDavid du Colombier 	    }
474*593dc095SDavid du Colombier 	    /*
475*593dc095SDavid du Colombier 	     * This image was named by NI.  Copy any dictionary elements
476*593dc095SDavid du Colombier 	     * from the named dictionary to the image stream, and then
477*593dc095SDavid du Colombier 	     * associate the name with the stream.
478*593dc095SDavid du Colombier 	     */
479*593dc095SDavid du Colombier 	    code = cos_dict_move_all(cos_stream_dict(pcs), named);
480*593dc095SDavid du Colombier 	    if (code < 0)
481*593dc095SDavid du Colombier 		return code;
482*593dc095SDavid du Colombier 	    pres->named = true;
483*593dc095SDavid du Colombier 	    /*
484*593dc095SDavid du Colombier 	     * We need to make the entry in the name dictionary point to
485*593dc095SDavid du Colombier 	     * the stream (pcs) rather than the object created by NI (named).
486*593dc095SDavid du Colombier 	     * Unfortunately, we no longer know what dictionary to use.
487*593dc095SDavid du Colombier 	     * Instead, overwrite the latter with the former's contents,
488*593dc095SDavid du Colombier 	     * and change the only relevant pointer.
489*593dc095SDavid du Colombier 	     */
490*593dc095SDavid du Colombier 	    *(cos_object_t *)named = *pco;
491*593dc095SDavid du Colombier 	    pres->object = COS_OBJECT(named);
492*593dc095SDavid du Colombier 	} else if (!pres->named) { /* named objects are written at the end */
493*593dc095SDavid du Colombier 	    code = pdf_substitute_resource(pdev, &piw->pres, resourceXObject, NULL, false);
494*593dc095SDavid du Colombier 	    if (code < 0)
495*593dc095SDavid du Colombier 		return code;
496*593dc095SDavid du Colombier 	    /*  Warning : If the substituted image used alternate streams,
497*593dc095SDavid du Colombier 		its space in the pdev->streams.strm file won't be released. */
498*593dc095SDavid du Colombier 	    piw->pres->where_used |= pdev->used_mask;
499*593dc095SDavid du Colombier 	}
500*593dc095SDavid du Colombier 	code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", piw->pres);
501*593dc095SDavid du Colombier 	if (code < 0)
502*593dc095SDavid du Colombier 	    return code;
5033ff48bf5SDavid du Colombier 	return 0;
5043ff48bf5SDavid du Colombier     } else {			/* in-line image */
5053ff48bf5SDavid du Colombier 	stream *s = pdev->strm;
506*593dc095SDavid du Colombier 	uint KeyLength = pdev->KeyLength;
5073ff48bf5SDavid du Colombier 
5083ff48bf5SDavid du Colombier 	stream_puts(s, "BI\n");
5093ff48bf5SDavid du Colombier 	cos_stream_elements_write(piw->data, pdev);
5103ff48bf5SDavid du Colombier 	stream_puts(s, (pdev->binary_ok ? "ID " : "ID\n"));
511*593dc095SDavid du Colombier 	pdev->KeyLength = 0; /* Disable encryption for the inline image. */
5123ff48bf5SDavid du Colombier 	cos_stream_contents_write(piw->data, pdev);
513*593dc095SDavid du Colombier 	pdev->KeyLength = KeyLength;
5143ff48bf5SDavid du Colombier 	pprints1(s, "\nEI%s\n", piw->end_string);
5153ff48bf5SDavid du Colombier 	COS_FREE(piw->data, "pdf_end_write_image");
5163ff48bf5SDavid du Colombier 	return 1;
5173ff48bf5SDavid du Colombier     }
5183ff48bf5SDavid du Colombier }
5193ff48bf5SDavid du Colombier 
5203ff48bf5SDavid du Colombier /* ------ Copy data ------ */
5213ff48bf5SDavid du Colombier 
5223ff48bf5SDavid du Colombier /* Copy the data for a mask or monobit bitmap. */
5233ff48bf5SDavid du Colombier int
pdf_copy_mask_bits(stream * s,const byte * base,int sourcex,int raster,int w,int h,byte invert)5243ff48bf5SDavid du Colombier pdf_copy_mask_bits(stream *s, const byte *base, int sourcex, int raster,
5253ff48bf5SDavid du Colombier 		   int w, int h, byte invert)
5263ff48bf5SDavid du Colombier {
5273ff48bf5SDavid du Colombier     int yi;
5283ff48bf5SDavid du Colombier 
5293ff48bf5SDavid du Colombier     for (yi = 0; yi < h; ++yi) {
5303ff48bf5SDavid du Colombier 	const byte *data = base + yi * raster + (sourcex >> 3);
5313ff48bf5SDavid du Colombier 	int sbit = sourcex & 7;
5323ff48bf5SDavid du Colombier 
5333ff48bf5SDavid du Colombier 	if (sbit == 0) {
5343ff48bf5SDavid du Colombier 	    int nbytes = (w + 7) >> 3;
5353ff48bf5SDavid du Colombier 	    int i;
5363ff48bf5SDavid du Colombier 
5373ff48bf5SDavid du Colombier 	    for (i = 0; i < nbytes; ++data, ++i)
538*593dc095SDavid du Colombier 		sputc(s, (byte)(*data ^ invert));
5393ff48bf5SDavid du Colombier 	} else {
5403ff48bf5SDavid du Colombier 	    int wleft = w;
5413ff48bf5SDavid du Colombier 	    int rbit = 8 - sbit;
5423ff48bf5SDavid du Colombier 
5433ff48bf5SDavid du Colombier 	    for (; wleft + sbit > 8; ++data, wleft -= 8)
544*593dc095SDavid du Colombier 		sputc(s, (byte)(((*data << sbit) + (data[1] >> rbit)) ^ invert));
5453ff48bf5SDavid du Colombier 	    if (wleft > 0)
546*593dc095SDavid du Colombier 		sputc(s, (byte)(((*data << sbit) ^ invert) &
547*593dc095SDavid du Colombier 		      (byte) (0xff00 >> wleft)));
5483ff48bf5SDavid du Colombier 	}
5493ff48bf5SDavid du Colombier     }
5503ff48bf5SDavid du Colombier     return 0;
5513ff48bf5SDavid du Colombier }
5523ff48bf5SDavid du Colombier 
5533ff48bf5SDavid du Colombier /* Copy the data for a colored image (device pixels). */
5543ff48bf5SDavid du Colombier int
pdf_copy_color_bits(stream * s,const byte * base,int sourcex,int raster,int w,int h,int bytes_per_pixel)5553ff48bf5SDavid du Colombier pdf_copy_color_bits(stream *s, const byte *base, int sourcex, int raster,
5563ff48bf5SDavid du Colombier 		    int w, int h, int bytes_per_pixel)
5573ff48bf5SDavid du Colombier {
5583ff48bf5SDavid du Colombier     int yi;
5593ff48bf5SDavid du Colombier 
5603ff48bf5SDavid du Colombier     for (yi = 0; yi < h; ++yi) {
5613ff48bf5SDavid du Colombier 	uint ignore;
5623ff48bf5SDavid du Colombier 
5633ff48bf5SDavid du Colombier 	sputs(s, base + sourcex * bytes_per_pixel + yi * raster,
5643ff48bf5SDavid du Colombier 	      w * bytes_per_pixel, &ignore);
5653ff48bf5SDavid du Colombier     }
5663ff48bf5SDavid du Colombier     return 0;
5673ff48bf5SDavid du Colombier }
568*593dc095SDavid du Colombier 
569*593dc095SDavid du Colombier /* Choose image compression - auxiliary procs */
much_bigger__DL(long l1,long l2)570*593dc095SDavid du Colombier private inline bool much_bigger__DL(long l1, long l2)
571*593dc095SDavid du Colombier {
572*593dc095SDavid du Colombier     return l1 > 1024*1024 && l2 < l1 / 3;
573*593dc095SDavid du Colombier }
574*593dc095SDavid du Colombier private void
pdf_choose_compression_cos(pdf_image_writer * piw,cos_stream_t * s[2],bool force)575*593dc095SDavid du Colombier pdf_choose_compression_cos(pdf_image_writer *piw, cos_stream_t *s[2], bool force)
576*593dc095SDavid du Colombier {   /*	Assume s[0] is Flate, s[1] is DCT, s[2] is chooser. */
577*593dc095SDavid du Colombier     long l0, l1;
578*593dc095SDavid du Colombier     int k0, k1;
579*593dc095SDavid du Colombier 
580*593dc095SDavid du Colombier     l0 = cos_stream_length(s[0]);
581*593dc095SDavid du Colombier     l1 = cos_stream_length(s[1]);
582*593dc095SDavid du Colombier 
583*593dc095SDavid du Colombier     if (force && l0 <= l1)
584*593dc095SDavid du Colombier 	k0 = 1; /* Use Flate if it is not longer. */
585*593dc095SDavid du Colombier     else {
586*593dc095SDavid du Colombier 	k0 = s_compr_chooser__get_choice(
587*593dc095SDavid du Colombier 	    (stream_compr_chooser_state *)piw->binary[2].strm->state, force);
588*593dc095SDavid du Colombier 	if (k0 && l0 > 0 && l1 > 0)
589*593dc095SDavid du Colombier 	    k0--;
590*593dc095SDavid du Colombier 	else if (much_bigger__DL(l0, l1))
591*593dc095SDavid du Colombier 	    k0 = 0;
592*593dc095SDavid du Colombier 	else if (much_bigger__DL(l1, l0) || force)
593*593dc095SDavid du Colombier 	    k0 = 1;
594*593dc095SDavid du Colombier 	else
595*593dc095SDavid du Colombier 	   return;
596*593dc095SDavid du Colombier     }
597*593dc095SDavid du Colombier     k1 = 1 - k0;
598*593dc095SDavid du Colombier     s_close_filters(&piw->binary[k0].strm, piw->binary[k0].target);
599*593dc095SDavid du Colombier     s[k0]->cos_procs->release((cos_object_t *)s[k0], "pdf_image_choose_filter");
600*593dc095SDavid du Colombier     s[k0]->written = 1;
601*593dc095SDavid du Colombier     piw->binary[0].strm = piw->binary[k1].strm;
602*593dc095SDavid du Colombier     s_close_filters(&piw->binary[2].strm, piw->binary[2].target);
603*593dc095SDavid du Colombier     piw->binary[1].strm = piw->binary[2].strm = 0; /* for GC */
604*593dc095SDavid du Colombier     piw->binary[1].target = piw->binary[2].target = 0;
605*593dc095SDavid du Colombier     s[k1]->id = piw->pres->object->id;
606*593dc095SDavid du Colombier     piw->pres->object = (cos_object_t *)s[k1];
607*593dc095SDavid du Colombier     piw->data = s[k1];
608*593dc095SDavid du Colombier     if (piw->alt_writer_count > 3) {
609*593dc095SDavid du Colombier 	piw->binary[1] = piw->binary[3];
610*593dc095SDavid du Colombier 	piw->binary[3].strm = 0; /* for GC */
611*593dc095SDavid du Colombier 	piw->binary[3].target = 0;
612*593dc095SDavid du Colombier     }
613*593dc095SDavid du Colombier     piw->alt_writer_count -= 2;
614*593dc095SDavid du Colombier }
615*593dc095SDavid du Colombier 
616*593dc095SDavid du Colombier /* End binary with choosing image compression. */
617*593dc095SDavid du Colombier int
pdf_choose_compression(pdf_image_writer * piw,bool end_binary)618*593dc095SDavid du Colombier pdf_choose_compression(pdf_image_writer * piw, bool end_binary)
619*593dc095SDavid du Colombier {
620*593dc095SDavid du Colombier     cos_stream_t *s[2];
621*593dc095SDavid du Colombier     s[0] = cos_stream_from_pipeline(piw->binary[0].strm);
622*593dc095SDavid du Colombier     s[1] = cos_stream_from_pipeline(piw->binary[1].strm);
623*593dc095SDavid du Colombier     if (end_binary) {
624*593dc095SDavid du Colombier 	int status;
625*593dc095SDavid du Colombier 
626*593dc095SDavid du Colombier     	status = s_close_filters(&piw->binary[0].strm, piw->binary[0].target);
627*593dc095SDavid du Colombier 	if (status < 0)
628*593dc095SDavid du Colombier 	    return status;
629*593dc095SDavid du Colombier 	status = s_close_filters(&piw->binary[1].strm, piw->binary[1].target);
630*593dc095SDavid du Colombier 	if (status < 0)
631*593dc095SDavid du Colombier 	    return status;
632*593dc095SDavid du Colombier     }
633*593dc095SDavid du Colombier     pdf_choose_compression_cos(piw, s, end_binary);
634*593dc095SDavid du Colombier     return 0;
635*593dc095SDavid du Colombier }
636