Coverage Report

Created: 2025-06-24 07:01

/src/ghostpdl/devices/vector/gdevpsdi.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
/* Image compression for PostScript and PDF writers */
18
#include "stdio_.h"   /* for jpeglib.h */
19
#include "jpeglib_.h"   /* for sdct.h */
20
#include "math_.h"
21
#include "string_.h"
22
#include "gx.h"
23
#include "gserrors.h"
24
#include "gscspace.h"
25
#include "gdevpsdf.h"
26
#include "gdevpsds.h"
27
#include "gxdevmem.h"
28
#include "gxcspace.h"
29
#include "gsparamx.h"
30
#include "strimpl.h"
31
#include "scfx.h"
32
#include "slzwx.h"
33
#include "spngpx.h"
34
#include "szlibx.h"
35
#include "sbrotlix.h"
36
#include "gsicc_manage.h"
37
#include "sisparam.h"
38
39
/* Define parameter-setting procedures. */
40
extern stream_state_proc_put_params(s_CF_put_params, stream_CF_state);
41
extern stream_template s_IScale_template;
42
43
/* ---------------- Image compression ---------------- */
44
45
/*
46
 * Add a filter to expand or reduce the pixel width if needed.
47
 * At least one of bpc_in and bpc_out is 8; the other is 1, 2, 4, or 8,
48
 * except if bpc_out is 8, bpc_in may be 12 (or 16).
49
 */
50
static int
51
pixel_resize(psdf_binary_writer * pbw, int width, int num_components,
52
             int bpc_in, int bpc_out)
53
86.9k
{
54
86.9k
    gs_memory_t *mem = pbw->dev->v_memory;
55
86.9k
    const stream_template *templat;
56
86.9k
    stream_1248_state *st;
57
86.9k
    int code;
58
59
86.9k
    if (bpc_out == bpc_in)
60
86.9k
        return 0;
61
0
    if (bpc_in != 8) {
62
0
        static const stream_template *const exts[17] = {
63
0
            0, &s_1_8_template, &s_2_8_template, 0, &s_4_8_template,
64
0
            0, 0, 0, 0, 0, 0, 0, &s_12_8_template, 0, 0, 0, &s_16_8_template
65
0
        };
66
67
0
        templat = exts[bpc_in];
68
0
    } else {
69
0
        static const stream_template *const rets[5] = {
70
0
            0, &s_8_1_template, &s_8_2_template, 0, &s_8_4_template
71
0
        };
72
73
0
        templat = rets[bpc_out];
74
0
    }
75
0
    st = (stream_1248_state *)
76
0
        s_alloc_state(mem, templat->stype, "pixel_resize state");
77
0
    if (st == 0)
78
0
        return_error(gs_error_VMerror);
79
0
    code = psdf_encode_binary(pbw, templat, (stream_state *) st);
80
0
    if (code < 0) {
81
0
        gs_free_object(mem, st, "pixel_resize state");
82
0
        return code;
83
0
    }
84
0
    s_1248_init(st, width, num_components);
85
0
    return 0;
86
0
}
87
88
static int
89
convert_color(gx_device *pdev, const gs_color_space *pcs, const gs_gstate * pgs,
90
              gs_client_color *cc, float c[3])
91
12.5k
{
92
12.5k
    int code;
93
12.5k
    gx_device_color dc;
94
95
12.5k
    cs_restrict_color(cc, pcs);
96
12.5k
    code = pcs->type->remap_color(cc, pcs, &dc, pgs, pdev, gs_color_select_texture);
97
12.5k
    if (code < 0)
98
0
        return code;
99
12.5k
    c[0] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[0]) & ((1 << pdev->color_info.comp_bits[0]) - 1));
100
12.5k
    c[1] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[1]) & ((1 << pdev->color_info.comp_bits[1]) - 1));
101
12.5k
    c[2] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[2]) & ((1 << pdev->color_info.comp_bits[2]) - 1));
102
12.5k
    return 0;
103
12.5k
}
104
105
/* A heuristic choice of DCT compression parameters - see bug 687174. */
106
static int
107
choose_DCT_params(gx_device *pdev, const gs_color_space *pcs,
108
                  const gs_gstate * pgs,
109
                  gs_c_param_list *list, gs_c_param_list **param,
110
                  stream_state *st)
111
6.15k
{
112
6.15k
    gx_device_memory mdev;
113
6.15k
    gs_client_color cc;
114
6.15k
    int code;
115
6.15k
    float c[4][3];
116
6.15k
    const float MIN_FLOAT = - MAX_FLOAT;
117
6.15k
    const float domination = (float)0.25;
118
6.15k
    const int one = 1, zero = 0;
119
120
6.15k
    if (pcs->type->num_components(pcs) != 3)
121
3.01k
        return 0;
122
3.13k
    if (*param != NULL) {
123
        /* Make a copy of the parameter list since we will modify it. */
124
3.13k
        code = param_list_copy((gs_param_list *)list, (gs_param_list *)*param);
125
3.13k
        if (code < 0)
126
0
            return code;
127
3.13k
    }
128
3.13k
    *param = list;
129
130
    /* Create a local memory device for transforming colors to DeviceRGB. */
131
3.13k
    gs_make_mem_device(&mdev, gdev_mem_device_for_bits(24), pdev->memory, 0, NULL);
132
3.13k
    gx_device_retain((gx_device *)&mdev, true);  /* prevent freeing */
133
3.13k
    set_linear_color_bits_mask_shift((gx_device *)&mdev);
134
3.13k
    mdev.color_info.separable_and_linear = GX_CINFO_SEP_LIN;
135
    /* Set mem device icc profile */
136
3.13k
    code = gsicc_init_device_profile_struct((gx_device *) &mdev, NULL, 0);
137
3.13k
    if (code < 0)
138
0
        return code;
139
140
3.13k
    if (pgs) {
141
        /* Check for an RGB-like color space.
142
           To recognize that we make a matrix as it were a linear operator,
143
           suppress an ununiformity by subtracting the image of {0,0,0},
144
           and then check for giagonal domination.  */
145
3.13k
        cc.paint.values[0] = cc.paint.values[1] = cc.paint.values[2] = MIN_FLOAT;
146
3.13k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[3]);
147
3.13k
        if (code < 0)
148
0
            return code;
149
3.13k
        cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MIN_FLOAT;
150
3.13k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[0]);
151
3.13k
        if (code < 0)
