Coverage Report

Created: 2022-10-31 07:00

/src/ghostpdl/devices/gdevpng.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2022 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  1305 Grant Avenue - Suite 200, Novato,
13
   CA 94945, U.S.A., +1(415)492-9861, for further information.
14
*/
15
16
17
/* PNG (Portable Network Graphics) Format.  Pronounced "ping". */
18
/* lpd 1999-09-24: changes PNG_NO_STDIO to PNG_NO_CONSOLE_IO for libpng
19
   versions 1.0.3 and later. */
20
/* lpd 1999-07-01: replaced remaining uses of gs_malloc and gs_free with
21
   gs_alloc_bytes and gs_free_object. */
22
/* lpd 1999-03-08: changed png.h to png_.h to allow compiling with only
23
   headers in /usr/include, no source code. */
24
/* lpd 1997-07-20: changed from using gs_malloc/png_xxx_int to png_create_xxx
25
 * for allocating structures, and from gs_free to png_write_destroy for
26
 * freeing them. */
27
/* lpd 1997-5-7: added PNG_LIBPNG_VER conditional for operand types of
28
 * dummy png_push_fill_buffer. */
29
/* lpd 1997-4-13: Added PNG_NO_STDIO to remove library access to stderr. */
30
/* lpd 1997-3-14: Added resolution (pHYs) to output. */
31
/* lpd 1996-6-24: Added #ifdef for compatibility with old libpng versions. */
32
/* lpd 1996-6-11: Edited to remove unnecessary color mapping code. */
33
/* lpd (L. Peter Deutsch) 1996-4-7: Modified for libpng 0.88. */
34
/* Original version by Russell Lang 1995-07-04 */
35
36
/* RJW: Include png header BEFORE the gs ones to avoid warnings. */
37
/*
38
 * libpng versions 1.0.3 and later allow disabling access to the stdxxx
39
 * files while retaining support for FILE * I/O.
40
 */
41
#define PNG_NO_CONSOLE_IO
42
/*
43
 * Earlier libpng versions require disabling FILE * I/O altogether.
44
 * This produces a compiler warning about no prototype for png_init_io.
45
 * The right thing will happen at link time, since the library itself
46
 * is compiled with stdio support.  Unfortunately, we can't do this
47
 * conditionally depending on PNG_LIBPNG_VER, because this is defined
48
 * in png.h.
49
 */
50
/*#define PNG_NO_STDIO*/
51
#include "png_.h"
52
53
#include "gdevprn.h"
54
#include "gdevmem.h"
55
#include "gdevpccm.h"
56
#include "gscdefs.h"
57
#include "gxdownscale.h"
58
#include "gxdevsop.h"
59
#include "gscms.h"
60
61
/* ------ The device descriptors ------ */
62
63
/*
64
 * Default X and Y resolution.
65
 */
66
#define X_DPI 72
67
#define Y_DPI 72
68
69
static dev_proc_print_page(png_print_page);
70
static dev_proc_print_page(png_print_page_monod);
71
static dev_proc_open_device(pngalpha_open);
72
static dev_proc_encode_color(pngalpha_encode_color);
73
static dev_proc_decode_color(pngalpha_decode_color);
74
static dev_proc_copy_alpha(pngalpha_copy_alpha);
75
static dev_proc_fillpage(pngalpha_fillpage);
76
static dev_proc_put_image(pngalpha_put_image);
77
static dev_proc_get_params(pngalpha_get_params);
78
static dev_proc_put_params(pngalpha_put_params);
79
static dev_proc_create_buf_device(pngalpha_create_buf_device);
80
static dev_proc_get_params(png_get_params_downscale);
81
static dev_proc_put_params(png_put_params_downscale);
82
static dev_proc_get_params(png_get_params_downscale_mfs);
83
static dev_proc_put_params(png_put_params_downscale_mfs);
84
static dev_proc_dev_spec_op(pngalpha_spec_op);
85
86
typedef struct gx_device_png_s gx_device_png;
87
struct gx_device_png_s {
88
    gx_device_common;
89
    gx_prn_device_common;
90
    gx_downscaler_params downscale;
91
};
92
93
/* Monochrome. */
94
95
const gx_device_png gs_pngmono_device =
96
{ /* The print_page proc is compatible with allowing bg printing */
97
  prn_device_body(gx_device_png, gdev_prn_initialize_device_procs_mono_bg, "pngmono",
98
           DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
99
           X_DPI, Y_DPI,
100
           0, 0, 0, 0,    /* margins */
101
           1, 1, 1, 1, 2, 2, png_print_page),
102
    GX_DOWNSCALER_PARAMS_DEFAULTS
103
};
104
105
106
/* 4-bit planar (EGA/VGA-style) color. */
107
108
/* Since the print_page doesn't alter the device, this device can print in the background */
109
static void
110
png16_initialize_device_procs(gx_device *dev)
111
0
{
112
0
    gdev_prn_initialize_device_procs_bg(dev);
113
114
0
    set_dev_proc(dev, map_rgb_color, pc_4bit_map_rgb_color);
115
0
    set_dev_proc(dev, map_color_rgb, pc_4bit_map_color_rgb);
116
0
    set_dev_proc(dev, encode_color, pc_4bit_map_rgb_color);
117
0
    set_dev_proc(dev, decode_color, pc_4bit_map_color_rgb);
118
0
}
119
120
const gx_device_png gs_png16_device = {
121
  prn_device_body(gx_device_png, png16_initialize_device_procs, "png16",
122
           DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
123
           X_DPI, Y_DPI,
124
           0, 0, 0, 0,    /* margins */
125
           3, 4, 1, 1, 2, 2, png_print_page),
126
    GX_DOWNSCALER_PARAMS_DEFAULTS
127
};
128
129
/* 8-bit (SuperVGA-style) color. */
130
/* (Uses a fixed palette of 3,3,2 bits.) */
131
132
/* Since the print_page doesn't alter the device, this device can print in the background */
133
static void
134
png256_initialize_device_procs(gx_device *dev)
135
0
{
136
0
    gdev_prn_initialize_device_procs_bg(dev);
137
138
0
    set_dev_proc(dev, map_rgb_color, pc_8bit_map_rgb_color);
139
0
    set_dev_proc(dev, map_color_rgb, pc_8bit_map_color_rgb);
140
0
    set_dev_proc(dev, encode_color, pc_8bit_map_rgb_color);
141
0
    set_dev_proc(dev, decode_color, pc_8bit_map_color_rgb);
142
0
}
143
144
const gx_device_png gs_png256_device = {
145
  prn_device_body(gx_device_png, png256_initialize_device_procs, "png256",
146
           DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
147
           X_DPI, Y_DPI,
148
           0, 0, 0, 0,    /* margins */
149
           3, 8, 5, 5, 6, 6, png_print_page),
150
    GX_DOWNSCALER_PARAMS_DEFAULTS
151
};
152
153
/* 8-bit gray */
154
155
/* Since the print_page doesn't alter the device, this device can print in the background */
156
static void
157
pnggray_initialize_device_procs(gx_device *dev)
158
0
{
159
0
    gdev_prn_initialize_device_procs_gray_bg(dev);
160
161
0
    set_dev_proc(dev, get_params, png_get_params_downscale);
162
0
    set_dev_proc(dev, put_params, png_put_params_downscale);
163
0
    set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color);
