Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/base/gxblend1.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 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.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
/* PDF 1.4 blending functions */
17
18
#include "memory_.h"
19
#include "gx.h"
20
#include "gp.h"
21
#include "gstparam.h"
22
#include "gsrect.h"
23
#include "gxblend.h"
24
#include "gxdcconv.h"
25
#include "gxdevcli.h"
26
#include "gxgstate.h"
27
#include "gdevdevn.h"
28
#include "gdevp14.h"
29
#include "gxdcconv.h"
30
#include "gsicc_cache.h"
31
#include "gxdevsop.h"
32
33
#ifdef DUMP_TO_PNG
34
#include "png_.h"
35
#endif
36
37
/* A case where we have RGB + spots.  This is actually an RGB color and we
38
 * should zero out the spot colorants */
39
void
40
pdf14_unpack_rgb_mix(int num_comp, gx_color_index color,
41
                     pdf14_device * p14dev, byte * out)
42
0
{
43
0
    int i;
44
45
0
    memset(out, 0, num_comp);
46
0
    for (i = 2; i >= 0; i--) {
47
0
        out[i] = (byte)(color & 0xff);
48
0
        color >>= 8;
49
0
    }
50
0
}
51
52
void
53
pdf14_unpack16_rgb_mix(int num_comp, gx_color_index color,
54
                       pdf14_device * p14dev, uint16_t * out)
55
0
{
56
0
    int i;
57
58
0
    memset(out, 0, num_comp);
59
0
    for (i = 2; i >= 0; i--) {
60
0
        out[i] = (uint16_t)color;
61
0
        color >>= 16;
62
0
    }
63
0
}
64
65
/* A case where we have Gray + spots.  This is actually a Gray color and we
66
* should zero out the spot colorants */
67
void
68
pdf14_unpack_gray_mix(int num_comp, gx_color_index color,
69
                      pdf14_device * p14dev, byte * out)
70
0
{
71
0
    memset(out, 0, num_comp);
72
0
    out[0] = (byte)(color & 0xff);
73
0
}
74
75
void
76
pdf14_unpack16_gray_mix(int num_comp, gx_color_index color,
77
                        pdf14_device * p14dev, uint16_t * out)
78
0
{
79
0
    memset(out, 0, num_comp);
80
0
    out[0] = (uint16_t)color;
81
0
}
82
83
/*
84
 * Unpack a device color.  This routine is similar to the device's
85
 * decode_color procedure except for two things.  The procedure produces 1
86
 * byte values instead of gx_color_values (2 bytes).  A separate
87
 * procedure is used instead of the decode_color to minimize execution time.
88
 */
89
void
90
pdf14_unpack_additive(int num_comp, gx_color_index color,
91
                      pdf14_device * p14dev, byte * out)
92
126M
{
93
126M
    int i;
94
95
462M
    for (i = num_comp - 1; i >= 0; i--) {
96
335M
        out[i] = (byte)(color & 0xff);
97
335M
        color >>= 8;
98
335M
    }
99
126M
}
100
101
void
102
pdf14_unpack16_additive(int num_comp, gx_color_index color,
103
                        pdf14_device * p14dev, uint16_t * out)
104
0
{
105
0
    int i;
106
107
0
    for (i = num_comp - 1; i >= 0; i--) {
108
0
        out[i] = (uint16_t)color;
109
0
        color >>= 16;
110
0
    }
111
0
}
112
113
/*
114
 * Unpack a device color.  This routine is similar to the device's
115
 * decode_color procedure except for two things.  The procedure produces 1
116
 * byte values instead of gx_color_values (2 bytes) and the output values
117
 * are inverted for subtractive color spaces (like CMYK).  A separate
118
 * procedure is used instead of the decode_color to minimize execution time.
119
 */
120
void
121
pdf14_unpack_subtractive(int num_comp, gx_color_index color,
122
                                pdf14_device * p14dev, byte * out)
123
9.78M
{
124
9.78M
    int i;
125
126
48.9M
    for (i = num_comp - 1; i >= 0; i--) {
127
39.1M
        out[i] = 0xff - (byte)(color & 0xff);
128
39.1M
        color >>= 8;
129
39.1M
    }
130
9.78M
}
131
132
void
133
pdf14_unpack16_subtractive(int num_comp, gx_color_index color,
134
                           pdf14_device * p14dev, uint16_t * out)
135
0
{
136
0
    int i;
137
138
0
    for (i = num_comp - 1; i >= 0; i--) {
139
0
        out[i] = (uint16_t)~color;
140
0
        color >>= 16;
141
0
    }
142
0
}
143
144
/*
145
 * Unpack a device color.  This routine is used for devices in which we do
146
 * not know the details of the process color model.  In this case we use
147
 * the device's decode_color procedure.
148
 */
149
void
150
pdf14_unpack_custom(int num_comp, gx_color_index color,
151
                                pdf14_device * p14dev, byte * out)
152
0
{
153
0
    int i;
154
0
    gx_device * tdev = p14dev->target;
155
0
    gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS];
156
157
0
    dev_proc(tdev, decode_color)(tdev, color, cm_values);
158
0
    for (i = 0; i < num_comp; i++)
159
0
        out[i] = 0xff - gx_color_value_to_byte(cm_values[i]);
160
0
}
161
162
void
163
pdf14_unpack16_custom(int num_comp, gx_color_index color,
164
                      pdf14_device * p14dev, uint16_t * out)
