Subversion Repositories planix.SVN

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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: gdevpdfj.c,v 1.49 2005/09/06 13:47:10 leonardo Exp $ */
18
/* Image-writing utilities for pdfwrite driver */
19
#include "memory_.h"
20
#include "string_.h"
21
#include "gx.h"
22
#include "gserrors.h"
23
#include "gdevpdfx.h"
24
#include "gdevpdfg.h"
25
#include "gdevpdfo.h"
26
#include "gxcspace.h"
27
#include "gsiparm4.h"
28
#include "gdevpsds.h"
29
#include "spngpx.h"
30
 
31
#define CHECK(expr)\
32
  BEGIN if ((code = (expr)) < 0) return code; END
33
 
34
/* GC descriptors */
35
public_st_pdf_image_writer();
36
private ENUM_PTRS_WITH(pdf_image_writer_enum_ptrs, pdf_image_writer *piw)
37
     index -= 4;
38
     if (index < psdf_binary_writer_max_ptrs * piw->alt_writer_count) {
39
	 gs_ptr_type_t ret =
40
	     ENUM_USING(st_psdf_binary_writer, &piw->binary[index / psdf_binary_writer_max_ptrs],
41
			sizeof(psdf_binary_writer), index % psdf_binary_writer_max_ptrs);
42
 
43
	 if (ret == 0)		/* don't stop early */
44
	     ENUM_RETURN(0);
45
	 return ret;
46
    }
47
    return 0;
48
case 0: ENUM_RETURN(piw->pres);
49
case 1: ENUM_RETURN(piw->data);
50
case 2: ENUM_RETURN(piw->named);
51
case 3: ENUM_RETURN(piw->pres_mask);
52
ENUM_PTRS_END
53
private RELOC_PTRS_WITH(pdf_image_writer_reloc_ptrs, pdf_image_writer *piw)
54
{
55
    int i;
56
 
57
    for (i = 0; i < piw->alt_writer_count; ++i)
58
	RELOC_USING(st_psdf_binary_writer, &piw->binary[i],
59
		    sizeof(psdf_binary_writer));
60
    RELOC_VAR(piw->pres);
61
    RELOC_VAR(piw->data);
62
    RELOC_VAR(piw->named);
63
    RELOC_VAR(piw->pres_mask);
64
}
65
RELOC_PTRS_END
66
 
67
/* ---------------- Image stream dictionaries ---------------- */
68
 
69
const pdf_image_names_t pdf_image_names_full = {
70
    { PDF_COLOR_SPACE_NAMES },
71
    { PDF_FILTER_NAMES },
72
    PDF_IMAGE_PARAM_NAMES
73
};
74
const pdf_image_names_t pdf_image_names_short = {
75
    { PDF_COLOR_SPACE_NAMES_SHORT },
76
    { PDF_FILTER_NAMES_SHORT },
77
    PDF_IMAGE_PARAM_NAMES_SHORT
78
};
79
 
80
/* Store the values of image parameters other than filters. */
81
/* pdev is used only for updating procsets. */
82
/* pcsvalue is not used for masks. */
83
private int
84
pdf_put_pixel_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
85
			   const gs_pixel_image_t *pim,
86
			   const gs_color_space *pcs,
87
			   const pdf_image_names_t *pin,
88
			   const cos_value_t *pcsvalue)
89
{
90
    int num_components;
91
    float indexed_decode[2];
92
    const float *default_decode = NULL;
93
    int code;
94
 
95
    if (pcs) {
96
	CHECK(cos_dict_put_c_key(pcd, pin->ColorSpace, pcsvalue));
97
	pdf_color_space_procsets(pdev, pcs);
98
	num_components = gs_color_space_num_components(pcs);
99
	if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
100
	    indexed_decode[0] = 0;
101
	    indexed_decode[1] = (float)((1 << pim->BitsPerComponent) - 1);
102
	    default_decode = indexed_decode;
103
	}
104
    } else
105
	num_components = 1;
106
    CHECK(cos_dict_put_c_key_int(pcd, pin->Width, pim->Width));
107
    CHECK(cos_dict_put_c_key_int(pcd, pin->Height, pim->Height));
108
    CHECK(cos_dict_put_c_key_int(pcd, pin->BitsPerComponent,
109
				 pim->BitsPerComponent));