164
0
    set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray);
165
0
}
166
167
const gx_device_png gs_pnggray_device =
168
{prn_device_body(gx_device_png, pnggray_initialize_device_procs, "pnggray",
169
                 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
170
                 X_DPI, Y_DPI,
171
                 0, 0, 0, 0,  /* margins */
172
                 1, 8, 255, 0, 256, 0, png_print_page),
173
    GX_DOWNSCALER_PARAMS_DEFAULTS
174
};
175
176
/* Monochrome (with error diffusion) */
177
178
/* Since the print_page doesn't alter the device, this device can print in the background */
179
static void
180
pngmonod_initialize_device_procs(gx_device *dev)
181
0
{
182
0
    gdev_prn_initialize_device_procs_gray_bg(dev);
183
184
0
    set_dev_proc(dev, get_params, png_get_params_downscale_mfs);
185
0
    set_dev_proc(dev, put_params, png_put_params_downscale_mfs);
186
0
    set_dev_proc(dev, encode_color, gx_default_8bit_map_gray_color);
187
0
    set_dev_proc(dev, decode_color, gx_default_8bit_map_color_gray);
188
0
}
189
190
const gx_device_png gs_pngmonod_device =
191
{prn_device_body(gx_device_png, pngmonod_initialize_device_procs, "pngmonod",
192
                 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
193
                 X_DPI, Y_DPI,
194
                 0, 0, 0, 0,  /* margins */
195
                 1, 8, 255, 0, 256, 0, png_print_page_monod),
196
    GX_DOWNSCALER_PARAMS_DEFAULTS
197
};
198
199
/* 24-bit color. */
200
201
/* Since the print_page doesn't alter the device, this device can print in the background */
202
static void
203
png16m_initialize_device_procs(gx_device *dev)
204
6.22k
{
205
6.22k
    gdev_prn_initialize_device_procs_rgb_bg(dev);
206
207
6.22k
    set_dev_proc(dev, get_params, png_get_params_downscale);
208
6.22k
    set_dev_proc(dev, put_params, png_put_params_downscale);
209
210
    /* The prn macros used in previous versions of the code leave
211
     * encode_color and decode_color set to NULL (which are then rewritten
212
     * by the system to the default. For compatibility we do the same. */
213
6.22k
    set_dev_proc(dev, encode_color, gx_default_rgb_map_rgb_color);
214
6.22k
    set_dev_proc(dev, decode_color, gx_default_rgb_map_color_rgb);
215
6.22k
}
216
217
const gx_device_png gs_png16m_device =
218
{prn_device_body(gx_device_png, png16m_initialize_device_procs, "png16m",
219
                 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
220
                 X_DPI, Y_DPI,
221
                 0, 0, 0, 0,  /* margins */
222
                 3, 24, 255, 255, 256, 256, png_print_page),
223
    GX_DOWNSCALER_PARAMS_DEFAULTS
224
};
225
226
/* 48 bit color. */
227
228
static void
229
png48_initialize_device_procs(gx_device *dev)
230
0
{
231
0
    gdev_prn_initialize_device_procs_rgb_bg(dev);
232
233
    /* The prn macros used in previous versions of the code leave
234
     * encode_color and decode_color set to NULL (which are then rewritten
235
     * by the system to the default. For compatibility we do the same. */
236
0
    set_dev_proc(dev, encode_color, gx_default_rgb_map_rgb_color);
237
0
    set_dev_proc(dev, decode_color, gx_default_rgb_map_color_rgb);
238
0
}
239
240
/* Since the print_page doesn't alter the device, this device can print in the background */
241
const gx_device_png gs_png48_device =
242
{prn_device_body(gx_device_png, png48_initialize_device_procs, "png48",
243
                 DEFAULT_WIDTH_10THS, DEFAULT_HEIGHT_10THS,
244
                 X_DPI, Y_DPI,
245
                 0, 0, 0, 0,  /* margins */
246
                 3, 48, 0, 65535, 1, 65536, png_print_page),
247
    GX_DOWNSCALER_PARAMS_DEFAULTS
248
};
249
250
/* 32-bit RGBA */
251
/* pngalpha device is 32-bit RGBA, with the alpha channel
252
 * indicating pixel coverage, not true transparency.
253
 * Anti-aliasing is enabled by default.
254
 * An erasepage will erase to transparent, not white.
255
 * It is intended to be used for creating web graphics with
256
 * a transparent background.
257
 */