152
0
            return code;
153
3.13k
        cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MAX_FLOAT; cc.paint.values[2] = MIN_FLOAT;
154
3.13k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[1]);
155
3.13k
        if (code < 0)
156
0
            return code;
157
3.13k
        cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MAX_FLOAT;
158
3.13k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[2]);
159
3.13k
        if (code < 0)
160
0
            return code;
161
3.13k
        c[0][0] -= c[3][0]; c[0][1] -= c[3][1]; c[0][2] -= c[3][2];
162
3.13k
        c[1][0] -= c[3][0]; c[1][1] -= c[3][1]; c[1][2] -= c[3][2];
163
3.13k
        c[2][0] -= c[3][0]; c[2][1] -= c[3][1]; c[2][2] -= c[3][2];
164
3.13k
        c[0][0] = any_abs(c[0][0]); c[0][1] = any_abs(c[0][1]); c[0][2] = any_abs(c[0][2]);
165
3.13k
        c[1][0] = any_abs(c[1][0]); c[1][1] = any_abs(c[1][1]); c[1][2] = any_abs(c[1][2]);
166
3.13k
        c[2][0] = any_abs(c[2][0]); c[2][1] = any_abs(c[2][1]); c[2][2] = any_abs(c[2][2]);
167
3.13k
        if (c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
168
3.13k
            c[1][1] * domination > c[1][0] && c[1][1] * domination > c[1][2] &&
169
3.13k
            c[2][2] * domination > c[2][0] && c[2][2] * domination > c[2][1]) {
170
            /* Yes, it looks like an RGB color space.
171
               Replace ColorTransform with 1. */
172
3.13k
            code = param_write_int((gs_param_list *)list, "ColorTransform", &one);
173
3.13k
            if (code < 0)
174
0
                goto error;
175
3.13k
            goto done;
176
3.13k
        }
177
178
        /* Check for a Lab-like color space.
179
           Colors {v,0,0} should map to grays. */
180
0
        cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = cc.paint.values[2] = 0;
181
0
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[0]);
182
0
        cc.paint.values[0] /= 2;
183
0
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[1]);
184
0
        cc.paint.values[0] /= 2;
185
0
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[2]);
186
0
        c[0][1] -= c[0][0]; c[0][2] -= c[0][0];
187
0
        c[1][1] -= c[1][0]; c[1][2] -= c[1][0];
188
0
        c[2][1] -= c[2][0]; c[2][2] -= c[2][0];
189
0
        c[0][1] = any_abs(c[0][1]); c[0][2] = any_abs(c[0][2]);
190
0
        c[1][1] = any_abs(c[1][1]); c[1][2] = any_abs(c[1][2]);
191
0
        c[2][1] = any_abs(c[2][1]); c[2][2] = any_abs(c[2][2]);
192
0
    }
193
0
    if (pgs && c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
194
0
        c[1][0] * domination > c[1][1] && c[1][0] * domination > c[1][2] &&
195
0
        c[2][0] * domination > c[2][1] && c[2][0] * domination > c[2][2]) {
196
        /* Yes, it looks like an Lab color space.
197
           Replace ColorTransform with 0. */
198
0
        code = param_write_int((gs_param_list *)list, "ColorTransform", &zero);
199
0
        if (code < 0)
200
0
            goto error;
201
0
    } else {
202
        /* Unknown color space type.
203
           Replace /HSamples [1 1 1 1] /VSamples [1 1 1 1] to avoid quality degradation. */
204
0
        gs_param_string a;
205
0
        static const byte v[4] = {1, 1, 1, 1};
206
207
0
        a.data = v;
208
0
        a.size = 4;
209
0
        a.persistent = true;
210
0
        code = param_write_string((gs_param_list *)list, "HSamples", &a);
211
0
        if (code < 0)
212
0
            goto error;
213
0
        code = param_write_string((gs_param_list *)list, "VSamples", &a);
214
0
        if (code < 0)
215
0
            goto error;
216
0
    }
217
3.13k
done:
218
3.13k
    gs_c_param_list_read(list);
219
3.13k
    gx_device_finalize(pdev->memory, &mdev);
220
3.13k
    return 0;
221
0
error:
222
0
    gx_device_finalize(pdev->memory, &mdev);
223
0
    return code;
224
0
}
225
226
/* Add the appropriate image compression filter, if any. */
227
static int
228
setup_image_compression(psdf_binary_writer *pbw, const psdf_image_params *pdip,
229
                        const gs_pixel_image_t * pim, const gs_gstate * pgs,
230
                        bool lossless)
