Coverage Report

Created: 2025-11-16 07:40

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