165
0
{
166
0
    int i;
167
0
    gx_device * tdev = p14dev->target;
168
0
    gx_color_value cm_values[GX_DEVICE_COLOR_MAX_COMPONENTS];
169
170
0
    dev_proc(tdev, decode_color)(tdev, color, cm_values);
171
0
    for (i = 0; i < num_comp; i++)
172
0
        out[i] = ~cm_values[i];
173
0
}
174
175
#if RAW_DUMP
176
extern unsigned int global_index;
177
#endif
178
179
static void
180
copy_plane_part(byte *des_ptr, int des_rowstride, byte *src_ptr, int src_rowstride,
181
                int width, int height, bool deep)
182
317k
{
183
317k
    int y;
184
185
317k
    width <<= deep;
186
187
317k
    if (width == des_rowstride && width == src_rowstride) {
188
246k
        width *= height;
189
246k
        height = 1;
190
246k
    }
191
192
1.31M
    for (y = 0; y < height; ++y) {
193
997k
        memcpy(des_ptr, src_ptr, width);
194
997k
        des_ptr += des_rowstride;
195
997k
        src_ptr += src_rowstride;
196
997k
    }
197
317k
}
198
199
static void
200
copy_extra_planes(byte *des_buf, pdf14_buf *des_info, byte *src_buf,
201
                  pdf14_buf *src_info, int width, int height)
202
78.3k
{
203
    /* alpha_g and shape do not copy */
204
78.3k
    des_buf += des_info->planestride * (size_t)((des_info->has_shape ? 1 : 0) +
205
78.3k
                                        (des_info->has_alpha_g ? 1 : 0));
206
78.3k
    src_buf += src_info->planestride * (size_t)((src_info->has_shape ? 1 : 0) +
207
78.3k
                                        (src_info->has_alpha_g ? 1 : 0));
208
    /* tags plane does copy */
209
78.3k
    if (des_info->has_tags) {
210
0
        if (src_info->has_tags) {
211
0
            copy_plane_part(des_buf, des_info->rowstride, src_buf,
212
0
                            src_info->rowstride, width, height, src_info->deep);
213
0
        }
214
0
    }
215
78.3k
}
216
217
int
218
pdf14_preserve_backdrop_cm(pdf14_buf *buf, cmm_profile_t *group_profile,
219
                           pdf14_buf *tos, cmm_profile_t *tos_profile,
220
                           gs_memory_t *memory, gs_gstate *pgs, gx_device *dev,
221
                           bool knockout_buff)
222
0
{
223
    /* Make copy of backdrop, but convert to new group's colorspace */
224
0
    int x0 = max(buf->rect.p.x, tos->rect.p.x);
225
0
    int x1 = min(buf->rect.q.x, tos->rect.q.x);
226
0
    int y0 = max(buf->rect.p.y, tos->rect.p.y);
227
0
    int y1 = min(buf->rect.q.y, tos->rect.q.y);
228
0
    bool deep = buf->deep;
229
0
    int code;
230
231
0
    if (x0 < x1 && y0 < y1) {
232
0
        int width = x1 - x0;
233
0
        int height = y1 - y0;
234
0
        byte *buf_plane, *tos_plane;
235
0
        gsicc_rendering_param_t rendering_params;
236
0
        gsicc_link_t *icc_link;
237
0
        gsicc_bufferdesc_t input_buff_desc;
238
0
        gsicc_bufferdesc_t output_buff_desc;
239
240
        /* Define the rendering intents */
241
0
        rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
242
0
        rendering_params.graphics_type_tag = GS_IMAGE_TAG;
243
0
        rendering_params.override_icc = false;
244
0
        rendering_params.preserve_black = gsBKPRESNOTSPECIFIED;
245
0
        rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
246
0
        rendering_params.cmm = gsCMM_DEFAULT;
247
        /* Request the ICC link for the transform that we will need to use */
248
0
        icc_link = gsicc_get_link_profile(pgs, dev, tos_profile, group_profile,
249
0
                                          &rendering_params, memory, false);
250
0
        if (icc_link == NULL)
251
0
            return gs_throw(gs_error_unknownerror, "ICC link failed.  Trans backdrop");
252
253
0
        if (icc_link->is_identity) {
254
0
            pdf14_preserve_backdrop(buf, tos, knockout_buff
255
#if RAW_DUMP
256
                                    , dev->memory
257
#endif
258
0
                                    );
259
0
            gsicc_release_link(icc_link);
260
0
            return 0;
261
0
        } else {
262
0
            if (knockout_buff) {
263
0
                buf_plane = buf->backdrop + ((x0 - buf->rect.p.x)<<deep) +
264
0
                        (y0 - buf->rect.p.y) * (size_t)buf->rowstride;
265
0
                tos_plane = tos->backdrop + ((x0 - tos->rect.p.x)<<deep) +
266
0
                        (y0 - tos->rect.p.y) * (size_t)tos->rowstride;
267
0
                memset(buf->backdrop, 0, buf->n_chan * ((size_t)buf->planestride)<<deep);
268
0
            } else {
269
0
                buf_plane = buf->data + ((x0 - buf->rect.p.x)<<deep) +
270
0
                        (y0 - buf->rect.p.y) * (size_t)buf->rowstride;
271
0
                tos_plane = tos->data + ((x0 - tos->rect.p.x)<<deep) +
272
0
                        (y0 - tos->rect.p.y) * (size_t)tos->rowstride;
273
                /* First clear out everything. There are cases where the incoming buf
274
                   has a region outside the existing tos group.  Need to check if this
275
                   is getting clipped in which case we need to fix the allocation of
276
                   the buffer to be smaller */
277
0
                memset(buf->data, 0, buf->n_planes * ((size_t)buf->planestride)<<deep);
278
0
            }
279
            /* Set up the buffer descriptors. */
280
0
            gsicc_init_buffer(&input_buff_desc, tos_profile->num_comps, 1<<deep, false,
281
0
                              false, true, tos->planestride, tos->rowstride, height,
282
0
                              width);
283
0
            gsicc_init_buffer(&output_buff_desc, group_profile->num_comps, 1<<deep, false,
284
0
                              false, true, buf->planestride, buf->rowstride, height,
285
0
                              width);
286
            /* Transform the data.  */
287
0
            code = (icc_link->procs.map_buffer)(dev, icc_link, &input_buff_desc,
288
0
                                         &output_buff_desc, tos_plane, buf_plane);
289
0
            gsicc_release_link(icc_link);
290
0
            if (code < 0)
291
0
                return gs_throw(gs_error_unknownerror, "ICC transform failed.  Trans backdrop");
292
0
        }
293
        /* Copy the alpha data */
294
0
        buf_plane += (buf->planestride) * (size_t)(buf->n_chan - 1);
295
0
        tos_plane += (tos->planestride) * (size_t)(tos->n_chan - 1);
296
0
        copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride, width,
297
0
                        height, deep);
298
0
        buf_plane += buf->planestride;
299
0
        tos_plane += tos->planestride;
300
301
0
        if (!knockout_buff)
302
0
            copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height);
