Coverage Report

Created: 2025-06-10 07:15

/src/ghostpdl/base/gxblend1.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
/* 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
118M
{
93
118M
    int i;
94
95
448M
    for (i = num_comp - 1; i >= 0; i--) {
96
329M
        out[i] = (byte)(color & 0xff);
97
329M
        color >>= 8;
98
329M
    }
99
118M
}
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
7.86M
{
124
7.86M
    int i;
125
126
39.3M
    for (i = num_comp - 1; i >= 0; i--) {
127
31.4M
        out[i] = 0xff - (byte)(color & 0xff);
128
31.4M
        color >>= 8;
129
31.4M
    }
130
7.86M
}
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
231k
{
183
231k
    int y;
184
185
231k
    width <<= deep;
186
187
231k
    if (width == des_rowstride && width == src_rowstride) {
188
114k
        width *= height;
189
114k
        height = 1;
190
114k
    }
191
192
1.56M
    for (y = 0; y < height; ++y) {
193
1.33M
        memcpy(des_ptr, src_ptr, width);
194
1.33M
        des_ptr += des_rowstride;
195
1.33M
        src_ptr += src_rowstride;
196
1.33M
    }
197
231k
}
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
56.9k
{
203
    /* alpha_g and shape do not copy */
204
56.9k
    des_buf += des_info->planestride * (size_t)((des_info->has_shape ? 1 : 0) +
205
56.9k
                                        (des_info->has_alpha_g ? 1 : 0));
206
56.9k
    src_buf += src_info->planestride * (size_t)((src_info->has_shape ? 1 : 0) +
207
56.9k
                                        (src_info->has_alpha_g ? 1 : 0));
208
    /* tags plane does copy */
209
56.9k
    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
56.9k
}
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
58.2k
{
323
    /* make copy of backdrop for compositing */
324
58.2k
    int x0 = max(buf->rect.p.x, tos->rect.p.x);
325
58.2k
    int x1 = min(buf->rect.q.x, tos->rect.q.x);
326
58.2k
    int y0 = max(buf->rect.p.y, tos->rect.p.y);
327
58.2k
    int y1 = min(buf->rect.q.y, tos->rect.q.y);
328
329
58.2k
    if (x0 < x1 && y0 < y1) {
330
56.9k
        int width = x1 - x0;
331
56.9k
        int height = y1 - y0;
332
56.9k
        byte *buf_plane, *tos_plane;
333
56.9k
        int i, n_planes;
334
56.9k
        bool deep = buf->deep;
335
336
56.9k
        buf_plane = buf->data;
337
56.9k
        n_planes = buf->n_planes;
338
56.9k
        if (from_backdrop) {
339
0
            tos_plane = tos->backdrop;
340
56.9k
        } else {
341
56.9k
            tos_plane = tos->data;
342
56.9k
        }
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
56.9k
        if (x0 > buf->rect.p.x || x1 < buf->rect.q.x ||
349
56.9k
            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
72
            memset(buf_plane, 0, n_planes * (size_t)buf->planestride);
353
56.8k
        } 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
56.8k
            int tag_plane_num = tos->n_chan + !!buf->has_shape + !!buf->has_alpha_g;
358
56.8k
            if (!from_backdrop && n_planes > tag_plane_num)
359
0
                n_planes = tag_plane_num;
360
56.8k
            if (n_planes > tos->n_chan)
361
56.8k
                memset(buf->data + tos->n_chan * (size_t)buf->planestride, 0,
362
56.8k
                       (n_planes - tos->n_chan) * (size_t)buf->planestride);
363
56.8k
        }
364
56.9k
        buf_plane += (y0 - buf->rect.p.y) * (size_t)buf->rowstride +
365
56.9k
                     ((x0 - buf->rect.p.x)<<deep);
366
56.9k
        tos_plane += (y0 - tos->rect.p.y) * (size_t)tos->rowstride +
367
56.9k
                     ((x0 - tos->rect.p.x)<<deep);
368
        /* Color and alpha plane */
369
288k
        for (i = 0; i < tos->n_chan; i++) {
370
231k
            copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride,
371
231k
                            width, height, buf->deep);
372
231k
            buf_plane += buf->planestride;
373
231k
            tos_plane += tos->planestride;
374
231k
        }
