Coverage Report

Created: 2025-08-28 07:06

/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
123k
{
54
123k
    gs_memory_t *mem = pbw->dev->v_memory;
55
123k
    const stream_template *templat;
56
123k
    stream_1248_state *st;
57
123k
    int code;
58
59
123k
    if (bpc_out == bpc_in)
60
123k
        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
22.0k
{
92
22.0k
    int code;
93
22.0k
    gx_device_color dc;
94
95
22.0k
    cs_restrict_color(cc, pcs);
96
22.0k
    code = pcs->type->remap_color(cc, pcs, &dc, pgs, pdev, gs_color_select_texture);
97
22.0k
    if (code < 0)
98
0
        return code;
99
22.0k
    c[0] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[0]) & ((1 << pdev->color_info.comp_bits[0]) - 1));
100
22.0k
    c[1] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[1]) & ((1 << pdev->color_info.comp_bits[1]) - 1));
101
22.0k
    c[2] = (float)((int)(dc.colors.pure >> pdev->color_info.comp_shift[2]) & ((1 << pdev->color_info.comp_bits[2]) - 1));
102
22.0k
    return 0;
103
22.0k
}
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
10.3k
{
112
10.3k
    gx_device_memory mdev;
113
10.3k
    gs_client_color cc;
114
10.3k
    int code;
115
10.3k
    float c[4][3];
116
10.3k
    const float MIN_FLOAT = - MAX_FLOAT;
117
10.3k
    const float domination = (float)0.25;
118
10.3k
    const int one = 1, zero = 0;
119
120
10.3k
    if (pcs->type->num_components(pcs) != 3)
121
4.84k
        return 0;
122
5.51k
    if (*param != NULL) {
123
        /* Make a copy of the parameter list since we will modify it. */
124
5.51k
        code = param_list_copy((gs_param_list *)list, (gs_param_list *)*param);
125
5.51k
        if (code < 0)
126
0
            return code;
127
5.51k
    }
128
5.51k
    *param = list;
129
130
    /* Create a local memory device for transforming colors to DeviceRGB. */
131
5.51k
    gs_make_mem_device(&mdev, gdev_mem_device_for_bits(24), pdev->memory, 0, NULL);
132
5.51k
    gx_device_retain((gx_device *)&mdev, true);  /* prevent freeing */
133
5.51k
    set_linear_color_bits_mask_shift((gx_device *)&mdev);
134
5.51k
    mdev.color_info.separable_and_linear = GX_CINFO_SEP_LIN;
135
    /* Set mem device icc profile */
136
5.51k
    code = gsicc_init_device_profile_struct((gx_device *) &mdev, NULL, 0);
137
5.51k
    if (code < 0)
138
0
        return code;
139
140
5.51k
    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
5.51k
        cc.paint.values[0] = cc.paint.values[1] = cc.paint.values[2] = MIN_FLOAT;
146
5.51k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[3]);
147
5.51k
        if (code < 0)
148
0
            return code;
149
5.51k
        cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MIN_FLOAT;
150
5.51k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[0]);
151
5.51k
        if (code < 0)
152
0
            return code;
153
5.51k
        cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MAX_FLOAT; cc.paint.values[2] = MIN_FLOAT;
154
5.51k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[1]);
155
5.51k
        if (code < 0)
156
0
            return code;
157
5.51k
        cc.paint.values[0] = MIN_FLOAT; cc.paint.values[1] = MIN_FLOAT; cc.paint.values[2] = MAX_FLOAT;
158
5.51k
        code = convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[2]);
159
5.51k
        if (code < 0)
160
0
            return code;
161
5.51k
        c[0][0] -= c[3][0]; c[0][1] -= c[3][1]; c[0][2] -= c[3][2];
162
5.51k
        c[1][0] -= c[3][0]; c[1][1] -= c[3][1]; c[1][2] -= c[3][2];
163
5.51k
        c[2][0] -= c[3][0]; c[2][1] -= c[3][1]; c[2][2] -= c[3][2];
164
5.51k
        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
5.51k
        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
5.51k
        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
