~ubuntu-branches/ubuntu/vivid/ghostscript/vivid-security

« back to all changes in this revision

Viewing changes to devices/vector/gdevpdfj.c

  • Committer: Package Import Robot
  • Author(s): Till Kamppeter
  • Date: 2013-08-09 20:01:36 UTC
  • mfrom: (1.1.37)
  • Revision ID: package-import@ubuntu.com-20130809200136-amb6zrr7hnjb5jq9
Tags: 9.08~rc1~dfsg-0ubuntu1
* New upstream release
   - Ghostscript 9.08rc1.
   - We are using the system's liblcms2 and libopenjpeg now.
* debian/patches/020130401-852e545-pxl-xl-driver-produced-drawing-commands-without-setting-color-space.patch:
  Removed patch backported from upstream.
* debian/patches/ojdk-8007925+8007926.patch,
  debian/patches/ojdk-8007927.patch,
  debian/patches/ojdk-8007929.patch,
  debian/patches/ojdk-8009654.patch: Removed patches on build in liblcms2, we
  use the system's liblcms2 now.
* debian/patches/2001_docdir_fix_for_debian.patch: Manually updated to new
  upstream source code.
* debian/patches/2003_support_multiarch.patch: Refreshed with quilt.
* debian/control: Added build dependencies on liblcms2-dev and
  libopenjpeg-dev.
* debian/rules: Check for removed lcms2/ and openjpeg/ subdirectories in
  the repackaging check again, also set build options for shared liblcms2
  and libopenjpeg libraries.
* debian/rules: Makefile.in and configure.ac are in the root directory of
  the source now and do not need to get linked from base/. Also there is no
  gstoraster and gstopxl CUPS filter in the package any more and no
  "install-cups" make target any more.
* debian/control, debian/rules, debian/ghostscript-cups.install,
  debian/ghostscript-cups.ppd-updater: Removed the ghostscript-cups binary
  package. The files are now provided by cups-filters.
* debian/symbols.common: Updated for new upstream source. Applied patch
  which dpkg-gensymbols generated for debian/libgs9.symbols to this file.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2001-2012 Artifex Software, Inc.
 
2
   All Rights Reserved.
 
3
 
 
4
   This software is provided AS-IS with no warranty, either express or
 
5
   implied.
 
6
 
 
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.
 
10
 
 
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.
 
14
*/
 
15
 
 
16
 
 
17
/* Image-writing utilities for pdfwrite driver */
 
18
#include "memory_.h"
 
19
#include "gx.h"
 
20
#include "gserrors.h"
 
21
#include "gdevpdfx.h"
 
22
#include "gdevpdfg.h"
 
23
#include "gdevpdfo.h"
 
24
#include "gxcspace.h"
 
25
#include "gsiparm4.h"
 
26
#include "gdevpsds.h"
 
27
#include "spngpx.h"
 
28
#include <stdlib.h> /* for atoi */
 
29
 
 
30
#define CHECK(expr)\
 
31
  BEGIN if ((code = (expr)) < 0) return code; END
 
32
 
 
33
/* GC descriptors */
 
34
public_st_pdf_image_writer();
 
35
static ENUM_PTRS_WITH(pdf_image_writer_enum_ptrs, pdf_image_writer *piw)
 
36
     index -= 4;
 
37
     if (index < psdf_binary_writer_max_ptrs * piw->alt_writer_count) {
 
38
         gs_ptr_type_t ret =
 
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);
 
41
 
 
42
         if (ret == 0)          /* don't stop early */
 
43
             ENUM_RETURN(0);
 
44
         return ret;
 
45
    }
 
46
    return 0;
 
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);
 
51
ENUM_PTRS_END
 
52
static RELOC_PTRS_WITH(pdf_image_writer_reloc_ptrs, pdf_image_writer *piw)
 
53
{
 
54
    int i;
 
55
 
 
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));
 
59
    RELOC_VAR(piw->pres);
 
60
    RELOC_VAR(piw->data);
 
61
    RELOC_VAR(piw->named);
 
62
    RELOC_VAR(piw->pres_mask);
 
63
}
 
64
RELOC_PTRS_END
 
65
 
 
66
/* ---------------- Image stream dictionaries ---------------- */
 
67
 
 
68
const pdf_image_names_t pdf_image_names_full = {
 
69
    { PDF_COLOR_SPACE_NAMES },
 
70
    { PDF_FILTER_NAMES },
 
71
    PDF_IMAGE_PARAM_NAMES
 
72
};
 
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
 
77
};
 
78
 
 
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. */
 
