Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpdfb.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2024 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.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* Low-level bitmap image handling for PDF-writing driver */
18
#include "string_.h"
19
#include "gx.h"
20
#include "gserrors.h"
21
#include "gdevpdfx.h"
22
#include "gdevpdfg.h"
23
#include "gdevpdfo.h"                /* for data stream */
24
#include "gxcspace.h"
25
#include "gxdcolor.h"
26
#include "gxpcolor.h"
27
#include "gxhldevc.h"
28
#include "gxchar.h"
29
#include "gdevpdtf.h"                /* Required to include gdevpdti.h */
30
#include "gdevpdti.h"                /* For pdf_charproc_x_offset */
31
#include "gsptype1.h"
32
#include "gdevpdtt.h"
33
34
/* We need this color space type for constructing temporary color spaces. */
35
extern const gs_color_space_type gs_color_space_type_Indexed;
36
37
/* ---------------- Utilities ---------------- */
38
39
/* Fill in the image parameters for a bitmap image. */
40
static void
41
pdf_make_bitmap_image(gs_image_t * pim, int x, int y, int w, int h)
42
1.81M
{
43
1.81M
    pim->Width = w;
44
1.81M
    pim->Height = h;
45
1.81M
    pdf_make_bitmap_matrix(&pim->ImageMatrix, x, y, w, h, h);
46
1.81M
}
47
48
/* ---------------- Driver procedures ---------------- */
49
50
/* Copy a mask bitmap.  for_pattern = -1 means put the image in-line, */
51
/* 1 means put the image in a resource. */
52
static int
53
pdf_copy_mask_data(gx_device_pdf * pdev, const byte * base, int sourcex,
54
                   int raster, gx_bitmap_id id, int x, int y, int w, int h,
55
                   gs_image_t *pim, pdf_image_writer *piw,
56
                   int for_pattern)
57
0
{
58
0
    uint64_t nbytes;
59
0
    int code;
60
0
    const byte *row_base;
61
0
    int row_step;
62
0
    bool in_line;
63
64
0
    gs_image_t_init_mask(pim, true);
65
0
    pdf_make_bitmap_image(pim, x, y, w, h);
66
0
    nbytes = ((uint64_t)w * h + 7) / 8;
67
68
0
    if (for_pattern) {
69
        /*
70
         * Patterns must be emitted in order of increasing user Y, i.e.,
71
         * the opposite of PDF's standard image order.
72
         */
73
0
        row_base = base + (h - 1) * raster;
74
0
        row_step = -raster;
75
0
        in_line = for_pattern < 0;
76
0
    } else {
77
0
        row_base = base;
78
0
        row_step = raster;
79
0
        in_line = nbytes < pdev->MaxInlineImageSize;
80
0
        pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
81
        /*
82
         * Check whether we've already made an XObject resource for this
83
         * image.
84
         */
85
0
        if (id != gx_no_bitmap_id) {
86
0
            piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
87
0
            if (piw->pres)
88
0
                return 0;
89
0
        }
90
0
    }
91
    /*
92
     * We have to be able to control whether to put Pattern images in line,
93
     * to avoid trying to create an XObject resource while we're in the
94
     * middle of writing a Pattern resource.
95
     */
96
0
    if (for_pattern < 0)
97
0
        stream_puts(pdev->strm, "q ");
98
0
    pdf_image_writer_init(piw);
99
0
    pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
100
0
    if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
101
0
        (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
102
0
                                            &piw->binary[0],
103
0
                                            (gs_pixel_image_t *)pim, in_line)) < 0 ||
104
0
        (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
105
0
                                     NULL, 0)) < 0
106
0
        )
107
0
        return code;
108
0
    pdf_copy_mask_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h, 0);
109
0
    pdf_end_image_binary(pdev, piw, piw->height);
110
0
    return pdf_end_write_image(pdev, piw);