110
    {
111
	int i;
112
 
113
	for (i = 0; i < num_components * 2; ++i) {
114
	    if (pim->Decode[i] !=
115
		(default_decode ? default_decode[i] : i & 1)
116
		)
117
		break;
118
	}
119
	if (i < num_components * 2) {
120
	    cos_array_t *pca =
121
		cos_array_alloc(pdev, "pdf_put_pixel_image_values(decode)");
122
 
123
	    if (pca == 0)
124
		return_error(gs_error_VMerror);
125
	    if (pcs == NULL) {
126
		/* 269-01.ps sets /Decode[0 100] with a mask image. */
127
		for (i = 0; i < num_components * 2; ++i)
128
		    CHECK(cos_array_add_real(pca, min(pim->Decode[i], 1)));
129
	    } else {
130
		for (i = 0; i < num_components * 2; ++i)
131
		    CHECK(cos_array_add_real(pca, pim->Decode[i]));
132
	    }
133
	    CHECK(cos_dict_put_c_key_object(pcd, pin->Decode,
134
					    COS_OBJECT(pca)));
135
	}
136
    }
137
    if (pim->Interpolate)
138
	CHECK(cos_dict_put_c_strings(pcd, pin->Interpolate, "true"));
139
    return 0;
140
}
141
int
142
pdf_put_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
143
		     const gs_pixel_image_t *pic,
144
		     const pdf_image_names_t *pin,
145
		     const cos_value_t *pcsvalue)
146
{
147
    const gs_color_space *pcs = pic->ColorSpace;
148
    int code;
149
 
150
    switch (pic->type->index) {
151
    case 1: {
152
	const gs_image1_t *pim = (const gs_image1_t *)pic;
153
 
154
	if (pim->ImageMask) {
155
	    CHECK(cos_dict_put_c_strings(pcd, pin->ImageMask, "true"));
156
	    pdev->procsets |= ImageB;
157
	    pcs = NULL;
158
	}
159
    }
160
	break;
161
    case 3: {
162
	/*
163
	 * Clients must treat this as a special case: they must call
164
	 * pdf_put_image_values for the MaskDict separately, and must
165
	 * add the Mask entry to the main image stream (dictionary).
166
	 */
167
	/*const gs_image3_t *pim = (const gs_image3_t *)pic;*/
168
 
169
	/* Masked images are only supported starting in PDF 1.3. */
170
	if (pdev->CompatibilityLevel < 1.3)
171
	    return_error(gs_error_rangecheck);
172
    }
173
	break;
174
    case 4: {
175
	const gs_image4_t *pim = (const gs_image4_t *)pic;
176
	int num_components = gs_color_space_num_components(pcs);
177
	cos_array_t *pca;
178
	int i;
179
 
180
	/* Masked images are only supported starting in PDF 1.3. */
181
	if (pdev->CompatibilityLevel < 1.3)
182
	    break; /* Will convert into an imagemask with a pattern color. */
183
	pca = cos_array_alloc(pdev, "pdf_put_image_values(mask)");
184
	if (pca == 0)
185
	    return_error(gs_error_VMerror);
186
	for (i = 0; i < num_components; ++i) {
187
	    int lo, hi;
188
 
189
	    if (pim->MaskColor_is_range)
190
		lo = pim->MaskColor[i * 2], hi = pim->MaskColor[i * 2 + 1];
191
	    else
192
		lo = hi = pim->MaskColor[i];
193
	    CHECK(cos_array_add_int(pca, lo));
194
	    CHECK(cos_array_add_int(pca, hi));
195
	}
196
	CHECK(cos_dict_put_c_key_object(pcd, "/Mask", COS_OBJECT(pca)));
197
    }
198
	break;
199
    default:
200
	return_error(gs_error_rangecheck);
201
    }
202
    return pdf_put_pixel_image_values(pcd, pdev, pic, pcs, pin, pcsvalue);
203
}
204
 
205
/* Store filters for an image. */
206
/* Currently this only saves parameters for CCITTFaxDecode. */
207
int
208
pdf_put_image_filters(cos_dict_t *pcd, gx_device_pdf *pdev,
209
		      const psdf_binary_writer * pbw,
210
		      const pdf_image_names_t *pin)
211
{
212
    return pdf_put_filters(pcd, pdev, pbw->strm, &pin->filter_names);
213
}
214
 
215
/* ---------------- Image writing ---------------- */
216
 