258
typedef struct gx_device_pngalpha_s gx_device_pngalpha;
259
struct gx_device_pngalpha_s {
260
    gx_device_common;
261
    gx_prn_device_common;
262
    gx_downscaler_params downscale;
263
    int background;
264
};
265
266
static void
267
pngalpha_initialize_device_procs(gx_device *dev)
268
0
{
269
0
    gdev_prn_initialize_device_procs_bg(dev);
270
271
0
    set_dev_proc(dev, open_device, pngalpha_open);
272
0
    set_dev_proc(dev, map_rgb_color, pngalpha_encode_color);
273
0
    set_dev_proc(dev, map_color_rgb, pngalpha_decode_color);
274
0
    set_dev_proc(dev, encode_color, pngalpha_encode_color);
275
0
    set_dev_proc(dev, decode_color, pngalpha_decode_color);
276
0
    set_dev_proc(dev, get_params, pngalpha_get_params);
277
0
    set_dev_proc(dev, put_params, pngalpha_put_params);
278
0
    set_dev_proc(dev, copy_alpha, pngalpha_copy_alpha);
279
0
    set_dev_proc(dev, get_color_mapping_procs, gx_default_DevRGB_get_color_mapping_procs);
280
0
    set_dev_proc(dev, get_color_comp_index, gx_default_DevRGB_get_color_comp_index);
281
0
    set_dev_proc(dev, fillpage, pngalpha_fillpage);
282
0
    set_dev_proc(dev, put_image, pngalpha_put_image);
283
0
    set_dev_proc(dev, dev_spec_op, pngalpha_spec_op);
284
0
}
285
286
const gx_device_pngalpha gs_pngalpha_device = {
287
        std_device_part1_(gx_device_pngalpha,
288
                pngalpha_initialize_device_procs, "pngalpha",
289
                &st_device_printer, open_init_closed),
290
        /* color_info */
291
        {3 /* max components */,
292
         3 /* number components */,
293
         GX_CINFO_POLARITY_ADDITIVE /* polarity */,
294
         32 /* depth */,
295
         -1 /* gray index */,
296
         255 /* max gray */,
297
         255 /* max color */,
298
         256 /* dither grays */,
299
         256 /* dither colors */,
300
         { 4, 4 } /* antialias info text, graphics */,
301
         GX_CINFO_UNKNOWN_SEP_LIN /* separable_and_linear */,
302
         { 0 } /* component shift */,
303
         { 0 } /* component bits */,
304
         { 0 } /* component mask */,
305
         "DeviceRGB" /* process color name */,
306
         GX_CINFO_OPMSUPPORTED_UNKNOWN /* opmsupported */,
307
         0 /* process_cmps */,
308
         0 /* icc_locations */
309
        },
310
        std_device_part2_(
311
          (int)((float)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10 + 0.5),
312
          (int)((float)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10 + 0.5),
313
           X_DPI, Y_DPI),
314
        offset_margin_values(0, 0, 0, 0, 0, 0),
315
        std_device_part3_(),
316
        prn_device_body_rest_(png_print_page),
317
        GX_DOWNSCALER_PARAMS_DEFAULTS,
318
        0xffffff  /* white background */
319
};
320
321
const gx_device_pngalpha gs_png16malpha_device = {
322
        std_device_part1_(gx_device_pngalpha,
323
                pngalpha_initialize_device_procs, "png16malpha",
324
                &st_device_printer, open_init_closed),
325
        /* color_info */
326
        {3 /* max components */,
327
         3 /* number components */,
328
         GX_CINFO_POLARITY_ADDITIVE /* polarity */,
329
         32 /* depth */,
330
         -1 /* gray index */,
331
         255 /* max gray */,
332
         255 /* max color */,
333
         256 /* dither grays */,
334
         256 /* dither colors */,
335
         { 1, 1 } /* antialias info text, graphics */,
336
         GX_CINFO_UNKNOWN_SEP_LIN /* separable_and_linear */,
337
         { 0 } /* component shift */,
338
         { 0 } /* component bits */,
339
         { 0 } /* component mask */,
340
         "DeviceRGB" /* process color name */,
341
         GX_CINFO_OPMSUPPORTED_UNKNOWN /* opmsupported */,
342
         0 /* process_cmps */,
343
         0 /* icc_locations */
344
        },
345
        std_device_part2_(
346
          (int)((float)(DEFAULT_WIDTH_10THS) * (X_DPI) / 10 + 0.5),
347
          (int)((float)(DEFAULT_HEIGHT_10THS) * (Y_DPI) / 10 + 0.5),
348
           X_DPI, Y_DPI),
349
        offset_margin_values(0, 0, 0, 0, 0, 0),
350
        std_device_part3_(),
351
        prn_device_body_rest_(png_print_page),
352
        GX_DOWNSCALER_PARAMS_DEFAULTS,
353
        0xffffff  /* white background */
354
};
355
356
/* ------ Private definitions ------ */
357
358
static int
359
png_get_params_downscale(gx_device * dev, gs_param_list * plist)
360
93.7k
{
361
93.7k
    gx_device_png *pdev = (gx_device_png *)dev;
362
93.7k
    int code, ecode;
363
364
93.7k
    ecode = 0;
365
93.7k
    if ((code = gx_downscaler_write_params(plist, &pdev->downscale, 0)) < 0)
366
0
        ecode = code;
367
368
93.7k
    code = gdev_prn_get_params(dev, plist);
369
93.7k
    if (code < 0)
370
0
        ecode = code;
371
372
93.7k
    return ecode;
373
93.7k
}
374
375
static int
376
png_put_params_downscale(gx_device *dev, gs_param_list *plist)
377
27.7k
{
378
27.7k
    gx_device_png *pdev = (gx_device_png *)dev;
379
27.7k
    int code, ecode;
380
381
27.7k
    ecode = gx_downscaler_read_params(plist, &pdev->downscale, 0);
382
383
27.7k
    code = gdev_prn_put_params(dev, plist);
384
27.7k
    if (code < 0)
385
13
        ecode = code;
386
387
27.7k
    return ecode;
388
27.7k
}
389
390
static int
391
png_get_params_downscale_mfs(gx_device *dev, gs_param_list *plist)
392
0
{
393
0
    gx_device_png *pdev = (gx_device_png *)dev;
394
0
    int code, ecode;
395
396
0
    ecode = gx_downscaler_write_params(plist, &pdev->downscale,
397
0
                                      GX_DOWNSCALER_PARAMS_MFS);
398
399
0
    code = gdev_prn_get_params(dev, plist);
400
0
    if (code < 0)
401
0
        ecode = code;
402
403
0
    return ecode;
404
0
}
405
406
static int
407
png_put_params_downscale_mfs(gx_device *dev, gs_param_list *plist)
408
0
{
409
0
    gx_device_png *pdev = (gx_device_png *)dev;
410
0
    int code, ecode;
411
412
0
    ecode = gx_downscaler_read_params(plist, &pdev->downscale,
413
0
                                      GX_DOWNSCALER_PARAMS_MFS);
414
415
0
    code = gdev_prn_put_params(dev, plist);
416
0
    if (code < 0)
417
0
        ecode = code;
418
419
0
    return ecode;
420
0
}
421
422
9.12k
#define PNG_MEM_ALIGN 16
423
static png_voidp
424
gdevpng_malloc(png_structp png, png_size_t size)
425
4.56k
{
426
4.56k
    gs_memory_t *mem = png_get_mem_ptr(png);
427
4.56k
    uchar *unaligned;
428
4.56k
    uchar *aligned;
429
430
4.56k
    if (size == 0)
431
0
        return NULL;
432
4.56k
    unaligned = gs_alloc_bytes(mem, size + PNG_MEM_ALIGN, "libpng");
433
4.56k
    if (unaligned == NULL)
434
0
        return NULL;
435
436
4.56k
    aligned = (uchar *)((intptr_t)(unaligned + PNG_MEM_ALIGN) & ~(PNG_MEM_ALIGN - 1));
437
4.56k
    aligned[-1] = (uchar)(aligned - unaligned);
438
439
4.56k
    return aligned;
440
4.56k
}
441
442
static void
443
gdevpng_free(png_structp png, png_voidp ptr)
444
4.56k
{
445
4.56k
    gs_memory_t *mem = png_get_mem_ptr(png);
446
4.56k
    uchar *aligned = ptr;
447
4.56k
    if (aligned == NULL)
448
0
        return;
449
4.56k
    gs_free_object(mem, aligned - aligned[-1], "libpng");
450
4.56k
}
451
452
static void
453
my_png_write(png_struct *png, png_bytep buf, png_size_t size)
454
7.29k
{
455
7.29k
    gp_file *file = png_get_io_ptr(png);
456
457
7.29k
    (void)gp_fwrite(buf, 1, size, file);
458
7.29k
}
459
460
static void
461
my_png_flush(png_struct *png)
462
0
{
463
0
    gp_file *file = png_get_io_ptr(png);
464
465
0
    (void)gp_fflush(file);
466
0
}
467
468
/* Write out a page in PNG format. */
469
/* This routine is used for all formats. */
470
static int
471
do_png_print_page(gx_device_png * pdev, gp_file * file, bool monod)
472
326
{
473
326
    gs_memory_t *mem = pdev->memory;
474
326
    int raster = gdev_prn_raster(pdev);
475
326
    gx_downscaler_t ds;
476
477
    /* PNG structures */
478
326
    byte *row = gs_alloc_bytes(mem, raster, "png raster buffer");
479
326
    png_struct *png_ptr =
480
326
        png_create_write_struct_2(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL, pdev->memory, gdevpng_malloc, gdevpng_free);
481
326
    png_info *info_ptr = png_create_info_struct(png_ptr);
482
326
    int depth = pdev->color_info.depth;
483
326
    int y;
484
326
    int code;     /* return code */
485
326
    char software_key[80];
486
326
    char software_text[256];
487
326
    png_text text_png;
488
326
    int dst_bpc, src_bpc;
489
326
    bool errdiff = 0;
490
491
326
    bool invert = false, endian_swap = false, bg_needed = false;
492
326
    png_byte bit_depth = 0;
493
326
    png_byte color_type = 0;
494
326
    png_uint_32 x_pixels_per_unit;
495
326
    png_uint_32 y_pixels_per_unit;
496
326
    png_byte phys_unit_type;
497
326
    png_color_16 background;
498
326
    png_uint_32 width, height;
499
326
#if PNG_LIBPNG_VER_MINOR >= 5
500
326
    png_color palette[256];
501
326
#endif
502
326
    png_color *palettep;
503
326
    png_uint_16 num_palette;
504
326
    png_uint_32 valid = 0;
505
326
    int upfactor, downfactor;
506
507
    /* Sanity check params */
508
326
    if (pdev->downscale.downscale_factor < 1)
509
0
        pdev->downscale.downscale_factor = 1;
510
326
    if (pdev->downscale.min_feature_size < 1)
511
218
        pdev->downscale.min_feature_size = 1;
512
108
    else if (pdev->downscale.min_feature_size > 2)
513
0
        pdev->downscale.min_feature_size = 2;
514
515
    /* Slightly nasty, but it saves us duplicating this entire routine. */
516
326
    if (monod) {
517
0
        errdiff = 1;
518
0
        depth = 1;
519
0
    }
520
521
326
    if (row == 0 || png_ptr == 0 || info_ptr == 0) {
522
0
        code = gs_note_error(gs_error_VMerror);
523
0
        goto done;
524
0
    }
525
    /* set error handling */
526
326
#if PNG_LIBPNG_VER_MINOR >= 5
527
326
    code = setjmp(png_jmpbuf(png_ptr));
528
#else
529
    code = setjmp(png_ptr->jmpbuf);
530
#endif
531
326
    if (code) {
532
        /* If we get here, we had a problem reading the file */
533
0
        code = gs_note_error(gs_error_VMerror);
534
0
        goto done;
535
0
    }
536
326
    code = 0;     /* for normal path */
537
    /* set up the output control */
538
326
    png_set_write_fn(png_ptr, file, my_png_write, my_png_flush);
539
540
    /* set the file information here */
541
326
    gx_downscaler_decode_factor(pdev->downscale.downscale_factor,
542
326
                                &upfactor, &downfactor);
543
    /* resolution is in pixels per meter vs. dpi */
544
326
    x_pixels_per_unit =
545
326
        (png_uint_32) (pdev->HWResolution[0] * upfactor * (100.0 / 2.54) / downfactor + 0.5);
546
326
    y_pixels_per_unit =
547
326
        (png_uint_32) (pdev->HWResolution[1] * upfactor * (100.0 / 2.54) / downfactor + 0.5);
548
549
326
    phys_unit_type = PNG_RESOLUTION_METER;
550
326
    valid |= PNG_INFO_pHYs;
551
552
326
    switch (depth) {
553
0
        case 32:
554
0
            bit_depth = 8;
555
0
            color_type = PNG_COLOR_TYPE_RGB_ALPHA;
556
0
            invert = true;
557
558
0
            {   gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
559
0
                background.index = 0;
560
0
                background.red =   (ppdev->background >> 16) & 0xff;
561
0
                background.green = (ppdev->background >> 8)  & 0xff;
562
0
                background.blue =  (ppdev->background)       & 0xff;
563
0
                background.gray = 0;
564
0
                bg_needed = true;
565
0
            }
566
0
            errdiff = 1;
567
0
            break;
568
0
        case 48:
569
0
            bit_depth = 16;
570
0
            color_type = PNG_COLOR_TYPE_RGB;
571
0
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN)
572
0
            endian_swap = true;
573
0
#endif
574
0
            break;
575
326
        case 24:
576
326
            bit_depth = 8;
577
326
            color_type = PNG_COLOR_TYPE_RGB;
578
326
            errdiff = 1;
579
326
            break;
580
0
        case 8:
581
0
            bit_depth = 8;
582
0
            if (gx_device_has_color(pdev)) {
583
0
                color_type = PNG_COLOR_TYPE_PALETTE;
584
0
                errdiff = 0;
585
0
            } else {
586
0
                color_type = PNG_COLOR_TYPE_GRAY;
587
0
                errdiff = 1;
588
0
            }
589
0
            break;
590
0
        case 4:
591
0
            bit_depth = 4;
592
0
            color_type = PNG_COLOR_TYPE_PALETTE;
593
0
            break;
594
0
        case 1:
595
0
            bit_depth = 1;
596
0
            color_type = PNG_COLOR_TYPE_GRAY;
597
            /* invert monochrome pixels */
598
0
            if (!monod) {
599
0
                invert = true;
600
0
            }
601
0
            break;
602
326
    }