111
0
}
112
113
static void
114
set_image_color(gx_device_pdf *pdev, gx_color_index c)
115
0
{
116
0
    pdf_set_pure_color(pdev, c, &pdev->saved_fill_color,
117
0
                        &pdev->fill_used_process_color,
118
0
                        &psdf_set_fill_color_commands);
119
0
    if (!pdev->HaveStrokeColor)
120
0
        pdf_set_pure_color(pdev, c, &pdev->saved_stroke_color,
121
0
                            &pdev->stroke_used_process_color,
122
0
                            &psdf_set_stroke_color_commands);
123
0
}
124
125
static int
126
pdf_copy_mono(gx_device_pdf *pdev,
127
              const byte *base, int sourcex, int raster, gx_bitmap_id id,
128
              int x, int y, int w, int h, gx_color_index zero,
129
              gx_color_index one, const gx_clip_path *pcpath)
130
1.81M
{
131
1.81M
    int code;
132
1.81M
    gs_color_space *pcs = NULL;
133
1.81M
    cos_value_t cs_value;
134
1.81M
    cos_value_t *pcsvalue;
135
1.81M
    byte palette[ARCH_SIZEOF_COLOR_INDEX * 2];
136
1.81M
    gs_image_t image;
137
1.81M
    pdf_image_writer writer;
138
1.81M
    pdf_stream_position_t ipos;
139
1.81M
    pdf_resource_t *pres = 0;
140
1.81M
    byte invert = 0;
141
1.81M
    bool in_line = false, char_proc_begun = false;
142
1.81M
    gs_show_enum *show_enum = (gs_show_enum *)pdev->pte;
143
1.81M
    int x_offset, y_offset;
144
1.81M
    double width;
145
146
    /* Update clipping. */
147
1.81M
    if (pdf_must_put_clip_path(pdev, pcpath)) {
148
30
        code = pdf_open_page(pdev, PDF_IN_STREAM);
149
30
        if (code < 0)
150
0
            return code;
151
30
        code = pdf_put_clip_path(pdev, pcpath);
152
30
        if (code < 0)
153
0
            return code;
154
30
    }
155
    /* We have 3 cases: mask, inverse mask, and solid. */
156
1.81M
    if (zero == gx_no_color_index) {
157
1.81M
        if (one == gx_no_color_index)
158
0
            return 0;
159
        /* If a mask has an id, assume it's a character. */
160
1.81M
        if (id != gx_no_bitmap_id && sourcex == 0 && show_enum) {
161
1.81M
            pdf_char_proc_t *pcp;
162
163
1.81M
            if (show_enum->use_wxy_float)
164
0
                pdev->char_width.x = show_enum->wxy_float.x;
165
1.81M
            else
166
1.81M
                pdev->char_width.x = fixed2float(show_enum->wxy.x);
167
1.81M
            pres = pdf_find_resource_by_gs_id(pdev, resourceCharProc, id);
168
1.81M
            if (pres == 0) {        /* Define the character in an embedded font. */
169
134k
                gs_image_t_init_mask(&image, false);
170
134k
                invert = 0xff;
171
134k
                x_offset = x - (int)show_enum->pgs->current_point.x;
172
134k
                y_offset = y - (int)show_enum->pgs->current_point.y;
173
134k
                x -= x_offset;
174
134k
                y -= y_offset;
175
134k
                y -= h;
176
134k
                pdf_make_bitmap_image(&image, x, y, w, h);
177
                /*
178
                 * The Y axis of the text matrix is inverted,
179
                 * so we need to negate the Y offset appropriately.
180
                 */
181
134k
                code = pdf_begin_char_proc(pdev, w, h, 0, y_offset, x_offset, id,
182
134k
                                           &pcp, &ipos);
183
134k
                if (code < 0)
184
0
                    return code;
185
134k
                char_proc_begun = true;
186
134k
                y_offset = -y_offset;
187
134k
                width = psdf_round(pdev->char_width.x, 100, 10); /* See
188
                        pdf_write_Widths about rounding. We need to provide
189
                        a compatible data for Tj. */
190
134k
                pprintg1(pdev->strm, "%g ", width);
191
134k
                pprintd4(pdev->strm, "0 %d %d %d %d d1\n",  x_offset, -h + y_offset, w + x_offset, y_offset);
192
134k
                pprintd4(pdev->strm, "%d 0 0 %d %d %d cm\n", w, h, x_offset,
193
134k
                         -h + y_offset);
194
134k
                pdf_image_writer_init(&writer);
195
134k
                code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, true);
196
134k
                if (code < 0)
197
0
                    goto fail;
198
134k
                pres = (pdf_resource_t *) pcp;
199
134k
                goto wr;
200
1.67M
            } else if (pdev->pte != NULL) {
201
                /* We're under pdf_text_process. It set a high level color. */
202
1.67M
            } else
203
0
                set_image_color(pdev, one);
204
1.67M
            pcp = (pdf_char_proc_t *) pres;
205
1.67M
            x -= pdf_charproc_x_offset(pcp);
206
1.67M
            y -= pdf_charproc_y_offset(pcp);
207
1.67M
            y -= h;
208
1.67M
            pdf_make_bitmap_image(&image, x, y, w, h);
209
1.67M
            goto rx;
210
1.81M
        }
211
3.15k
        if (pdev->pte == NULL)
212
0
            set_image_color(pdev, one);
213
3.15k
        gs_image_t_init_mask(&image, false);
214
3.15k
        invert = 0xff;
215
3.15k
    } else if (one == gx_no_color_index) {
216
0
        gs_image_t_init_mask(&image, false);
217
0
        if (pdev->pte == NULL)
218
0
            set_image_color(pdev, zero);
219
0
    } else if (zero == pdev->black && one == pdev->white) {
220
0
        pcs = gs_cspace_new_DeviceGray(pdev->memory);
221
0
        if (pcs == NULL) {
222
0
            code = gs_note_error(gs_error_VMerror);
223
0
            goto fail;
224
0
        }
225
0
        gs_image_t_init(&image, pcs);
226
0
    } else if (zero == pdev->white && one == pdev->black) {
227
0
        pcs = gs_cspace_new_DeviceGray(pdev->memory);
228
0
        if (pcs == NULL) {
229
0
            code = gs_note_error(gs_error_VMerror);
230
0
            goto fail;
231
0
        }
232
0
        gs_image_t_init(&image, pcs);
233
0
        invert = 0xff;
234
0
    } else {
235
        /*
236
         * We think this code is never executed when interpreting PostScript
237
         * or PDF: the library never uses monobit non-mask images
238
         * internally, and high-level images don't go through this code.
239
         * However, we still want the code to work.
240
         */
241
0
        gs_color_space *pcs_base;
242
0
        gx_color_index c[2];
243
0
        int i, j;
244
0
        int ncomp = pdev->color_info.num_components;
245
0
        byte *p;
246
247
0
        code = pdf_cspace_init_Device(pdev->memory, &pcs_base, ncomp);
248
0
        if (code < 0)
249
0
            goto fail;
250
0
        c[0] = psdf_adjust_color_index((gx_device_vector *)pdev, zero);
251
0
        c[1] = psdf_adjust_color_index((gx_device_vector *)pdev, one);
252
0
        pcs = gs_cspace_alloc(pdev->memory, &gs_color_space_type_Indexed);
253
0
        if (pcs == NULL) {
254
0
            rc_decrement_cs(pcs_base, "pdf_copy_mono");
255
0
            code = gs_note_error(gs_error_VMerror);
256
0
            goto fail;
257
0
        }
258
0
        pcs->base_space = pcs_base;
259
0
        pcs->params.indexed.hival = 1;
260
0
        pcs->params.indexed.n_comps = ncomp;
261
0
        p = palette;
262
0
        for (i = 0; i < 2; ++i)
263
0
            for (j = ncomp - 1; j >= 0; --j)
264
0
                *p++ = (byte)(c[i] >> (j * 8));
265
0
        pcs->params.indexed.lookup.table.data = palette;
266
0
        pcs->params.indexed.lookup.table.size = p - palette;
267
0
        pcs->params.indexed.use_proc = false;
268
0
        gs_image_t_init(&image, pcs);
269
0
        image.BitsPerComponent = 1;
270
0
    }