375
56.9k
        if (!from_backdrop)
376
56.9k
            copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height);
377
56.9k
    }
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
58.2k
}
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
65.3M
{
398
65.3M
    gx_color_index color = 0;
399
65.3M
    uchar i;
400
65.3M
    uchar ncomp = dev->color_info.num_components;
401
65.3M
    COLROUND_VARS;
402
403
65.3M
    COLROUND_SETUP(8);
404
258M
    for (i = 0; i < ncomp; i++) {
405
192M
        color <<= 8;
406
192M
        color |= COLROUND_ROUND(colors[i]);
407
192M
    }
408
65.3M
    return (color == gx_no_color_index ? color ^ 1 : color);
409
65.3M
}
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 - 1;
437
0
    COLROUND_VARS;
438
439
0
    COLROUND_SETUP(8);
440
    /* Add in the tag information */
441
0
    color = dev->graphics_type_tag & 255;
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 - 1;
455
0
    COLROUND_VARS;
456
457
0
    COLROUND_SETUP(16);
458
    /* Add in the tag information */
459
0
    color = dev->graphics_type_tag & 65535;
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
0
{
511
0
    uchar num_comp = dev->color_info.num_components;
512
513
0
    out[0] = out[1] = out[2] = gray;
514
0
    for (--num_comp; num_comp > 2; num_comp--)
515
0
        out[num_comp] = 0;
516
0
}
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
0
{
522
0
    uchar num_comp = dev->color_info.num_components;
523
524
0
    out[0] = r;
525
0
    out[1] = g;
526
0
    out[2] = b;
527
0
    for (--num_comp; num_comp > 2; num_comp--)
528
0
        out[num_comp] = 0;
529
0
}
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
0
{
534
0
    uchar num_comp = dev->color_info.num_components;
535
536
0
    color_cmyk_to_rgb(c, m, y, k, NULL, out, dev->memory);
537
0
    for (--num_comp; num_comp > 2; num_comp--)
538
0
        out[num_comp] = 0;
539
0
}
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
0
{
612
0
    uchar num_comp = dev->color_info.num_components;
613
614
0
    out[0] = c;
615
0
    out[1] = m;
616
0
    out[2] = y;
617
0
    out[3] = k;
618
0
    for (--num_comp; num_comp > 3; num_comp--)
619
0
        out[num_comp] = 0;
620
0
}
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.63M
{
732
1.63M
    size_t inc = planestride * (size_t)num_comp;
733
734
1.63M
    buf_ptr += inc - 1;
735
1.83G
    for (; width > 0; width--) {
736
        /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
737
1.82G
        byte a = *++buf_ptr;
738
1.82G
        int i = num_comp;
739
740
1.82G
        if (a == 0) {
741
2.29G
            do {
742
2.29G
                *linebuf++ = bg;
743
2.29G
            } while (--i);
744
1.06G
        } else {
745
1.06G
            buf_ptr -= inc;
746
1.06G
            if (a == 0xff) {
747
3.09G
                do {
748
3.09G
                    *linebuf++ = *buf_ptr;
749
3.09G
                    buf_ptr += planestride;
750
3.09G
                } while (--i);
751
1.01G
            } else {
752
50.5M
                a ^= 0xff;
753
151M
                do {
754
151M
                    byte comp = *buf_ptr;
755
151M
                    int tmp = ((bg - comp) * a) + 0x80;
756
151M
                    buf_ptr += planestride;
757
151M
                    comp += (tmp + (tmp >> 8)) >> 8;
758
151M
                    *linebuf++ = comp;
759
151M
                } while (--i);
760
50.5M
            }
761
1.06G
        }
762
1.82G
    }
763
1.63M
}
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, int additive)
815
0
{
816
0
    int x, y;
817
0
    int position;
818
0
    byte comp, a;
819
0
    int tmp, comp_num;
820
821
0
    if (additive) {
822
0
        if (num_comp > 3) {
823
0
            for (y = 0; y < height; y++) {
824
0
                position = y * rowstride;
825
0
                for (x = 0; x < width; x++) {
826
                    /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
827
0
                    a = buf_ptr[position + planestride * (size_t)num_comp];
828
0
                    if ((a + 1) & 0xfe) {
829
0
                        int b = 0xFF;
830
0
                        a ^= 0xff;
831
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
832
0
                            if (comp_num == 3)
833
0
                                b = 0;
834
0
                            comp = buf_ptr[position + planestride * (size_t)comp_num];
835
0
                            tmp = ((b - comp) * a) + 0x80;
836
0
                            comp += (tmp + (tmp >> 8)) >> 8;
837
0
                            buf_ptr[position + planestride * (size_t)comp_num] = comp;
838
0
                        }
839
0
                    } else if (a == 0) {
840
0
                        for (comp_num = 0; comp_num < 3; comp_num++)
841
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 0xFF;
842
0
                        for (; comp_num < num_comp; comp_num++)
843
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 0;
844
0
                    }
845
0
                    position += 1;
846
0
                }
847
0
            }
848
0
        }
849
0
        else {
850
0
            for (y = 0; y < height; y++) {
851
0
                position = y * rowstride;
852
0
                for (x = 0; x < width; x++) {
853
                    /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
854
0
                    a = buf_ptr[position + planestride * (size_t)num_comp];
855
0
                    if ((a + 1) & 0xfe) {
856
0
                        a ^= 0xff;
857
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
858
0
                            comp = buf_ptr[position + planestride * (size_t)comp_num];
859
0
                            tmp = ((0xFF - comp) * a) + 0x80;
860
0
                            comp += (tmp + (tmp >> 8)) >> 8;
861
0
                            buf_ptr[position + planestride * (size_t)comp_num] = comp;
862
0
                        }
863
0
                    } else if (a == 0) {
864
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++)
865
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 0xFF;
866
0
                    }
867
0
                    position += 1;
868
0
                }
869
0
            }
