Coverage Report

Created: 2026-04-01 07:17

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/gdevtifs.c
Line
Count
Source
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* 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
    gsicc_free_link_dev(tfdev->icclink);
80
0
    tfdev->icclink = NULL;
81
82
0
    return gdev_prn_close(pdev);
83
0
}
84
85
static int
86
tiff_get_some_params(gx_device * dev, gs_param_list * plist, int which)
87
0
{
88
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
89
0
    int code = gdev_prn_get_params(dev, plist);
90
0
    int ecode = code;
91
0
    gs_param_string comprstr;
92
93
0
    if ((code = param_write_bool(plist, "BigEndian", &tfdev->BigEndian)) < 0)
94
0
        ecode = code;
95
0
    if ((code = param_write_bool(plist, "EmbedProfile", &tfdev->EmbedProfile)) < 0)
96
0
        ecode = code;
97
0
#if (TIFFLIB_VERSION >= 20111221)
98
0
    if ((code = param_write_bool(plist, "UseBigTIFF", &tfdev->UseBigTIFF)) < 0)
99
0
        ecode = code;
100
0
#endif
101
0
    if ((code = param_write_bool(plist, "TIFFDateTime", &tfdev->write_datetime)) < 0)
102
0
        ecode = code;
103
0
    if ((code = tiff_compression_param_string(&comprstr, tfdev->Compression)) < 0 ||
104
0
        (code = param_write_string(plist, "Compression", &comprstr)) < 0)
105
0
        ecode = code;
106
0
    if ((code = param_write_long(plist, "MaxStripSize", &tfdev->MaxStripSize)) < 0)
107
0
        ecode = code;
108
0
    if ((code = param_write_long(plist, "AdjustWidth", &tfdev->AdjustWidth)) < 0)
109
0
        ecode = code;
110
0
    if (which & 1) {
111
0
        if ((code = gx_downscaler_write_params(plist, &tfdev->downscale,
112
0
                                               GX_DOWNSCALER_PARAMS_MFS |
113
0
                                               (which & 2 ? GX_DOWNSCALER_PARAMS_TRAP : 0) |
114
0
                                               (which & 4 ? GX_DOWNSCALER_PARAMS_ETS : 0))) < 0)
115
0
            ecode = code;
116
0
    }
117
0
    return ecode;
118
0
}
119
120
int
121
tiff_get_params(gx_device * dev, gs_param_list * plist)
122
0
{
123
0
    return tiff_get_some_params(dev, plist, 0);
124
0
}
125
126
int
127
tiff_get_params_downscale(gx_device * dev, gs_param_list * plist)
128
0
{
129
0
    return tiff_get_some_params(dev, plist, 1);
130
0
}
131
132
int
133
tiff_get_params_downscale_cmyk(gx_device * dev, gs_param_list * plist)
134
0
{
135
0
    return tiff_get_some_params(dev, plist, 3);
136
0
}
137
138
int
139
tiff_get_params_downscale_cmyk_ets(gx_device * dev, gs_param_list * plist)
140
0
{
141
0
    return tiff_get_some_params(dev, plist, 7);
142
0
}
143
144
static int
145
tiff_put_some_params(gx_device * dev, gs_param_list * plist, int which)
146
0
{
147
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
148
0
    int ecode = 0;
149
0
    int code;
150
0
    const char *param_name;
151
0
    bool embed_profile = tfdev->EmbedProfile;
152
0
    bool big_endian = tfdev->BigEndian;
153
0
    bool usebigtiff = tfdev->UseBigTIFF;
154
0
    bool write_datetime = tfdev->write_datetime;
155
0
    uint16_t 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 EmbedProfile option as bool */
171
0
    switch (code = param_read_bool(plist, (param_name = "EmbedProfile"), &embed_profile)) {
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
    /* Read UseBigTIFF option as bool */
181
0
    switch (code = param_read_bool(plist, (param_name = "UseBigTIFF"), &usebigtiff)) {
182
0
        default:
183
0
            ecode = code;
184
0
            param_signal_error(plist, param_name, ecode);
185
0
        case 0:
186
0
        case 1:
187
0
            break;
188
0
    }
189
190
#if !(TIFFLIB_VERSION >= 20111221)
191
    if (usebigtiff)
192
        dmlprintf(dev->memory, "Warning: this version of libtiff does not support BigTIFF, ignoring parameter\n");
193
    usebigtiff = false;
194
#endif
195
196
0
    switch (code = param_read_bool(plist, (param_name = "TIFFDateTime"), &write_datetime)) {
197
0
        default:
198
0
            ecode = code;
199
0
            param_signal_error(plist, param_name, ecode);
200
0
        case 0:
201
0
        case 1:
202
0
            break;
203
0
    }
204
205
    /* Read Compression */
206
0
    switch (code = param_read_string(plist, (param_name = "Compression"), &comprstr)) {
207
0
        case 0:
208
0
            if ((ecode = tiff_compression_id(&compr, &comprstr)) < 0) {
209
210
0
                errprintf(tfdev->memory, "Unknown compression setting\n");
211
0
                param_signal_error(plist, param_name, ecode);
212
0
                return ecode;
213
0
            }
214
215
0
            if ( !tiff_compression_allowed(compr, (which & 1 ? 1 : (dev->color_info.depth / dev->color_info.num_components)))) {
216
217
0
                errprintf(tfdev->memory, "Invalid compression setting for this bitdepth\n");
218
0
                param_signal_error(plist, param_name, gs_error_rangecheck);
219
0
                return_error(gs_error_rangecheck);
220
0
            }
221
0
            break;
222
0
        case 1:
223
0
            break;
224
0
        default:
225
0
            ecode = code;
226
0
            param_signal_error(plist, param_name, ecode);
227
0
    }
228
0
    if (which & 1)
229
0
    {
230
0
        code = gx_downscaler_read_params(plist, &tfdev->downscale,
231
0
                                         (GX_DOWNSCALER_PARAMS_MFS |
232
0
                                          (which & 2 ? GX_DOWNSCALER_PARAMS_TRAP : 0) |
233
0
                                          (which & 4 ? GX_DOWNSCALER_PARAMS_ETS : 0)));
234
0
        if (code < 0)
235
0
        {
236
0
            ecode = code;
237
0
            param_signal_error(plist, param_name, ecode);
238
0
        }
239
0
    }
240
0
    switch (code = param_read_long(plist, (param_name = "MaxStripSize"), &mss)) {
241
0
        case 0:
242
            /*
243
             * Strip must be large enough to accommodate a raster line.
244
             * If the max strip size is too small, we still write a single
245
             * line per strip rather than giving an error.
246
             */
247
0
            if (mss >= 0)
248
0
                break;
249
0
            code = gs_error_rangecheck;
250
0
        default:
251
0
            ecode = code;
252
0
            param_signal_error(plist, param_name, ecode);
253
0
        case 1:
254
0
            break;
255
0
    }
256
0
    switch (code = param_read_long(plist, (param_name = "AdjustWidth"), &aw)) {
257
0
        case 0:
258
0
            if (aw >= 0)
259
0
                break;
260
0
            code = gs_error_rangecheck;
261
0
        default:
262
0
            ecode = code;
263
0
            param_signal_error(plist, param_name, ecode);
264
0
        case 1:
265
0
            break;
266
0
    }
267
268
0
    if (ecode < 0)
269
0
        return ecode;
270
0
    code = gdev_prn_put_params(dev, plist);
271
0
    if (code < 0)
272
0
        return code;
273
274
0
    tfdev->BigEndian = big_endian;
275
0
    tfdev->EmbedProfile = embed_profile;
276
0
    tfdev->UseBigTIFF = usebigtiff;
277
0
    tfdev->write_datetime = write_datetime;
278
0
    tfdev->Compression = compr;
279
0
    tfdev->MaxStripSize = mss;
280
0
    tfdev->AdjustWidth = aw;
281
0
    return code;
282
0
}
283
284
int
285
tiff_put_params(gx_device * dev, gs_param_list * plist)
286
0
{
287
0
    return tiff_put_some_params(dev, plist, 0);
288
0
}
289
290
int
291
tiff_put_params_downscale(gx_device * dev, gs_param_list * plist)
292
0
{
293
0
    return tiff_put_some_params(dev, plist, 1);
294
0
}
295
296
int
297
tiff_put_params_downscale_cmyk(gx_device * dev, gs_param_list * plist)
298
0
{
299
0
    return tiff_put_some_params(dev, plist, 3);
300
0
}
301
302
int
303
tiff_put_params_downscale_cmyk_ets(gx_device * dev, gs_param_list * plist)
304
0
{
305
0
    return tiff_put_some_params(dev, plist, 7);
306
0
}
307
308
int gdev_tiff_begin_page(gx_device_tiff *tfdev,
309
                         gp_file *file)
310
0
{
311
0
    gx_device_printer *const pdev = (gx_device_printer *)tfdev;
312
0
    int code;
313
314
0
    if (gdev_prn_file_is_new(pdev)) {
315
        /* open the TIFF device */
316
0
        tfdev->tif = tiff_from_filep(pdev, pdev->dname, file, tfdev->BigEndian, tfdev->UseBigTIFF);
317
0
        if (!tfdev->tif)
318
0
            return_error(gs_error_invalidfileaccess);
319
        /* Set up the icc link settings at this time */
320
0
        code = gx_downscaler_create_post_render_link((gx_device *)pdev,
321
0
                                                     &tfdev->icclink);
322
0
        if (code < 0)
323
0
            return code;
324
0
    }
325
326
0
    return tiff_set_fields_for_printer(pdev, tfdev->tif, tfdev->downscale.downscale_factor,
327
0
                                       tfdev->AdjustWidth,
328
0
                                       tfdev->write_datetime);
329
0
}
330
331
int tiff_set_compression(gx_device_printer *pdev,
332
                         TIFF *tif,
333
                         uint compression,
334
                         long max_strip_size)
335
20.1k
{
336
20.1k
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
337
338
20.1k
    if (max_strip_size == 0) {
339
0
        TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, pdev->height);
340
0
    }
341
20.1k
    else {
342
20.1k
        int rows = 0;
343
344
20.1k
        if (pdev->width >=1) {
345
20.1k
            rows = max_strip_size /
346
20.1k
            gdev_mem_bytes_per_scan_line((gx_device *)pdev);
347
20.1k
            TIFFSetField(tif,
348
20.1k
                     TIFFTAG_ROWSPERSTRIP,
349
20.1k
                     TIFFDefaultStripSize(tif, max(1, rows)));
350
20.1k
        } else
351
0
            return_error(gs_error_rangecheck);
352
20.1k
    }
353
354
20.1k
    return 0;
355
20.1k
}
356
357
int tiff_set_fields_for_printer(gx_device_printer *pdev,
358
                                TIFF              *tif,
359
                                int                factor,
360
                                int                adjustWidth,
361
                                bool               writedatetime)