303
0
    }
304
#if RAW_DUMP
305
    if (x0 < x1 && y0 < y1) {
306
        byte *buf_plane = buf->data + ((x0 - buf->rect.p.x)<<deep) +
307
            (y0 - buf->rect.p.y) * (size_t)buf->rowstride;
308
        dump_raw_buffer(dev->memory, y1 - y0, x1 - x0, buf->n_planes, buf->planestride,
309
                        buf->rowstride, "BackDropInit_CM", buf_plane, deep);
310
        global_index++;
311
    }
312
#endif
313
0
    return 0;
314
0
}
315
316
void
317
pdf14_preserve_backdrop(pdf14_buf *buf, pdf14_buf *tos, bool from_backdrop
318
#if RAW_DUMP
319
                        , const gs_memory_t *mem
320
#endif
321
                        )
322
78.4k
{
323
    /* make copy of backdrop for compositing */
324
78.4k
    int x0 = max(buf->rect.p.x, tos->rect.p.x);
325
78.4k
    int x1 = min(buf->rect.q.x, tos->rect.q.x);
326
78.4k
    int y0 = max(buf->rect.p.y, tos->rect.p.y);
327
78.4k
    int y1 = min(buf->rect.q.y, tos->rect.q.y);
328
329
78.4k
    if (x0 < x1 && y0 < y1) {
330
78.3k
        int width = x1 - x0;
331
78.3k
        int height = y1 - y0;
332
78.3k
        byte *buf_plane, *tos_plane;
333
78.3k
        int i, n_planes;
334
78.3k
        bool deep = buf->deep;
335
336
78.3k
        buf_plane = buf->data;
337
78.3k
        n_planes = buf->n_planes;
338
78.3k
        if (from_backdrop) {
339
41
            tos_plane = tos->backdrop;
340
78.3k
        } else {
341
78.3k
            tos_plane = tos->data;
342
78.3k
        }
343
344
        /* First clear out everything. There are cases where the incoming buf
345
           has a region outside the existing tos group.  Need to check if this
346
           is getting clipped in which case we need to fix the allocation of
347
           the buffer to be smaller */
348
78.3k
        if (x0 > buf->rect.p.x || x1 < buf->rect.q.x ||
349
78.3k
            y0 > buf->rect.p.y || y1 < buf->rect.q.y) {
350
            /* FIXME: There is potential for more optimisation here,
351
             * but I don't know how often we hit this case. */
352
447
            memset(buf_plane, 0, n_planes * (size_t)buf->planestride);
353
77.9k
        } else if (n_planes > tos->n_chan) {
354
            /* The next planes are alpha_g, shape, tags. We need to clear
355
             * alpha_g and shape, but don't need to clear the tag plane
356
             * if it would be copied below (and if it exists). */
357
77.9k
            int tag_plane_num = tos->n_chan + !!buf->has_shape + !!buf->has_alpha_g;
358
77.9k
            if (!from_backdrop && n_planes > tag_plane_num)
359
0
                n_planes = tag_plane_num;
360
77.9k
            if (n_planes > tos->n_chan)
361
77.9k
                memset(buf->data + tos->n_chan * (size_t)buf->planestride, 0,
362
77.9k
                       (n_planes - tos->n_chan) * (size_t)buf->planestride);
363
77.9k
        }
364
78.3k
        buf_plane += (y0 - buf->rect.p.y) * (size_t)buf->rowstride +
365
78.3k
                     ((x0 - buf->rect.p.x)<<deep);
366
78.3k
        tos_plane += (y0 - tos->rect.p.y) * (size_t)tos->rowstride +
367
78.3k
                     ((x0 - tos->rect.p.x)<<deep);
368
        /* Color and alpha plane */
369
395k
        for (i = 0; i < tos->n_chan; i++) {
370
317k
            copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride,
371
317k
                            width, height, buf->deep);
372
317k
            buf_plane += buf->planestride;
373
317k
            tos_plane += tos->planestride;
374
317k
        }
375
78.3k
        if (!from_backdrop)
376
78.3k
            copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height);