870
0
        }
871
0
    } else {
872
0
        for (y = 0; y < height; y++) {
873
0
            position = y * rowstride;
874
0
            for (x = 0; x < width; x++) {
875
                /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
876
0
                a = buf_ptr[position + planestride * (size_t)num_comp];
877
0
                if ((a + 1) & 0xfe) {
878
0
                    a ^= 0xff;
879
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
880
0
                        comp = buf_ptr[position + planestride * (size_t)comp_num];
881
0
                        tmp = ((- comp) * a) + 0x80;
882
0
                        comp += (tmp + (tmp >> 8)) >> 8;
883
0
                        buf_ptr[position + planestride * (size_t)comp_num] = comp;
884
0
                    }
885
0
                } else if (a == 0) {
886
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++)
887
0
                        buf_ptr[position + planestride * (size_t)comp_num] = 0;
888
0
                }
889
0
                position += 1;
890
0
            }
891
0
        }
892
0
    }
893
0
}
894
895
void
896
gx_blend_image_buffer16(byte *buf_ptr_, int width, int height, int rowstride,
897
                        int planestride, int num_comp, int additive, bool keep_native)
898
0
{
899
0
    uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_;
900
0
    int x, y;
901
0
    int position;
902
0
    int comp, a;
903
0
    int tmp, comp_num;
904
905
    /* planestride and rowstride are in bytes, and we want them in shorts */
906
0
    planestride >>= 1;
907
0
    rowstride >>= 1;
908
909
0
    if (additive)
910
0
    {
911
0
        if (num_comp > 3) {
912
            /* Note that the input here is native endian, and the output must be in big endian! */
913
0
            for (y = 0; y < height; y++) {
914
0
                position = y * rowstride;
915
0
                for (x = 0; x < width; x++) {
916
                    /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
917
0
                    a = buf_ptr[position + planestride * (size_t)num_comp];
918
0
                    if (a == 0) {
919
0
                        for (comp_num = 0; comp_num < 3; comp_num++)
920
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 65535;
921
0
                        for (; comp_num < num_comp; comp_num++)
922
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 0;
923
0
                    } else if (a == 0xffff) {
924
#if ARCH_IS_BIG_ENDIAN
925
#else
926
0
                        if (!keep_native) {
927
0
                            for (comp_num = 0; comp_num < num_comp; comp_num++) {
928
0
                                comp = buf_ptr[position + planestride * (size_t)comp_num];
929
0
                                ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
930
0
                                ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
931
0
                            }
932
0
                        }
933
0
#endif
934
0
                    } else {
935
0
                        int b = 65535;
936
0
                        a ^= 0xffff;
937
0
                        a += a >> 15; /* a is now 0 to 0x10000 */
938
0
                        a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */
939
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
940
0
                            if (comp_num == 3)
941
0
                                b = 0;
942
0
                            comp = buf_ptr[position + planestride * (size_t)comp_num];
943
0
                            tmp = ((b - comp) * a) + 0x4000;
944
0
                            comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */
945
                            /* Store as big endian */
946
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
947
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
948
0
                        }
949
0
                    }
950
0
                    position += 1;
951
0
                }
952
0
            }
953
0
        }
954
0
        else {
955
            /* Note that the input here is native endian, and the output must be in big endian! */
956
0
            for (y = 0; y < height; y++) {
957
0
                position = y * rowstride;
958
0
                for (x = 0; x < width; x++) {
959
                    /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
960
0
                    a = buf_ptr[position + planestride * (size_t)num_comp];
961
0
                    if (a == 0) {
962
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
963
0
                            buf_ptr[position + planestride * (size_t)comp_num] = 65535;
964
0
                        }
965
0
                    } else if (a == 0xffff) {
966
#if ARCH_IS_BIG_ENDIAN
967
#else
968
0
                        if (!keep_native) {
969
0
                            for (comp_num = 0; comp_num < num_comp; comp_num++) {
970
0
                                comp = buf_ptr[position + planestride * (size_t)comp_num];
971
0
                                ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
972
0
                                ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
973
0
                            }
974
0
                        }
975
0
#endif
976
0
                    } else {
977
0
                        a ^= 0xffff;
978
0
                        a += a >> 15; /* a is now 0 to 0x10000 */
979
0
                        a >>= 1; /* We can only use 15 bits as bg-comp has a sign bit we can't lose */
980
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
981
0
                            comp = buf_ptr[position + planestride * (size_t)comp_num];
982
0
                            tmp = ((65535 - comp) * a) + 0x4000;
983
0
                            comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */
984
                            /* Store as big endian */
985
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
986
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
987
0
                        }
988
0
                    }
989
0
                    position += 1;
990
0
                }
991
0
            }
