Coverage Report

Created: 2025-04-22 06:20

/src/libspectre/ghostscript/devices/gdevtifs.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2020 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
/* TIFF-writing substructure */
18
19
#include "stdint_.h"   /* for tiff.h */
20
#include "stdio_.h"
21
#include "time_.h"
22
#include "gdevtifs.h"
23
#include "gstypes.h"
24
#include "gscdefs.h"
25
#include "gdevprn.h"
26
#include "minftrsz.h"
27
#include "gxdownscale.h"
28
#include "scommon.h"
29
#include "stream.h"
30
#include "strmio.h"
31
#include "gsicc_cache.h"
32
#include "gscms.h"
33
#include "gstiffio.h"
34
#include "gdevkrnlsclass.h" /* 'standard' built in subclasses, currently First/Last Page and obejct filter */
35
36
int
37
tiff_open(gx_device *pdev)
38
0
{
39
0
    gx_device_printer *ppdev = (gx_device_printer *)pdev;
40
0
    int code;
41
0
    bool update_procs = false;
42
43
    /* Use our own warning and error message handlers in libtiff */
44
0
    tiff_set_handlers();
45
46
0
    code = install_internal_subclass_devices((gx_device **)&pdev, &update_procs);
47
0
    if (code < 0)
48
0
        return code;
49
    /* If we've been subclassed, find the terminal device */
50
0
    while(pdev->child)
51
0
        pdev = pdev->child;
52
0
    ppdev = (gx_device_printer *)pdev;
53
54
0
    ppdev->file = NULL;
55
0
    code = gdev_prn_allocate_memory(pdev, NULL, 0, 0);
56
0
    if (code < 0)
57
0
        return code;
58
0
    if (update_procs) {
59
0
        if (pdev->ObjectHandlerPushed) {
60
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_obj_filter_device);
61
0
            pdev = pdev->parent;
62
0
        }
63
0
        if (pdev->PageHandlerPushed)
64
0
            gx_copy_device_procs(pdev->parent, pdev, &gs_flp_device);
65
0
    }
66
0
    if (ppdev->OpenOutputFile)
67
0
        code = gdev_prn_open_printer_seekable(pdev, 1, true);
68
0
    return code;
69
0
}
70
71
int
72
tiff_close(gx_device * pdev)
73
0
{
74
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)pdev;
75
76
0
    if (tfdev->tif)
77
0
        TIFFClose(tfdev->tif);
78
79
0
    if (tfdev->icclink != NULL)
80
0
    {
81
0
        tfdev->icclink->procs.free_link(tfdev->icclink);
82
0
        gsicc_free_link_dev(pdev->memory, tfdev->icclink);
83
0
        tfdev->icclink = NULL;
84
0
    }
85
0
    return gdev_prn_close(pdev);