217
/*
218
 * Fill in the image parameters for a device space bitmap.
219
 * PDF images are always specified top-to-bottom.
220
 * data_h is the actual number of data rows, which may be less than h.
221
 */
222
void
223
pdf_make_bitmap_matrix(gs_matrix * pmat, int x, int y, int w, int h,
224
		       int h_actual)
225
{
226
    pmat->xx = (float)w;
227
    pmat->xy = 0;
228
    pmat->yx = 0;
229
    pmat->yy = (float)(-h_actual);
230
    pmat->tx = (float)x;
231
    pmat->ty = (float)(y + h);
232
}
233
 
234
/*
235
 * Put out the gsave and matrix for an image.  y_scale adjusts the matrix
236
 * for images that end prematurely.
237
 */
238
void
239
pdf_put_image_matrix(gx_device_pdf * pdev, const gs_matrix * pmat,
240
		     floatp y_scale)
241
{
242
    gs_matrix imat;
243
 
244
    gs_matrix_translate(pmat, 0.0, 1.0 - y_scale, &imat);
245
    gs_matrix_scale(&imat, 1.0, y_scale, &imat);
246
    pdf_put_matrix(pdev, "q ", &imat, "cm\n");
247
}
248
 
249
/* Put out a reference to an image resource. */
250
int
251
pdf_do_image_by_id(gx_device_pdf * pdev, double scale,
252
	     const gs_matrix * pimat, bool in_contents, gs_id id)
253
{
254
    /* fixme : in_contents is always true (there are no calls with false). */
255
    if (in_contents) {
256
	int code = pdf_open_contents(pdev, PDF_IN_STREAM);
257
 
258
	if (code < 0)
259
	    return code;
260
    }
261
    if (pimat)
262
	pdf_put_image_matrix(pdev, pimat, scale);
263
    pprintld1(pdev->strm, "/R%ld Do\nQ\n", id);
264
    return pdf_register_charproc_resource(pdev, id, resourceXObject);
265
}
266
int
267
pdf_do_image(gx_device_pdf * pdev, const pdf_resource_t * pres,
268
	     const gs_matrix * pimat, bool in_contents)
269
{
270
    /* fixme : call pdf_do_image_by_id when pimam == NULL. */
271
    double scale = 1;
272
 
273
    if (pimat) {
274
	/* Adjust the matrix to account for short images. */
275
	const pdf_x_object_t *const pxo = (const pdf_x_object_t *)pres;
276
	scale = (double)pxo->data_height / pxo->height;
277
    }
278
    return pdf_do_image_by_id(pdev, scale, pimat, in_contents, pdf_resource_id(pres));
279
}
280
 
281
/* ------ Begin / finish ------ */
282
 
283
/* Initialize image writer. */
284
void
285
pdf_image_writer_init(pdf_image_writer * piw)
286
{
287
    memset(piw, 0, sizeof(*piw));
288
    piw->alt_writer_count = 1; /* Default. */
289
}
290
 
291
/*
292
 * Begin writing an image, creating the resource if not in-line, and setting
293
 * up the binary writer.  If pnamed != 0, it is a stream object created by a
294
 * NI pdfmark.
295
 */
296
int
297
pdf_begin_write_image(gx_device_pdf * pdev, pdf_image_writer * piw,
298
		      gx_bitmap_id id, int w, int h, cos_dict_t *named,
299
		      bool in_line)
300
{
301
    /* Patch pdev->strm so the right stream gets into the writer. */
302
    stream *save_strm = pdev->strm;
303
    cos_stream_t *data;
304
    bool mask = (piw->data != NULL);
305
    int alt_stream_index = (!mask ? 0 : piw->alt_writer_count);
306
    int code;
307
 
308
    if (in_line) {
309
	piw->pres = 0;
310
	piw->pin = &pdf_image_names_short;
311
	data = cos_stream_alloc(pdev, "pdf_begin_image_data");
312
	if (data == 0)
313
	    return_error(gs_error_VMerror);
314
	piw->end_string = " Q";
315
	piw->named = 0;		/* must have named == 0 */
316
    } else {
317
	pdf_x_object_t *pxo;
318
	cos_stream_t *pcos;
319
	pdf_resource_t *pres;
320
 
321
	/*
322
	 * Note that if named != 0, there are two objects with the same id
323
	 * while the image is being accumulated: named, and pres->object.
324
	 */
325
	code = pdf_alloc_resource(pdev, resourceXObject, id, &pres,
326
				  (named ? named->id : -1L));
327
	if (code < 0)
328
	    return code;
329
	*(mask ? &piw->pres_mask : &piw->pres) = pres;
330
	cos_become(pres->object, cos_type_stream);
331
	pres->rid = id;
332
	piw->pin = &pdf_image_names_full;
333
	pxo = (pdf_x_object_t *)pres;
334
	pcos = (cos_stream_t *)pxo->object;
335
	CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype",
336
				     "/Image"));