231
86.9k
{
232
86.9k
    gx_device_psdf *pdev = pbw->dev;
233
86.9k
    gs_memory_t *mem = pdev->v_memory;
234
86.9k
    const stream_template *templat = pdip->filter_template;
235
86.9k
    const stream_template *lossless_template;
236
86.9k
    const gs_color_space *pcs = pim->ColorSpace; /* null if mask */
237
86.9k
    int Colors = (pcs ? gs_color_space_num_components(pcs) : 1);
238
86.9k
    bool Indexed =
239
86.9k
        (pcs != 0 &&
240
86.9k
         gs_color_space_get_index(pcs) == gs_color_space_index_Indexed);
241
86.9k
    gs_c_param_list *dict = pdip->Dict;
242
86.9k
    stream_state *st;
243
86.9k
    int code;
244
245
86.9k
    if (pdev->params.UseBrotliCompression) {
246
0
        lossless_template = &s_brotliE_template;
247
86.9k
    } else {
248
86.9k
        if (pdev->params.UseFlateCompression && pdev->version >= psdf_version_ll3)
249
22.8k
            lossless_template = &s_zlibE_template;
250
64.0k
        else
251
64.0k
            lossless_template = &s_LZWE_template;
252
86.9k
    }
253
254
86.9k
    if (!pdip->Encode)    /* no compression */
255
0
        return 0;
256
86.9k
    if (pdip->AutoFilter) {
257
        /*
258
         * Disregard the requested filter.  What we should do at this point
259
         * is analyze the image to decide whether to use JPEG encoding
260
         * (DCTEncode with ACSDict) or the lossless filter.  However, since
261
         * we don't buffer the entire image, we'll make the choice on-fly,
262
         * forking the image data into 3 streams : (1) JPEG, (2) lossless,
263
         * (3) the compression chooser. In this case this function is
264
         * called 2 times with different values of the 'lossless' argument.
265
         */
266
73.2k
        if (lossless) {
267
67.0k
            templat = lossless_template;
268
67.0k
        } else if (templat == NULL || templat == &s_zlibE_template ||
269
6.25k
                   templat == &s_LZWE_template) {
270
0
            templat = &s_DCTE_template;
271
0
        }
272
73.2k
        dict = pdip->ACSDict;
273
73.2k
    } else if (!lossless)
274
0
      return_error(gs_error_rangecheck); /* Reject the alternative stream. */
275
86.9k
    if (pdev->version < psdf_version_ll3 && templat == &s_zlibE_template)
276
12.1k
        templat = lossless_template;
277
86.9k
    if (dict != NULL) /* Some interpreters don't supply filter parameters. */
278
27.3k
        gs_c_param_list_read(dict); /* ensure param list is in read mode */
279
86.9k
    if (templat == 0 || pdev->JPEG_PassThrough || pdev->JPX_PassThrough)  /* no compression */
280
1.13k
        return 0;
281
85.7k
    if (pim->Width < 200 && pim->Height < 200) /* Prevent a fixed overflow. */
282
77.4k
        if (pim->Width * pim->Height * Colors * pim->BitsPerComponent <= 160)
283
44.6k
            return 0;  /* not worth compressing */
284
    /* Only use DCTE for 8-bit, non-Indexed data. */
285
41.1k
    if (templat == &s_DCTE_template) {
286
6.68k
        if (Indexed ||
287
6.68k
            !(pdip->Downsample ?
288
0
              pdip->Depth == 8 ||
289
0
              (pdip->Depth == -1 && pim->BitsPerComponent == 8) :
290
6.18k
              pim->BitsPerComponent == 8)
291
6.68k
            ) {
292
            /* Use LZW/Flate/Brotli instead. */
293
536
            templat = lossless_template;
294
536
        }
295
6.68k
    }
296
41.1k
    st = s_alloc_state(mem, templat->stype, "setup_image_compression");
297
41.1k
    if (st == 0)
298
0
        return_error(gs_error_VMerror);
299
300
41.1k
    st->templat = templat;
301
302
41.1k
    if (templat->set_defaults)
303
41.1k
        (*templat->set_defaults) (st);
304
41.1k
    if (templat == &s_CFE_template) {
305
75
        stream_CFE_state *const ss = (stream_CFE_state *) st;
306
307
75
        if (pdip->Dict != 0 && pdip->filter_template == templat) {
308
75
            s_CF_put_params((gs_param_list *)pdip->Dict,
309
75
                            (stream_CF_state *)ss); /* ignore errors */
310
75
        } else {
311
0
            ss->K = -1;
312
0
            ss->BlackIs1 = true;
313
0
        }
314
75
        ss->Columns = pim->Width;
315
75
        ss->Rows = (ss->EndOfBlock ? 0 : pim->Height);
316
41.0k
    } else if ((templat == &s_LZWE_template ||
317
41.0k
                (templat == &s_zlibE_template) || templat == &s_brotliE_template) &&
318
41.0k
               pdev->version >= psdf_version_ll3) {
319
11.8k
        int Effort = -1, Predictor = 15;
320
321
11.8k
        if (templat == &s_zlibE_template || templat == &s_brotliE_template) {
322
11.8k
            gs_c_param_list *param = pdip->Dict;
323
324
11.8k
            if (pdip->AutoFilter)
325
10.4k
                param = pdip->ACSDict;
326
327
11.8k
            if (param != NULL) {
328
7.81k
                code = param_read_int((gs_param_list *)param, "Effort", &Effort);
329
7.81k
                if (code == 0 && templat == &s_zlibE_template) {
330
0
                    stream_zlib_state *const ss = (stream_zlib_state *)st;
331
0
                    ss->level = Effort;
332
0
                }
333
7.81k
                if (code == 0 && templat == &s_brotliE_template) {
334
0
                    stream_brotlie_state *const ss = (stream_brotlie_state *)st;
335
0
                    ss->level = Effort;
336
0
                }
337
7.81k
                (void)param_read_int((gs_param_list *)param, "Predictor", &Predictor);
338
7.81k
            }
339
11.8k
        }
340
        /* If not Indexed, add a PNGPredictor filter. */
341
11.8k
        if (!Indexed && Predictor >= 10) {
342
11.3k
            code = psdf_encode_binary(pbw, templat, st);
343
11.3k
            if (code < 0)
344
0
                goto fail;
345
11.3k
            templat = &s_PNGPE_template;
346
11.3k
            st = s_alloc_state(mem, templat->stype, "setup_image_compression");
347
11.3k
            if (st == 0) {
348
0
                code = gs_note_error(gs_error_VMerror);
349
0
                goto fail;
350
0
            }
351
11.3k
            st->templat = templat;
352
11.3k
            if (templat->set_defaults)
353
11.3k
                (*templat->set_defaults) (st);
354
11.3k
            {
355
11.3k
                stream_PNGP_state *const ss = (stream_PNGP_state *) st;
356
357
11.3k
                ss->Colors = Colors;
358
11.3k
                ss->Columns = pim->Width;
359
11.3k
                ss->Predictor = Predictor;
360
11.3k
            }
361
11.3k
        }
362
29.1k
    } else if (templat == &s_DCTE_template) {
363
6.15k
        gs_c_param_list list, *param = dict;
364
365
6.15k
        gs_c_param_list_write(&list, mem);
366
6.15k
        code = choose_DCT_params((gx_device *)pbw->dev, pcs, pgs, &list, &param, st);
367
6.15k
        if (code < 0) {
368
0
            gs_c_param_list_release(&list);
369
0
            return code;
370
0
        }
371
6.15k
        code = psdf_DCT_filter((gs_param_list *)param,
372
6.15k
                               st, pim->Width, pim->Height, Colors, pbw);
373
6.15k
        gs_c_param_list_release(&list);
374
6.15k
        if (code < 0)
375
0
            goto fail;
376
        /* psdf_DCT_filter already did the psdf_encode_binary. */
377
6.15k
        return 0;
378
6.15k
    }
379
35.0k
    code = psdf_encode_binary(pbw, templat, st);
380
35.0k
    if (code >= 0)
381
35.0k
        return 0;
382
0
 fail:
383
0
    gs_free_object(mem, st, "setup_image_compression");
384
0
    return code;
385
35.0k
}
386
387
/* Determine whether an image should be downsampled. */
388
static bool
389
do_downsample(const psdf_image_params *pdip, const gs_pixel_image_t *pim,
390
              double resolution)