86
0
}
87
88
static int
89
tiff_get_some_params(gx_device * dev, gs_param_list * plist, int which)
90
0
{
91
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
92
0
    int code = gdev_prn_get_params(dev, plist);
93
0
    int ecode = code;
94
0
    gs_param_string comprstr;
95
96
0
    if ((code = param_write_bool(plist, "BigEndian", &tfdev->BigEndian)) < 0)
97
0
        ecode = code;
98
0
#if (TIFFLIB_VERSION >= 20111221)
99
0
    if ((code = param_write_bool(plist, "UseBigTIFF", &tfdev->UseBigTIFF)) < 0)
100
0
        ecode = code;
101
0
#endif
102
0
    if ((code = param_write_bool(plist, "TIFFDateTime", &tfdev->write_datetime)) < 0)
103
0
        ecode = code;
104
0
    if ((code = tiff_compression_param_string(&comprstr, tfdev->Compression)) < 0 ||
105
0
        (code = param_write_string(plist, "Compression", &comprstr)) < 0)
106
0
        ecode = code;
107
0
    if ((code = param_write_long(plist, "MaxStripSize", &tfdev->MaxStripSize)) < 0)
108
0
        ecode = code;
109
0
    if ((code = param_write_long(plist, "AdjustWidth", &tfdev->AdjustWidth)) < 0)
110
0
        ecode = code;
111
0
    if (which & 1) {
112
0
        if ((code = gx_downscaler_write_params(plist, &tfdev->downscale,
113
0
                                               GX_DOWNSCALER_PARAMS_MFS |
114
0
                                               (which & 2 ? GX_DOWNSCALER_PARAMS_TRAP : 0) |
115
0
                                               (which & 4 ? GX_DOWNSCALER_PARAMS_ETS : 0))) < 0)
116
0
            ecode = code;
117
0
    }
118
0
    return ecode;
119
0
}
120
121
int
122
tiff_get_params(gx_device * dev, gs_param_list * plist)
123
0
{
124
0
    return tiff_get_some_params(dev, plist, 0);
125
0
}
126
127
int
128
tiff_get_params_downscale(gx_device * dev, gs_param_list * plist)
129
0
{
130
0
    return tiff_get_some_params(dev, plist, 1);
131
0
}
132
133
int
134
tiff_get_params_downscale_cmyk(gx_device * dev, gs_param_list * plist)
135
0
{
136
0
    return tiff_get_some_params(dev, plist, 3);
137
0
}
138
139
int
140
tiff_get_params_downscale_cmyk_ets(gx_device * dev, gs_param_list * plist)
141
0
{
142
0
    return tiff_get_some_params(dev, plist, 7);
143
0
}
144
145
static int
146
tiff_put_some_params(gx_device * dev, gs_param_list * plist, int which)
147
0
{
148
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
149
0
    int ecode = 0;
150
0
    int code;
151
0
    const char *param_name;
152
0
    bool big_endian = tfdev->BigEndian;
153
0
    bool usebigtiff = tfdev->UseBigTIFF;
154
0
    bool write_datetime = tfdev->write_datetime;
155
0
    uint16 compr = tfdev->Compression;
156
0
    gs_param_string comprstr;
157
0
    long mss = tfdev->MaxStripSize;
158
0
    long aw = tfdev->AdjustWidth;
159
160
    /* Read BigEndian option as bool */
161
0
    switch (code = param_read_bool(plist, (param_name = "BigEndian"), &big_endian)) {
162
0
        default:
163
0
            ecode = code;
164
0
            param_signal_error(plist, param_name, ecode);
165
0
        case 0:
166
0
        case 1:
167
0
            break;
168
0
    }
169
170
    /* Read UseBigTIFF option as bool */
171
0
    switch (code = param_read_bool(plist, (param_name = "UseBigTIFF"), &usebigtiff)) {
172
0
        default:
173
0
            ecode = code;
174
0
            param_signal_error(plist, param_name, ecode);
175
0
        case 0:
176
0
        case 1:
177
0
            break;
178
0
    }
179
180
#if !(TIFFLIB_VERSION >= 20111221)
181
    if (usebigtiff)
182
        dmlprintf(dev->memory, "Warning: this version of libtiff does not support BigTIFF, ignoring parameter\n");
183
    usebigtiff = false;
184
#endif
185
186
0
    switch (code = param_read_bool(plist, (param_name = "TIFFDateTime"), &write_datetime)) {
187
0
        default:
188
0
            ecode = code;
189
0
            param_signal_error(plist, param_name, ecode);
190
0
        case 0:
191
0
        case 1:
192
0
            break;
193
0
    }
194
195
    /* Read Compression */
196
0
    switch (code = param_read_string(plist, (param_name = "Compression"), &comprstr)) {
197
0
        case 0:
198
0
            if ((ecode = tiff_compression_id(&compr, &comprstr)) < 0) {
199
200
0
                errprintf(tfdev->memory, "Unknown compression setting\n");
201
0
                param_signal_error(plist, param_name, ecode);
202
0
                return ecode;
203
0
            }
204
205
0
            if ( !tiff_compression_allowed(compr, (which & 1 ? 1 : (dev->color_info.depth / dev->color_info.num_components)))) {
206
207
0
                errprintf(tfdev->memory, "Invalid compression setting for this bitdepth\n");
208
0
                param_signal_error(plist, param_name, gs_error_rangecheck);
209
0
                return_error(gs_error_rangecheck);
210
0
            }
211
0
            break;
212
0
        case 1:
213
0
            break;
214
0
        default:
215
0
            ecode = code;
216
0
            param_signal_error(plist, param_name, ecode);
217
0
    }
218
0
    if (which & 1)
219
0
    {
220
0
        code = gx_downscaler_read_params(plist, &tfdev->downscale,
221
0
                                         (GX_DOWNSCALER_PARAMS_MFS |
222
0
                                          (which & 2 ? GX_DOWNSCALER_PARAMS_TRAP : 0) |
223
0
                                          (which & 4 ? GX_DOWNSCALER_PARAMS_ETS : 0)));
224
0
        if (code < 0)
225
0
        {
226
0
            ecode = code;
227
0
            param_signal_error(plist, param_name, ecode);
228
0
        }
229
0
    }
230
0
    switch (code = param_read_long(plist, (param_name = "MaxStripSize"), &mss)) {
231
0
        case 0:
232
            /*
233
             * Strip must be large enough to accommodate a raster line.
234
             * If the max strip size is too small, we still write a single
235
             * line per strip rather than giving an error.
236
             */
237
0
            if (mss >= 0)
238
0
                break;
239
0
            code = gs_error_rangecheck;
240
0
        default:
241
0
            ecode = code;
242
0
            param_signal_error(plist, param_name, ecode);
243
0
        case 1:
244
0
            break;
245
0
    }
246
0
    switch (code = param_read_long(plist, (param_name = "AdjustWidth"), &aw)) {
247
0
        case 0:
248
0
            if (aw >= 0)
249
0
                break;
250
0
            code = gs_error_rangecheck;
251
0
        default:
252
0
            ecode = code;
253
0
            param_signal_error(plist, param_name, ecode);
254
0
        case 1:
255
0
            break;
256
0
    }
257
258
0
    if (ecode < 0)
259
0
        return ecode;
260
0
    code = gdev_prn_put_params(dev, plist);
261
0
    if (code < 0)
262
0
        return code;
263
264
0
    tfdev->BigEndian = big_endian;
265
0
    tfdev->UseBigTIFF = usebigtiff;
266
0
    tfdev->write_datetime = write_datetime;
267
0
    tfdev->Compression = compr;
268
0
    tfdev->MaxStripSize = mss;
269
0
    tfdev->AdjustWidth = aw;
270
0
    return code;
271
0
}
272
273
int
274
tiff_put_params(gx_device * dev, gs_param_list * plist)
275
0
{
276
0
    return tiff_put_some_params(dev, plist, 0);
277
0
}
278
279
int
280
tiff_put_params_downscale(gx_device * dev, gs_param_list * plist)
281
0
{
282
0
    return tiff_put_some_params(dev, plist, 1);
283
0
}
284
285
int
286
tiff_put_params_downscale_cmyk(gx_device * dev, gs_param_list * plist)
287
0
{
288
0
    return tiff_put_some_params(dev, plist, 3);
289
0
}
290
291
int
292
tiff_put_params_downscale_cmyk_ets(gx_device * dev, gs_param_list * plist)
293
0
{
294
0
    return tiff_put_some_params(dev, plist, 7);
295
0
}
296
297
int gdev_tiff_begin_page(gx_device_tiff *tfdev,
298
                         gp_file *file)