82
static int
 
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)
 
88
{
 
89
    int num_components;
 
90
    float indexed_decode[2];
 
91
    const float *default_decode = NULL;
 
92
    int code;
 
93
 
 
94
    if (pcs) {
 
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;
 
102
        }
 
103
    } else
 
104
        num_components = 1;
 
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));
 
109
    {
 
110
        int i;
 
111
 
 
112
        for (i = 0; i < num_components * 2; ++i) {
 
113
            if (pim->Decode[i] !=
 
114
                (default_decode ? default_decode[i] : i & 1)
 
115
                )
 
116
                break;
 
117
        }
 
118
        if (i < num_components * 2) {
 
119
            cos_array_t *pca =
 
120
                cos_array_alloc(pdev, "pdf_put_pixel_image_values(decode)");
 
121
 
 
122
            if (pca == 0)
 
123
                return_error(gs_error_VMerror);
 
124
            if (pcs == NULL) {
 
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)));
 
128
            } else {
 
129
                for (i = 0; i < num_components * 2; ++i)
 
130
                    CHECK(cos_array_add_real(pca, pim->Decode[i]));
 
131
            }
 
132
            CHECK(cos_dict_put_c_key_object(pcd, pin->Decode,
 
133
                                            COS_OBJECT(pca)));
 
134
        }
 
135
    }
 
136
    if (pim->Interpolate) {
 
137
        if (pdev->PDFA != 0)
 
138
            emprintf(pdev->memory,
 
139
                     "PDFA doesn't allow images with Interpolate true.\n");
 
140
        else
 
141
            CHECK(cos_dict_put_c_strings(pcd, pin->Interpolate, "true"));
 
142
    }
 
143
    return 0;
 
144
}
 
145
int
 
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)
 
150
{
 
151
    const gs_color_space *pcs = pic->ColorSpace;
 
152
    int code;
 
153
 
 
154
    switch (pic->type->index) {
 
155
    case 1: {
 
156
        const gs_image1_t *pim = (const gs_image1_t *)pic;
 
157
 
 
158
        if (pim->ImageMask) {
 
159
            CHECK(cos_dict_put_c_strings(pcd, pin->ImageMask, "true"));
 
160
            pdev->procsets |= ImageB;
 
161
            pcs = NULL;
 
162
        }
 
163
    }
 
164
        break;
 
165
    case 3: {
 
166
        /*
 
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).
 
170
         */
 
171
        /*const gs_image3_t *pim = (const gs_image3_t *)pic;*/
 
172
 
 
173
        /* Masked images are only supported starting in PDF 1.3. */
 
174
        if (pdev->CompatibilityLevel < 1.3)
 
175
            return_error(gs_error_rangecheck);
 
176
    }
 
177
        break;
 
178
    case 4: {
 
179
        const gs_image4_t *pim = (const gs_image4_t *)pic;
 
180
        int num_components = gs_color_space_num_components(pcs);
 
181
        cos_array_t *pca;
 
182
        int i;
 
183
 
 
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)");
 
188
        if (pca == 0)
 
189
            return_error(gs_error_VMerror);
 
190
        for (i = 0; i < num_components; ++i) {
 
191
            int lo, hi;
 
192
 
 
193
            if (pim->MaskColor_is_range)
 
194
                lo = pim->MaskColor[i * 2], hi = pim->MaskColor[i * 2 + 1];
 
195
            else
 
196
                lo = hi = pim->MaskColor[i];
 
197
            CHECK(cos_array_add_int(pca, lo));
 
198
            CHECK(cos_array_add_int(pca, hi));
 
199
        }
 
200
        CHECK(cos_dict_put_c_key_object(pcd, "/Mask", COS_OBJECT(pca)));
 
201
    }
 
202
        break;
 
203
    default:
 
204
        return_error(gs_error_rangecheck);
 
205
    }
 
206
    return pdf_put_pixel_image_values(pcd, pdev, pic, pcs, pin, pcsvalue);
 
207
}
 
208
 
 
209
/* Store filters for an image. */
 
210
/* Currently this only saves parameters for CCITTFaxDecode. */
 
211
int
 
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)
 
215
{
 
216
    return pdf_put_filters(pcd, pdev, pbw->strm, &pin->filter_names);
 
217
}
 
218
 
 
219
/* ---------------- Image writing ---------------- */
 
220
 
 
221
/*
 
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.
 
225
 */
 
226
void
 
227
pdf_make_bitmap_matrix(gs_matrix * pmat, int x, int y, int w, int h,
 
228
                       int h_actual)
 