391
86.9k
{
392
86.9k
    double factor = resolution / pdip->Resolution;
393
394
86.9k
    return (pdip->Downsample && factor >= pdip->DownsampleThreshold &&
395
86.9k
            factor <= pim->Width && factor <= pim->Height);
396
86.9k
}
397
398
/* Add downsampling, antialiasing, and compression filters. */
399
/* Uses AntiAlias, Depth, DownsampleThreshold, DownsampleType, Resolution. */
400
/* Assumes do_downsampling() is true. */
401
static int
402
setup_downsampling(psdf_binary_writer * pbw, const psdf_image_params * pdip,
403
                   gs_pixel_image_t * pim, const gs_gstate * pgs,
404
                   double resolution, bool lossless)
405
0
{
406
0
    gx_device_psdf *pdev = pbw->dev;
407
0
    const stream_template *templat = &s_Subsample_template;
408
0
    float factor = resolution / pdip->Resolution;
409
0
    int orig_bpc = pim->BitsPerComponent;
410
0
    int orig_width = pim->Width;
411
0
    int orig_height = pim->Height;
412
0
    stream_state *st;
413
0
    int code;
414
415
    /* We can't apply anything other than a simple downsample to monochrome
416
     * image without turning them into greyscale images. We set the default
417
     * to subsample above, so just ignore it if the current image is monochtome.
418
     */
419
0
    if (pim->BitsPerComponent > 1) {
420
0
        switch (pdip->DownsampleType) {
421
0
            case ds_Subsample:
422
0
                templat = &s_Subsample_template;
423
0
                break;
424
0
            case ds_Average:
425
0
                templat = &s_Average_template;
426
0
                break;
427
0
            case ds_Bicubic:
428
0
                templat = &s_IScale_template;
429
                /* We now use the Mitchell filter instead of the 'bicubic' filter
430
                 * because it gives better results.
431
                templat = &s_Bicubic_template;
432
                 */
433
0
                break;
434
0
            default:
435
0
                dmprintf1(pdev->v_memory, "Unsupported downsample type %d\n", pdip->DownsampleType);
436
0
                return gs_note_error(gs_error_rangecheck);
437
0
        }
438
439
0
        if (pdip->DownsampleType != ds_Bicubic) {
440
            /* If downsample type is not bicubic, ensure downsample factor is
441
             * an integer if we're close to one (< 0.1) or silently switch to
442
             * bicubic transform otherwise. See bug #693917. */
443
0
            float rfactor = floor(factor + 0.5);
444
0
            if (fabs(rfactor-factor) < 0.1 || pim->ColorSpace->type->index == gs_color_space_index_Indexed)
445
0
                factor = rfactor;  /* round factor to nearest integer */
446
0
            else
447
0
                templat = &s_Bicubic_template;  /* switch to bicubic */
448
0
        }
449
0
    } else {
450
0
        if (pdip->DownsampleType != ds_Subsample) {
451
0
            dmprintf(pdev->memory, "The only Downsample filter for monochrome images is Subsample, ignoring request.\n");
452
0
        }
453
0
    }
454
455
0
    st = s_alloc_state(pdev->v_memory, templat->stype,
456
0
                       "setup_downsampling");
457
0
    if (st == 0)
458
0
        return_error(gs_error_VMerror);
459
0
    if (templat->set_defaults)
460
0
        templat->set_defaults(st);
461
462
0
    if (templat != &s_IScale_template)
463
0
    {
464
0
        stream_Downsample_state *const ss = (stream_Downsample_state *) st;
465
466
0
        ss->Colors =
467
0
            (pim->ColorSpace == 0 ? 1 /*mask*/ :
468
0
             gs_color_space_num_components(pim->ColorSpace));
469
0
        ss->WidthIn = pim->Width;
470
0
        ss->HeightIn = pim->Height;
471
0
        ss->XFactor = ss->YFactor = factor;
472
0
        ss->AntiAlias = pdip->AntiAlias;
473
0
        ss->padX = ss->padY = false; /* should be true */
474
475
0
        if (pim->BitsPerComponent == 1) {
476
0
            if (floor(ss->XFactor) != ss->XFactor)
477
0
                factor = ss->YFactor = ss->XFactor = floor(ss->XFactor + 0.5);
478
0
        }
479
0
        if (templat->init) {
480
0
            code = templat->init(st);
481
0
            if (code < 0) {
482
0
                dmprintf(st->memory, "Failed to initialise downsample filter, downsampling aborted\n");
483
0
                gs_free_object(pdev->v_memory, st, "setup_image_compression");
484
0
                return 0;
485
0
            }
486
0
        }
487
0
        pim->BitsPerComponent = pdip->Depth;
488
0
        pim->Width = s_Downsample_size_out(pim->Width, factor, false);
489
0
        pim->Height = s_Downsample_size_out(pim->Height, factor, false);
490
0
        gs_matrix_scale(&pim->ImageMatrix, (double)pim->Width / orig_width,
491
0
                        (double)pim->Height / orig_height,
492
0
                        &pim->ImageMatrix);
493
        /****** NO ANTI-ALIASING YET ******/
494
0
        if ((code = setup_image_compression(pbw, pdip, pim, pgs, lossless)) < 0 ||
495
0
            (code = pixel_resize(pbw, pim->Width, ss->Colors,
496
0
                                 8, pdip->Depth)) < 0 ||
497
0
            (code = psdf_encode_binary(pbw, templat, st)) < 0 ||
498
0
            (code = pixel_resize(pbw, orig_width, ss->Colors,
499
0
                                 orig_bpc, 8)) < 0
500
0
            ) {
501
0
            gs_free_object(pdev->v_memory, st, "setup_image_compression");
502
0
            return code;
503
0
        }
504
0
    } else {
505
        /* The setup for the Mitchell filter is quite different to the other filters
506
         * because it isn't one of ours.
507
         */
508
0
        int Colors = (pim->ColorSpace == 0 ? 1 /*mask*/ :
509
0
             gs_color_space_num_components(pim->ColorSpace));
510
511
0
        stream_image_scale_state *ss = (stream_image_scale_state *)st;
512
513
0
        ss->params.EntireWidthIn = ss->params.WidthIn = ss->params.PatchWidthIn = pim->Width;
514
0
        ss->params.EntireHeightIn = ss->params.HeightIn = ss->params.PatchHeightIn = pim->Height;
515
0
        ss->params.EntireWidthOut = ss->params.WidthOut = ss->params.PatchWidthOut = s_Downsample_size_out(pim->Width, factor, false);
516
0
        ss->params.EntireHeightOut = ss->params.HeightOut = ss->params.PatchHeightOut = ss->params.PatchHeightOut2 = s_Downsample_size_out(pim->Height, factor, false);
517
518
        /* Bug #697944 The code below to apply the downsampling filter always
519
         * resizes the input data to the filter with 8BPC and then resizes the output back to whatever
520
         * the original BPC was. So we need to make sure that the stream state
521
         * for the downsampling filter uses 8 BPC, no more and no less.
522
         */
523
0
        ss->params.BitsPerComponentIn = ss->params.BitsPerComponentOut = 8;
524
525
0
        ss->params.spp_interp = ss->params.spp_decode = Colors;
526
0
        ss->params.TopMarginIn = ss->params.TopMarginOut = ss->params.TopMarginOut2 = ss->params.LeftMarginIn = ss->params.LeftMarginOut = 0;
527
0
        ss->params.src_y_offset = ss->params.pad_y = 0;
528
0
        ss->params.early_cm = true;
529
0
        ss->params.MaxValueIn = ss->params.MaxValueOut = (int)pow(2, pdip->Depth);
530
531
        /* No idea what's a sensible value here, but we need to have something or we get a crash
532
         * It looks like this is for scaling up, and we don't do that, so fix it to 1. Parameter
533
         * Added by Ray in commit a936cf for Bug #693684, allows limiting interpolation to less#
534
         * than device resolution.
535
         */
536
0
        ss->params.abs_interp_limit = 1;
537
        /* Apparently ColorPolairtyAdditive is only used by the 'SpecialDownScale filter', don't
538
         * know what that is and we don't use it, so just set it to 0 to avoid uninitialised
539
         * variables
540
         */
541
0
        ss->params.ColorPolarityAdditive = 0;
542
        /* Active = 1 to match gxiscale.c, around line 374 in gs_image_class_0_interpolate() */
543
0
        ss->params.Active = 1;
544
545
0
        if (templat->init) {
546
0
            code = templat->init(st);
547
0
            if (code < 0) {
548
0
                dmprintf(st->memory, "Failed to initialise downsample filter, downsampling aborted\n");
549
0
                gs_free_object(pdev->v_memory, st, "setup_image_compression");
550
0
                return 0;
551
0
            }
552
0
        }
553
0
        pim->Width = s_Downsample_size_out(pim->Width, factor, false);
554
0
        pim->Height = s_Downsample_size_out(pim->Height, factor, false);
555
0
        pim->BitsPerComponent = pdip->Depth;
556
0
        gs_matrix_scale(&pim->ImageMatrix, (double)pim->Width / orig_width,
557
0
                        (double)pim->Height / orig_height,
558
0
                        &pim->ImageMatrix);
559
        /****** NO ANTI-ALIASING YET ******/
560
0
        if ((code = setup_image_compression(pbw, pdip, pim, pgs, lossless)) < 0 ||
561
0
            (code = pixel_resize(pbw, pim->Width, Colors,
562
0
                                 8, pdip->Depth)) < 0 ||
563
0
            (code = psdf_encode_binary(pbw, templat, st)) < 0 ||
564
0
            (code = pixel_resize(pbw, orig_width, Colors,
565
0
                                 orig_bpc, 8)) < 0
566
0
            ) {
567
0
            gs_free_object(pdev->v_memory, st, "setup_image_compression");
568
0
            return code;
569
0
        }
570
0
    }
571
0
    return 0;
572
0
}
573
574
/* Decive whether to convert an image to RGB. */
575
bool
576
psdf_is_converting_image_to_RGB(const gx_device_psdf * pdev,
577
                const gs_gstate * pgs, const gs_pixel_image_t * pim)