5.51k
        if (c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
168
5.51k
            c[1][1] * domination > c[1][0] && c[1][1] * domination > c[1][2] &&
169
5.51k
            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
5.50k
            code = param_write_int((gs_param_list *)list, "ColorTransform", &one);
173
5.50k
            if (code < 0)
174
0
                goto error;
175
5.50k
            goto done;
176
5.50k
        }
177
178
        /* Check for a Lab-like color space.
179
           Colors {v,0,0} should map to grays. */
180
11
        cc.paint.values[0] = MAX_FLOAT; cc.paint.values[1] = cc.paint.values[2] = 0;
181
11
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[0]);
182
11
        cc.paint.values[0] /= 2;
183
11
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[1]);
184
11
        cc.paint.values[0] /= 2;
185
11
        convert_color((gx_device *)&mdev, pcs, pgs, &cc, c[2]);
186
11
        c[0][1] -= c[0][0]; c[0][2] -= c[0][0];
187
11
        c[1][1] -= c[1][0]; c[1][2] -= c[1][0];
188
11
        c[2][1] -= c[2][0]; c[2][2] -= c[2][0];
189
11
        c[0][1] = any_abs(c[0][1]); c[0][2] = any_abs(c[0][2]);
190
11
        c[1][1] = any_abs(c[1][1]); c[1][2] = any_abs(c[1][2]);
191
11
        c[2][1] = any_abs(c[2][1]); c[2][2] = any_abs(c[2][2]);
192
11
    }
193
11
    if (pgs && c[0][0] * domination > c[0][1] && c[0][0] * domination > c[0][2] &&
194
11
        c[1][0] * domination > c[1][1] && c[1][0] * domination > c[1][2] &&
195
11
        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
9
    } else {
202
        /* Unknown color space type.
203
           Replace /HSamples [1 1 1 1] /VSamples [1 1 1 1] to avoid quality degradation. */
204
9
        gs_param_string a;
205
9
        static const byte v[4] = {1, 1, 1, 1};
206
207
9
        a.data = v;
208
9
        a.size = 4;
209
9
        a.persistent = true;
210
9
        code = param_write_string((gs_param_list *)list, "HSamples", &a);
211
9
        if (code < 0)
212
0
            goto error;
213
9
        code = param_write_string((gs_param_list *)list, "VSamples", &a);
214
9
        if (code < 0)
215
0
            goto error;
216
9
    }
217
5.51k
done:
218
5.51k
    gs_c_param_list_read(list);
219
5.51k
    gx_device_finalize(pdev->memory, &mdev);
220
5.51k
    return 0;
221
0
error:
222
0
    gx_device_finalize(pdev->memory, &mdev);
223
0
    return code;
