Coverage Report

Created: 2025-06-24 07:01

/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
700M
{
93
700M
    int i;
94
95
2.49G
    for (i = num_comp - 1; i >= 0; i--) {
96
1.79G
        out[i] = (byte)(color & 0xff);
97
1.79G
        color >>= 8;
98
1.79G
    }
99
700M
}
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
71.7M
{
124
71.7M
    int i;
125
126
358M
    for (i = num_comp - 1; i >= 0; i--) {
127
287M
        out[i] = 0xff - (byte)(color & 0xff);
128
287M
        color >>= 8;
129
287M
    }
130
71.7M
}
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
1.65M
{
183
1.65M
    int y;
184
185
1.65M
    width <<= deep;
186
187
1.65M
    if (width == des_rowstride && width == src_rowstride) {
188
864k
        width *= height;
189
864k
        height = 1;
190
864k
    }
191
192
10.6M
    for (y = 0; y < height; ++y) {
193
9.04M
        memcpy(des_ptr, src_ptr, width);
194
9.04M
        des_ptr += des_rowstride;
195
9.04M
        src_ptr += src_rowstride;
196
9.04M
    }
197
1.65M
}
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
453k
{
203
    /* alpha_g and shape do not copy */
204
453k
    des_buf += des_info->planestride * (size_t)((des_info->has_shape ? 1 : 0) +
205
453k
                                        (des_info->has_alpha_g ? 1 : 0));
206
453k
    src_buf += src_info->planestride * (size_t)((src_info->has_shape ? 1 : 0) +
207
453k
                                        (src_info->has_alpha_g ? 1 : 0));
208
    /* tags plane does copy */
209
453k
    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
453k
}
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
468k
{
323
    /* make copy of backdrop for compositing */
324
468k
    int x0 = max(buf->rect.p.x, tos->rect.p.x);
325
468k
    int x1 = min(buf->rect.q.x, tos->rect.q.x);
326
468k
    int y0 = max(buf->rect.p.y, tos->rect.p.y);
327
468k
    int y1 = min(buf->rect.q.y, tos->rect.q.y);
328
329
468k
    if (x0 < x1 && y0 < y1) {
330
453k
        int width = x1 - x0;
331
453k
        int height = y1 - y0;
332
453k
        byte *buf_plane, *tos_plane;
333
453k
        int i, n_planes;
334
453k
        bool deep = buf->deep;
335
336
453k
        buf_plane = buf->data;
337
453k
        n_planes = buf->n_planes;
338
453k
        if (from_backdrop) {
339
28
            tos_plane = tos->backdrop;
340
453k
        } else {
341
453k
            tos_plane = tos->data;
342
453k
        }
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
453k
        if (x0 > buf->rect.p.x || x1 < buf->rect.q.x ||
349
453k
            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
457
            memset(buf_plane, 0, n_planes * (size_t)buf->planestride);
353
452k
        } 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
452k
            int tag_plane_num = tos->n_chan + !!buf->has_shape + !!buf->has_alpha_g;
358
452k
            if (!from_backdrop && n_planes > tag_plane_num)
359
0
                n_planes = tag_plane_num;
360
452k
            if (n_planes > tos->n_chan)
361
452k
                memset(buf->data + tos->n_chan * (size_t)buf->planestride, 0,
362
452k
                       (n_planes - tos->n_chan) * (size_t)buf->planestride);
363
452k
        }
364
453k
        buf_plane += (y0 - buf->rect.p.y) * (size_t)buf->rowstride +
365
453k
                     ((x0 - buf->rect.p.x)<<deep);
366
453k
        tos_plane += (y0 - tos->rect.p.y) * (size_t)tos->rowstride +
367
453k
                     ((x0 - tos->rect.p.x)<<deep);
368
        /* Color and alpha plane */
369
2.10M
        for (i = 0; i < tos->n_chan; i++) {
370
1.65M
            copy_plane_part(buf_plane, buf->rowstride, tos_plane, tos->rowstride,
371
1.65M
                            width, height, buf->deep);
372
1.65M
            buf_plane += buf->planestride;
373
1.65M
            tos_plane += tos->planestride;
374
1.65M
        }
375
453k
        if (!from_backdrop)
376
453k
            copy_extra_planes(buf_plane, buf, tos_plane, tos, width, height);
377
453k
    }
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
468k
}
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
380M
{
398
380M
    gx_color_index color = 0;
399
380M
    uchar i;
400
380M
    uchar ncomp = dev->color_info.num_components;
401
380M
    COLROUND_VARS;
402
403
380M
    COLROUND_SETUP(8);
404
1.50G
    for (i = 0; i < ncomp; i++) {
405
1.12G
        color <<= 8;
406
1.12G
        color |= COLROUND_ROUND(colors[i]);
407
1.12G
    }
408
380M
    return (color == gx_no_color_index ? color ^ 1 : color);
409
380M
}
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
4
{
499
4
    uchar num_comp = dev->color_info.num_components;
500
501
4
    out[0] = out[1] = out[2] = frac_0;
502
4
    out[3] = frac_1 - gray;
503
4
    for (--num_comp; num_comp > 3; num_comp--)
504
0
        out[num_comp] = 0;
505
4
}
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
2.28k
{
511
2.28k
    uchar num_comp = dev->color_info.num_components;
512
513
2.28k
    out[0] = out[1] = out[2] = gray;
514
2.28k
    for (--num_comp; num_comp > 2; num_comp--)
515
0
        out[num_comp] = 0;
516
2.28k
}
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
6.75M
{
522
6.75M
    uchar num_comp = dev->color_info.num_components;
523
524
6.75M
    out[0] = r;
525
6.75M
    out[1] = g;
526
6.75M
    out[2] = b;
527
6.77M
    for (--num_comp; num_comp > 2; num_comp--)
528
11.3k
        out[num_comp] = 0;
529
6.75M
}
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
868
{
534
868
    uchar num_comp = dev->color_info.num_components;
535
536
868
    color_cmyk_to_rgb(c, m, y, k, NULL, out, dev->memory);
537
868
    for (--num_comp; num_comp > 2; num_comp--)
538
0
        out[num_comp] = 0;
539
868
}
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
7.20M
{
612
7.20M
    uchar num_comp = dev->color_info.num_components;
613
614
7.20M
    out[0] = c;
615
7.20M
    out[1] = m;
616
7.20M
    out[2] = y;
617
7.20M
    out[3] = k;
618
7.20M
    for (--num_comp; num_comp > 3; num_comp--)
619
1
        out[num_comp] = 0;
620
7.20M
}
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
11.4M
{
732
11.4M
    size_t inc = planestride * (size_t)num_comp;
733
734
11.4M
    buf_ptr += inc - 1;
735
12.4G
    for (; width > 0; width--) {
736
        /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
737
12.4G
        byte a = *++buf_ptr;
738
12.4G
        int i = num_comp;
739
740
12.4G
        if (a == 0) {
741
13.4G
            do {
742
13.4G
                *linebuf++ = bg;
743
13.4G
            } while (--i);
744
7.15G
        } else {
745
7.15G
            buf_ptr -= inc;
746
7.15G
            if (a == 0xff) {
747
19.3G
                do {
748
19.3G
                    *linebuf++ = *buf_ptr;
749
19.3G
                    buf_ptr += planestride;
750
19.3G
                } while (--i);
751
6.83G
            } else {
752
323M
                a ^= 0xff;
753
917M
                do {
754
917M
                    byte comp = *buf_ptr;
755
917M
                    int tmp = ((bg - comp) * a) + 0x80;
756
917M
                    buf_ptr += planestride;
757
917M
                    comp += (tmp + (tmp >> 8)) >> 8;
758
917M
                    *linebuf++ = comp;
759
917M
                } while (--i);
760
323M
            }
761
7.15G
        }
762
12.4G
    }
763
11.4M
}
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
35.5k
{
816
35.5k
    int x, y;
817
35.5k
    int position;
818
35.5k
    byte comp, a;
819
35.5k
    int tmp, comp_num;
820
821
35.5k
    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
35.5k
    } else {
872
397k
        for (y = 0; y < height; y++) {
873
362k
            position = y * rowstride;
874
343M
            for (x = 0; x < width; x++) {
875
                /* composite RGBA (or CMYKA, etc.) pixel with over solid background */
876
343M
                a = buf_ptr[position + planestride * (size_t)num_comp];
877
343M
                if ((a + 1) & 0xfe) {
878
5.09M
                    a ^= 0xff;
879
25.4M
                    for (comp_num = 0; comp_num < num_comp; comp_num++) {
880
20.3M
                        comp = buf_ptr[position + planestride * (size_t)comp_num];
881
20.3M
                        tmp = ((- comp) * a) + 0x80;
882
20.3M
                        comp += (tmp + (tmp >> 8)) >> 8;
883
20.3M
                        buf_ptr[position + planestride * (size_t)comp_num] = comp;
884
20.3M
                    }
885
338M
                } else if (a == 0) {
886
1.04G
                    for (comp_num = 0; comp_num < num_comp; comp_num++)
887
834M
                        buf_ptr[position + planestride * (size_t)comp_num] = 0;
888
208M
                }
889
343M
                position += 1;
890
343M
            }
891
362k
        }
892
35.5k
    }
893
35.5k
}
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
}