578
5.70k
{
579
5.70k
    return pdev->params.ConvertCMYKImagesToRGB &&
580
5.70k
            pgs != 0 && pim->ColorSpace &&
581
5.70k
            (gs_color_space_get_index(pim->ColorSpace) == gs_color_space_index_DeviceCMYK ||
582
0
            (gs_color_space_get_index(pim->ColorSpace) == gs_color_space_index_ICC
583
0
            && gsicc_get_default_type(pim->ColorSpace->cmm_icc_profile_data) ==
584
0
            gs_color_space_index_DeviceCMYK));
585
5.70k
}
586
587
/* Set up compression and downsampling filters for an image. */
588
/* Note that this may modify the image parameters. */
589
int
590
psdf_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw,
591
                         gs_pixel_image_t * pim, const gs_matrix * pctm,
592
                         const gs_gstate * pgs, bool lossless, bool in_line)
593
5.70k
{
594
    /*
595
     * The following algorithms are per Adobe Tech Note # 5151,
596
     * "Acrobat Distiller Parameters", revised 16 September 1996
597
     * for Acrobat(TM) Distiller(TM) 3.0.
598
     *
599
     * The control structure is a little tricky, because filter
600
     * pipelines must be constructed back-to-front.
601
     */
602
5.70k
    int code = 0;
603
5.70k
    psdf_image_params params;
604
5.70k
    int bpc = pim->BitsPerComponent;
605
5.70k
    int bpc_out = pim->BitsPerComponent = min(bpc, 8);
606
5.70k
    int ncomp;
607
5.70k
    double resolution;
608
609
    /*
610
     * The Adobe documentation doesn't say this, but mask images are
611
     * compressed on the same basis as 1-bit-deep monochrome images,
612
     * except that anti-aliasing (resolution/depth tradeoff) is not
613
     * allowed.
614
     */
615
5.70k
    if (pim->ColorSpace == NULL) { /* mask image */
616
3.15k
        params = pdev->params.MonoImage;
617
3.15k
        params.Depth = 1;
618
3.15k
        ncomp = 1;
619
3.15k
    } else {
620
2.54k
        ncomp = gs_color_space_num_components(pim->ColorSpace);
621
2.54k
        if (pim->ColorSpace->type->index == gs_color_space_index_Indexed) {
622
0
            params = pdev->params.ColorImage;
623
            /* Ensure we don't use JPEG on a /Indexed colour space */
624
0
            params.AutoFilter = false;
625
0
            if (pdev->params.UseBrotliCompression)
626
0
                params.Filter = "BrotliEncode";
627
0
            else
628
0
                params.Filter = "FlateEncode";
629
2.54k
        } else {
630
2.54k
            if (ncomp == 1) {
631
0
                if (bpc == 1)
632
0
                    params = pdev->params.MonoImage;
633
0
                else
634
0
                    params = pdev->params.GrayImage;
635
0
                if (params.Depth == -1)
636
0
                    params.Depth = bpc;
637
2.54k
            } else {
638
2.54k
                params = pdev->params.ColorImage;
639
            /* params.Depth is reset below */
640
2.54k
            }
641
2.54k
        }
642
2.54k
    }
643
644
    /*
645
     * We can compute the image resolution by:
646
     *    W / (W * ImageMatrix^-1 * CTM / HWResolution).
647
     * We can replace W by 1 to simplify the computation.
648
     */
649
5.70k
    if (pctm == 0)
650
5.70k
        resolution = -1;
651
0
    else {
652
0
        gs_point pt;
653
654
        /* We could do both X and Y, but why bother? */
655
0
        code = gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt);
656
0
        if (code < 0)
657
0
            return code;
658
0
        gs_distance_transform(pt.x, pt.y, pctm, &pt);
659
0
        resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0],