224
11
}
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
123k
{
232
123k
    gx_device_psdf *pdev = pbw->dev;
233
123k
    gs_memory_t *mem = pdev->v_memory;
234
123k
    const stream_template *templat = pdip->filter_template;
235
123k
    const stream_template *lossless_template;
236
123k
    const gs_color_space *pcs = pim->ColorSpace; /* null if mask */
237
123k
    int Colors = (pcs ? gs_color_space_num_components(pcs) : 1);
238
123k
    bool Indexed =
239
123k
        (pcs != 0 &&
240
123k
         gs_color_space_get_index(pcs) == gs_color_space_index_Indexed);
241
123k
    gs_c_param_list *dict = pdip->Dict;
242
123k
    stream_state *st;
243
123k
    int code;
244
245
123k
    if (pdev->params.UseBrotliCompression) {
246
0
        lossless_template = &s_brotliE_template;
247
123k
    } else {
248
123k
        if (pdev->params.UseFlateCompression && pdev->version >= psdf_version_ll3)
249
61.9k
            lossless_template = &s_zlibE_template;
250
61.7k
        else
251
61.7k
            lossless_template = &s_LZWE_template;
252
123k
    }
253
254
123k
    if (!pdip->Encode)    /* no compression */
255
0
        return 0;
256
123k
    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
108k
        if (lossless) {
267
98.1k
            templat = lossless_template;
268
98.1k
        } else if (templat == NULL || templat == &s_zlibE_template ||
269
10.7k
                   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
108k
        dict = pdip->ACSDict;
278
108k
    } else if (!lossless)
279
0
      return_error(gs_error_rangecheck); /* Reject the alternative stream. */
280
123k
    if (pdev->version < psdf_version_ll3 && templat == &s_zlibE_template)
281
11.7k
        templat = lossless_template;
282
123k
    if (dict != NULL) /* Some interpreters don't supply filter parameters. */
283
41.0k
        gs_c_param_list_read(dict); /* ensure param list is in read mode */
284
123k
    if (templat == 0 || pdev->JPEG_PassThrough || pdev->JPX_PassThrough)  /* no compression */
285
4.85k
        return 0;
286
118k
    if (pim->Width < 200 && pim->Height < 200) /* Prevent a fixed overflow. */
287
108k
        if (pim->Width * pim->Height * Colors * pim->BitsPerComponent <= 160)
288
65.9k
            return 0;  /* not worth compressing */
289
    /* Only use DCTE for 8-bit, non-Indexed data. */
290
52.9k
    if (templat == &s_DCTE_template) {
291
11.4k
        if (Indexed ||
292
11.4k
            !(pdip->Downsample ?
293
0
              pdip->Depth == 8 ||
294
0
              (pdip->Depth == -1 && pim->BitsPerComponent == 8) :
295
10.3k
              pim->BitsPerComponent == 8)
296
11.4k
            ) {
297
            /* Use LZW/Flate/Brotli instead. */
298
1.05k
            templat = lossless_template;
299
1.05k
        }
300
11.4k
    }
301
52.9k
    st = s_alloc_state(mem, templat->stype, "setup_image_compression");
302
52.9k
    if (st == 0)
303
0
        return_error(gs_error_VMerror);
304
305
52.9k
    st->templat = templat;
306
307
52.9k
    if (templat->set_defaults)
308
52.9k
        (*templat->set_defaults) (st);
309
52.9k
    if (templat == &s_CFE_template) {
310
350
        stream_CFE_state *const ss = (stream_CFE_state *) st;
311
312
350
        if (pdip->Dict != 0 && pdip->filter_template == templat) {
313
350
            s_CF_put_params((gs_param_list *)pdip->Dict,
314
350
                            (stream_CF_state *)ss); /* ignore errors */
315
350
        } else {
316
0
            ss->K = -1;
317
0
            ss->BlackIs1 = true;
318
0
        }
319
350
        ss->Columns = pim->Width;
320
350
        ss->Rows = (ss->EndOfBlock ? 0 : pim->Height);
321
52.6k
    } else if ((templat == &s_LZWE_template ||
322
52.6k
                (templat == &s_zlibE_template) || templat == &s_brotliE_template) &&
323
52.6k
               pdev->version >= psdf_version_ll3) {
324
20.1k
        int Effort = -1, Predictor = 15;
325
326
20.1k
        if (templat == &s_zlibE_template || templat == &s_brotliE_template) {
327
20.1k
            gs_c_param_list *param = pdip->Dict;
328
329
20.1k
            if (pdip->AutoFilter)
330
17.2k
                param = pdip->ACSDict;
331
332
20.1k
            if (param != NULL) {
333
13.8k
                code = param_read_int((gs_param_list *)param, "Effort", &Effort);
334
13.8k
                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
13.8k
                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
13.8k
                (void)param_read_int((gs_param_list *)param, "Predictor", &Predictor);
343
13.8k
            }
344
20.1k
        }
345
        /* If not Indexed, add a PNGPredictor filter. */
346
20.1k
        if (!Indexed && Predictor >= 10) {
347
19.1k
            code = psdf_encode_binary(pbw, templat, st);
348
19.1k
            if (code < 0)
349
0
                goto fail;
350
19.1k
            templat = &s_PNGPE_template;
351
19.1k
            st = s_alloc_state(mem, templat->stype, "setup_image_compression");
352
19.1k
            if (st == 0) {
353
0
                code = gs_note_error(gs_error_VMerror);
354
0
                goto fail;
355
0
            }
356
19.1k
            st->templat = templat;
357
19.1k
            if (templat->set_defaults)
358
19.1k
                (*templat->set_defaults) (st);
359
19.1k
            {
360
19.1k
                stream_PNGP_state *const ss = (stream_PNGP_state *) st;
361
362
19.1k
                ss->Colors = Colors;
363
19.1k
                ss->Columns = pim->Width;
364
19.1k
                ss->Predictor = Predictor;
365
19.1k
            }
366
19.1k
        }
367
32.4k
    } else if (templat == &s_DCTE_template) {
368
10.3k
        gs_c_param_list list, *param = dict;
369
370
10.3k
        gs_c_param_list_write(&list, mem);
371
10.3k
        code = choose_DCT_params((gx_device *)pbw->dev, pcs, pgs, &list, &param, st);
372
10.3k
        if (code < 0) {
373
0
            gs_c_param_list_release(&list);
374
0
            return code;
375
0
        }
376
10.3k
        code = psdf_DCT_filter((gs_param_list *)param,
377
10.3k
                               st, pim->Width, pim->Height, Colors, pbw);
378
10.3k
        gs_c_param_list_release(&list);
379
10.3k
        if (code < 0)
380
0
            goto fail;
381
        /* psdf_DCT_filter already did the psdf_encode_binary. */
382
10.3k
        return 0;
383
10.3k
    }
384
42.6k
    code = psdf_encode_binary(pbw, templat, st);
385
42.6k
    if (code >= 0)
386
42.6k
        return 0;
387
0
 fail:
388
0
    gs_free_object(mem, st, "setup_image_compression");
389
0
    return code;
390
42.6k
}
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
123k
{
397
123k
    double factor = resolution / pdip->Resolution;
398
399
123k
    return (pdip->Downsample && factor >= pdip->DownsampleThreshold &&
400
123k
            factor <= pim->Width && factor <= pim->Height);
401
123k
}
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
6.03k
{
584
6.03k
    return pdev->params.ConvertCMYKImagesToRGB &&
585
6.03k
            pgs != 0 && pim->ColorSpace &&
586
6.03k
            (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
6.03k
}
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
6.03k
{
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
6.03k
    int code = 0;
608
6.03k
    psdf_image_params params;
609
6.03k
    int bpc = pim->BitsPerComponent;
610
6.03k
    int bpc_out = pim->BitsPerComponent = min(bpc, 8);
611
6.03k
    int ncomp;
612
6.03k
    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
6.03k
    if (pim->ColorSpace == NULL) { /* mask image */
621
3.91k
        params = pdev->params.MonoImage;
622
3.91k
        params.Depth = 1;
623
3.91k
        ncomp = 1;
624
3.91k
    } else {
625
2.12k
        ncomp = gs_color_space_num_components(pim->ColorSpace);
626
2.12k
        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
2.12k
        } else {
635
2.12k
            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
2.12k
            } else {
643
2.12k
                params = pdev->params.ColorImage;
644
            /* params.Depth is reset below */
645
2.12k
            }
646
2.12k
        }
647
2.12k
    }
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
6.03k
    if (pctm == 0)