299
0
{
300
0
    gx_device_printer *const pdev = (gx_device_printer *)tfdev;
301
0
    cmm_dev_profile_t *profile_struct;
302
0
    gsicc_rendering_param_t rendering_params;
303
0
    int code;
304
305
0
    if (gdev_prn_file_is_new(pdev)) {
306
        /* open the TIFF device */
307
0
        tfdev->tif = tiff_from_filep(pdev, pdev->dname, file, tfdev->BigEndian, tfdev->UseBigTIFF);
308
0
        if (!tfdev->tif)
309
0
            return_error(gs_error_invalidfileaccess);
310
        /* Set up the icc link settings at this time */
311
0
        code = dev_proc(pdev, get_profile)((gx_device *)pdev, &profile_struct);
312
0
        if (code < 0)
313
0
            return_error(gs_error_undefined);
314
0
        if (profile_struct->postren_profile != NULL) {
315
0
            rendering_params.black_point_comp = gsBLACKPTCOMP_ON;
316
0
            rendering_params.graphics_type_tag = GS_UNKNOWN_TAG;
317
0
            rendering_params.override_icc = false;
318
0
            rendering_params.preserve_black = gsBLACKPRESERVE_OFF;
319
0
            rendering_params.rendering_intent = gsRELATIVECOLORIMETRIC;
320
0
            rendering_params.cmm = gsCMM_DEFAULT;
321
0
            if (profile_struct->oi_profile != NULL) {
322
0
                tfdev->icclink = gsicc_alloc_link_dev(pdev->memory,
323
0
                    profile_struct->oi_profile, profile_struct->postren_profile,
324
0
                    &rendering_params);
325
0
            } else if (profile_struct->link_profile != NULL) {
326
0
                tfdev->icclink = gsicc_alloc_link_dev(pdev->memory,
327
0
                    profile_struct->link_profile, profile_struct->postren_profile,
328
0
                    &rendering_params);
329
0
            } else {
330
0
                tfdev->icclink = gsicc_alloc_link_dev(pdev->memory,
331
0
                    profile_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE],
332
0
                    profile_struct->postren_profile, &rendering_params);
333
0
            }
334
0
            if (tfdev->icclink == NULL) {
335
0
                return_error(gs_error_VMerror);
336
0
            }
337
            /* If it is identity, release it now and set link to NULL */
338
0
            if (tfdev->icclink->is_identity) {
339
0
                tfdev->icclink->procs.free_link(tfdev->icclink);
340
0
                gsicc_free_link_dev(pdev->memory, tfdev->icclink);
341
0
                tfdev->icclink = NULL;
342
0
            }
343
0
        }
344
0
    }