660
0
                                 pt.y / pdev->HWResolution[1]);
661
0
    }
662
5.70k
    if (ncomp == 1 && pim->ColorSpace && pim->ColorSpace->type->index != gs_color_space_index_Indexed) {
663
        /* Monochrome, gray, or mask */
664
        /* Check for downsampling. */
665
0
        if (do_downsample(&params, pim, resolution)) {
666
            /* Use the downsampled depth, not the original data depth. */
667
0
            if (params.Depth == 1) {
668
0
                params.Filter = pdev->params.MonoImage.Filter;
669
0
                params.filter_template = pdev->params.MonoImage.filter_template;
670
0
                params.Dict = pdev->params.MonoImage.Dict;
671
0
            } else {
672
0
                params.Filter = pdev->params.GrayImage.Filter;
673
0
                params.filter_template = pdev->params.GrayImage.filter_template;
674
0
                params.Dict = pdev->params.GrayImage.Dict;
675
0
            }
676
0
            code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
677
0
        } else {
678
0
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
679
0
        }
680
0
        if (code < 0)
681
0
            return code;
682
0
        code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
683
5.70k
    } else {
684
        /* Color */
685
5.70k
        bool cmyk_to_rgb = psdf_is_converting_image_to_RGB(pdev, pgs, pim);
686
687
5.70k
        if (cmyk_to_rgb) {
688
0
            gs_memory_t *mem = pdev->v_memory;
689
690
            /* {csrc} decref old colorspace? */
691
0
            rc_decrement_only_cs(pim->ColorSpace, "psdf_setup_image_filters");
692
0
            pim->ColorSpace = gs_cspace_new_DeviceRGB(mem);
693
0
            if (pim->ColorSpace == NULL)
694
0
                return_error(gs_error_VMerror);
695
0
        }
696
5.70k
        if (params.Depth == -1)
697
2.54k
            params.Depth = (cmyk_to_rgb ? 8 : bpc_out);
698
5.70k
        if (do_downsample(&params, pim, resolution)) {
699
0
            code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
700
5.70k
        } else {
701
5.70k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
702
5.70k
        }
703
5.70k
        if (code < 0)
704
0
            return code;
705
5.70k
        if (cmyk_to_rgb) {
706
0
            gs_memory_t *mem = pdev->v_memory;
707
0
            stream_C2R_state *ss = (stream_C2R_state *)
708
0
                s_alloc_state(mem, s_C2R_template.stype, "C2R state");
709
0
            int code = pixel_resize(pbw, pim->Width, 3, 8, bpc_out);
710
711
0
            if (ss == 0)
712
0
                return_error(gs_error_VMerror);
713
714
0
            if (code < 0 ||
715
0
                (code = psdf_encode_binary(pbw, &s_C2R_template,
716
0
                                           (stream_state *) ss)) < 0 ||
717
0
                (code = pixel_resize(pbw, pim->Width, 4, bpc, 8)) < 0
718
0
                )
719
0
                return code;
720
0
            s_C2R_init(ss, pgs);
721
5.70k
        } else {
722
5.70k
            code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
723
5.70k
            if (code < 0)
724
0
                return code;
725
5.70k
        }
726
5.70k
    }
727
5.70k
    return code;
728
5.70k
}
729
730
/* Set up compression filters for a lossless image, downsampling is permitted, */
731
/* no color space conversion, and only lossless filters. */
732
/* Note that this may modify the image parameters. */
733
int
734
psdf_setup_lossless_filters(gx_device_psdf *pdev, psdf_binary_writer *pbw,
735
                            gs_pixel_image_t *pim, bool in_line)
736
2.54k
{
737
    /*
738
     * Set up a device with modified parameters for computing the image
739
     * compression filters.  Don't allow downsampling or lossy compression.
740
     */
741
2.54k
    gx_device_psdf ipdev;
742
743
2.54k
    ipdev = *pdev;
744
2.54k
    ipdev.params.ColorImage.AutoFilter = false;
745
2.54k
    if (pdev->params.UseBrotliCompression) {
746
0
        ipdev.params.ColorImage.Filter = "BrotliEncode";
747
0
        ipdev.params.ColorImage.filter_template = &s_brotliE_template;
748
0
        ipdev.params.GrayImage.Filter = "BrotliEncode";
749
0
        ipdev.params.GrayImage.filter_template = &s_brotliE_template;
750
2.54k
    } else {
751
2.54k
        ipdev.params.ColorImage.Filter = "FlateEncode";
752
2.54k
        ipdev.params.ColorImage.filter_template = &s_zlibE_template;
753
2.54k
        ipdev.params.GrayImage.Filter = "FlateEncode";
754
2.54k
        ipdev.params.GrayImage.filter_template = &s_zlibE_template;
755
2.54k
    }
756
2.54k
    ipdev.params.ConvertCMYKImagesToRGB = false;
757
2.54k
    ipdev.params.GrayImage.AutoFilter = false;
758
2.54k
    return psdf_setup_image_filters(&ipdev, pbw, pim, NULL, NULL, true, in_line);
759
2.54k
}
760
761
/* Set up image compression chooser. */
762
int
763
psdf_setup_compression_chooser(psdf_binary_writer *pbw, gx_device_psdf *pdev,
764
                    int width, int height, int depth, int bits_per_sample)