655
6.03k
        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
6.03k
    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
6.03k
    } else {
689
        /* Color */
690
6.03k
        bool cmyk_to_rgb = psdf_is_converting_image_to_RGB(pdev, pgs, pim);
691
692
6.03k
        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
6.03k
        if (params.Depth == -1)
702
2.12k
            params.Depth = (cmyk_to_rgb ? 8 : bpc_out);
703
6.03k
        if (do_downsample(&params, pim, resolution)) {
704
0
            code = setup_downsampling(pbw, &params, pim, pgs, resolution, lossless);
705
6.03k
        } else {
706
6.03k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
707
6.03k
        }
708
6.03k
        if (code < 0)
709
0
            return code;
710
6.03k
        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
6.03k
        } else {
727
6.03k
            code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
728
6.03k
            if (code < 0)
729
0
                return code;
730
6.03k
        }
731
6.03k
    }
732
6.03k
    return code;
733
6.03k
}
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
2.12k
{
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
2.12k
    gx_device_psdf ipdev;
747
748
2.12k
    ipdev = *pdev;
749
2.12k
    ipdev.params.ColorImage.AutoFilter = false;
750
2.12k
    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
2.12k
    } else {
756
2.12k
        ipdev.params.ColorImage.Filter = "FlateEncode";
757
2.12k
        ipdev.params.ColorImage.filter_template = &s_zlibE_template;
758
2.12k
        ipdev.params.GrayImage.Filter = "FlateEncode";
759
2.12k
        ipdev.params.GrayImage.filter_template = &s_zlibE_template;
760
2.12k
    }