345
346
0
    return tiff_set_fields_for_printer(pdev, tfdev->tif, tfdev->downscale.downscale_factor,
347
0
                                       tfdev->AdjustWidth,
348
0
                                       tfdev->write_datetime);
349
0
}
350
351
int tiff_set_compression(gx_device_printer *pdev,
352
                         TIFF *tif,
353
                         uint compression,
354
                         long max_strip_size)
355
0
{
356
0
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
357
358
0
    if (max_strip_size == 0) {
359
0
        TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, pdev->height);
360
0
    }
361
0
    else {
362
0
        int rows = max_strip_size /
363
0
            gdev_mem_bytes_per_scan_line((gx_device *)pdev);
364
0
        TIFFSetField(tif,
365
0
                     TIFFTAG_ROWSPERSTRIP,
366
0
                     TIFFDefaultStripSize(tif, max(1, rows)));
367
0
    }
368
369
0
    return 0;
370
0
}
371
372
int tiff_set_fields_for_printer(gx_device_printer *pdev,
373
                                TIFF              *tif,
374
                                int                factor,
375
                                int                adjustWidth,
376
                                bool               writedatetime)
377
0
{
378
0
    int width = gx_downscaler_scale(pdev->width, factor);
379
0
    int height = gx_downscaler_scale(pdev->height, factor);
380
0
    int xpi = gx_downscaler_scale((int)pdev->x_pixels_per_inch, factor);
381
0
    int ypi = gx_downscaler_scale((int)pdev->y_pixels_per_inch, factor);
382
0
    width = fax_adjusted_width(width, adjustWidth);
383
0
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
384
0
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
385
0
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
386
0
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
387
388
0
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
389
0
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xpi);
390
0
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)ypi);
391
392
0
    {
393
0
        char revs[32];
394
0
#define maxSoftware 40
395
0
        char softwareValue[maxSoftware];
396
0
        int revision = gs_revision_number();
397
0
        int major = (int)(revision / 1000);
398
0
        int minor = (int)(revision - (major * 1000)) / 10;
399
0
        int patch =  revision % 10;
400
401
0
        strncpy(softwareValue, gs_product, maxSoftware);
402
0
        softwareValue[maxSoftware - 1] = 0;
403
0
        gs_sprintf(revs, " %d.%2d.%d", major, minor, patch);
404
0
        strncat(softwareValue, revs,
405
0
                maxSoftware - strlen(softwareValue) - 1);
406
407
0
        TIFFSetField(tif, TIFFTAG_SOFTWARE, softwareValue);
408
0
    }