992
0
        }
993
0
    } else {
994
        /* Note that the input here is native endian, and the output must be in big endian! */
995
0
        for (y = 0; y < height; y++) {
996
0
            position = y * rowstride;
997
0
            for (x = 0; x < width; x++) {
998
                /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
999
0
                a = buf_ptr[position + planestride * (size_t)num_comp];
1000
0
                if (a == 0) {
1001
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1002
0
                        buf_ptr[position + planestride * (size_t)comp_num] = 0;
1003
0
                    }
1004
0
                } else if (a == 0xffff) {
1005
#if ARCH_IS_BIG_ENDIAN
1006
#else
1007
0
                    if (!keep_native) {
1008
0
                        for (comp_num = 0; comp_num < num_comp; comp_num++) {
1009
0
                            comp = buf_ptr[position + planestride * (size_t)comp_num];
1010
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
1011
0
                            ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
1012
0
                        }
1013
0
                    }
1014
0
#endif
1015
0
                } else {
1016
0
                    a ^= 0xffff;
1017
0
                    a += a >> 15; /* a is now 0 to 0x10000 */
1018
0
                    a >>= 1; /* We can only use 15 bits as -comp has a sign bit we can't lose */
1019
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1020
0
                        comp = buf_ptr[position + planestride * (size_t)comp_num];
1021
0
                        tmp = ((- comp) * a) + 0x4000;
1022
0
                        comp += (tmp >> 15); /* Errors in bit 16 upwards will be ignored */
1023
                        /* Store as big endian */
1024
0
                        ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[0] = comp >> 8;
1025
0
                        ((byte *)&buf_ptr[position + planestride * (size_t)comp_num])[1] = comp;
1026
0
                    }
1027
0
                }
1028
0
                position += 1;
1029
0
            }