765
6.25k
{
766
6.25k
    int code;
767
6.25k
    stream_state *ss = s_alloc_state(pdev->memory, s_compr_chooser_template.stype,
768
6.25k
                                     "psdf_setup_compression_chooser");
769
770
6.25k
    if (ss == 0)
771
0
        return_error(gs_error_VMerror);
772
6.25k
    ss->templat = &s_compr_chooser_template;
773
774
6.25k
    pbw->memory = pdev->memory;
775
6.25k
    pbw->strm = pdev->strm; /* just a stub - will not write to it. */
776
6.25k
    pbw->dev = pdev;
777
6.25k
    pbw->target = pbw->strm; /* Since s_add_filter may insert NullEncode to comply buffering,
778
                                 will need to close a chain of filetrs. */
779
6.25k
    code = psdf_encode_binary(pbw, &s_compr_chooser_template, ss);
780
6.25k
    if (code < 0)
781
0
        return code;
782
6.25k
    code = s_compr_chooser_set_dimensions((stream_compr_chooser_state *)ss,
783
6.25k
                    width, height, depth, bits_per_sample);
784
6.25k
    return code;
785
6.25k
}
786
787
/* Set up an "image to mask" filter. */
788
int
789
psdf_setup_image_to_mask_filter(psdf_binary_writer *pbw, gx_device_psdf *pdev,
790
                                int width, int height, int input_width,
791
                                int depth, int bits_per_sample, uint *MaskColor)
792
0
{
793
0
    int code;
794
0
    stream_state *ss = s_alloc_state(pdev->memory, s__image_colors_template.stype,
795
0
        "psdf_setup_image_colors_filter");
796
797
0
    if (ss == 0)
798
0
        return_error(gs_error_VMerror);
799
0
    pbw->memory = pdev->memory;
800
0
    pbw->dev = pdev;
801
0
    code = psdf_encode_binary(pbw, &s__image_colors_template, ss);
802
0
    if (code < 0)
803
0
        return code;
804
0
    s_image_colors_set_dimensions((stream_image_colors_state *)ss,
805
0
                                  width, height, input_width, depth, bits_per_sample);
806
0
    s_image_colors_set_mask_colors((stream_image_colors_state *)ss, MaskColor);
807
0
    return 0;
808
0
}
809
810
/* Set up an image colors filter. */
811
int
812
psdf_setup_image_colors_filter(psdf_binary_writer *pbw,
813
                               gx_device_psdf *pdev,
814
                               const gs_pixel_image_t *input_pim,
815
                               gs_pixel_image_t * pim,
816
                               const gs_gstate *pgs)
817
1.62k
{   /* fixme: currently it's a stub convertion to mask. */
818
1.62k
    int code;
819
1.62k
    stream_state *ss = s_alloc_state(pdev->memory, s__image_colors_template.stype,
820
1.62k
        "psdf_setup_image_colors_filter");
821
1.62k
    unsigned char i;
822
823
1.62k
    if (ss == 0)
824
0
        return_error(gs_error_VMerror);
825
1.62k
    pbw->memory = pdev->memory;
826
1.62k
    pbw->dev = pdev;
827
1.62k
    code = psdf_encode_binary(pbw, &s__image_colors_template, ss);
828
1.62k
    if (code < 0)
829
0
        return code;
830
1.62k
    s_image_colors_set_dimensions((stream_image_colors_state *)ss,
831
1.62k
                                  pim->Width, pim->Height, input_pim->Width,
832
1.62k
                                  gs_color_space_num_components(pim->ColorSpace),
833
1.62k
                                  pim->BitsPerComponent);
834
1.62k
    s_image_colors_set_color_space((stream_image_colors_state *)ss,
835
1.62k
                    (gx_device *)pdev, pim->ColorSpace, pgs, pim->Decode);
836
1.62k
    pim->BitsPerComponent = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
837
6.51k
    for (i = 0; i < pdev->color_info.num_components; i++) {
838
4.88k
        pim->Decode[i * 2 + 0] = 0;
839
4.88k
        pim->Decode[i * 2 + 1] = 1;
840
4.88k
    }
841
1.62k
    return 0;
842
1.62k
}
843
844
/* Set up compression and downsampling filters for an image. */
845
/* Note that this may modify the image parameters. */
846
int
847
new_setup_image_filters(gx_device_psdf * pdev, psdf_binary_writer * pbw,
848
                         gs_pixel_image_t * pim, const gs_matrix * pctm,
849
                         const gs_gstate * pgs, bool lossless, bool in_line,
850
                         bool colour_conversion)
851
81.2k
{
852
    /*
853
     * The following algorithms are per Adobe Tech Note # 5151,
854
     * "Acrobat Distiller Parameters", revised 16 September 1996
855
     * for Acrobat(TM) Distiller(TM) 3.0.
856
     *
857
     * The control structure is a little tricky, because filter
858
     * pipelines must be constructed back-to-front.
859
     */
860
81.2k
    int code = 0;
861
81.2k
    psdf_image_params params;
862
81.2k
    int bpc = pim->BitsPerComponent;
863
81.2k
    int bpc_out = pim->BitsPerComponent = min(bpc, 8);
864
81.2k
    int ncomp;
865
81.2k
    double resolution, resolutiony;
866
867
    /*
868
     * The Adobe documentation doesn't say this, but mask images are
869
     * compressed on the same basis as 1-bit-deep monochrome images,
870
     * except that anti-aliasing (resolution/depth tradeoff) is not
871
     * allowed.
872
     */
873
81.2k
    if (pim->ColorSpace == NULL) { /* mask image */
874
55.8k
        params = pdev->params.MonoImage;
875
55.8k
        params.Depth = 1;
876
55.8k
        ncomp = 1;
877
55.8k
    } else {
878
25.3k
        ncomp = gs_color_space_num_components(pim->ColorSpace);
879
25.3k
        if (pim->ColorSpace->type->index == gs_color_space_index_Indexed) {
880
1.89k
            params = pdev->params.ColorImage;
881
            /* Ensure we don't use JPEG on a /Indexed colour space */
882
1.89k
            params.AutoFilter = false;
883
1.89k
            if (pdev->params.UseBrotliCompression)
884
0
                params.Filter = "FlateEncode";
885
1.89k
            else
886
1.89k
                params.Filter = "BrotliEncode";
887
23.4k
        } else {
888
23.4k
            if (ncomp == 1) {
889
7.25k
                if (bpc == 1)
890
541
                    params = pdev->params.MonoImage;
891
6.71k
                else
892
6.71k
                    params = pdev->params.GrayImage;
893
7.25k
                if (params.Depth == -1)
894
7.25k
                    params.Depth = bpc;
895
16.1k
            } else {
896
16.1k
                params = pdev->params.ColorImage;
897
            /* params.Depth is reset below */
898
16.1k
            }
899
23.4k
        }
900
25.3k
    }
901
902
    /*
903
     * We can compute the image resolution by:
904
     *    W / (W * ImageMatrix^-1 * CTM / HWResolution).
905
     * We can replace W by 1 to simplify the computation.
906
     */
907
81.2k
    if (pctm == 0)
908
0
        resolution = -1;
909
81.2k
    else {
910
81.2k
        gs_point pt;
911
912
        /* We could do both X and Y, but why bother? */
913
81.2k
        code = gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt);
914
81.2k
        if (code < 0)
915
0
            return code;
916
81.2k
        gs_distance_transform(pt.x, pt.y, pctm, &pt);
917
81.2k
        resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0],