271
3.15k
    pdf_make_bitmap_image(&image, x, y, w, h);
272
3.15k
    {
273
3.15k
        uint64_t nbytes = (uint64_t) ((w + 7) >> 3) * h;
274
275
3.15k
        code = pdf_open_page(pdev, PDF_IN_STREAM);
276
3.15k
        if (code < 0)
277
0
            goto fail;
278
3.15k
        in_line = nbytes < pdev->MaxInlineImageSize;
279
3.15k
        if (in_line)
280
3.15k
            pdf_put_image_matrix(pdev, &image.ImageMatrix, 1.0);
281
3.15k
        pdf_image_writer_init(&writer);
282
3.15k
        code = pdf_begin_write_image(pdev, &writer, gs_no_id, w, h, NULL, in_line);
283
3.15k
        if (code < 0)
284
0
            goto fail;
285
3.15k
    }
286
137k
  wr:
287
137k
    if (image.ImageMask)
288
137k
        pcsvalue = NULL;
289
0
    else {
290
        /*
291
         * We don't have to worry about color space scaling: the color
292
         * space is always a Device space.
293
         */
294
0
        code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs,
295
0
                               &writer.pin->color_spaces, in_line, NULL, 0, false);
296
0
        if (code < 0)
297
0
            goto fail;