409
0
    if (writedatetime) {
410
0
        struct tm tms;
411
0
        time_t t;
412
0
        char dateTimeValue[20];
413
414
#ifdef CLUSTER
415
        memset(&t, 0, sizeof(t));
416
        memset(&tms, 0, sizeof(tms));
417
#else
418
0
        time(&t);
419
0
        tms = *localtime(&t);
420
0
#endif
421
0
        gs_sprintf(dateTimeValue, "%04d:%02d:%02d %02d:%02d:%02d",
422
0
                tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
423
0
                tms.tm_hour, tms.tm_min, tms.tm_sec);
424
425
0
        TIFFSetField(tif, TIFFTAG_DATETIME, dateTimeValue);
426
0
    }
427
428
0
    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
429
0
    TIFFSetField(tif, TIFFTAG_PAGENUMBER, pdev->PageCount, 0);
430
431
    /* Set the ICC profile.  Test to avoid issues with separations and also
432
       if the color space is set to LAB, we do that as an enumerated type. Do
433
       NOT set the profile if the bit depth is less than 8 or if fast color
434
       was used. */
435
0
    if (pdev->color_info.depth >= 8) {
436
        /* Select from one of three profiles.. */
437
0
        cmm_profile_t *icc_profile;
438
439
0
        if (pdev->icc_struct->postren_profile != NULL)
440
0
            icc_profile = pdev->icc_struct->postren_profile;
441
0
        else if (pdev->icc_struct->oi_profile != NULL)
442
0
            icc_profile = pdev->icc_struct->oi_profile;
443
0
        else
444
0
            icc_profile = pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE];
445
446
0
        if (icc_profile->num_comps == pdev->color_info.num_components &&
447
0
            icc_profile->data_cs != gsCIELAB && !(pdev->icc_struct->usefastcolor)) {
448
0
            TIFFSetField(tif, TIFFTAG_ICCPROFILE, icc_profile->buffer_size,
449
0
                icc_profile->buffer);
450
0
        }
451
0
    }
452
0
    return 0;