761
2.12k
    ipdev.params.ConvertCMYKImagesToRGB = false;
762
2.12k
    ipdev.params.GrayImage.AutoFilter = false;
763
2.12k
    return psdf_setup_image_filters(&ipdev, pbw, pim, NULL, NULL, true, in_line);
764
2.12k
}
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
10.7k
{
771
10.7k
    int code;
772
10.7k
    stream_state *ss = s_alloc_state(pdev->memory, s_compr_chooser_template.stype,
773
10.7k
                                     "psdf_setup_compression_chooser");
774
775
10.7k
    if (ss == 0)
776
0
        return_error(gs_error_VMerror);
777
10.7k
    ss->templat = &s_compr_chooser_template;
778
779
10.7k
    pbw->memory = pdev->memory;
780
10.7k
    pbw->strm = pdev->strm; /* just a stub - will not write to it. */
781
10.7k
    pbw->dev = pdev;
782
10.7k
    pbw->target = pbw->strm; /* Since s_add_filter may insert NullEncode to comply buffering,
783
                                 will need to close a chain of filetrs. */
784
10.7k
    code = psdf_encode_binary(pbw, &s_compr_chooser_template, ss);
785
10.7k
    if (code < 0)
786
0
        return code;
787
10.7k
    code = s_compr_chooser_set_dimensions((stream_compr_chooser_state *)ss,
788
10.7k
                    width, height, depth, bits_per_sample);
789
10.7k
    return code;
790
10.7k
}
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.53k
{   /* fixme: currently it's a stub convertion to mask. */
823
1.53k
    int code;
824
1.53k
    stream_state *ss = s_alloc_state(pdev->memory, s__image_colors_template.stype,
825
1.53k
        "psdf_setup_image_colors_filter");
826
1.53k
    unsigned char i;
827
828
1.53k
    if (ss == 0)
829
0
        return_error(gs_error_VMerror);
830
1.53k
    pbw->memory = pdev->memory;
831
1.53k
    pbw->dev = pdev;
832
1.53k
    code = psdf_encode_binary(pbw, &s__image_colors_template, ss);
833
1.53k
    if (code < 0)
834
0
        return code;
835
1.53k
    s_image_colors_set_dimensions((stream_image_colors_state *)ss,
836
1.53k
                                  pim->Width, pim->Height, input_pim->Width,
837
1.53k
                                  gs_color_space_num_components(pim->ColorSpace),
838
1.53k
                                  pim->BitsPerComponent);
839
1.53k
    s_image_colors_set_color_space((stream_image_colors_state *)ss,
840
1.53k
                    (gx_device *)pdev, pim->ColorSpace, pgs, pim->Decode);
841
1.53k
    pim->BitsPerComponent = pdev->color_info.comp_bits[0]; /* Same precision for all components. */
842
6.15k
    for (i = 0; i < pdev->color_info.num_components; i++) {
843
4.61k
        pim->Decode[i * 2 + 0] = 0;
844
4.61k
        pim->Decode[i * 2 + 1] = 1;
845
4.61k
    }
846
1.53k
    return 0;
847
1.53k
}
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
117k
{
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
117k
    int code = 0;
866
117k
    psdf_image_params params;
867
117k
    int bpc = pim->BitsPerComponent;
868
117k
    int bpc_out = pim->BitsPerComponent = min(bpc, 8);
869
117k
    int ncomp;
870
117k
    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
117k
    if (pim->ColorSpace == NULL) { /* mask image */
879
77.9k
        params = pdev->params.MonoImage;
880
77.9k
        params.Depth = 1;
881
77.9k
        ncomp = 1;
882
77.9k
    } else {
883
39.8k
        ncomp = gs_color_space_num_components(pim->ColorSpace);
884
39.8k
        if (pim->ColorSpace->type->index == gs_color_space_index_Indexed) {
885
2.55k
            params = pdev->params.ColorImage;
886
            /* Ensure we don't use JPEG on a /Indexed colour space */
887
2.55k
            params.AutoFilter = false;
888
2.55k
            if (pdev->params.UseBrotliCompression)
889
0
                params.Filter = "FlateEncode";
890
2.55k
            else
891
2.55k
                params.Filter = "BrotliEncode";
892
37.2k
        } else {
893
37.2k
            if (ncomp == 1) {
894
12.2k
                if (bpc == 1)
895
894
                    params = pdev->params.MonoImage;
896
11.3k
                else
897
11.3k
                    params = pdev->params.GrayImage;
898
12.2k
                if (params.Depth == -1)
899
12.2k
                    params.Depth = bpc;
900
25.0k
            } else {
901
25.0k
                params = pdev->params.ColorImage;
902
            /* params.Depth is reset below */
903
25.0k
            }
904
37.2k
        }
905
39.8k
    }
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
117k
    if (pctm == 0)
913
0
        resolution = -1;
914
117k
    else {
915
117k
        gs_point pt;
916
917
        /* We could do both X and Y, but why bother? */
918
117k
        code = gs_distance_transform_inverse(1.0, 0.0, &pim->ImageMatrix, &pt);
919
117k
        if (code < 0)
920
0
            return code;
921
117k
        gs_distance_transform(pt.x, pt.y, pctm, &pt);
922
117k
        resolution = 1.0 / hypot(pt.x / pdev->HWResolution[0],
923
117k
                                 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
117k
        code = gs_distance_transform_inverse(0.0, 1.0, &pim->ImageMatrix, &pt);
930
117k
        if (code < 0)
931
0
            return code;
932
117k
        gs_distance_transform(pt.x, pt.y, pctm, &pt);
933
117k
        resolutiony = 1.0 / hypot(pt.x / pdev->HWResolution[0],
934
117k
                                 pt.y / pdev->HWResolution[1]);
935
117k
        if (resolutiony < resolution)
936
16.3k
            resolution = resolutiony;
937
117k
    }
938
939
117k
    if (bpc != bpc_out) {
940
0
        pdev->JPEG_PassThrough = 0;
941
0
        pdev->JPX_PassThrough = 0;
942
0
    }
943
944
117k
    if (ncomp == 1 && pim->ColorSpace && pim->ColorSpace->type->index != gs_color_space_index_Indexed) {
945
        /* Monochrome, gray, or mask */
946
        /* Check for downsampling. */
947
12.2k
        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
12.2k
        } else {
964
12.2k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
965
12.2k
        }
966
12.2k
        if (code < 0)
967
0
            return code;
968
12.2k
        code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
969
105k
    } else {
970
        /* Color */
971
105k
        if (params.Depth == -1)
972
27.5k
            params.Depth = (colour_conversion ? 8 : bpc_out);
973
105k
        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
105k
        } else {
978
105k
            code = setup_image_compression(pbw, &params, pim, pgs, lossless);
979
105k
        }
980
105k
        if (code < 0)
981
0
            return code;
982
105k
        code = pixel_resize(pbw, pim->Width, ncomp, bpc, bpc_out);
983
105k
        if (code < 0)
984
0
            return code;
985
105k
    }
986
117k
    return code;
987
117k
}
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
89.7k
{
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
89.7k
    gx_device_psdf ipdev;
999
1000
89.7k
    ipdev = *pdev;
1001
89.7k
    ipdev.params.ColorImage.AutoFilter = false;
1002
89.7k
    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
89.7k
    } else {
1008
89.7k
        ipdev.params.ColorImage.Filter = "FlateEncode";
1009
89.7k
        ipdev.params.ColorImage.filter_template = &s_zlibE_template;
1010
89.7k
        ipdev.params.GrayImage.Filter = "FlateEncode";
1011
89.7k
        ipdev.params.GrayImage.filter_template = &s_zlibE_template;
1012
89.7k
    }
1013
89.7k
    ipdev.params.ConvertCMYKImagesToRGB = false;
1014
89.7k
    ipdev.params.GrayImage.AutoFilter = false;
1015
89.7k
    ipdev.params.GrayImage.Downsample = false;
1016
89.7k
    return new_setup_image_filters(&ipdev, pbw, pim, pctm, pgs, true, in_line, colour_conversion);
1017
89.7k
}
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
}