229
{
 
230
    pmat->xx = (float)w;
 
231
    pmat->xy = 0;
 
232
    pmat->yx = 0;
 
233
    pmat->yy = (float)(-h_actual);
 
234
    pmat->tx = (float)x;
 
235
    pmat->ty = (float)(y + h);
 
236
}
 
237
 
 
238
/*
 
239
 * Put out the gsave and matrix for an image.  y_scale adjusts the matrix
 
240
 * for images that end prematurely.
 
241
 */
 
242
void
 
243
pdf_put_image_matrix(gx_device_pdf * pdev, const gs_matrix * pmat,
 
244
                     floatp y_scale)
 
245
{
 
246
    gs_matrix imat = {1, 0, 0, 1, 0 ,0};
 
247
 
 
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");
 
251
}
 
252
 
 
253
/* Put out a reference to an image resource. */
 
254
int
 
255
pdf_do_image_by_id(gx_device_pdf * pdev, double scale,
 
256
             const gs_matrix * pimat, bool in_contents, gs_id id)
 
257
{
 
258
    /* fixme : in_contents is always true (there are no calls with false). */
 
259
    if (in_contents) {
 
260
        int code = pdf_open_contents(pdev, PDF_IN_STREAM);
 
261
 
 
262
        if (code < 0)
 
263
            return code;
 
264
    }
 
265
    if (pimat)
 
266
        pdf_put_image_matrix(pdev, pimat, scale);
 
267
    pprintld1(pdev->strm, "/R%ld Do\nQ\n", id);
 
268
    return 0;
 
269
}
 
270
int
 
271
pdf_do_image(gx_device_pdf * pdev, const pdf_resource_t * pres,
 
272
             const gs_matrix * pimat, bool in_contents)
 
273
{
 
274
    /* fixme : call pdf_do_image_by_id when pimam == NULL. */
 
275
    double scale = 1;
 
276
 
 
277
    if (pimat) {
 
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;
 
281
    }
 
282
    return pdf_do_image_by_id(pdev, scale, pimat, in_contents, pdf_resource_id(pres));
 
283
}
 
284
 
 
285
/* ------ Begin / finish ------ */
 
286
 
 
287
/* Initialize image writer. */
 
288
void
 
289
pdf_image_writer_init(pdf_image_writer * piw)
 
290
{
 
291
    memset(piw, 0, sizeof(*piw));
 
292
    piw->alt_writer_count = 1; /* Default. */
 
293
}
 
294
 
 
295
/*
 
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
 
298
 * NI pdfmark.
 
299
 */
 
300
int
 
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,
 
303
                      bool in_line)
 
304
{
 
305
    /* Patch pdev->strm so the right stream gets into the writer. */
 
306
    stream *save_strm = pdev->strm;
 
307
    cos_stream_t *data;
 
308
    bool mask = (piw->data != NULL);
 
309
    int alt_stream_index = (!mask ? 0 : piw->alt_writer_count);
 
310
    int code;
 
311
 
 
312
    if (in_line) {
 
313
        piw->pres = 0;
 
314
        piw->pin = &pdf_image_names_short;
 
315
        data = cos_stream_alloc(pdev, "pdf_begin_image_data");
 
316
        if (data == 0)
 
317
            return_error(gs_error_VMerror);
 
318
        piw->end_string = " Q";
 
319
        piw->named = 0;         /* must have named == 0 */
 
320
    } else {
 
321
        pdf_x_object_t *pxo;
 
322
        cos_stream_t *pcos;
 
323
        pdf_resource_t *pres;
 
324
 
 
325
        /*
 
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.
 
328
         */
 
329
        code = pdf_alloc_resource(pdev, resourceXObject, id, &pres,
 
330
                                  (named ? named->id : -1L));
 
331
        if (code < 0)
 
332
            return code;
 
333
        *(mask ? &piw->pres_mask : &piw->pres) = pres;
 
334
        cos_become(pres->object, cos_type_stream);
 
335
        pres->rid = id;
 
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",
 
340
                                     "/Image"));
 
341
        pxo->width = w;
 
342
        pxo->height = h;
 
343
        /* Initialize data_height for the benefit of copy_{mono,color}. */
 
344
        pxo->data_height = h;
 
345
        data = pcos;
 
346
        if (!mask)
 
347
            piw->named = named;
 
348
    }
 
349
    pdev->strm = pdev->streams.strm;
 
350
    pdev->strm = cos_write_stream_alloc(data, pdev, "pdf_begin_write_image");
 
351
    if (pdev->strm == 0)
 
