Coverage Report

Created: 2022-10-31 07:00

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