362
20.1k
{
363
20.1k
    gx_device_tiff *const tiffdev = (gx_device_tiff *)pdev;
364
20.1k
    int width = gx_downscaler_scale(pdev->width, factor);
365
20.1k
    int height = gx_downscaler_scale(pdev->height, factor);
366
20.1k
    int xpi = gx_downscaler_scale((int)pdev->x_pixels_per_inch, factor);
367
20.1k
    int ypi = gx_downscaler_scale((int)pdev->y_pixels_per_inch, factor);
368
20.1k
    width = fax_adjusted_width(width, adjustWidth);
369
20.1k
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
370
20.1k
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
371
20.1k
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
372
20.1k
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
373
374
20.1k
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
375
20.1k
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xpi);
376
20.1k
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)ypi);
377
378
20.1k
#ifndef CLUSTER
379
20.1k
    {
380
20.1k
        char revs[32];
381
60.4k
#define maxSoftware 40
382
20.1k
        char softwareValue[maxSoftware];
383
20.1k
        int revision = gs_revision_number();
384
20.1k
        int major = (int)(revision / 1000);
385
20.1k
        int minor = (int)(revision - (major * 1000)) / 10;
386
20.1k
        int patch =  revision % 10;
387
388
20.1k
        strncpy(softwareValue, gs_product, maxSoftware);
389
20.1k
        softwareValue[maxSoftware - 1] = 0;
390
20.1k
        gs_snprintf(revs, sizeof(revs), " %d.%02d.%d", major, minor, patch);
391
20.1k
        strncat(softwareValue, revs,
392
20.1k
                maxSoftware - strlen(softwareValue) - 1);
393
394
20.1k
        TIFFSetField(tif, TIFFTAG_SOFTWARE, softwareValue);
395
20.1k
    }
