Coverage Report

Created: 2025-04-22 06:20

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