298
0
        pcsvalue = &cs_value;
299
0
    }
300
    /*
301
     * There are 3 different cases at this point:
302
     *      - Writing an in-line image (pres == 0, writer.pres == 0);
303
     *      - Writing an XObject image (pres == 0, writer.pres != 0);
304
     *      - Writing the image for a CharProc (pres != 0).
305
     * We handle them with in-line code followed by a switch,
306
     * rather than making the shared code into a procedure,
307
     * simply because there would be an awful lot of parameters
308
     * that would need to be passed.
309
     */
310
137k
    if (pres) {
311
134k
        if (!pdev->NoT3CCITT) {
312
            /*
313
             * Always use CCITTFax 2-D for character bitmaps.  It takes less
314
             * space to invert the data with Decode than to set BlackIs1.
315
             */
316
134k
            float d0 = image.Decode[0];
317
318
134k
            image.Decode[0] = image.Decode[1];
319
134k
            image.Decode[1] = d0;
320
134k
            psdf_CFE_binary(&writer.binary[0], image.Width, image.Height, true);
321
134k
            invert ^= 0xff;
322
134k
        }
323
134k
    } else {
324
        /* Use the Distiller compression parameters. */
325
3.15k
        pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
326
3.15k
        psdf_setup_image_filters((gx_device_psdf *) pdev, &writer.binary[0],
327
3.15k
                                 (gs_pixel_image_t *)&image, NULL, NULL, true, in_line);
328
3.15k
    }
329
137k
    code = pdf_begin_image_data(pdev, &writer, (const gs_pixel_image_t *)&image,
330
137k
                         pcsvalue, 0);
331
137k
    if (code < 0)
332
0
        goto fail;
333
334
137k
    code = pdf_copy_mask_bits(writer.binary[0].strm, base, sourcex, raster,
335
137k
                              w, h, invert);
336
137k
    if (code < 0)
337
0
        goto fail;
338
137k
    code = pdf_end_image_binary(pdev, &writer, writer.height);
339
137k
    if (code < 0)
340
0
        goto fail;
341
342
137k
    if (!pres) {
343
3.15k
        switch ((code = pdf_end_write_image(pdev, &writer))) {
344
0
            default:                /* error */
345
0
                goto fail;
346
3.15k
            case 1:
347
3.15k
                code = 0;
348
3.15k
                goto fail;
349
0
            case 0:
350
0
                code = pdf_do_image(pdev, writer.pres, &image.ImageMatrix,
351
0
                                    true);
352
0
                goto fail;
353
3.15k
        }
354
3.15k
    }
355
134k
    writer.end_string = "";        /* no Q */
356
134k
    switch ((code = pdf_end_write_image(pdev, &writer))) {
357
0
    default:                /* error */
358
0
        goto fail;
359
0
        return code;
360
0
    case 0:                        /* not possible */
361
0
        code = gs_note_error(gs_error_Fatal);
362
0
        goto fail;
363
134k
    case 1:
364
134k
        break;
365
134k
    }
366
134k
    code = pdf_end_char_proc(pdev, &ipos);
367
134k
    if (code < 0)
368
0
        return code;