337
	pxo->width = w;
338
	pxo->height = h;
339
	/* Initialize data_height for the benefit of copy_{mono,color}. */
340
	pxo->data_height = h;
341
	data = pcos;
342
	if (!mask)
343
	    piw->named = named;
344
    }
345
    pdev->strm = pdev->streams.strm;
346
    pdev->strm = cos_write_stream_alloc(data, pdev, "pdf_begin_write_image");
347
    if (pdev->strm == 0)
348
	return_error(gs_error_VMerror);
349
    if (!mask)
350
	piw->data = data;
351
    piw->height = h;
352
    code = psdf_begin_binary((gx_device_psdf *) pdev, &piw->binary[alt_stream_index]);
353
    piw->binary[alt_stream_index].target = NULL; /* We don't need target with cos_write_stream. */
354
    pdev->strm = save_strm;
355
    return code;
356
}
357
 
358
/*
359
 *  Make alternative stream for image compression choice.
360
 */
361
int
362
pdf_make_alt_stream(gx_device_pdf * pdev, psdf_binary_writer * pbw)
363
{
364
    stream *save_strm = pdev->strm;
365
    cos_stream_t *pcos = cos_stream_alloc(pdev, "pdf_make_alt_stream");
366
    int code;
367
 
368
    if (pcos == 0)
369
        return_error(gs_error_VMerror);
370
    pcos->id = 0;
371
    CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype", "/Image"));
372
    pbw->strm = cos_write_stream_alloc(pcos, pdev, "pdf_make_alt_stream");
373
    if (pbw->strm == 0)
374
        return_error(gs_error_VMerror);
375
    pbw->dev = (gx_device_psdf *)pdev;
376
    pbw->memory = pdev->pdf_memory;
377
    pdev->strm = pbw->strm;
378
    code = psdf_begin_binary((gx_device_psdf *) pdev, pbw);
379
    pdev->strm = save_strm;
380
    pbw->target = NULL; /* We don't need target with cos_write_stream. */
381
    return code;
382
}
383
 
384
/* Begin writing the image data, setting up the dictionary and filters. */
385
int
386
pdf_begin_image_data(gx_device_pdf * pdev, pdf_image_writer * piw,
387
		     const gs_pixel_image_t * pim, const cos_value_t *pcsvalue,
388
		     int alt_writer_index)
389
{
390
 
391
    cos_stream_t *s = cos_stream_from_pipeline(piw->binary[alt_writer_index].strm);
392
    cos_dict_t *pcd = cos_stream_dict(s);
393
    int code = pdf_put_image_values(pcd, pdev, pim, piw->pin, pcsvalue);
394
 
395
    if (code >= 0)
396
	code = pdf_put_image_filters(pcd, pdev, &piw->binary[alt_writer_index], piw->pin);
397
    if (code < 0) {
398
	if (!piw->pres)
399
	    COS_FREE(piw->data, "pdf_begin_image_data");
400
	piw->data = 0;
401
    }
402
    return code;
403
}
404
 
405
/* Complete image data. */
406
int
407
pdf_complete_image_data(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h,
408
			int width, int bits_per_pixel)
409
{
410
    if (data_h != piw->height) {
411
	if (piw->binary[0].strm->procs.process == s_DCTE_template.process || 
412
	    piw->binary[0].strm->procs.process == s_PNGPE_template.process ) {
413
	    /* 	Since DCTE and PNGPE can't safely close with incomplete data,
414
		we add stub data to complete the stream.
415
	    */
416
	    int bytes_per_line = (width * bits_per_pixel + 7) / 8;
417
	    int lines_left = piw->height - data_h;
418
	    byte buf[256];
419
	    const uint lb = sizeof(buf);
420
	    int i, l, status;
421
	    uint ignore;
422
 
423
	    memset(buf, 128, lb);
424
	    for (; lines_left; lines_left--) 
425
		for (i = 0; i < piw->alt_writer_count; i++) {
426
		    for (l = bytes_per_line; l > 0; l -= lb)
427
			if ((status = sputs(piw->binary[i].strm, buf, min(l, lb), 
428
					    &ignore)) < 0)
429
			    return_error(gs_error_ioerror);
430
		}
431
	}
432
    }
433
    return 0;
434
}
435
 
