Coverage Report

Created: 2025-08-28 07:06

/src/ghostpdl/devices/gdevtifs.c
Line
Count
Source (jump to first uncovered line)
1
/* Copyright (C) 2001-2025 Artifex Software, Inc.
2
   All Rights Reserved.
3
4
   This software is provided AS-IS with no warranty, either express or
5
   implied.
6
7
   This software is distributed under license and may not be copied,
8
   modified or distributed except as expressly authorized under the terms
9
   of the license contained in the file LICENSE in this distribution.
10
11
   Refer to licensing information at http://www.artifex.com or contact
12
   Artifex Software, Inc.,  39 Mesa Street, Suite 108A, San Francisco,
13
   CA 94129, USA, for further information.
14
*/
15
16
17
/* 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
23.1k
{
336
23.1k
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
337
338
23.1k
    if (max_strip_size == 0) {
339
0
        TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, pdev->height);
340
0
    }
341
23.1k
    else {
342
23.1k
        int rows = 0;
343
344
23.1k
        if (pdev->width >=1) {
345
23.1k
            rows = max_strip_size /
346
23.1k
            gdev_mem_bytes_per_scan_line((gx_device *)pdev);
347
23.1k
            TIFFSetField(tif,
348
23.1k
                     TIFFTAG_ROWSPERSTRIP,
349
23.1k
                     TIFFDefaultStripSize(tif, max(1, rows)));
350
23.1k
        } else
351
12
            return_error(gs_error_rangecheck);
352
23.1k
    }
353
354
23.1k
    return 0;
355
23.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
23.1k
{
363
23.1k
    gx_device_tiff *const tiffdev = (gx_device_tiff *)pdev;
364
23.1k
    int width = gx_downscaler_scale(pdev->width, factor);
365
23.1k
    int height = gx_downscaler_scale(pdev->height, factor);
366
23.1k
    int xpi = gx_downscaler_scale((int)pdev->x_pixels_per_inch, factor);
367
23.1k
    int ypi = gx_downscaler_scale((int)pdev->y_pixels_per_inch, factor);
368
23.1k
    width = fax_adjusted_width(width, adjustWidth);
369
23.1k
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
370
23.1k
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
371
23.1k
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
372
23.1k
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
373
374
23.1k
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
375
23.1k
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xpi);
376
23.1k
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)ypi);
377
378
23.1k
#ifndef CLUSTER
379
23.1k
    {
380
23.1k
        char revs[32];
381
69.5k
#define maxSoftware 40
382
23.1k
        char softwareValue[maxSoftware];
383
23.1k
        int revision = gs_revision_number();
384
23.1k
        int major = (int)(revision / 1000);
385
23.1k
        int minor = (int)(revision - (major * 1000)) / 10;
386
23.1k
        int patch =  revision % 10;
387
388
23.1k
        strncpy(softwareValue, gs_product, maxSoftware);
389
23.1k
        softwareValue[maxSoftware - 1] = 0;
390
23.1k
        gs_snprintf(revs, sizeof(revs), " %d.%02d.%d", major, minor, patch);
391
23.1k
        strncat(softwareValue, revs,
392
23.1k
                maxSoftware - strlen(softwareValue) - 1);
393
394
23.1k
        TIFFSetField(tif, TIFFTAG_SOFTWARE, softwareValue);
395
23.1k
    }
396
23.1k
#endif
397
23.1k
    if (writedatetime) {
398
23.1k
        struct tm tms;
399
23.1k
        time_t t;
400
23.1k
        char dateTimeValue[20];
401
402
#ifdef CLUSTER
403
        memset(&t, 0, sizeof(t));
404
        memset(&tms, 0, sizeof(tms));
405
#else
406
23.1k
        time(&t);
407
23.1k
        tms = *localtime(&t);
408
23.1k
#endif
409
23.1k
        gs_snprintf(dateTimeValue, sizeof(dateTimeValue), "%04d:%02d:%02d %02d:%02d:%02d",
410
23.1k
                tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
411
23.1k
                tms.tm_hour, tms.tm_min, tms.tm_sec);
412
413
23.1k
        TIFFSetField(tif, TIFFTAG_DATETIME, dateTimeValue);
414
23.1k
    }
415
416
23.1k
    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
417
23.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
23.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
23.1k
    return 0;
439
23.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
226k
{
606
226k
    struct compression_string *c;
607
904k
    for (c = compression_strings; c->str; c++)
608
904k
        if (id == c->id) {
609
226k
            param_string_from_string(*param, c->str);
610
226k
            return 0;
611
226k
        }
612
226k
    return_error(gs_error_undefined);
613
226k
}
614
615
int
616
tiff_compression_id(uint16_t *id, gs_param_string *param)
617
6.18k
{
618
6.18k
    struct compression_string *c;
619
24.7k
    for (c = compression_strings; c->str; c++)
620
24.7k
        if (!bytes_compare(param->data, param->size,
621
24.7k
                           (const byte *)c->str, strlen(c->str)))
622
6.18k
        {
623
6.18k
            *id = c->id;
624
6.18k
            return 0;
625
6.18k
        }
626
6.18k
    return_error(gs_error_undefined);
627
6.18k
}
628
629
int tiff_compression_allowed(uint16_t compression, byte depth)
630
6.18k
{
631
6.18k
    return ((depth == 1 && (compression == COMPRESSION_NONE ||
632
6.18k
                          compression == COMPRESSION_CCITTRLE ||
633
6.18k
                          compression == COMPRESSION_CCITTFAX3 ||
634
6.18k
                          compression == COMPRESSION_CCITTFAX4 ||
635
6.18k
                          compression == COMPRESSION_LZW ||
636
6.18k
                          compression == COMPRESSION_PACKBITS))
637
6.18k
           || ((depth == 8 || depth == 16) && (compression == COMPRESSION_NONE ||
638
0
                          compression == COMPRESSION_LZW ||
639
0
                          compression == COMPRESSION_PACKBITS)));
640
641
6.18k
}