369
1.81M
  rx:{
370
1.81M
        gs_matrix imat;
371
372
1.81M
        imat = image.ImageMatrix;
373
1.81M
        imat.xx /= w;
374
1.81M
        imat.xy /= h;
375
1.81M
        imat.yx /= w;
376
1.81M
        imat.yy /= h;
377
1.81M
        return pdf_do_char_image(pdev, (const pdf_char_proc_t *)pres, &imat);
378
134k
    }
379
380
3.15k
fail:
381
3.15k
    if (char_proc_begun)
382
0
        (void)pdf_end_char_proc(pdev, &ipos);
383
3.15k
    return code;
384
134k
}
385
int
386
gdev_pdf_copy_mono(gx_device * dev,
387
                   const byte * base, int sourcex, int raster, gx_bitmap_id id,
388
                   int x, int y, int w, int h, gx_color_index zero,
389
                   gx_color_index one)
390
20.8k
{
391
20.8k
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
392
393
20.8k
    if (w <= 0 || h <= 0)
394
20.8k
        return 0;
395
0
    return pdf_copy_mono(pdev, base, sourcex, raster, id, x, y, w, h,
396
0
                         zero, one, NULL);
397
20.8k
}
398
399
/* Copy a color bitmap.  for_pattern = -1 means put the image in-line, */
400
/* 1 means put the image in a resource, 2 means image is a rasterized shading. */
401
int
402
pdf_copy_color_data(gx_device_pdf * pdev, const byte * base, int sourcex,
403
                    int raster, gx_bitmap_id id, int x, int y, int w, int h,
404
                    gs_image_t *pim, pdf_image_writer *piw,
405
                    int for_pattern)
406
2.54k
{
407
2.54k
    int depth = pdev->color_info.depth;
408
2.54k
    int bytes_per_pixel = depth >> 3;
409
2.54k
    gs_color_space *pcs;
410
2.54k
    cos_value_t cs_value;
411
2.54k
    uint64_t nbytes;
412
2.54k
    int code = pdf_cspace_init_Device(pdev->memory, &pcs, bytes_per_pixel);
413
2.54k
    const byte *row_base;
414
2.54k
    int row_step;
415
2.54k
    bool in_line;
416
417
2.54k
    if (code < 0)
418
0
        return code;                /* can't happen */
419
2.54k
    if (!base)
420
0
        return 1;
421
2.54k
    gs_image_t_init(pim, pcs);
422
2.54k
    pdf_make_bitmap_image(pim, x, y, w, h);
423
2.54k
    pim->BitsPerComponent = 8;
424
2.54k
    nbytes = (uint64_t)w * bytes_per_pixel * h;
425
426
2.54k
    if (for_pattern == 1) {
427
        /*
428
         * Patterns must be emitted in order of increasing user Y, i.e.,
429
         * the opposite of PDF's standard image order.
430
         */
431
0
        row_base = base + (h - 1) * raster;
432
0
        row_step = -raster;
433
0
        in_line = for_pattern < 0;
434
2.54k
    } else {
435
2.54k
        row_base = base;
436
2.54k
        row_step = raster;
437
2.54k
        in_line = nbytes < pdev->MaxInlineImageSize;
438
2.54k
        pdf_put_image_matrix(pdev, &pim->ImageMatrix, 1.0);
439
        /*
440
         * Check whether we've already made an XObject resource for this
441
         * image.
442
         */
443
2.54k
        if (id != gx_no_bitmap_id) {
444
0
            piw->pres = pdf_find_resource_by_gs_id(pdev, resourceXObject, id);
445
0
            if (piw->pres)
446
0
                return 0;
447
0
        }
448
2.54k
    }
449
    /*
450
     * We have to be able to control whether to put Pattern images in line,
451
     * to avoid trying to create an XObject resource while we're in the
452
     * middle of writing a Pattern resource.
453
     */
454
2.54k
    if (for_pattern < 0)
455
0
        stream_puts(pdev->strm, "q ");
456
    /*
457
     * We don't have to worry about color space scaling: the color
458
     * space is always a Device space.
459
     */
460
2.54k
    pdf_image_writer_init(piw);
461
2.54k
    pdev->ParamCompatibilityLevel = pdev->CompatibilityLevel;
462
2.54k
    if ((code = pdf_begin_write_image(pdev, piw, id, w, h, NULL, in_line)) < 0 ||
463
2.54k
        (code = pdf_color_space_named(pdev, NULL, &cs_value, NULL, pcs,
464
2.54k
                                &piw->pin->color_spaces, in_line, NULL, 0, false)) < 0 ||
465
2.54k
        (for_pattern < 2 || nbytes < 512000 ?
466
2.54k
            (code = psdf_setup_lossless_filters((gx_device_psdf *) pdev,
467
2.54k
                        &piw->binary[0], (gs_pixel_image_t *)pim, false)) :
468
2.54k
            (code = psdf_setup_image_filters((gx_device_psdf *) pdev,
469
0
                        &piw->binary[0], (gs_pixel_image_t *)pim, NULL, NULL, false, false))
470
2.54k
        ) < 0 ||
471
2.54k
        (code = pdf_begin_image_data(pdev, piw, (const gs_pixel_image_t *)pim,
472
2.54k
                                     &cs_value, 0)) < 0
473
2.54k
        )
474
0
        return code;
475
2.54k
    pdf_copy_color_bits(piw->binary[0].strm, row_base, sourcex, row_step, w, h,
476
2.54k
                        bytes_per_pixel);
477
2.54k
    pdf_end_image_binary(pdev, piw, piw->height);
478
2.54k
    rc_decrement(pcs, "pdf_copy_color_data");
479
2.54k
    return pdf_end_write_image(pdev, piw);
480
2.54k
}
481
482
int
483
gdev_pdf_copy_color(gx_device * dev, const byte * base, int sourcex,
484
                    int raster, gx_bitmap_id id, int x, int y, int w, int h)