603
604
    /* set the palette if there is one */
605
326
    if (color_type == PNG_COLOR_TYPE_PALETTE) {
606
0
        int i;
607
0
        int num_colors = 1 << depth;
608
0
        gx_color_value rgb[3];
609
610
0
#if PNG_LIBPNG_VER_MINOR >= 5
611
0
        palettep = palette;
612
#else
613
        palettep =
614
            (void *)gs_alloc_bytes(mem, 256 * sizeof(png_color),
615
                                   "png palette");
616
        if (palettep == 0) {
617
            code = gs_note_error(gs_error_VMerror);
618
            goto done;
619
        }
620
#endif
621
0
        num_palette = num_colors;
622
0
        valid |= PNG_INFO_PLTE;
623
0
        for (i = 0; i < num_colors; i++) {
624
0
            (*dev_proc(pdev, map_color_rgb)) ((gx_device *) pdev,
625
0
                                              (gx_color_index) i, rgb);
626
0
            palettep[i].red = gx_color_value_to_byte(rgb[0]);
627
0
            palettep[i].green = gx_color_value_to_byte(rgb[1]);
628
0
            palettep[i].blue = gx_color_value_to_byte(rgb[2]);
629
0
        }
630
0
    }
631
326
    else {
632
326
        palettep = NULL;
633
326
        num_palette = 0;
634
326
    }