352
        return_error(gs_error_VMerror);
 
353
    if (!mask)
 
354
        piw->data = data;
 
355
    piw->height = h;
 
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;
 
359
    return code;
 
360
}
 
361
 
 
362
/*
 
363
 *  Make alternative stream for image compression choice.
 
364
 */
 
365
int
 
366
pdf_make_alt_stream(gx_device_pdf * pdev, psdf_binary_writer * pbw)
 
367
{
 
368
    stream *save_strm = pdev->strm;
 
369
    cos_stream_t *pcos = cos_stream_alloc(pdev, "pdf_make_alt_stream");
 
370
    int code;
 
371
 
 
372
    if (pcos == 0)
 
373
        return_error(gs_error_VMerror);
 
374
    pcos->id = 0;
 
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");
 
377
    if (pbw->strm == 0)
 
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. */
 
385
    return code;
 
386
}
 
387
 
 
388
/* Begin writing the image data, setting up the dictionary and filters. */
 
389
int
 
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)
 
393
{
 
394
 
 
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);
 
398
 
 
399
    if (code >= 0)
 
400
        code = pdf_put_image_filters(pcd, pdev, &piw->binary[alt_writer_index], piw->pin);
 
401
    if (code < 0) {
 
402
        if (!piw->pres)
 
403
            COS_FREE(piw->data, "pdf_begin_image_data");
 
404
        piw->data = 0;
 
405
    }
 
406
    return code;
 
407
}
 
408
 
 
409
/* Complete image data. */
 
410
int
 
411
pdf_complete_image_data(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h,
 
412
                        int width, int bits_per_pixel)
 
413
{
 
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.
 
419
            */
 
420
            int bytes_per_line = (width * bits_per_pixel + 7) / 8;
 
421
            int lines_left = piw->height - data_h;
 
422
            byte buf[256];
 
423
            const uint lb = sizeof(buf);
 
424
            int i, l;
 
425
            uint ignore;
 
426
 
 
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),
 
432
                                            &ignore)) < 0)
 
433
                            return_error(gs_error_ioerror);
 
434
                }
 
435
        }
 
436
    }
 
437
    return 0;
 
438
}
 
439
 
 
440
/* Finish writing the binary image data. */
 
441
int
 
442
pdf_end_image_binary(gx_device_pdf *pdev, pdf_image_writer *piw, int data_h)
 
443
{
 
444
    int code, code1 = 0;
 
445
 
 
446
    if (piw->alt_writer_count > 2)
 
447
        code = pdf_choose_compression(piw, true);
 
448
    else
 
449
        code = psdf_end_binary(&piw->binary[0]);
 
450
    /* If the image ended prematurely, update the Height. */
 
451
    if (data_h != piw->height) {
 
452
        char data[255];
 
453
        int OutHeight;
 
454
        cos_value_t *value;
 
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.
 
466
             */
 
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);
 
471
        } else {
 
472
 
 
473
            code1 = cos_dict_put_c_key_int(cos_stream_dict(piw->data),
 
474
                                      piw->pin->Height, data_h);
 
475
        }
 
476
    }
 
477
    return code < 0 ? code : code1;
 
478
}
 
479
 
 
480
/*
 
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.
 
483
 */
 
484
int
 
485
pdf_end_write_image(gx_device_pdf * pdev, pdf_image_writer * piw)
 
486
{
 
487
    pdf_resource_t *pres = piw->pres;
 
488
 
 
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;
 
493
        int code;
 
494
 
 
495
        if (named) {
 
496
            if (pdev->ForOPDFRead) {
 
497
                code = cos_dict_put_c_key_bool(named, "/.Global", true);
 
498
                if (code < 0)
 
499
                    return code;
 
500
            }
 
501
            /*
 
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.
 
505
             */
 
506
            code = cos_dict_move_all(cos_stream_dict(pcs), named);
 
507
            if (code < 0)
 
508
                return code;
 
509
            pres->named = true;
 
510
            /*
 
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.
 
516
             */
 
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;
 
523
 
 
524
                code = pdf_substitute_resource(pdev, &piw->pres, resourceXObject, NULL, false);
 
525
                if (code < 0)
 
526
                    return code;
 
527
 
 
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.
 
531
                 */
 
532
                pxo = (pdf_x_object_t *)piw->pres;
 
533
                pxo->height = height;
 
534
                pxo->width = width;
 
535
            } else {
 
536
                pdf_reserve_object_id(pdev, piw->pres, gs_no_id);
 
537
            }
 
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;
 
541
        }
 