377
78.3k
    }
378
#if RAW_DUMP
379
    if (x0 < x1 && y0 < y1) {
380
        byte *buf_plane = (from_backdrop ? buf->backdrop : buf->data);
381
        if (buf_plane != NULL) {
382
            buf_plane += ((x0 - buf->rect.p.x) << buf->deep) +
383
                (y0 - buf->rect.p.y) * (size_t)buf->rowstride;
384
            dump_raw_buffer(mem, y1 - y0, x1 - x0, buf->n_planes, buf->planestride,
385
                buf->rowstride, "BackDropInit", buf_plane, buf->deep);
386
            global_index++;
387
        }
388
    }
389
#endif
390
78.4k
}
391
392
/*
393
 * Encode a list of colorant values into a gx_color_index_value.
394
 */
395
gx_color_index
396
pdf14_encode_color(gx_device *dev, const gx_color_value colors[])
397
61.4M
{
398
61.4M
    gx_color_index color = 0;
399
61.4M
    uchar i;
400
61.4M
    uchar ncomp = dev->color_info.num_components;
401
61.4M
    COLROUND_VARS;
402
403
61.4M
    COLROUND_SETUP(8);
404
242M
    for (i = 0; i < ncomp; i++) {
405
181M
        color <<= 8;
406
181M
        color |= COLROUND_ROUND(colors[i]);
407
181M
    }
408
61.4M
    return (color == gx_no_color_index ? color ^ 1 : color);
409
61.4M
}
410
411
gx_color_index
412
pdf14_encode_color16(gx_device *dev, const gx_color_value colors[])
413
0
{
414
0
    gx_color_index color = 0;
415
0
    uchar i;
416
0
    uchar ncomp = dev->color_info.num_components;
417
0
    COLROUND_VARS;
418
419
0
    COLROUND_SETUP(16);
420
0
    for (i = 0; i < ncomp; i++) {
421
0
        color <<= 16;
422
0
        color |= COLROUND_ROUND(colors[i]);
423
0
    }
424
0
    return (color == gx_no_color_index ? color ^ 1 : color);
425
0
}
426
427
/*
428
 * Encode a list of colorant values into a gx_color_index_value.
429
   Stick the tag information at the end.
430
 */
431
gx_color_index
432
pdf14_encode_color_tag(gx_device *dev, const gx_color_value colors[])
433
0
{
434
0
    gx_color_index color;
435
0
    uchar i;
436
0
    uchar ncomp = dev->color_info.num_components;
437
0
    COLROUND_VARS;
438
439
0
    COLROUND_SETUP(8);
440
    /* Add in the tag information */
441
0
    color = dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS;
442
0
    for (i = 0; i < ncomp; i++) {
443
0
        color <<= 8;
444
0
        color |= COLROUND_ROUND(colors[i]);
445
0
    }
446
0
    return (color == gx_no_color_index ? color ^ 1 : color);
447
0
}
448
449
gx_color_index
450
pdf14_encode_color16_tag(gx_device *dev, const gx_color_value colors[])
451
0
{
452
0
    gx_color_index color;
453
0
    uchar i;
454
0
    uchar ncomp = dev->color_info.num_components;
455
0
    COLROUND_VARS;
456
457
0
    COLROUND_SETUP(16);
458
    /* Add in the tag information */
459
0
    color = dev->graphics_type_tag & ~GS_DEVICE_ENCODES_TAGS;
460
0
    for (i = 0; i < ncomp; i++) {
461
0
        color <<= 16;
462
0
        color |= COLROUND_ROUND(colors[i]);
463
0
    }
464
0
    return (color == gx_no_color_index ? color ^ 1 : color);
465
0
}
466
467
/*
468
 * Decode a gx_color_index value back to a list of colorant values.
469
 */
470
int
471
pdf14_decode_color(gx_device * dev, gx_color_index color, gx_color_value * out)
472
0
{
473
0
    uchar i;
474
0
    uchar ncomp = dev->color_info.num_components;
475
476
0
    for (i = 0; i < ncomp; i++) {
477
0
        out[ncomp - i - 1] = (gx_color_value) ((color & 0xff) * 0x101);
478
0
        color >>= 8;
479
0
    }
480
0
    return 0;
481
0
}
482
483
int
484
pdf14_decode_color16(gx_device * dev, gx_color_index color, gx_color_value * out)
485
0
{
486
0
    uchar i;
487
0
    uchar ncomp = dev->color_info.num_components;
488
489
0
    for (i = 0; i < ncomp; i++) {
490
0
        out[ncomp - i - 1] = (gx_color_value) (color & 0xffff);
491
0
        color >>= 16;
492
0
    }
493
0
    return 0;
494
0
}
495
496
void
497
pdf14_gray_cs_to_cmyk_cm(const gx_device * dev, frac gray, frac out[])
498
0
{
499
0
    uchar num_comp = dev->color_info.num_components;
500
501
0
    out[0] = out[1] = out[2] = frac_0;
502
0
    out[3] = frac_1 - gray;
503
0
    for (--num_comp; num_comp > 3; num_comp--)
504
0
        out[num_comp] = 0;
505
0
}
506
507
/* These three must handle rgb + spot */
508
void
509
pdf14_gray_cs_to_rgbspot_cm(const gx_device * dev, frac gray, frac out[])
510
142
{
511
142
    uchar num_comp = dev->color_info.num_components;
512
513
142
    out[0] = out[1] = out[2] = gray;
514
142
    for (--num_comp; num_comp > 2; num_comp--)
515
0
        out[num_comp] = 0;
516
142
}
517
518
void
519
pdf14_rgb_cs_to_rgbspot_cm(const gx_device * dev, const gs_gstate *pgs,
520
    frac r, frac g, frac b, frac out[])