635
    /* add comment */
636
#ifdef CLUSTER
637
    strncpy(software_key, "GPL Ghostscript", sizeof(software_key));
638
    strncpy(software_text, "GPL Ghostscript", sizeof(software_text));
639
#else
640
326
    strncpy(software_key, "Software", sizeof(software_key));
641
326
    {
642
326
        int major = (int)(gs_revision / 1000);
643
326
        int minor = (int)(gs_revision - (major * 1000)) / 10;
644
326
        int patch = gs_revision % 10;
645
646
326
        gs_snprintf(software_text, sizeof(software_text), "%s %d.%02d.%d", gs_product, major, minor, patch);
647
326
    }
648
326
#endif
649
326
    text_png.compression = -1;  /* uncompressed */
650
326
    text_png.key = software_key;
651
326
    text_png.text = software_text;
652
326
    text_png.text_length = strlen(software_text);
653
654
326
    dst_bpc = bit_depth;
655
326
    src_bpc = dst_bpc;
656
326
    if (errdiff)
657
326
        src_bpc = 8;
658
0
    else
659
0
        pdev->downscale.downscale_factor = upfactor = downfactor = 1;
660
326
    width = pdev->width * upfactor / downfactor;
661
326
    height = pdev->height * upfactor / downfactor;
662
663
326
#if PNG_LIBPNG_VER_MINOR >= 5
664
326
    png_set_pHYs(png_ptr, info_ptr,
665
326
                 x_pixels_per_unit, y_pixels_per_unit, phys_unit_type);
666
667
326
    png_set_IHDR(png_ptr, info_ptr,
668
326
                 width, height, bit_depth,
669
326
                 color_type, PNG_INTERLACE_NONE,
670
326
                 PNG_COMPRESSION_TYPE_DEFAULT,
671
326
                 PNG_FILTER_TYPE_DEFAULT);
672
326
    if (palettep)
673
0
        png_set_PLTE(png_ptr, info_ptr, palettep, num_palette);
674
675
326
    png_set_text(png_ptr, info_ptr, &text_png, 1);
676
677
326
    if (pdev->icc_struct != NULL && pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE] != NULL) {
678
326
        cmm_profile_t *icc_profile = pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE];
679
326
        if (icc_profile->hash_is_valid && icc_profile->hashcode == ARTIFEX_sRGB_HASH) {
680
            /* sRGB case. Just use the tag */
681
326
            png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_RELATIVE);
682
326
        } else {
683
            /* PNG can only be RGB or gray.  No CIELAB :(  */
684
0
            if (icc_profile->data_cs == gsRGB || icc_profile->data_cs == gsGRAY) {
685
0
                if (icc_profile->num_comps == pdev->color_info.num_components &&
686
0
                    !(pdev->icc_struct->usefastcolor)) {
687
0
                    png_set_iCCP(png_ptr, info_ptr, icc_profile->name,
688
0
                        PNG_COMPRESSION_TYPE_DEFAULT, icc_profile->buffer,
689
0
                        icc_profile->buffer_size);
690
0
                }
691
0
            }
692
0
        }
693
326
    }
694
#else
695
    info_ptr->bit_depth = bit_depth;
696
    info_ptr->color_type = color_type;
697
    info_ptr->width = width;
698
    info_ptr->height = height;
699
    info_ptr->x_pixels_per_unit = x_pixels_per_unit;
700
    info_ptr->y_pixels_per_unit = y_pixels_per_unit;
701
    info_ptr->phys_unit_type = phys_unit_type;
702
    info_ptr->palette = palettep;
703
    info_ptr->num_palette = num_palette;
704
    info_ptr->valid |= valid;
705
    info_ptr->text = &text_png;
706
    info_ptr->num_text = 1;
707
    /* Set up the ICC information */
708
    if (pdev->icc_struct != NULL && pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE] != NULL) {
709
        cmm_profile_t *icc_profile = pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE];
710
        if (icc_profile->hash_is_valid && icc_profile->hashcode == ARTIFEX_sRGB_HASH) {
711
            /* sRGB case. Just use the tag */
712
            png_set_sRGB(png_ptr, info_ptr, PNG_sRGB_INTENT_RELATIVE);
713
        } else {
714
            /* PNG can only be RGB or gray.  No CIELAB :(  */
715
            if (icc_profile->data_cs == gsRGB || icc_profile->data_cs == gsGRAY) {
716
                if (icc_profile->num_comps == pdev->color_info.num_components &&
717
                    !(pdev->icc_struct->usefastcolor)) {
718
                    info_ptr->iccp_name = icc_profile->name;
719
                    info_ptr->iccp_profile = icc_profile->buffer;
720
                    info_ptr->iccp_proflen = icc_profile->buffer_size;
721
                    info_ptr->valid |= PNG_INFO_iCCP;
722
                }
723
            }
724
        }