396
20.1k
#endif
397
20.1k
    if (writedatetime) {
398
20.1k
        struct tm tms;
399
20.1k
        time_t t;
400
20.1k
        char dateTimeValue[20];
401
402
#ifdef CLUSTER
403
        memset(&t, 0, sizeof(t));
404
        memset(&tms, 0, sizeof(tms));
405
#else
406
20.1k
        time(&t);
407
20.1k
        tms = *localtime(&t);
408
20.1k
#endif
409
20.1k
        gs_snprintf(dateTimeValue, sizeof(dateTimeValue), "%04d:%02d:%02d %02d:%02d:%02d",
410
20.1k
                tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
411
20.1k
                tms.tm_hour, tms.tm_min, tms.tm_sec);
412
413
20.1k
        TIFFSetField(tif, TIFFTAG_DATETIME, dateTimeValue);
414
20.1k
    }
415
416
20.1k
    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
417
20.1k
    TIFFSetField(tif, TIFFTAG_PAGENUMBER, pdev->PageCount, 0);
418
419
    /* Set the ICC profile.  Test to avoid issues with separations and also
420
       if the color space is set to LAB, we do that as an enumerated type. Do
421
       NOT set the profile if the bit depth is less than 8 or if fast color
422
       was used. */
423
20.1k
    if (pdev->color_info.depth >= 8) {
424
        /* Select from one of three profiles.. */
425
0
        cmm_profile_t *icc_profile;
426
427
0
        if (pdev->icc_struct->postren_profile != NULL)
428
0
            icc_profile = pdev->icc_struct->postren_profile;
429
0
        else
430
0
            icc_profile = pdev->icc_struct->device_profile[GS_DEFAULT_DEVICE_PROFILE];
431
432
0
        if (icc_profile->num_comps == pdev->color_info.num_components &&
433
0
            icc_profile->data_cs != gsCIELAB && !(pdev->icc_struct->usefastcolor) && tiffdev->EmbedProfile) {
434
0
            TIFFSetField(tif, TIFFTAG_ICCPROFILE, icc_profile->buffer_size,
435
0
                icc_profile->buffer);
436
0
        }
437
0
    }