521
4.48M
{
522
4.48M
    uchar num_comp = dev->color_info.num_components;
523
524
4.48M
    out[0] = r;
525
4.48M
    out[1] = g;
526
4.48M
    out[2] = b;
527
4.49M
    for (--num_comp; num_comp > 2; num_comp--)
528
5.88k
        out[num_comp] = 0;
529
4.48M
}
530
531
void
532
pdf14_cmyk_cs_to_rgbspot_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
533
6
{
534
6
    uchar num_comp = dev->color_info.num_components;
535
536
6
    color_cmyk_to_rgb(c, m, y, k, NULL, out, dev->memory);
537
6
    for (--num_comp; num_comp > 2; num_comp--)
538
0
        out[num_comp] = 0;
539
6
}
540
541
/* These three must handle gray + spot */
542
void
543
pdf14_gray_cs_to_grayspot_cm(const gx_device * dev, frac gray, frac out[])
544
0
{
545
0
    uchar num_comp = dev->color_info.num_components;
546
547
0
    out[0] = gray;
548
0
    for (--num_comp; num_comp > 0; num_comp--)
549
0
        out[num_comp] = 0;
550
0
}
551
552
void
553
pdf14_rgb_cs_to_grayspot_cm(const gx_device * dev, const gs_gstate *pgs,
554
    frac r, frac g, frac b, frac out[])
555
0
{
556
0
    uchar num_comp = dev->color_info.num_components;
557
558
0
    out[0] = (r + g + b) / 3;
559
0
    for (--num_comp; num_comp > 0; num_comp--)
560
0
        out[num_comp] = 0;
561
0
}
562
563
void
564
pdf14_cmyk_cs_to_grayspot_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
565
0
{
566
0
    uchar num_comp = dev->color_info.num_components;
567
568
0
    out[0] = color_cmyk_to_gray(c, m, y, k, NULL);
569
0
    for (--num_comp; num_comp > 0; num_comp--)
570
0
        out[num_comp] = 0;
571
0
}
572
573
/*
574
 * Default map from DeviceRGB color space to DeviceCMYK color
575
 * model. Since this mapping is defined by the PostScript language
576
 * it is unlikely that any device with a DeviceCMYK color model
577
 * would define this mapping on its own.
578
 *
579
 * If the gs_gstate is not available, map as though the black
580
 * generation and undercolor removal functions are identity
581
 * transformations. This mode is used primarily to support the
582
 * raster operation (rop) feature of PCL, which requires that
583
 * the raster operation be performed in an RGB color space.
584
 * Note that default black generation and undercolor removal
585
 * functions in PostScript need NOT be identity transformations:
586
 * often they are { pop 0 }.
587
 */
588
void
589
pdf14_rgb_cs_to_cmyk_cm(const gx_device * dev, const gs_gstate *pgs,
590
                           frac r, frac g, frac b, frac out[])
