1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
4
This software is provided AS-IS with no warranty, either express or
7
This software is distributed under license and may not be copied,
8
modified or distributed except as expressly authorized under the terms
9
of the license contained in the file LICENSE in this distribution.
11
Refer to licensing information at http://www.artifex.com or contact
12
Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134, San Rafael,
13
CA 94903, U.S.A., +1(415)492-9861, for further information.
17
/* Image-writing utilities for pdfwrite driver */
28
#include <stdlib.h> /* for atoi */
31
BEGIN if ((code = (expr)) < 0) return code; END
34
public_st_pdf_image_writer();
35
static ENUM_PTRS_WITH(pdf_image_writer_enum_ptrs, pdf_image_writer *piw)
37
if (index < psdf_binary_writer_max_ptrs * piw->alt_writer_count) {
39
ENUM_USING(st_psdf_binary_writer, &piw->binary[index / psdf_binary_writer_max_ptrs],
40
sizeof(psdf_binary_writer), index % psdf_binary_writer_max_ptrs);
42
if (ret == 0) /* don't stop early */
47
case 0: ENUM_RETURN(piw->pres);
48
case 1: ENUM_RETURN(piw->data);
49
case 2: ENUM_RETURN(piw->named);
50
case 3: ENUM_RETURN(piw->pres_mask);
52
static RELOC_PTRS_WITH(pdf_image_writer_reloc_ptrs, pdf_image_writer *piw)
56
for (i = 0; i < piw->alt_writer_count; ++i)
57
RELOC_USING(st_psdf_binary_writer, &piw->binary[i],
58
sizeof(psdf_binary_writer));
61
RELOC_VAR(piw->named);
62
RELOC_VAR(piw->pres_mask);
66
/* ---------------- Image stream dictionaries ---------------- */
68
const pdf_image_names_t pdf_image_names_full = {
69
{ PDF_COLOR_SPACE_NAMES },
73
const pdf_image_names_t pdf_image_names_short = {
74
{ PDF_COLOR_SPACE_NAMES_SHORT },
75
{ PDF_FILTER_NAMES_SHORT },
76
PDF_IMAGE_PARAM_NAMES_SHORT
79
/* Store the values of image parameters other than filters. */
80
/* pdev is used only for updating procsets. */
81
/* pcsvalue is not used for masks. */
83
pdf_put_pixel_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
84
const gs_pixel_image_t *pim,
85
const gs_color_space *pcs,
86
const pdf_image_names_t *pin,
87
const cos_value_t *pcsvalue)
90
float indexed_decode[2];
91
const float *default_decode = NULL;
95
CHECK(cos_dict_put_c_key(pcd, pin->ColorSpace, pcsvalue));
96
pdf_color_space_procsets(pdev, pcs);
97
num_components = gs_color_space_num_components(pcs);
98
if (gs_color_space_get_index(pcs) == gs_color_space_index_Indexed) {
99
indexed_decode[0] = 0;
100
indexed_decode[1] = (float)((1 << pim->BitsPerComponent) - 1);
101
default_decode = indexed_decode;
105
CHECK(cos_dict_put_c_key_int(pcd, pin->Width, pim->Width));
106
CHECK(cos_dict_put_c_key_int(pcd, pin->Height, pim->Height));
107
CHECK(cos_dict_put_c_key_int(pcd, pin->BitsPerComponent,
108
pim->BitsPerComponent));
112
for (i = 0; i < num_components * 2; ++i) {
113
if (pim->Decode[i] !=
114
(default_decode ? default_decode[i] : i & 1)
118
if (i < num_components * 2) {
120
cos_array_alloc(pdev, "pdf_put_pixel_image_values(decode)");
123
return_error(gs_error_VMerror);
125
/* 269-01.ps sets /Decode[0 100] with a mask image. */
126
for (i = 0; i < num_components * 2; ++i)
127
CHECK(cos_array_add_real(pca, min(pim->Decode[i], 1)));
129
for (i = 0; i < num_components * 2; ++i)
130
CHECK(cos_array_add_real(pca, pim->Decode[i]));
132
CHECK(cos_dict_put_c_key_object(pcd, pin->Decode,
136
if (pim->Interpolate) {
138
emprintf(pdev->memory,
139
"PDFA doesn't allow images with Interpolate true.\n");
141
CHECK(cos_dict_put_c_strings(pcd, pin->Interpolate, "true"));
146
pdf_put_image_values(cos_dict_t *pcd, gx_device_pdf *pdev,
147
const gs_pixel_image_t *pic,
148
const pdf_image_names_t *pin,
149
const cos_value_t *pcsvalue)
151
const gs_color_space *pcs = pic->ColorSpace;
154
switch (pic->type->index) {
156
const gs_image1_t *pim = (const gs_image1_t *)pic;
158
if (pim->ImageMask) {
159
CHECK(cos_dict_put_c_strings(pcd, pin->ImageMask, "true"));
160
pdev->procsets |= ImageB;
167
* Clients must treat this as a special case: they must call
168
* pdf_put_image_values for the MaskDict separately, and must
169
* add the Mask entry to the main image stream (dictionary).
171
/*const gs_image3_t *pim = (const gs_image3_t *)pic;*/
173
/* Masked images are only supported starting in PDF 1.3. */
174
if (pdev->CompatibilityLevel < 1.3)
175
return_error(gs_error_rangecheck);
179
const gs_image4_t *pim = (const gs_image4_t *)pic;
180
int num_components = gs_color_space_num_components(pcs);
184
/* Masked images are only supported starting in PDF 1.3. */
185
if (pdev->CompatibilityLevel < 1.3)
186
break; /* Will convert into an imagemask with a pattern color. */
187
pca = cos_array_alloc(pdev, "pdf_put_image_values(mask)");
189
return_error(gs_error_VMerror);
190
for (i = 0; i < num_components; ++i) {
193
if (pim->MaskColor_is_range)
194
lo = pim->MaskColor[i * 2], hi = pim->MaskColor[i * 2 + 1];
196
lo = hi = pim->MaskColor[i];
197
CHECK(cos_array_add_int(pca, lo));
198
CHECK(cos_array_add_int(pca, hi));
200
CHECK(cos_dict_put_c_key_object(pcd, "/Mask", COS_OBJECT(pca)));
204
return_error(gs_error_rangecheck);
206
return pdf_put_pixel_image_values(pcd, pdev, pic, pcs, pin, pcsvalue);
209
/* Store filters for an image. */
210
/* Currently this only saves parameters for CCITTFaxDecode. */
212
pdf_put_image_filters(cos_dict_t *pcd, gx_device_pdf *pdev,
213
const psdf_binary_writer * pbw,
214
const pdf_image_names_t *pin)
216
return pdf_put_filters(pcd, pdev, pbw->strm, &pin->filter_names);
219
/* ---------------- Image writing ---------------- */
222
* Fill in the image parameters for a device space bitmap.
223
* PDF images are always specified top-to-bottom.
224
* data_h is the actual number of data rows, which may be less than h.
227
pdf_make_bitmap_matrix(gs_matrix * pmat, int x, int y, int w, int h,
233
pmat->yy = (float)(-h_actual);
235
pmat->ty = (float)(y + h);
239
* Put out the gsave and matrix for an image. y_scale adjusts the matrix
240
* for images that end prematurely.
243
pdf_put_image_matrix(gx_device_pdf * pdev, const gs_matrix * pmat,
246
gs_matrix imat = {1, 0, 0, 1, 0 ,0};
248
gs_matrix_translate(pmat, 0.0, 1.0 - y_scale, &imat);
249
gs_matrix_scale(&imat, 1.0, y_scale, &imat);
250
pdf_put_matrix(pdev, "q ", &imat, "cm\n");
253
/* Put out a reference to an image resource. */
255
pdf_do_image_by_id(gx_device_pdf * pdev, double scale,
256
const gs_matrix * pimat, bool in_contents, gs_id id)
258
/* fixme : in_contents is always true (there are no calls with false). */
260
int code = pdf_open_contents(pdev, PDF_IN_STREAM);
266
pdf_put_image_matrix(pdev, pimat, scale);
267
pprintld1(pdev->strm, "/R%ld Do\nQ\n", id);
271
pdf_do_image(gx_device_pdf * pdev, const pdf_resource_t * pres,
272
const gs_matrix * pimat, bool in_contents)
274
/* fixme : call pdf_do_image_by_id when pimam == NULL. */
278
/* Adjust the matrix to account for short images. */
279
const pdf_x_object_t *const pxo = (const pdf_x_object_t *)pres;
280
scale = (double)pxo->data_height / pxo->height;
282
return pdf_do_image_by_id(pdev, scale, pimat, in_contents, pdf_resource_id(pres));
285
/* ------ Begin / finish ------ */
287
/* Initialize image writer. */
289
pdf_image_writer_init(pdf_image_writer * piw)
291
memset(piw, 0, sizeof(*piw));
292
piw->alt_writer_count = 1; /* Default. */
296
* Begin writing an image, creating the resource if not in-line, and setting
297
* up the binary writer. If pnamed != 0, it is a stream object created by a
301
pdf_begin_write_image(gx_device_pdf * pdev, pdf_image_writer * piw,
302
gx_bitmap_id id, int w, int h, cos_dict_t *named,
305
/* Patch pdev->strm so the right stream gets into the writer. */
306
stream *save_strm = pdev->strm;
308
bool mask = (piw->data != NULL);
309
int alt_stream_index = (!mask ? 0 : piw->alt_writer_count);
314
piw->pin = &pdf_image_names_short;
315
data = cos_stream_alloc(pdev, "pdf_begin_image_data");
317
return_error(gs_error_VMerror);
318
piw->end_string = " Q";
319
piw->named = 0; /* must have named == 0 */
323
pdf_resource_t *pres;
326
* Note that if named != 0, there are two objects with the same id
327
* while the image is being accumulated: named, and pres->object.
329
code = pdf_alloc_resource(pdev, resourceXObject, id, &pres,
330
(named ? named->id : -1L));
333
*(mask ? &piw->pres_mask : &piw->pres) = pres;
334
cos_become(pres->object, cos_type_stream);
336
piw->pin = &pdf_image_names_full;
337
pxo = (pdf_x_object_t *)pres;
338
pcos = (cos_stream_t *)pxo->object;
339
CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype",
343
/* Initialize data_height for the benefit of copy_{mono,color}. */
344
pxo->data_height = h;
349
pdev->strm = pdev->streams.strm;
350
pdev->strm = cos_write_stream_alloc(data, pdev, "pdf_begin_write_image");
352
return_error(gs_error_VMerror);
356
code = psdf_begin_binary((gx_device_psdf *) pdev, &piw->binary[alt_stream_index]);
357
piw->binary[alt_stream_index].target = NULL; /* We don't need target with cos_write_stream. */
358
pdev->strm = save_strm;
363
* Make alternative stream for image compression choice.
366
pdf_make_alt_stream(gx_device_pdf * pdev, psdf_binary_writer * pbw)
368
stream *save_strm = pdev->strm;
369
cos_stream_t *pcos = cos_stream_alloc(pdev, "pdf_make_alt_stream");
373
return_error(gs_error_VMerror);
375
CHECK(cos_dict_put_c_strings(cos_stream_dict(pcos), "/Subtype", "/Image"));
376
pbw->strm = cos_write_stream_alloc(pcos, pdev, "pdf_make_alt_stream");
378
return_error(gs_error_VMerror);
379
pbw->dev = (gx_device_psdf *)pdev;
380
pbw->memory = pdev->pdf_memory;
381
pdev->strm = pbw->strm;
382
code = psdf_begin_binary((gx_device_psdf *) pdev, pbw);
383
pdev->strm = save_strm;
384
pbw->target = NULL; /* We don't need target with cos_write_stream. */
388
/* Begin writing the image data, setting up the dictionary and filters. */
390
pdf_begin_image_data(gx_device_pdf * pdev, pdf_image_writer * piw,
391
const gs_pixel_image_t * pim, const cos_value_t *pcsvalue,
392
int alt_writer_index)
395
cos_stream_t *s = cos_stream_from_pipeline(piw->binary[alt_writer_index].strm);
396
cos_dict_t *pcd = cos_stream_dict(s);
397
int code = pdf_put_image_values(pcd, pdev, pim, piw->pin, pcsvalue);
400
code = pdf_put_image_filters(pcd, pdev, &piw->binary[alt_writer_index], piw->pin);
403
COS_FREE(piw->data, "pdf_begin_image_data");
409
/* Complete image data. */
411
pdf_complete_image_data(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h,
412
int width, int bits_per_pixel)
414
if (data_h != piw->height) {
415
if (piw->binary[0].strm->procs.process == s_DCTE_template.process ||
416
piw->binary[0].strm->procs.process == s_PNGPE_template.process ) {
417
/* Since DCTE and PNGPE can't safely close with incomplete data,
418
we add stub data to complete the stream.
420
int bytes_per_line = (width * bits_per_pixel + 7) / 8;
421
int lines_left = piw->height - data_h;
423
const uint lb = sizeof(buf);
427
memset(buf, 128, lb);
428
for (; lines_left; lines_left--)
429
for (i = 0; i < piw->alt_writer_count; i++) {
430
for (l = bytes_per_line; l > 0; l -= lb)
431
if ((sputs(piw->binary[i].strm, buf, min(l, lb),
433
return_error(gs_error_ioerror);
440
/* Finish writing the binary image data. */
442
pdf_end_image_binary(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h)
446
if (piw->alt_writer_count > 2)
447
code = pdf_choose_compression(piw, true);
449
code = psdf_end_binary(&piw->binary[0]);
450
/* If the image ended prematurely, update the Height. */
451
if (data_h != piw->height) {
455
value = (cos_value_t *)cos_dict_find(cos_stream_dict(piw->data),
456
(const byte *)piw->pin->Height, strlen(piw->pin->Height));
457
if (!value || value->contents.chars.size > 255)
458
return(gs_error_rangecheck);
459
strncpy((char *)&data, (const char *)value->contents.chars.data, value->contents.chars.size);
460
data[value->contents.chars.size] = 0x00;
461
OutHeight = atoi(data);
462
if (OutHeight != piw->height) {
463
/* Looks like we are downsampling, so we can't use the number
464
* of rows of data actually received, we must divide those by
465
* the sampling factor.
467
float factor = (float)OutHeight / piw->height;
468
OutHeight = (int)(factor * data_h);
469
code1 = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
470
piw->pin->Height, OutHeight);
473
code1 = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
474
piw->pin->Height, data_h);
477
return code < 0 ? code : code1;
481
* Finish writing an image. If in-line, write the BI/dict/ID/data/EI and
482
* return 1; if a resource, write the resource definition and return 0.
485
pdf_end_write_image(gx_device_pdf * pdev, pdf_image_writer * piw)
487
pdf_resource_t *pres = piw->pres;
489
if (pres) { /* image resource */
490
cos_object_t *const pco = pres->object;
491
cos_stream_t *const pcs = (cos_stream_t *)pco;
492
cos_dict_t *named = piw->named;
496
if (pdev->ForOPDFRead) {
497
code = cos_dict_put_c_key_bool(named, "/.Global", true);
502
* This image was named by NI. Copy any dictionary elements
503
* from the named dictionary to the image stream, and then
504
* associate the name with the stream.
506
code = cos_dict_move_all(cos_stream_dict(pcs), named);
511
* We need to make the entry in the name dictionary point to
512
* the stream (pcs) rather than the object created by NI (named).
513
* Unfortunately, we no longer know what dictionary to use.
514
* Instead, overwrite the latter with the former's contents,
515
* and change the only relevant pointer.
517
*(cos_object_t *)named = *pco;
518
pres->object = COS_OBJECT(named);
519
} else if (!pres->named) { /* named objects are written at the end */
520
if (pdev->DetectDuplicateImages) {
521
pdf_x_object_t *pxo = (pdf_x_object_t *)piw->pres;
522
int height = pxo->height, width = pxo->width;
524
code = pdf_substitute_resource(pdev, &piw->pres, resourceXObject, NULL, false);
528
/* These values are related to the image matrix and should *not* be
529
* substituted if we found a duplicate image, or the matrix calculation
530
* will be incorrect! This only seems to matter for the PCL interpreter.
532
pxo = (pdf_x_object_t *)piw->pres;
533
pxo->height = height;
536
pdf_reserve_object_id(pdev, piw->pres, gs_no_id);
538
/* Warning : If the substituted image used alternate streams,
539
its space in the pdev->streams.strm file won't be released. */
540
piw->pres->where_used |= pdev->used_mask;
542
code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", piw->pres);
546
} else { /* in-line image */
547
stream *s = pdev->strm;
548
uint KeyLength = pdev->KeyLength;
550
stream_puts(s, "BI\n");
551
cos_stream_elements_write(piw->data, pdev);
552
stream_puts(s, (pdev->binary_ok ? "ID " : "ID\n"));
553
pdev->KeyLength = 0; /* Disable encryption for the inline image. */
554
cos_stream_contents_write(piw->data, pdev);
555
pdev->KeyLength = KeyLength;
556
pprints1(s, "\nEI%s\n", piw->end_string);
557
COS_FREE(piw->data, "pdf_end_write_image");
562
/* ------ Copy data ------ */
564
/* Copy the data for a mask or monobit bitmap. */
566
pdf_copy_mask_bits(stream *s, const byte *base, int sourcex, int raster,
567
int w, int h, byte invert)
571
for (yi = 0; yi < h; ++yi) {
572
const byte *data = base + yi * raster + (sourcex >> 3);
573
int sbit = sourcex & 7;
576
int nbytes = (w + 7) >> 3;
579
for (i = 0; i < nbytes; ++data, ++i)
580
sputc(s, (byte)(*data ^ invert));
585
for (; wleft + sbit > 8; ++data, wleft -= 8)
586
sputc(s, (byte)(((*data << sbit) + (data[1] >> rbit)) ^ invert));
588
sputc(s, (byte)(((*data << sbit) ^ invert) &
589
(byte) (0xff00 >> wleft)));
595
/* Copy the data for a colored image (device pixels). */
597
pdf_copy_color_bits(stream *s, const byte *base, int sourcex, int raster,
598
int w, int h, int bytes_per_pixel)
602
for (yi = 0; yi < h; ++yi) {
605
sputs(s, base + sourcex * bytes_per_pixel + yi * raster,
606
w * bytes_per_pixel, &ignore);
611
/* Choose image compression - auxiliary procs */
612
static inline bool much_bigger__DL(long l1, long l2)
614
return l1 > 1024*1024 && l2 < l1 / 3;
617
pdf_choose_compression_cos(pdf_image_writer *piw, cos_stream_t *s[2], bool force)
618
{ /* Assume s[0] is Flate, s[1] is DCT, s[2] is chooser. */
622
l0 = cos_stream_length(s[0]);
623
l1 = cos_stream_length(s[1]);
625
if ((force && l0 <= l1) || l1 == -1)
626
k0 = 1; /* Use Flate if it is not longer. Or if the DCT failed */
628
k0 = s_compr_chooser__get_choice(
629
(stream_compr_chooser_state *)piw->binary[2].strm->state, force);
630
if (k0 && l0 > 0 && l1 > 0)
632
else if (much_bigger__DL(l0, l1))
634
else if (much_bigger__DL(l1, l0) || force)
640
s_close_filters(&piw->binary[k0].strm, piw->binary[k0].target);
641
s[k0]->cos_procs->release((cos_object_t *)s[k0], "pdf_image_choose_filter");
643
piw->binary[0].strm = piw->binary[k1].strm;
644
s_close_filters(&piw->binary[2].strm, piw->binary[2].target);
645
piw->binary[1].strm = piw->binary[2].strm = 0; /* for GC */
646
piw->binary[1].target = piw->binary[2].target = 0;
647
s[k1]->id = piw->pres->object->id;
648
piw->pres->object = (cos_object_t *)s[k1];
650
if (piw->alt_writer_count > 3) {
651
piw->binary[1] = piw->binary[3];
652
piw->binary[3].strm = 0; /* for GC */
653
piw->binary[3].target = 0;
655
piw->alt_writer_count -= 2;
658
/* End binary with choosing image compression. */
660
pdf_choose_compression(pdf_image_writer * piw, bool end_binary)
663
s[0] = cos_stream_from_pipeline(piw->binary[0].strm);
664
s[1] = cos_stream_from_pipeline(piw->binary[1].strm);
668
status = s_close_filters(&piw->binary[0].strm, piw->binary[0].target);
670
return_error(gs_error_ioerror);
671
status = s_close_filters(&piw->binary[1].strm, piw->binary[1].target);
675
pdf_choose_compression_cos(piw, s, end_binary);