485
3
{
486
3
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
487
3
    gs_image_t image;
488
3
    pdf_image_writer writer;
489
3
    int code;
490
491
3
    if (w <= 0 || h <= 0)
492
0
        return 0;
493
3
    code = pdf_open_page(pdev, PDF_IN_STREAM);
494
3
    if (code < 0)
495
0
        return code;
496
    /* Make sure we aren't being clipped. */
497
3
    code = pdf_put_clip_path(pdev, NULL);
498
3
    if (code < 0)
499
0
        return code;
500
3
    code = pdf_copy_color_data(pdev, base, sourcex, raster, id, x, y, w, h,
501
3
                               &image, &writer, 0);
502
3
    switch (code) {
503
0
        default:
504
0
            return code;        /* error */
505
3
        case 1:
506
3
            return 0;
507
0
        case 0:
508
0
            return pdf_do_image(pdev, writer.pres, NULL, true);
509
3
    }
510
3
}
511
512
/* Fill a mask. */
513
int
514
gdev_pdf_fill_mask(gx_device * dev,
515
                   const byte * data, int data_x, int raster, gx_bitmap_id id,
516
                   int x, int y, int width, int height,
517
                   const gx_drawing_color * pdcolor, int depth,
518
                   gs_logical_operation_t lop, const gx_clip_path * pcpath)