453
0
}
454
455
int
456
tiff_print_page(gx_device_printer *dev, TIFF *tif, int min_feature_size)
457
0
{
458
0
    int code = 0;
459
0
    byte *data;
460
0
    int size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
461
0
    int max_size = max(size, TIFFScanlineSize(tif));
462
0
    int row;
463
0
    int bpc = dev->color_info.depth / dev->color_info.num_components;
464
0
    void *min_feature_data = NULL;
465
0
    int line_lag = 0;
466
0
    int filtered_count;
467
468
0
    data = gs_alloc_bytes(dev->memory, max_size, "tiff_print_page(data)");
469
0
    if (data == NULL)
470
0
        return_error(gs_error_VMerror);
471
0
    if (bpc != 1)
472
0
        min_feature_size = 1;
473
0
    if (min_feature_size > 1) {
474
0
        code = min_feature_size_init(dev->memory, min_feature_size,
475
0
                                     dev->width, dev->height,
476
0
                                     &min_feature_data);
477
0
        if (code < 0)
478
0
            goto cleanup;
479
0
    }
480
481
0
    code = TIFFCheckpointDirectory(tif);
482
483
0
    memset(data, 0, max_size);
484
0
    for (row = 0; row < dev->height && code >= 0; row++) {
485
0
        code = gdev_prn_copy_scan_lines(dev, row, data, size);
486
0
        if (code < 0)
487
0
            goto cleanup;
488
0
        if (min_feature_size > 1) {
489
0
            filtered_count = min_feature_size_process(data, min_feature_data);
490
0
            if (filtered_count == 0)
491
0
                line_lag++;
492
0
        }
493
494
0
        if (row - line_lag >= 0) {
495
0
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN)
496
0
            if (bpc == 16)
497
0
                TIFFSwabArrayOfShort((uint16 *)data,
498
0
                                     dev->width * (long)dev->color_info.num_components);
499
0
#endif
500
501
0
            code = TIFFWriteScanline(tif, data, row - line_lag, 0);
502
0
        }
503
0
    }
504
0
    for (row -= line_lag ; row < dev->height && code >= 0; row++)
505
0
    {
506
0
        filtered_count = min_feature_size_process(data, min_feature_data);
507
0
        code = TIFFWriteScanline(tif, data, row, 0);
508
0
    }
509
510
0
    if (code >= 0)
511
0
        code = TIFFWriteDirectory(tif);
512
0
cleanup:
513
0
    if (min_feature_size > 1)
514
0
        min_feature_size_dnit(min_feature_data);
515
0
    gs_free_object(dev->memory, data, "tiff_print_page(data)");
516
517
0
    return code;
518
0
}
519
520
/* void gsicc_init_buffer(gsicc_bufferdesc_t *buffer_desc, unsigned char num_chan,
521
    unsigned char bytes_per_chan, bool has_alpha, bool alpha_first,
522
    bool is_planar, int plane_stride, int row_stride, int num_rows,
523
    int pixels_per_row); */
524
525
static int tiff_chunky_post_cm(void  *arg, byte **dst, byte **src, int w, int h,
526
    int raster)
527
0
{
528
0
    gsicc_bufferdesc_t input_buffer_desc, output_buffer_desc;
529
0
    gsicc_link_t *icclink = (gsicc_link_t*)arg;
530
531
0
    gsicc_init_buffer(&input_buffer_desc, icclink->num_input, 1, false,
532
0
        false, false, 0, raster, h, w);
533
0
    gsicc_init_buffer(&output_buffer_desc, icclink->num_output, 1, false,
534
0
        false, false, 0, raster, h, w);
535
0
    icclink->procs.map_buffer(NULL, icclink, &input_buffer_desc, &output_buffer_desc,
536
0
        src[0], dst[0]);
537
0
    return 0;
538
0
}
539
540
/* Special version, called with 8 bit grey input to be downsampled to 1bpp
541
 * output. */
542
int
543
tiff_downscale_and_print_page(gx_device_printer *dev, TIFF *tif,
544
                              gx_downscaler_params *params,
545
                              int aw, int bpc, int num_comps)