591
0
{
592
0
    uchar num_comp = dev->color_info.num_components;
593
594
0
    if (pgs != 0)
595
0
        color_rgb_to_cmyk(r, g, b, pgs, out, dev->memory);
596
0
    else {
597
0
        frac    c = frac_1 - r, m = frac_1 - g, y = frac_1 - b;
598
0
        frac    k = min(c, min(m, y));
599
600
0
        out[0] = c - k;
601
0
        out[1] = m - k;
602
0
        out[2] = y - k;
603
0
        out[3] = k;
604
0
    }
605
0
    for (--num_comp; num_comp > 3; num_comp--)
606
0
        out[num_comp] = 0;
607
0
}
608
609
void
610
pdf14_cmyk_cs_to_cmyk_cm(const gx_device * dev, frac c, frac m, frac y, frac k, frac out[])
611
2.19M
{
612
2.19M
    uchar num_comp = dev->color_info.num_components;
613
614
2.19M
    out[0] = c;
615
2.19M
    out[1] = m;
616
2.19M
    out[2] = y;
617
2.19M
    out[3] = k;
618
2.19M
    for (--num_comp; num_comp > 3; num_comp--)
619
0
        out[num_comp] = 0;
620
2.19M
}
621
622
#ifdef DUMP_TO_PNG
623
/* Dumps a planar RGBA image to a PNG file. */
624
static  int
625
dump_planar_rgba(gs_memory_t *mem, const pdf14_buf *pbuf)
626
{
627
    size_t rowstride = pbuf->rowstride, planestride = pbuf->planestride;
628
    int rowbytes = width << 2;
629
    gs_int_rect rect = buf->rect;
630
    int x1 = min(pdev->width, rect.q.x);
631
    int y1 = min(pdev->height, rect.q.y);
632
    int width = x1 - rect.p.x;
633
    int height = y1 - rect.p.y;
634
    byte *buf_ptr = buf->data + rect.p.y * (size_t)buf->rowstride + rect.p.x;
635
    byte *row = gs_malloc(mem, rowbytes, 1, "png raster buffer");
636
    png_struct *png_ptr =
637
    png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
638
    png_info *info_ptr =
639
    png_create_info_struct(png_ptr);
640
    const char *software_key = "Software";
641
    char software_text[256];
642
    png_text text_png;
643
    gp_file *file;
644
    int code;
645
    int y;
646
647
    if (buf->data == NULL)
648
        return 0;
649
650
    file = gp_fopen (mem, "c:\\temp\\tmp.png", "wb");
651
652
    if_debug0m('v', mem, "[v]pnga_output_page\n");
653
654
    if (row == 0 || png_ptr == 0 || info_ptr == 0) {
655
        code = gs_note_error(gs_error_VMerror);
656
        goto done;
657
    }
658
    /* set error handling */
659
    if (setjmp(png_ptr->jmpbuf)) {
660
        /* If we get here, we had a problem reading the file */
661
        code = gs_note_error(gs_error_VMerror);
662
        goto done;
663
    }
664
665
    code = 0;     /* for normal path */
666
    /* set up the output control */
667
    png_init_io(png_ptr, file);
668
669
    /* set the file information here */
670
    info_ptr->width = width;
671
    info_ptr->height = height;
672
    /* resolution is in pixels per meter vs. dpi */
673
    info_ptr->x_pixels_per_unit =
674
        (png_uint_32) (96.0 * (100.0 / 2.54));
675
    info_ptr->y_pixels_per_unit =
676
        (png_uint_32) (96.0 * (100.0 / 2.54));
677
    info_ptr->phys_unit_type = PNG_RESOLUTION_METER;
678
    info_ptr->valid |= PNG_INFO_pHYs;
679
680
    /* At present, only supporting 32-bit rgba */
681
    info_ptr->bit_depth = 8;
682
    info_ptr->color_type = PNG_COLOR_TYPE_RGB_ALPHA;
683
684
    /* add comment */
685
    gs_snprintf(software_text, sizeof(software_text), "%s %d.%02d", gs_product,
686
            (int)(gs_revision / 100), (int)(gs_revision % 100));
687
    text_png.compression = -1;  /* uncompressed */
688
    text_png.key = (char *)software_key;  /* not const, unfortunately */
689
    text_png.text = software_text;
690
    text_png.text_length = strlen(software_text);
691
    info_ptr->text = &text_png;
692
    info_ptr->num_text = 1;
693
694
    /* write the file information */
695
    png_write_info(png_ptr, info_ptr);
696
697
    /* don't write the comments twice */
698
    info_ptr->num_text = 0;
699
    info_ptr->text = NULL;
700
701
    /* Write the contents of the image. */
702
    for (y = 0; y < height; ++y) {
703
        int x;
704
705
        for (x = 0; x < width; ++x) {
706
            row[(x << 2)] = buf_ptr[x];
707
            row[(x << 2) + 1] = buf_ptr[x + planestride];
708
            row[(x << 2) + 2] = buf_ptr[x + planestride * (size_t)2];
709
            row[(x << 2) + 3] = buf_ptr[x + planestride * (size_t)3];
710
        }
711
        png_write_row(png_ptr, row);
712
        buf_ptr += rowstride;
713
    }
714
715
    /* write the rest of the file */
716
    png_write_end(png_ptr, info_ptr);
717
718
  done:
719
    /* free the structures */
720
    png_destroy_write_struct(&png_ptr, &info_ptr);
721
    gs_free(mem, row, rowbytes, 1, "png raster buffer");
722
723
    fclose (file);
724
    return code;
725
}
726
#endif
727
728
void
729
gx_build_blended_image_row(const byte *gs_restrict buf_ptr, int planestride,
730
                           int width, int num_comp, uint16_t bg, byte *gs_restrict linebuf)
731
1.83M
{
732
1.83M
    size_t inc = planestride * (size_t)num_comp;
733
734
1.83M
    buf_ptr += inc - 1;
735
1.99G
    for (; width > 0; width--) {
736
        /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
737
1.98G
        byte a = *++buf_ptr;
738
1.98G
        int i = num_comp;
739
740
1.98G
        if (a == 0) {
741
2.79G
            do {
742
2.79G
                *linebuf++ = bg;
743
2.79G
            } while (--i);
744
1.02G
        } else {
745
1.02G
            buf_ptr -= inc;
746
1.02G
            if (a == 0xff) {
747
2.96G
                do {
748
2.96G
                    *linebuf++ = *buf_ptr;
749
2.96G
                    buf_ptr += planestride;
750
2.96G
                } while (--i);
751
982M
            } else {
752
47.0M
                a ^= 0xff;
753
140M
                do {
754
140M
                    byte comp = *buf_ptr;
755
140M
                    int tmp = ((bg - comp) * a) + 0x80;
756
140M
                    buf_ptr += planestride;
757
140M
                    comp += (tmp + (tmp >> 8)) >> 8;
758
140M
                    *linebuf++ = comp;
759
140M
                } while (--i);
760
47.0M
            }
761
1.02G
        }
762
1.98G
    }
763
1.83M
}
764
765
void
766
gx_build_blended_image_row16(const byte *gs_restrict buf_ptr_, int planestride,
767
                             int width, int num_comp, uint16_t bg, byte *gs_restrict linebuf)