725
    }
726
#endif
727
326
    if (invert) {
728
0
        if (depth == 32)
729
0
            png_set_invert_alpha(png_ptr);
730
0
        else
731
0
            png_set_invert_mono(png_ptr);
732
0
    }
733
326
    if (bg_needed) {
734
0
        png_set_bKGD(png_ptr, info_ptr, &background);
735
0
    }
736
326
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN)
737
326
    if (endian_swap) {
738
0
        png_set_swap(png_ptr);
739
0
    }
740
326
#endif
741
742
    /* write the file information */
743
326
    png_write_info(png_ptr, info_ptr);
744
745
326
#if PNG_LIBPNG_VER_MINOR >= 5
746
#else
747
    /* don't write the comments twice */
748
    info_ptr->num_text = 0;
749
    info_ptr->text = NULL;
750
#endif
751
752
    /* For simplicity of code, we always go through the downscaler. For
753
     * non-supported depths, it will pass through with minimal performance
754
     * hit. So ensure that we only trigger downscales when we need them.
755
     */
756
326
    code = gx_downscaler_init(&ds, (gx_device *)pdev, src_bpc, dst_bpc,
757
326
                              depth/dst_bpc, &pdev->downscale, NULL, 0);
758
326
    if (code >= 0)
759
326
    {
760
#ifdef CLUSTER
761
        int bitlen = width*dst_bpc;
762
        int end = bitlen>>3;
763
        int mask = 255>>(bitlen&7);
764
        if (bitlen & 7)
765
            mask = ~mask;
766
        else
767
            end--;
768
#endif
769
        /* Write the contents of the image. */
770
639k
        for (y = 0; y < height; y++) {
771
639k
            gx_downscaler_getbits(&ds, row, y);
772
#ifdef CLUSTER
773
            row[end] &= mask;
774
#endif
775
639k
            png_write_rows(png_ptr, &row, 1);
776
639k
        }
777
326
        gx_downscaler_fin(&ds);
778
326
    }
779
780
    /* write the rest of the file */
781
326
    png_write_end(png_ptr, info_ptr);
782
783
326
#if PNG_LIBPNG_VER_MINOR >= 5
784
#else
785
    /* if you alloced the palette, free it here */
786
    gs_free_object(mem, palettep, "png palette");
787
#endif
788
789
326
  done:
790
    /* free the structures */
791
326
    png_destroy_write_struct(&png_ptr, &info_ptr);
792
326
    gs_free_object(mem, row, "png raster buffer");
793
794
326
    return code;
795
326
}
796
797
static int
798
png_print_page(gx_device_printer * pdev, gp_file * file)
799
326
{
800
326
    return do_png_print_page((gx_device_png *)pdev, file, 0);
801
326
}
802
803
static int
804
png_print_page_monod(gx_device_printer * pdev, gp_file * file)
805
0
{
806
0
    return do_png_print_page((gx_device_png *)pdev, file, 1);
807
0
}
808
809
#if PNG_LIBPNG_VER_MINOR < 5
810
811
/*
812
 * Patch around a static reference to a never-used procedure.
813
 * This could be avoided if we were willing to edit pngconf.h to
814
 *      #undef PNG_PROGRESSIVE_READ_SUPPORTED
815
 */
816
#ifdef PNG_PROGRESSIVE_READ_SUPPORTED
817
#  if PNG_LIBPNG_VER >= 95
818
#    define PPFB_LENGTH_T png_size_t
819
#  else
820
#    define PPFB_LENGTH_T png_uint_32
821
#  endif
822
void
823
png_push_fill_buffer(png_structp, png_bytep, PPFB_LENGTH_T);
824
void
825
png_push_fill_buffer(png_structp png_ptr, png_bytep buffer,
826
                     PPFB_LENGTH_T length)
827
{
828
}
829
#endif
830
#endif
831
832
static int
833
pngalpha_open(gx_device * pdev)
834
0
{
835
0
    gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
836
0
    int code;
837
    /* We replace create_buf_device so we can replace copy_alpha
838
     * for memory device, but not clist. We also replace the fillpage
839
     * proc with our own to fill with transparent.
840
     */
841
0
    ppdev->printer_procs.buf_procs.create_buf_device =
842
0
        pngalpha_create_buf_device;
843
0
    code = gdev_prn_open(pdev);
844
0
    return code;
845
0
}
846
847
static int
848
pngalpha_create_buf_device(gx_device **pbdev, gx_device *target, int y,
849
   const gx_render_plane_t *render_plane, gs_memory_t *mem,
850
   gx_color_usage_t *color_usage)