438
20.1k
    return 0;
439
20.1k
}
440
441
int
442
tiff_print_page(gx_device_printer *dev, TIFF *tif, int min_feature_size)
443
0
{
444
0
    int code = 0;
445
0
    byte *data;
446
0
    size_t size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
447
0
    size_t max_size = max(size, TIFFScanlineSize(tif));
448
0
    int row;
449
0
    int bpc = dev->color_info.depth / dev->color_info.num_components;
450
0
    void *min_feature_data = NULL;
451
0
    int line_lag = 0;
452
0
    int filtered_count;
453
454
0
    data = gs_alloc_bytes(dev->memory, max_size, "tiff_print_page(data)");
455
0
    if (data == NULL)
456
0
        return_error(gs_error_VMerror);
457
0
    if (bpc != 1)
458
0
        min_feature_size = 1;
459
0
    if (min_feature_size > 1) {
460
0
        code = min_feature_size_init(dev->memory, min_feature_size,
461
0
                                     dev->width, dev->height,
462
0
                                     &min_feature_data);
463
0
        if (code < 0)
464
0
            goto cleanup;
465
0
    }
466
467
0
    code = TIFFCheckpointDirectory(tif);
468
469
0
    memset(data, 0, max_size);
470
0
    for (row = 0; row < dev->height && code >= 0; row++) {
471
0
        code = gdev_prn_copy_scan_lines(dev, row, data, size);
472
0
        if (code < 0)
473
0
            goto cleanup;
474
0
        if (min_feature_size > 1) {
475
0
            filtered_count = min_feature_size_process(data, min_feature_data);
476
0
            if (filtered_count == 0)
477
0
                line_lag++;
478
0
        }
479
480
0
        if (row - line_lag >= 0) {
481
0
#if defined(ARCH_IS_BIG_ENDIAN) && (!ARCH_IS_BIG_ENDIAN)
482
0
            if (bpc == 16)
483
0
                TIFFSwabArrayOfShort((uint16_t *)data,
484
0
                                     dev->width * (long)dev->color_info.num_components);
485
0
#endif
486
487
0
            code = TIFFWriteScanline(tif, data, row - line_lag, 0);
488
0
        }
489
0
    }
490
0
    for (row -= line_lag ; row < dev->height && code >= 0; row++)
491
0
    {
492
0
        filtered_count = min_feature_size_process(data, min_feature_data);
493
0
        code = TIFFWriteScanline(tif, data, row, 0);
494
0
    }
495
496
0
    if (code >= 0)
497
0
        code = TIFFWriteDirectory(tif);
498
0
cleanup:
499
0
    if (min_feature_size > 1)
500
0
        min_feature_size_dnit(min_feature_data);
501
0
    gs_free_object(dev->memory, data, "tiff_print_page(data)");
502
503
0
    return code;
504
0
}
505
506
/* void gsicc_init_buffer(gsicc_bufferdesc_t *buffer_desc, unsigned char num_chan,
507
    unsigned char bytes_per_chan, bool has_alpha, bool alpha_first,
508
    bool is_planar, int plane_stride, int row_stride, int num_rows,
509
    int pixels_per_row); */