768
0
{
769
0
    const uint16_t *gs_restrict buf_ptr = (const uint16_t *)(const void *)buf_ptr_;
770
0
    size_t inc;
771
772
    /* Note that we read in in native endian and blend,
773
     * then store out in big endian. */
774
0
    planestride >>= 1; /* Array indexing, not byte indexing */
775
0
    inc = planestride * (size_t)num_comp;
776
0
    buf_ptr += inc - 1;
777
0
    for (; width > 0; width--) {
778
        /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
779
0
        uint16_t a = *++buf_ptr;
780
0
        int i = num_comp;
781
782
0
        if (a == 0) {
783
0
            do {
784
0
                *linebuf++ = bg>>8;
785
0
                *linebuf++ = bg;
786
0
            } while (--i);
787
0
        } else {
788
0
            buf_ptr -= inc;
789
0
            if (a == 0xffff) {
790
0
                do {
791
0
                    uint16_t comp = *buf_ptr;
792
0
                    *linebuf++ = comp>>8;
793
0
                    *linebuf++ = comp;
794
0
                    buf_ptr += planestride;
795
0
                } while (--i);
796
0
            } else {
797
0
                a ^= 0xffff;
798
0
                a += a>>15;
799
0
                do {
800
0
                    uint32_t comp = *buf_ptr;
801
0
                    comp += (((bg - comp) * a) + 0x8000)>>16;
802
                    /* Errors in bit 16 and above will be ignored */
803
0
                    buf_ptr += planestride;
804
0
                    *linebuf++ = comp>>8;
805
0
                    *linebuf++ = comp;
806
0
                } while (--i);
807
0
            }
808
0
        }
809
0
    }
810
0
}
811
812
void
813
gx_blend_image_buffer(byte *buf_ptr, int width, int height, int rowstride,
814
                      int planestride, int num_comp, byte bg)
815
3.66k
{
816
3.66k
    int x, y;
817
3.66k
    int position;
818
3.66k
    byte comp, a;
819
3.66k
    int tmp, comp_num;
820
821
41.6k
    for (y = 0; y < height; y++) {
822
38.0k
        position = y * rowstride;
823
35.6M
        for (x = 0; x < width; x++) {
824
            /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
825
35.5M
            a = buf_ptr[position + planestride * (size_t)num_comp];
826
35.5M
            if ((a + 1) & 0xfe) {
827
23.6k
                a ^= 0xff;
828
118k
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
829
94.7k
                    comp  = buf_ptr[position + planestride * (size_t)comp_num];
830
94.7k
                    tmp = ((bg - comp) * a) + 0x80;
831
94.7k
                    comp += (tmp + (tmp >> 8)) >> 8;
832
94.7k
                    buf_ptr[position + planestride * (size_t)comp_num] = comp;
833
94.7k
                }
834
35.5M
            } else if (a == 0) {
835
110M
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
836
88.5M
                    buf_ptr[position + planestride * (size_t)comp_num] = bg;
837
88.5M
                }
838
22.1M
            }
839
35.5M
            position+=1;
840
35.5M
        }
841
38.0k
    }
842
3.66k
}
843
844
void
845
gx_blend_image_buffer16(byte *buf_ptr_, int width, int height, int rowstride,
846
                        int planestride, int num_comp, uint16_t bg, bool keep_native)
847
0
{
848
0
    uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_;
849
0
    int x, y;
850
0
    int position;
851
0
    int comp, a;
852
0
    int tmp, comp_num;
853
0
    uint16_t bebg;
854
855
    /* Convert bg to be */
856
0
    ((byte *)&bebg)[0] = bg >> 8;
857
0
    ((byte *)&bebg)[1] = bg;
858
859
    /* planestride and rowstride are in bytes, and we want them in shorts */
860
0
    planestride >>= 1;
861
0
    rowstride >>= 1;
862
863
    /* Note that the input here is native endian, and the output must be in big endian! */
864
0
    for (y = 0; y < height; y++) {
865
0
        position = y * rowstride;
866
0
        for (x = 0; x < width; x++) {
867
            /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
868
0
            a = buf_ptr[position + planestride * (size_t)num_comp];
869
0
            if (a == 0) {
870
0
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
871
0
                    buf_ptr[position + planestride * (size_t)comp_num] = bebg;
872
0
                }
873
0
            } else if (a == 0xffff) {
874
#if ARCH_IS_BIG_ENDIAN
875
#else
876
0
                if (!keep_native) {
877
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
878
0
                        comp = buf_ptr[position + planestride * (size_t)comp_num];
879
0
                        ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
880
0
                        ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
881
0
                    }
882
0
                }
883
0
#endif
884
0
            } else {
885
0
                a ^= 0xffff;
886
0
                a += a>>15; /* a is now 0 to 0x10000 */
887
0
                a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */
888
0
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
889
0
                    comp  = buf_ptr[position + planestride * (size_t)comp_num];
890
0
                    tmp = (((int)bg - comp) * a) + 0x4000;
891
0
                    comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */
892
                    /* Store as big endian */
893
0
                    ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp>>8;
894
0
                    ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
895
0
                }
896
0
            }