851
0
{
852
0
    gx_device_printer *ptarget;
853
0
    int code = gx_default_create_buf_device(pbdev, target, y,
854
0
        render_plane, mem, color_usage);
855
    /* Now set copy_alpha to one that handles RGBA */
856
857
    /* this is really pretty nasty. The pngalpha device is going to replace
858
     * the device methods in the memory rendering device with some of its own.
859
     * To me this seems fraught with peril, its making a lot of assumptions
860
     * about the compatibility of the devices!
861
     * This, of course, totally breaks device chaining, but since the memory
862
     * device wasn't going to pass on the intermediate method calls to the
863
     * 'terminating' device, we can work around it here. We simply descend
864
     * the chain of devices to the terminating device, and pull the methods
865
     * we need directly from that device. I don't know why we are using
866
     * 'orig_procs' either, but its safe to do so because this is only
867
     * done here for the PNG device, and we know that this is a gx_device_prn
868
     * based device.
869
     */
870
0
    while (target->child != NULL)
871
0
        target = target->child;
872
873
0
    ptarget= (gx_device_printer *)target;
874
0
    set_dev_proc(*pbdev, copy_alpha, ptarget->orig_procs.copy_alpha);
875
0
    set_dev_proc(*pbdev, dev_spec_op, ptarget->orig_procs.dev_spec_op);
876
0
    set_dev_proc(*pbdev, fillpage, pngalpha_fillpage);
877
0
    return code;
878
0
}
879
880
static int
881
pngalpha_put_params(gx_device * pdev, gs_param_list * plist)
882
0
{
883
0
    gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
884
0
    int background;
885
0
    int code, ecode;
886
887
    /* BackgroundColor in format 16#RRGGBB is used for bKGD chunk */
888
0
    switch(code = param_read_int(plist, "BackgroundColor", &background)) {
889
0
        case 0:
890
0
            ppdev->background = background & 0xffffff;
891
0
            break;
892
0
        case 1:   /* not found */
893
0
            code = 0;
894
0
            break;
895
0
        default:
896
0
            param_signal_error(plist, "BackgroundColor", code);
897
0
            break;
898
0
    }
899
900
0
    if ((ecode = gx_downscaler_read_params(plist, &ppdev->downscale, 0)) < 0)
901
0
        code = ecode;
902
903
0
    if (code == 0) {
904
0
        code = gdev_prn_put_params(pdev, plist);
905
0
    }
906
907
0
    return code;
908
0
}
909
910
/* Get device parameters */
911
static int
912
pngalpha_get_params(gx_device * pdev, gs_param_list * plist)
913
0
{
914
0
    gx_device_pngalpha *ppdev = (gx_device_pngalpha *)pdev;
915
0
    int code = gdev_prn_get_params(pdev, plist);
916
0
    int ecode;
917
0
    if (code >= 0)
918
0
        code = param_write_int(plist, "BackgroundColor",
919
0
                                &(ppdev->background));
920
0
    ecode = 0;
921
0
    if ((ecode = gx_downscaler_write_params(plist, &ppdev->downscale, 0)) < 0)
922
0
        code = ecode;
923
924
0
    return code;
925
0
}
926
927
/* RGB mapping for 32-bit RGBA color devices */
928
929
static gx_color_index
930
pngalpha_encode_color(gx_device * dev, const gx_color_value cv[])
931
0
{
932
    /* low 7 are alpha, stored inverted to avoid white/opaque
933
     * being 0xffffffff which is also gx_no_color_index.
934
     * So 0xff is transparent and 0x00 is opaque.
935
     * We always return opaque colors (bits 0-7 = 0).
936
     * Return value is 0xRRGGBB00.
937
     */
938
0
    return
939
0
        ((uint) gx_color_value_to_byte(cv[2]) << 8) +
940
0
        ((ulong) gx_color_value_to_byte(cv[1]) << 16) +
941
0
        ((ulong) gx_color_value_to_byte(cv[0]) << 24);
942
0
}
943
944
/* Map a color index to a r-g-b color. */
945
static int
946
pngalpha_decode_color(gx_device * dev, gx_color_index color,
947
                             gx_color_value prgb[3])
948
0
{
949
0
    prgb[0] = gx_color_value_from_byte((color >> 24) & 0xff);
950
0
    prgb[1] = gx_color_value_from_byte((color >> 16) & 0xff);
951
0
    prgb[2] = gx_color_value_from_byte((color >> 8)  & 0xff);
952
0
    return 0;
953
0
}
954
955
/* fill the page fills with transparent */
956
static int
957
pngalpha_fillpage(gx_device *dev, gs_gstate * pgs, gx_device_color *pdevc)
958
0
{
959
0
    return (*dev_proc(dev, fill_rectangle))(dev, 0, 0, dev->width, dev->height,  0xffffffff);
960
0
}
961
962
/* Handle the RGBA planes from the PDF 1.4 compositor */
963
static int
964
pngalpha_put_image (gx_device *pdev, gx_device *mdev, const byte **buffers, int num_chan, int xstart,
965
              int ystart, int width, int height, int row_stride,
966
              int alpha_plane_index, int tag_plane_index)
967
0
{
968
0
    gx_device_memory *pmemdev = (gx_device_memory *)mdev;
969
0
    byte *buffer_prn;
970
0
    int yend = ystart + height;
971
0
    int xend = xstart + width;
972
0
    int x, y;
973
0
    int src_position, des_position;
974
975
0
    if (num_chan != 3 || alpha_plane_index <= 0)
976
0
            return_error(gs_error_unknownerror);        /* can't handle these cases */
977
978
    /* Now we need to convert the 4 channels (RGBA) planar into what   */
979
    /* the do_png_print_page expects -- chunky inverted data. For that */
980
    /* we need to find the underlying gx_device_memory buffer for the  */
981
    /* data (similar to bit_put_image, and borrwed from there).        */
982
    /* Drill down to get the appropriate memory buffer pointer */
983
0
    buffer_prn = pmemdev->base;
984
    /* Now go ahead and process the planes into chunky as the memory device needs */
985
0
    for ( y = ystart; y < yend; y++ ) {
986
0
        src_position = (y - ystart) * row_stride;
987
0
        des_position = y * pmemdev->raster + xstart * 4;
988
0
        for ( x = xstart; x < xend; x++ ) {
989
0
            buffer_prn[des_position++] =  buffers[0][src_position];
990
0
            buffer_prn[des_position++] =  buffers[1][src_position];
991
0
            buffer_prn[des_position++] =  buffers[2][src_position];
992
            /* Alpha data in low bits. Note that Alpha is inverted. */
993
0
            buffer_prn[des_position++] = (255 - buffers[alpha_plane_index][src_position]);
994
0
            src_position += 1;
995
0
        }
996
0
    }
997
0
    return height;        /* we used all of the data */
998
0
}
999
1000
/* Implementation for 32-bit RGBA in a memory buffer */
1001
/* Derived from gx_default_copy_alpha, but now maintains alpha channel. */
1002
static int
1003
pngalpha_copy_alpha(gx_device * dev, const byte * data, int data_x,
1004
           int raster, gx_bitmap_id id, int x, int y, int width, int height,
1005
                      gx_color_index color, int depth)