918
81.2k
                                 pt.y / pdev->HWResolution[1]);
919
920
        /* Actually we must do both X and Y, in case the image is ananmorphically scaled
921
         * and one axis is not high enough resolution to be downsampled.
922
         * Bug #696152
923
         */
924
81.2k
        code = gs_distance_transform_inverse(0.0, 1.0, &pim->ImageMatrix, &pt);
925
81.2k
        if (code < 0)
926
0
            return code;
927
81.2k
        gs_distance_transform(pt.x, pt.y, pctm, &pt);
928
81.2k
        resolutiony = 1.0 / hypot(pt.x / pdev->HWResolution[0],
929
81.2k
                                 pt.y / pdev->HWResolution[1]);
930
81.2k
        if (resolutiony < resolution)
931
12.9k
            resolution = resolutiony;
932
81.2k
    }
933
934
81.2k
    if (bpc != bpc_out) {
935
0
        pdev->JPEG_PassThrough = 0;
936
0
        pdev->JPX_PassThrough = 0;
937
0
    }
938
939
81.2k
    if (ncomp == 1 && pim->ColorSpace && pim->ColorSpace->type->index != gs_color_space_index_Indexed) {
940
        /* Monochrome, gray, or mask */
941
        /* Check for downsampling. */
942
7.25k
        if (do_downsample(&params, pim, resolution)) {
943
            /* Use the downsampled depth, not the original data depth. */
944
0
            if (params.Depth == 1) {
945
0
                params.Filter = pdev->params.MonoImage.Filter;
946
0
                params.filter_template = pdev->params.MonoImage.filter_template;
947
0
                params.Dict = pdev->params.MonoImage.Dict;
948
0
            } else {
949
0
                if (params.Depth > 8)
950
0
                    params.Depth = bpc_out;
951
0
                params.Filter = pdev->params.GrayImage.Filter;
952
0
                params.filter_template = pdev->params.GrayImage.filter_template;
953
0
                params.Dict = pdev->params.GrayImage.Dict;
954
0
            }
955
0
            pdev->JPEG_PassThrough = 0;
956
0
            pdev->JPX_PassThrough = 0;
957
0
            code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
958
7.25k
        } else {
959
7.25k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
960
7.25k
        }
961
7.25k
        if (code < 0)
962
0
            return code;
963
7.25k
        code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
964
73.9k
    } else {
965
        /* Color */
966
73.9k
        if (params.Depth == -1)
967
18.0k
            params.Depth = (colour_conversion ? 8 : bpc_out);
968
73.9k
        if (do_downsample(&params, pim, resolution)) {
969
0
            pdev->JPEG_PassThrough = 0;
970
0
            pdev->JPX_PassThrough = 0;
971
0
            code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
972
73.9k
        } else {
973
73.9k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
974
73.9k
        }
975
73.9k
        if (code < 0)
976
0
            return code;
977
73.9k
        code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
978
73.9k
        if (code < 0)
979
0
            return code;
980
73.9k
    }
981
81.2k
    return code;
982
81.2k
}
983
984
int
985
new_setup_lossless_filters(gx_device_psdf *pdev, psdf_binary_writer *pbw,
986
                            gs_pixel_image_t *pim, bool in_line,
987
                            bool colour_conversion, const gs_matrix *pctm, gs_gstate * pgs)
988
66.8k
{
989
    /*
990
     * Set up a device with modified parameters for computing the image
991
     * compression filters.  Don't allow lossy compression, but do allow downsampling.
992
     */
993
66.8k
    gx_device_psdf ipdev;
994
995
66.8k
    ipdev = *pdev;
996
66.8k
    ipdev.params.ColorImage.AutoFilter = false;
997
66.8k
    if (pdev->params.UseBrotliCompression) {
998
0
        ipdev.params.ColorImage.Filter = "BrotliEncode";
999
0
        ipdev.params.ColorImage.filter_template = &s_brotliE_template;
1000
0
        ipdev.params.GrayImage.Filter = "BrotliEncode";
1001
0
        ipdev.params.GrayImage.filter_template = &s_brotliE_template;
1002
66.8k
    } else {
1003
66.8k
        ipdev.params.ColorImage.Filter = "FlateEncode";
1004
66.8k
        ipdev.params.ColorImage.filter_template = &s_zlibE_template;
1005
66.8k
        ipdev.params.GrayImage.Filter = "FlateEncode";
1006
66.8k
        ipdev.params.GrayImage.filter_template = &s_zlibE_template;
1007
66.8k
    }
1008
66.8k
    ipdev.params.ConvertCMYKImagesToRGB = false;
1009
66.8k
    ipdev.params.GrayImage.AutoFilter = false;
1010
66.8k
    ipdev.params.GrayImage.Downsample = false;
1011
66.8k
    return new_setup_image_filters(&ipdev, pbw, pim, pctm, pgs, true, in_line, colour_conversion);
1012
66.8k
}
1013
1014
int new_resize_input(psdf_binary_writer *pbw, int width, int num_comps, int bpc_in, int bpc_out)
1015
0
{
1016
0
    return pixel_resize(pbw, width, num_comps, bpc_in, bpc_out);
1017
0
}