546
0
{
547
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
548
0
    int code = 0;
549
0
    byte *data = NULL;
550
0
    int size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
551
0
    int max_size = max(size, TIFFScanlineSize(tif));
552
0
    int row;
553
0
    int factor = params->downscale_factor;
554
0
    int height = dev->height/factor;
555
0
    gx_downscaler_t ds;
556
557
0
    code = TIFFCheckpointDirectory(tif);
558
0
    if (code < 0)
559
0
        return code;
560
561
0
    if (num_comps == 4)
562
0
        params->trap_w = params->trap_h = 1;
563
0
    if (tfdev->icclink == NULL) {
564
0
        code = gx_downscaler_init(&ds, (gx_device *)dev,
565
0
                                  8, bpc, num_comps,
566
0
                                  params,
567
0
                                  &fax_adjusted_width, aw);
568
0
    } else {
569
0
        code = gx_downscaler_init_cm(&ds, (gx_device *)dev,
570
0
                                     8, bpc, num_comps,
571
0
                                     params,
572
0
                                     &fax_adjusted_width, aw,
573
0
                                     tiff_chunky_post_cm, tfdev->icclink,
574
0
                                     tfdev->icclink->num_output);
575
0
    }
576
0
    if (code < 0)
577
0
        return code;
578
579
0
    data = gs_alloc_bytes(dev->memory, max_size, "tiff_print_page(data)");
580
0
    if (data == NULL) {
581
0
        gx_downscaler_fin(&ds);
582
0
        return_error(gs_error_VMerror);
583
0
    }
584
585
0
    for (row = 0; row < height && code >= 0; row++) {
586
0
        code = gx_downscaler_getbits(&ds, data, row);
587
0
        if (code < 0)
588
0
            break;
589
590
0
        code = TIFFWriteScanline(tif, data, row, 0);
591
0
        if (code < 0)
592
0
            break;
593
0
    }
594
595
0
    if (code >= 0)
596
0
        code = TIFFWriteDirectory(tif);
597
598
0
    gx_downscaler_fin(&ds);
599
0
    gs_free_object(dev->memory, data, "tiff_print_page(data)");
600
601
0
    return code;
602
0
}
603
604
605
static struct compression_string {
606
    uint16 id;
607
    const char *str;
608
} compression_strings [] = {
609
    { COMPRESSION_NONE, "none" },
610
    { COMPRESSION_CCITTRLE, "crle" },
611
    { COMPRESSION_CCITTFAX3, "g3" },
612
    { COMPRESSION_CCITTFAX4, "g4" },
613
    { COMPRESSION_LZW, "lzw" },
614
    { COMPRESSION_PACKBITS, "pack" },
615
616
    { 0, NULL }
617
};
618
619
int
620
tiff_compression_param_string(gs_param_string *param, uint16 id)
621
0
{
622
0
    struct compression_string *c;
623
0
    for (c = compression_strings; c->str; c++)
624
0
        if (id == c->id) {
625
0
            param_string_from_string(*param, c->str);
626
0
            return 0;
627
0
        }
628
0
    return_error(gs_error_undefined);
629
0
}
630
631
int
632
tiff_compression_id(uint16 *id, gs_param_string *param)
633
0
{
634
0
    struct compression_string *c;
635
0
    for (c = compression_strings; c->str; c++)
636
0
        if (!bytes_compare(param->data, param->size,
637
0
                           (const byte *)c->str, strlen(c->str)))
638
0
        {
639
0
            *id = c->id;
640
0
            return 0;
641
0
        }
642
0
    return_error(gs_error_undefined);
643
0
}
644
645
int tiff_compression_allowed(uint16 compression, byte depth)
646
0
{
647
0
    return ((depth == 1 && (compression == COMPRESSION_NONE ||
648
0
                          compression == COMPRESSION_CCITTRLE ||
649
0
                          compression == COMPRESSION_CCITTFAX3 ||
650
0
                          compression == COMPRESSION_CCITTFAX4 ||
651
0
                          compression == COMPRESSION_LZW ||
652
0
                          compression == COMPRESSION_PACKBITS))
653
0
           || ((depth == 8 || depth == 16) && (compression == COMPRESSION_NONE ||
654
0
                          compression == COMPRESSION_LZW ||
655
0
                          compression == COMPRESSION_PACKBITS)));
656
657
0
}