436
/* Finish writing the binary image data. */
437
int
438
pdf_end_image_binary(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h)
439
{
440
    int code, code1 = 0;
441
 
442
    if (piw->alt_writer_count > 2)
443
	code = pdf_choose_compression(piw, true);
444
    else
445
	code = psdf_end_binary(&piw->binary[0]);
446
    /* If the image ended prematurely, update the Height. */
447
    if (data_h != piw->height)
448
	code1 = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
449
				      piw->pin->Height, data_h);
450
    return code < 0 ? code : code1;
451
}
452
 
453
/*
454
 * Finish writing an image.  If in-line, write the BI/dict/ID/data/EI and
455
 * return 1; if a resource, write the resource definition and return 0.
456
 */
457
int
458
pdf_end_write_image(gx_device_pdf * pdev, pdf_image_writer * piw)
459
{
460
    pdf_resource_t *pres = piw->pres;
461
 
462
    if (pres) {			/* image resource */
463
	cos_object_t *const pco = pres->object;
464
	cos_stream_t *const pcs = (cos_stream_t *)pco;
465
	cos_dict_t *named = piw->named;
466
	int code;
467
 
468
	if (named) {
469
	    if (pdev->ForOPDFRead) {
470
		code = cos_dict_put_c_key_bool(named, "/.Global", true);
471
		if (code < 0)
472
		    return code;
473
	    }
474
	    /*
475
	     * This image was named by NI.  Copy any dictionary elements
476
	     * from the named dictionary to the image stream, and then
477
	     * associate the name with the stream.
478
	     */
479
	    code = cos_dict_move_all(cos_stream_dict(pcs), named);
480
	    if (code < 0)
481
		return code;
482
	    pres->named = true;
483
	    /*
484
	     * We need to make the entry in the name dictionary point to
485
	     * the stream (pcs) rather than the object created by NI (named).
486
	     * Unfortunately, we no longer know what dictionary to use.
487
	     * Instead, overwrite the latter with the former's contents,
488
	     * and change the only relevant pointer.
489
	     */
490
	    *(cos_object_t *)named = *pco;
491
	    pres->object = COS_OBJECT(named);
492
	} else if (!pres->named) { /* named objects are written at the end */
493
	    code = pdf_substitute_resource(pdev, &piw->pres, resourceXObject, NULL, false);
494
	    if (code < 0)
495
		return code;
496
	    /*  Warning : If the substituted image used alternate streams,
497
		its space in the pdev->streams.strm file won't be released. */
498
	    piw->pres->where_used |= pdev->used_mask;
499
	}
500
	code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", piw->pres);
501
	if (code < 0)
502
	    return code;
503
	return 0;
504
    } else {			/* in-line image */
505
	stream *s = pdev->strm;
506
	uint KeyLength = pdev->KeyLength;
507
 
508
	stream_puts(s, "BI\n");
509
	cos_stream_elements_write(piw->data, pdev);
510
	stream_puts(s, (pdev->binary_ok ? "ID " : "ID\n"));
511
	pdev->KeyLength = 0; /* Disable encryption for the inline image. */
512
	cos_stream_contents_write(piw->data, pdev);
513
	pdev->KeyLength = KeyLength;
514
	pprints1(s, "\nEI%s\n", piw->end_string);
515
	COS_FREE(piw->data, "pdf_end_write_image");
516
	return 1;
517
    }
518
}
519
 
520
/* ------ Copy data ------ */
521
 
522
/* Copy the data for a mask or monobit bitmap. */
523
int
524
pdf_copy_mask_bits(stream *s, const byte *base, int sourcex, int raster,
525
		   int w, int h, byte invert)