897
0
            position+=1;
898
0
        }
899
0
    }
900
0
}
901
902
void
903
gx_blend_image_buffer8to16(const byte *buf_ptr_in, unsigned short *buf_ptr_out, int width,
904
    int height, int rowstride, int planestride, int num_comp, byte bg)
905
0
{
906
0
    int x, y;
907
0
    int position;
908
0
    int comp, a;
909
0
    int tmp, comp_num;
910
0
    int bg_out = bg + (bg << 8);
911
912
0
    for (y = 0; y < height; y++) {
913
0
        position = y * rowstride;
914
0
        for (x = 0; x < width; x++) {
915
            /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
916
0
            a = buf_ptr_in[position + planestride * (size_t)num_comp];
917
0
            if (a == 0xff) {
918
0
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
919
0
                    comp = buf_ptr_in[position + planestride * (size_t)comp_num];
920
0
                    buf_ptr_out[position + planestride * (size_t)comp_num] = (comp + (comp << 8));
921
0
                }
922
0
            } else if (a == 0) {
923
0
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
924
0
                    buf_ptr_out[position + planestride * (size_t)comp_num] = bg_out;
925
0
                }
926
0
            } else {
927
0
                a ^= 0xff;
928
0
                a += (a << 8);
929
0
                for (comp_num = 0; comp_num < num_comp; comp_num++) {
930
0
                    comp = buf_ptr_in[position + planestride * (size_t)comp_num];
931
0
                    comp += (comp << 8);
932
0
                    tmp = ((bg_out - comp) * a) + 0x8000;
933
0
                    comp += (tmp + (tmp >> 16)) >> 16;
934
0
                    comp = ((comp & 0xff) << 8) + ((comp & 0xff00) >> 8);
935
0
                    buf_ptr_out[position + planestride * (size_t)comp_num] = comp;
936
0
                }
937
0
            }
938
0
            position += 1;
939
0
        }
940
0
    }
941
0
}
942
943
int
944
gx_put_blended_image_custom(gx_device *target, byte *buf_ptr_,
945
                      int planestride, int rowstride,
946
                      int x0, int y0, int width, int height,
947
                      int num_comp, uint16_t bg, bool deep)
948
0
{
949
0
    int code = 0;
950
0
    int x, y, tmp, comp_num;
951
0
    gx_color_index color;
952
0
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
953
0
    gx_color_value comp;
954
0
    uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_;
955
956
    /* Send pixel data to the target device. */
957
0
    if (deep) {
958
0
        for (y = 0; y < height; y++) {
959
0
            for (x = 0; x < width; x++) {
960
961
                /* composite CMYKA, etc. pixel with over solid background */
962
0
#define GET16(v) (*((uint16_t *)(void *)&(v)))
963
0
                uint16_t a = GET16(buf_ptr[x + planestride * (size_t)num_comp]);
964
965
0
                if (a == 0) {
966
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
967
0
                        cv[comp_num] = bg;
968
0
                    }
969
0
                } else if (a == 0xffff) {
970
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
971
0
                        comp = buf_ptr[x + planestride * (size_t)comp_num];
972
0
                        cv[comp_num] = comp;
973
0
                    }
974
0
                } else {
975
0
                    a ^= 0xffff;
976
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
977
0
                        comp  = GET16(buf_ptr[x + planestride * (size_t)comp_num]);
978
0
                        tmp = ((bg - comp) * a) + 0x8000;
979
0
                        cv[comp_num] = comp + ((tmp + (tmp>>16))>>16);
980
0
                    }
981
0
                }
982
0
                color = dev_proc(target, encode_color)(target, cv);
983
0
                code = dev_proc(target, fill_rectangle)(target, x + x0,
984
0
                                                                y + y0, 1, 1, color);
985
0
                if (code < 0)
986
0
                    return code;
987
0
            }
988
989
0
            buf_ptr += rowstride;
990
0
        }
991
0
    } else {
992
0
        bg >>= 8;
993
0
        for (y = 0; y < height; y++) {
994
0
            for (x = 0; x < width; x++) {
995
996
                /* composite CMYKA, etc. pixel with over solid background */
997
0
                byte a = buf_ptr[x + planestride * (size_t)num_comp];
998
999
0
                if ((a + 1) & 0xfe) {
1000
0
                    a ^= 0xff;
1001
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1002
0
                        comp  = buf_ptr[x + planestride * (size_t)comp_num];
1003
0
                        tmp = ((bg - comp) * a) + 0x80;
1004
0
                        comp += tmp + (tmp >> 8);
1005
0
                        cv[comp_num] = comp;
1006
0
                    }
1007
0
                } else if (a == 0) {
1008
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1009
0
                        cv[comp_num] = bg;
1010
0
                    }
1011
0
                } else {
1012
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1013
0
                        comp = buf_ptr[x + planestride * (size_t)comp_num];
1014
0
                        cv[comp_num] = (comp << 8) + comp;
1015
0
                    }
1016
0
                }
1017
0
                color = dev_proc(target, encode_color)(target, cv);
1018
0
                code = dev_proc(target, fill_rectangle)(target, x + x0,
1019
0
                                                                y + y0, 1, 1, color);
1020
0
                if (code < 0)
1021
0
                    return code;
1022
0
            }
1023
1024
0
            buf_ptr += rowstride;
1025
0
        }
1026
0
    }
1027
0
    return code;
1028
0
}