542
        code = pdf_add_resource(pdev, pdev->substream_Resources, "/XObject", piw->pres);
 
543
        if (code < 0)
 
544
            return code;
 
545
        return 0;
 
546
    } else {                    /* in-line image */
 
547
        stream *s = pdev->strm;
 
548
        uint KeyLength = pdev->KeyLength;
 
549
 
 
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");
 
558
        return 1;
 
559
    }
 
560
}
 
561
 
 
562
/* ------ Copy data ------ */
 
563
 
 
564
/* Copy the data for a mask or monobit bitmap. */
 
565
int
 
566
pdf_copy_mask_bits(stream *s, const byte *base, int sourcex, int raster,
 
567
                   int w, int h, byte invert)
 
568
{
 
569
    int yi;
 
570
 
 
571
    for (yi = 0; yi < h; ++yi) {
 
572
        const byte *data = base + yi * raster + (sourcex >> 3);
 
573
        int sbit = sourcex & 7;
 
574
 
 
575
        if (sbit == 0) {
 
576
            int nbytes = (w + 7) >> 3;
 
577
            int i;
 
578
 
 
579
            for (i = 0; i < nbytes; ++data, ++i)
 
580
                sputc(s, (byte)(*data ^ invert));
 
581
        } else {
 
582
            int wleft = w;
 
583
            int rbit = 8 - sbit;
 
584
 
 
585
            for (; wleft + sbit > 8; ++data, wleft -= 8)
 
586
                sputc(s, (byte)(((*data << sbit) + (data[1] >> rbit)) ^ invert));
 
587
            if (wleft > 0)
 
588
                sputc(s, (byte)(((*data << sbit) ^ invert) &
 
589
                      (byte) (0xff00 >> wleft)));
 
590
        }
 
591
    }
 
592
    return 0;
 
593
}
 
594
 
 
595
/* Copy the data for a colored image (device pixels). */
 
596
int
 
597
pdf_copy_color_bits(stream *s, const byte *base, int sourcex, int raster,
 
598
                    int w, int h, int bytes_per_pixel)
 
599
{
 
600
    int yi;
 
601
 
 
602
    for (yi = 0; yi < h; ++yi) {
 
603
        uint ignore;
 
604
 
 
605
        sputs(s, base + sourcex * bytes_per_pixel + yi * raster,
 
606
              w * bytes_per_pixel, &ignore);
 
607
    }
 
608
    return 0;
 
609
}
 
610
 
 
611
/* Choose image compression - auxiliary procs */
 
612
static inline bool much_bigger__DL(long l1, long l2)
 
613
{
 
614
    return l1 > 1024*1024 && l2 < l1 / 3;
 
615
}
 
616
static void
 
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. */
 
619
    long l0, l1;
 
620
    int k0, k1;
 
621
 
 
622
    l0 = cos_stream_length(s[0]);
 
623
    l1 = cos_stream_length(s[1]);
 
624
 
 
625
    if ((force && l0 <= l1) || l1 == -1)
 
626
        k0 = 1; /* Use Flate if it is not longer. Or if the DCT failed */
 
627
    else {
 
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)
 
631
            k0--;
 
632
        else if (much_bigger__DL(l0, l1))
 
633
            k0 = 0;
 
634
        else if (much_bigger__DL(l1, l0) || force)
 
635
            k0 = 1;
 
636
        else
 
637
           return;
 
638
    }
 
639
    k1 = 1 - k0;
 
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");
 
642
    s[k0]->written = 1;
 
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];
 
649
    piw->data = 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;
 
654
    }
 
655
    piw->alt_writer_count -= 2;
 
656
}
 
657
 
 
658
/* End binary with choosing image compression. */
 
659
int
 
660
pdf_choose_compression(pdf_image_writer * piw, bool end_binary)
 
661
{
 
662
    cos_stream_t *s[2];
 
663
    s[0] = cos_stream_from_pipeline(piw->binary[0].strm);
 
664
    s[1] = cos_stream_from_pipeline(piw->binary[1].strm);
 
665
    if (end_binary) {
 
666
        int status;
 
667
 
 
668
        status = s_close_filters(&piw->binary[0].strm, piw->binary[0].target);
 
669
        if (status < 0)
 
670
            return_error(gs_error_ioerror);
 
671
        status = s_close_filters(&piw->binary[1].strm, piw->binary[1].target);
 
672
        if (status < 0)
 
673
            s[1]->length = -1;
 
674
    }
 
675
    pdf_choose_compression_cos(piw, s, end_binary);
 
676
    return 0;
 
677
}