519
2.31M
{
520
2.31M
    gx_device_pdf *pdev = (gx_device_pdf *) dev;
521
2.31M
    pdf_text_enum_t *penum = (pdf_text_enum_t *)pdev->OCR_enum;
522
523
2.31M
    if (width <= 0 || height <= 0)
524
495k
        return 0;
525
526
    /* If OCRStage is 'OCR_Rendering' then we are handling an image which is a rendered glyph
527
     * that we want to have OCR software process and return a Unicode code point for.
528
     * We specifically do *not* want to send the image to the output PDF file!
529
     */
530
1.81M
    if (pdev->OCRStage == OCR_Rendering) {
531
0
        int code = 0;
532
0
        ocr_glyph_t *new_glyph = NULL;
533
0
        int index;
534
535
0
        new_glyph = (ocr_glyph_t *)gs_alloc_bytes(pdev->pdf_memory, sizeof(ocr_glyph_t), "");
536
0
        if (new_glyph == NULL)
537
0
            return_error(gs_error_VMerror);
538
0
        new_glyph->data = gs_alloc_bytes(pdev->pdf_memory, raster*height, "");
539
0
        if (new_glyph->data == NULL)
540
0
            return_error(gs_error_VMerror);
541
0
        memcpy(new_glyph->data, data, raster * height);
542
0
        new_glyph->height = height;
543
0
        new_glyph->width = width;
544
0
        new_glyph->raster = raster;
545
0
        new_glyph->x = x;
546
0
        new_glyph->y = y;
547
0
        if (penum != NULL) {
548
0
            new_glyph->char_code = penum->pte_default->returned.current_char;
549
0
            new_glyph->glyph = penum->pte_default->returned.current_glyph;
550
0
        } else {
551
0
            new_glyph->char_code = pdev->OCR_char_code;
552
0
            new_glyph->glyph = pdev->OCR_glyph;
553
0
        }
554
0
        new_glyph->next = NULL;
555
0
        new_glyph->is_space = true;
556
0
        for(index = 0; index < height * raster;index++){
557
0
            if(data[index] != 0x00) {
558
0
                new_glyph->is_space = false;
559
0
                break;
560
0
            }
561
0
        }
562
0
        if (pdev->ocr_glyphs == NULL)
563
0
            pdev->ocr_glyphs = new_glyph;
564
0
        else {
565
0
            ocr_glyph_t *next = pdev->ocr_glyphs;
566
567
0
            while (next->next != NULL)
568
0
                next = next->next;
569
0
            next->next = new_glyph;
570
0
        }
571
0
        return code;
572
0
    }
573
574
1.81M
    if (depth > 1 || (!gx_dc_is_pure(pdcolor) != 0 && !(gx_dc_is_pattern1_color(pdcolor))))
575
0
        return gx_default_fill_mask(dev, data, data_x, raster, id,
576
0
                                    x, y, width, height, pdcolor, depth, lop,
577
0
                                    pcpath);
578
1.81M
    return pdf_copy_mono(pdev, data, data_x, raster, id, x, y, width, height,
579
1.81M
                         gx_no_color_index, gx_dc_pure_color(pdcolor),
580
1.81M
                         pcpath);
581
1.81M
}
582
583
/* Tile with a bitmap.  This is important for pattern fills. */
584
int
585
gdev_pdf_strip_tile_rectangle(gx_device * dev, const gx_strip_bitmap * tiles,
586
                              int x, int y, int w, int h,
587
                              gx_color_index color0, gx_color_index color1,
588
                              int px, int py)