526
{
527
    int yi;
528
 
529
    for (yi = 0; yi < h; ++yi) {
530
	const byte *data = base + yi * raster + (sourcex >> 3);
531
	int sbit = sourcex & 7;
532
 
533
	if (sbit == 0) {
534
	    int nbytes = (w + 7) >> 3;
535
	    int i;
536
 
537
	    for (i = 0; i < nbytes; ++data, ++i)
538
		sputc(s, (byte)(*data ^ invert));
539
	} else {
540
	    int wleft = w;
541
	    int rbit = 8 - sbit;
542
 
543
	    for (; wleft + sbit > 8; ++data, wleft -= 8)
544
		sputc(s, (byte)(((*data << sbit) + (data[1] >> rbit)) ^ invert));
545
	    if (wleft > 0)
546
		sputc(s, (byte)(((*data << sbit) ^ invert) &
547
		      (byte) (0xff00 >> wleft)));
548
	}
549
    }
550
    return 0;
551
}
552
 
553
/* Copy the data for a colored image (device pixels). */
554
int
555
pdf_copy_color_bits(stream *s, const byte *base, int sourcex, int raster,
556
		    int w, int h, int bytes_per_pixel)
557
{
558
    int yi;
559
 
560
    for (yi = 0; yi < h; ++yi) {
561
	uint ignore;
562
 
563
	sputs(s, base + sourcex * bytes_per_pixel + yi * raster,
564
	      w * bytes_per_pixel, &ignore);
565
    }
566
    return 0;
567
}
568
 
569
/* Choose image compression - auxiliary procs */
570
private inline bool much_bigger__DL(long l1, long l2)
571
{
572
    return l1 > 1024*1024 && l2 < l1 / 3;
573
}
574
private void
575
pdf_choose_compression_cos(pdf_image_writer *piw, cos_stream_t *s[2], bool force)
576
{   /*	Assume s[0] is Flate, s[1] is DCT, s[2] is chooser. */
577
    long l0, l1;
578
    int k0, k1;
579
 
580
    l0 = cos_stream_length(s[0]);
581
    l1 = cos_stream_length(s[1]);
582
 
583
    if (force && l0 <= l1)
584
	k0 = 1; /* Use Flate if it is not longer. */
585
    else {
586
	k0 = s_compr_chooser__get_choice(
587
	    (stream_compr_chooser_state *)piw->binary[2].strm->state, force);
588
	if (k0 && l0 > 0 && l1 > 0)
589
	    k0--;
590
	else if (much_bigger__DL(l0, l1))
591
	    k0 = 0; 
592
	else if (much_bigger__DL(l1, l0) || force)
593
	    k0 = 1; 
594
	else
595
	   return;
596
    }
597
    k1 = 1 - k0;
598
    s_close_filters(&piw->binary[k0].strm, piw->binary[k0].target);
599
    s[k0]->cos_procs->release((cos_object_t *)s[k0], "pdf_image_choose_filter");
600
    s[k0]->written = 1;
601
    piw->binary[0].strm = piw->binary[k1].strm;
602
    s_close_filters(&piw->binary[2].strm, piw->binary[2].target);
603
    piw->binary[1].strm = piw->binary[2].strm = 0; /* for GC */
604
    piw->binary[1].target = piw->binary[2].target = 0;
605
    s[k1]->id = piw->pres->object->id;
606
    piw->pres->object = (cos_object_t *)s[k1];
607
    piw->data = s[k1];
608
    if (piw->alt_writer_count > 3) {
609
	piw->binary[1] = piw->binary[3];
610
	piw->binary[3].strm = 0; /* for GC */
611
	piw->binary[3].target = 0;
612
    }
613
    piw->alt_writer_count -= 2;
614
}
615
 
616
/* End binary with choosing image compression. */
617
int
618
pdf_choose_compression(pdf_image_writer * piw, bool end_binary)
619
{
620
    cos_stream_t *s[2];
621
    s[0] = cos_stream_from_pipeline(piw->binary[0].strm);
622
    s[1] = cos_stream_from_pipeline(piw->binary[1].strm);
623
    if (end_binary) {
624
	int status;
625
 
626
    	status = s_close_filters(&piw->binary[0].strm, piw->binary[0].target);
627
	if (status < 0)
628
	    return status;
629
	status = s_close_filters(&piw->binary[1].strm, piw->binary[1].target);
630
	if (status < 0)
631
	    return status;
632
    }
633
    pdf_choose_compression_cos(piw, s, end_binary);
634
    return 0;
635
}