510
511
static int tiff_chunky_post_cm(void  *arg, byte **dst, byte **src, int w, int h,
512
    int raster)
513
0
{
514
0
    gsicc_bufferdesc_t input_buffer_desc, output_buffer_desc;
515
0
    gsicc_link_t *icclink = (gsicc_link_t*)arg;
516
517
0
    gsicc_init_buffer(&input_buffer_desc, icclink->num_input, 1, false,
518
0
        false, false, 0, raster, h, w);
519
0
    gsicc_init_buffer(&output_buffer_desc, icclink->num_output, 1, false,
520
0
        false, false, 0, raster, h, w);
521
0
    icclink->procs.map_buffer(NULL, icclink, &input_buffer_desc, &output_buffer_desc,
522
0
        src[0], dst[0]);
523
0
    return 0;
524
0
}
525
526
/* Special version, called with 8 bit grey input to be downsampled to 1bpp
527
 * output. */
528
int
529
tiff_downscale_and_print_page(gx_device_printer *dev, TIFF *tif,
530
                              gx_downscaler_params *params,
531
                              int aw, int bpc, int num_comps)
532
0
{
533
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
534
0
    int code = 0;
535
0
    byte *data = NULL;
536
0
    size_t size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
537
0
    size_t max_size = max(size, TIFFScanlineSize(tif));
538
0
    int row;
539
0
    int factor = params->downscale_factor;
540
0
    int height = dev->height/factor;
541
0
    gx_downscaler_t ds;
542
543
0
    code = TIFFCheckpointDirectory(tif);
544
0
    if (code < 0)
545
0
        return code;
546
547
0
    if (tfdev->icclink == NULL) {
548
0
        code = gx_downscaler_init(&ds, (gx_device *)dev,
549
0
                                  8, bpc, num_comps,
550
0
                                  params,
551
0
                                  &fax_adjusted_width, aw);
552
0
    } else {
553
0
        code = gx_downscaler_init_cm(&ds, (gx_device *)dev,
554
0
                                     8, bpc, num_comps,
555
0
                                     params,
556
0
                                     &fax_adjusted_width, aw,
557
0
                                     tiff_chunky_post_cm, tfdev->icclink,
558
0
                                     tfdev->icclink->num_output);
559
0
    }
560
0
    if (code < 0)
561
0
        return code;
562
563
0
    data = gs_alloc_bytes(dev->memory, max_size, "tiff_print_page(data)");
564
0
    if (data == NULL) {
565
0
        gx_downscaler_fin(&ds);
566
0
        return_error(gs_error_VMerror);
567
0
    }
568
569
0
    for (row = 0; row < height && code >= 0; row++) {
570
0
        code = gx_downscaler_getbits(&ds, data, row);
571
0
        if (code < 0)
572
0
            break;
573
574
0
        code = TIFFWriteScanline(tif, data, row, 0);
575
0
        if (code < 0)
576
0
            break;
577
0
    }
578
579
0
    if (code >= 0)
580
0
        code = TIFFWriteDirectory(tif);
581
582
0
    gx_downscaler_fin(&ds);
583
0
    gs_free_object(dev->memory, data, "tiff_print_page(data)");
584
585
0
    return code;
586
0
}
587
588
589
static struct compression_string {
590
    uint16_t id;
591
    const char *str;
592
} compression_strings [] = {
593
    { COMPRESSION_NONE, "none" },
594
    { COMPRESSION_CCITTRLE, "crle" },
595
    { COMPRESSION_CCITTFAX3, "g3" },
596
    { COMPRESSION_CCITTFAX4, "g4" },
597
    { COMPRESSION_LZW, "lzw" },
598
    { COMPRESSION_PACKBITS, "pack" },
599
600
    { 0, NULL }
601
};
602
603
int
604
tiff_compression_param_string(gs_param_string *param, uint16_t id)
605
194k
{
606
194k
    struct compression_string *c;
607
778k
    for (c = compression_strings; c->str; c++)
608
778k
        if (id == c->id) {
609
194k
            param_string_from_string(*param, c->str);
610
194k
            return 0;
611
194k
        }
612
194k
    return_error(gs_error_undefined);
613
194k
}
614
615
int
616
tiff_compression_id(uint16_t *id, gs_param_string *param)
617
5.54k
{
618
5.54k
    struct compression_string *c;
619
22.1k
    for (c = compression_strings; c->str; c++)
620
22.1k
        if (!bytes_compare(param->data, param->size,
621
22.1k
                           (const byte *)c->str, strlen(c->str)))
622
5.54k
        {
623
5.54k
            *id = c->id;
624
5.54k
            return 0;
625
5.54k
        }
626
5.54k
    return_error(gs_error_undefined);
627
5.54k
}
628
629
int tiff_compression_allowed(uint16_t compression, byte depth)
630
5.54k
{
631
5.54k
    return ((depth == 1 && (compression == COMPRESSION_NONE ||
632
5.54k
                          compression == COMPRESSION_CCITTRLE ||
633
5.54k
                          compression == COMPRESSION_CCITTFAX3 ||
634
5.54k
                          compression == COMPRESSION_CCITTFAX4 ||
635
0
                          compression == COMPRESSION_LZW ||
636
0
                          compression == COMPRESSION_PACKBITS))
637
0
           || ((depth == 8 || depth == 16) && (compression == COMPRESSION_NONE ||
638
0
                          compression == COMPRESSION_LZW ||
639
0
                          compression == COMPRESSION_PACKBITS)));
640
641
5.54k
}