589
1
{
590
1
    gx_device_pdf *const pdev = (gx_device_pdf *) dev;
591
1
    int tw = tiles->rep_width, th = tiles->rep_height;
592
1
    double xscale = pdev->HWResolution[0] / 72.0,
593
1
        yscale = pdev->HWResolution[1] / 72.0;
594
1
    bool mask;
595
1
    int depth;
596
1
    int (*copy_data)(gx_device_pdf *, const byte *, int, int,
597
1
                     gx_bitmap_id, int, int, int, int,
598
1
                     gs_image_t *, pdf_image_writer *, int);
599
1
    pdf_resource_t *pres;
600
1
    cos_value_t cs_value;
601
1
    int code;
602
603
1
    if (tiles->id == gx_no_bitmap_id || tiles->shift != 0 ||
604
1
        (w < tw && h < th) ||
605
1
        color0 != gx_no_color_index
606
1
        )
607
1
        goto use_default;
608
0
    if (color1 != gx_no_color_index) {
609
        /* This is a mask pattern. */
610
0
        mask = true;
611
0
        depth = 1;
612
0
        copy_data = pdf_copy_mask_data;
613
0
        code = pdf_cs_Pattern_uncolored(pdev, &cs_value);
614
0
    } else {
615
        /* This is a colored pattern. */
616
0
        mask = false;
617
0
        depth = pdev->color_info.depth;
618
0
        copy_data = pdf_copy_color_data;
619
0
        code = pdf_cs_Pattern_colored(pdev, &cs_value);
620
0
    }
621
0
    if (code < 0)
622
0
        goto use_default;
623
0
    pres = pdf_find_resource_by_gs_id(pdev, resourcePattern, tiles->id);
624
0
    if (!pres) {
625
        /* Create the Pattern resource. */
626
0
        int code;
627
0
        int64_t length_id;
628
0
        gs_offset_t start, end;
629
0
        stream *s;
630
0
        gs_image_t image;
631
0
        pdf_image_writer writer;
632
0
        int64_t image_bytes = ((int64_t)tw * depth + 7) / 8 * th;
633
0
        bool in_line = image_bytes < pdev->MaxInlineImageSize;
634
0
        int64_t tile_id =
635
0
            (tw == tiles->size.x && th == tiles->size.y ? tiles->id :
636
0
             gx_no_bitmap_id);
637
638
0
        if (!in_line)
639
0
            goto use_default;
640
641
0
        code = pdf_begin_resource(pdev, resourcePattern, tiles->id, &pres);
642
0
        if (code < 0)
643
0
            goto use_default;
644
0
        s = pdev->strm;
645
0
        pprintd1(s, "/PatternType 1/PaintType %d/TilingType 1/Resources<<\n",
646
0
                 (mask ? 2 : 1));
647
648
0
        if (pdev->CompatibilityLevel <= 1.7)
649
0
            pprints1(s, "/ProcSet[/PDF/Image%s]>>\n", (mask ? "B" : "C"));
650
        /*
651
         * Because of bugs in Acrobat Reader's Print function, we can't use
652
         * the natural BBox and Step here: they have to be 1.
653
         */
654
0
        pprintg2(s, "/Matrix[%g 0 0 %g 0 0]", tw / xscale, th / yscale);
655
0
        stream_puts(s, "/BBox[0 0 1 1]/XStep 1/YStep 1/Length ");
656
0
        length_id = pdf_obj_ref(pdev);
657
0
        pprinti64d1(s, "%"PRId64" 0 R>>stream\n", length_id);
658
0
        start = pdf_stell(pdev);
659
0
        code = copy_data(pdev, tiles->data, 0, tiles->raster,
660
0
                         tile_id, 0, 0, tw, th, &image, &writer, -1);
661
0
        switch (code) {
662
0
        default:
663
0
            return code;        /* error */
664
0
        case 1:
665
0
            break;
666
0
        case 0:                        /* not possible */
667
0
            return_error(gs_error_Fatal);
668
0
        }
669
0
        end = pdf_stell(pdev);
670
0
        stream_puts(s, "\nendstream\n");
671
0
        pdf_end_resource(pdev, resourcePattern);
672
0
        pdf_open_separate(pdev, length_id, resourceNone);
673
0
        pprinti64d1(pdev->strm, "%"PRId64"\n", end - start);
674
0
        pdf_end_separate(pdev, resourceNone);
675
0
        pres->object->written = true; /* don't write at end of page */
676
0
    }
677
    /* Fill the rectangle with the Pattern. */
678
0
    {
679
0
        int code = pdf_open_page(pdev, PDF_IN_STREAM);
680
0
        stream *s;
681
682
0
        if (code < 0)
683
0
            goto use_default;
684
        /* Make sure we aren't being clipped. */
685
0
        code = pdf_put_clip_path(pdev, NULL);
686
0
        if (code < 0)
687
0
            return code;
688
0
        s = pdev->strm;
689
        /*
690
         * Because of bugs in Acrobat Reader's Print function, we can't
691
         * leave the CTM alone here: we have to reset it to the default.
692
         */
693
0
        pprintg2(s, "q %g 0 0 %g 0 0 cm\n", xscale, yscale);
694
0
        cos_value_write(&cs_value, pdev);
695
0
        stream_puts(s, " cs");
696
0
        if (mask)
697
0
            pprintg3(s, " %g %g %g", (int)(color1 >> 16) / 255.0,
698
0
                     (int)((color1 >> 8) & 0xff) / 255.0,
699
0
                     (int)(color1 & 0xff) / 255.0);
700
0
        pprinti64d1(s, "/R%"PRId64" scn", pdf_resource_id(pres));
701
0
        pprintg4(s, " %g %g %g %g re f Q\n",
702
0
                 x / xscale, y / yscale, w / xscale, h / xscale);
703
0
    }
704
0
    return 0;
705
1
use_default:
706
1
    return gx_default_strip_tile_rectangle(dev, tiles, x, y, w, h,
707
1
                                           color0, color1, px, py);
708
0
}