1030
0
        }
1031
0
    }
1032
0
}
1033
1034
int
1035
gx_put_blended_image_custom(gx_device *target, byte *buf_ptr_,
1036
                      int planestride, int rowstride,
1037
                      int x0, int y0, int width, int height,
1038
                      int num_comp, uint16_t bg, bool deep)
1039
0
{
1040
0
    int code = 0;
1041
0
    int x, y, tmp, comp_num;
1042
0
    gx_color_index color;
1043
0
    gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1044
0
    gx_color_value comp;
1045
0
    uint16_t *buf_ptr = (uint16_t *)(void *)buf_ptr_;
1046
1047
    /* Send pixel data to the target device. */
1048
0
    if (deep) {
1049
0
        for (y = 0; y < height; y++) {
1050
0
            for (x = 0; x < width; x++) {
1051
1052
                /* composite CMYKA, etc. pixel with over solid background */
1053
0
#define GET16(v) (*((uint16_t *)(void *)&(v)))
1054
0
                uint16_t a = GET16(buf_ptr[x + planestride * (size_t)num_comp]);
1055
1056
0
                if (a == 0) {
1057
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1058
0
                        cv[comp_num] = bg;
1059
0
                    }
1060
0
                } else if (a == 0xffff) {
1061
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1062
0
                        comp = buf_ptr[x + planestride * (size_t)comp_num];
1063
0
                        cv[comp_num] = comp;
1064
0
                    }
1065
0
                } else {
1066
0
                    a ^= 0xffff;
1067
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1068
0
                        comp  = GET16(buf_ptr[x + planestride * (size_t)comp_num]);
1069
0
                        tmp = ((bg - comp) * a) + 0x8000;
1070
0
                        cv[comp_num] = comp + ((tmp + (tmp>>16))>>16);
1071
0
                    }
1072
0
                }
1073
0
                color = dev_proc(target, encode_color)(target, cv);
1074
0
                code = dev_proc(target, fill_rectangle)(target, x + x0,
1075
0
                                                                y + y0, 1, 1, color);
1076
0
                if (code < 0)
1077
0
                    return code;
1078
0
            }
1079
1080
0
            buf_ptr += rowstride;
1081
0
        }
1082
0
    } else {
1083
0
        bg >>= 8;
1084
0
        for (y = 0; y < height; y++) {
1085
0
            for (x = 0; x < width; x++) {
1086
1087
                /* composite CMYKA, etc. pixel with over solid background */
1088
0
                byte a = buf_ptr[x + planestride * (size_t)num_comp];
1089
1090
0
                if ((a + 1) & 0xfe) {
1091
0
                    a ^= 0xff;
1092
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1093
0
                        comp  = buf_ptr[x + planestride * (size_t)comp_num];
1094
0
                        tmp = ((bg - comp) * a) + 0x80;
1095
0
                        comp += tmp + (tmp >> 8);
1096
0
                        cv[comp_num] = comp;
1097
0
                    }
1098
0
                } else if (a == 0) {
1099
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1100
0
                        cv[comp_num] = bg;
1101
0
                    }
1102
0
                } else {
1103
0
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
1104
0
                        comp = buf_ptr[x + planestride * (size_t)comp_num];
1105
0
                        cv[comp_num] = (comp << 8) + comp;
1106
0
                    }
1107
0
                }
1108
0
                color = dev_proc(target, encode_color)(target, cv);
1109
0
                code = dev_proc(target, fill_rectangle)(target, x + x0,
1110
0
                                                                y + y0, 1, 1, color);
1111
0
                if (code < 0)
1112
0
                    return code;
1113
0
            }
1114
1115
0
            buf_ptr += rowstride;
1116
0
        }
1117
0
    }
1118
0
    return code;
1119
0
}