1006
0
{       /* This might be called with depth = 1.... */
1007
0
    if (depth == 1)
1008
0
        return (*dev_proc(dev, copy_mono)) (dev, data, data_x, raster, id,
1009
0
                                            x, y, width, height,
1010
0
                                            gx_no_color_index, color);
1011
    /*
1012
     * Simulate alpha by weighted averaging of RGB values.
1013
     * This is very slow, but functionally correct.
1014
     */
1015
0
    {
1016
0
        const byte *row;
1017
0
        gs_memory_t *mem = dev->memory;
1018
0
        int bpp = dev->color_info.depth;
1019
0
        int ncomps = dev->color_info.num_components;
1020
0
        uint in_size = gx_device_raster(dev, false);
1021
0
        byte *lin;
1022
0
        uint out_size;
1023
0
        byte *lout;
1024
0
        int code = 0;
1025
0
        gx_color_value color_cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1026
0
        int ry;
1027
0
        gs_int_rect rect;
1028
0
        gs_get_bits_params_t params;
1029
1030
0
        fit_copy(dev, data, data_x, raster, id, x, y, width, height);
1031
0
        row = data;
1032
0
        out_size = bitmap_raster(width * bpp);
1033
0
        lin = gs_alloc_bytes(mem, in_size, "copy_alpha(lin)");
1034
0
        lout = gs_alloc_bytes(mem, out_size, "copy_alpha(lout)");
1035
0
        if (lin == 0 || lout == 0) {
1036
0
            code = gs_note_error(gs_error_VMerror);
1037
0
            goto out;
1038
0
        }
1039
0
        (*dev_proc(dev, decode_color)) (dev, color, color_cv);
1040
0
        rect.p.x = 0;
1041
0
        rect.q.x = dev->width;
1042
0
        params.x_offset = 0;
1043
0
        params.raster = bitmap_raster(dev->width * dev->color_info.depth);
1044
0
        for (ry = y; ry < y + height; row += raster, ++ry) {
1045
0
            byte *line;
1046
0
            int sx, rx;
1047
1048
0
            byte *l_dptr = lout;
1049
0
            int l_dbit = 0;
1050
0
            byte l_dbyte = ((l_dbit) ? (byte)(*(l_dptr) & (0xff00 >> (l_dbit))) : 0);
1051
0
            int l_xprev = x;
1052
1053
0
            rect.p.y = ry;
1054
0
            rect.q.y = ry+1;
1055
1056
0
            params.options = (GB_ALIGN_ANY |
1057
0
                              (GB_RETURN_COPY | GB_RETURN_POINTER) |
1058
0
                              GB_OFFSET_0 |
1059
0
                              GB_RASTER_STANDARD | GB_PACKING_CHUNKY |
1060
0
                              GB_COLORS_NATIVE | GB_ALPHA_NONE);
1061
0
            params.data[0] = lin;
1062
0
            code = (*dev_proc(dev, get_bits_rectangle))(dev, &rect, &params);
1063
0
            if (code < 0)
1064
0
                break;
1065
0
            line = params.data[0];
1066
0
            for (sx = data_x, rx = x; sx < data_x + width; ++sx, ++rx) {
1067
0
                gx_color_index previous = gx_no_color_index;
1068
0
                gx_color_index composite;
1069
0
                uint32_t alpha2, alpha;
1070
1071
0
                switch(depth)
1072
0
                {
1073
0
                case 2: /* map 0 - 3 to 0 - 255 */
1074
0
                    alpha = ((row[sx >> 2] >> ((3 - (sx & 3)) << 1)) & 3) * 85;
1075
0
                    break;
1076
0
                case 4:
1077
0
                    alpha2 = row[sx >> 1];
1078
0
                    alpha = (sx & 1 ? alpha2 & 0xf : alpha2 >> 4) * 17;
1079
0
                    break;
1080
0
                case 8:
1081
0
                    alpha = row[sx];
1082
0
                    break;
1083
0
                default:
1084
0
      return_error(gs_error_rangecheck);
1085
0
                }
1086
0
                if (alpha == 255) { /* Just write the new color. */
1087
0
                    composite = color;
1088
0
                } else {
1089
0
                    if (previous == gx_no_color_index) { /* Extract the old color. */
1090
0
                        const byte *src = line + (rx * (bpp >> 3));
1091
0
                        previous = 0;
1092
0
                        previous += (gx_color_index) * src++ << 24;
1093
0
                        previous += (gx_color_index) * src++ << 16;
1094
0
                        previous += (gx_color_index) * src++ << 8;
1095
0
                        previous += *src++;
1096
0
                    }
1097
0
                    if (alpha == 0) { /* Just write the old color. */
1098
0
                        composite = previous;
1099
0
                    } else { /* Blend values. */
1100
0
                        gx_color_value cv[GX_DEVICE_COLOR_MAX_COMPONENTS];
1101
0
                        int i;
1102
0
                        uint32_t old_coverage;
1103
0
                        uint32_t new_coverage;
1104
1105
0
                        (*dev_proc(dev, decode_color)) (dev, previous, cv);
1106
                        /* decode color doesn't give us coverage */
1107
0
                        cv[3] = previous & 0xff;
1108
0
                        old_coverage = 255 - cv[3];
1109
0
                        new_coverage =
1110
0
                            (255 * alpha + old_coverage * (255 - alpha)) / 255;
1111
0
                        for (i=0; i<ncomps; i++)
1112
0
                            cv[i] = min(((255 * alpha * color_cv[i]) +
1113
0
                                         (old_coverage * (255 - alpha ) * cv[i]))
1114
0
                                        / (new_coverage * 255), gx_max_color_value);
1115
0
                        composite =
1116
0
                            (*dev_proc(dev, encode_color)) (dev, cv);
1117
                        /* encode color doesn't include coverage */
1118
0
                        composite |= (255 - new_coverage) & 0xff;
1119
1120
                        /* composite can never be gx_no_color_index
1121
                         * because pixel is never completely transparent
1122
                         * (low byte != 0xff).
1123
                         */
1124
0
                    }
1125
0
                }
1126
0
                if (sizeof(composite) > 4) {
1127
0
                    if (sample_store_next64(composite, &l_dptr, &l_dbit, bpp, &l_dbyte) < 0)
1128
0
                        return_error(gs_error_rangecheck);
1129
0
                }
1130
0
                else {
1131
0
                    if (sample_store_next32(composite, &l_dptr, &l_dbit, bpp, &l_dbyte) < 0)
1132
0
                        return_error(gs_error_rangecheck);
1133
0
                }
1134
0
            }
1135
0
            if ( rx > l_xprev ) {
1136
0
                sample_store_flush(l_dptr, l_dbit, l_dbyte);
1137
0
                code = (*dev_proc(dev, copy_color))
1138
0
                  (dev, lout, l_xprev - x, raster,
1139
0
                   gx_no_bitmap_id, l_xprev, ry, rx - l_xprev, 1);
1140
0
                if (code < 0)
1141
0
                    return code;
1142
0
            }
1143
0
        }
1144
0
      out:gs_free_object(mem, lout, "copy_alpha(lout)");
1145
0
        gs_free_object(mem, lin, "copy_alpha(lin)");
1146
0
        return code;
1147
0
    }
1148
0
}
1149
1150
static int
1151
pngalpha_spec_op(gx_device* pdev, int dso, void* ptr, int size)
1152
0
{
1153
0
    switch (dso)
1154
0
    {
1155
0
    case gxdso_supports_alpha:
1156
0
        return 1;
1157
0
    }
1158
1159
0
    return gdev_prn_dev_spec_op(pdev, dso, ptr, size);
1160
0
}