Coverage Report

Created: 2025-06-24 07:01

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