Coverage Report

Created: 2026-09-14 07:34

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/ghostpdl/devices/gdevtifs.c
Line
Count
Source
1
/* Copyright (C) 2001-2026 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
16.9k
{
336
16.9k
    TIFFSetField(tif, TIFFTAG_COMPRESSION, compression);
337
338
16.9k
    if (max_strip_size == 0) {
339
0
        TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, pdev->height);
340
0
    }
341
16.9k
    else {
342
16.9k
        int rows = 0;
343
344
16.9k
        if (pdev->width >=1) {
345
16.9k
            rows = max_strip_size /
346
16.9k
            gdev_mem_bytes_per_scan_line((gx_device *)pdev);
347
16.9k
            TIFFSetField(tif,
348
16.9k
                     TIFFTAG_ROWSPERSTRIP,
349
16.9k
                     TIFFDefaultStripSize(tif, max(1, rows)));
350
16.9k
        } else
351
0
            return_error(gs_error_rangecheck);
352
16.9k
    }
353
354
16.9k
    return 0;
355
16.9k
}
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
16.9k
{
363
16.9k
    gx_device_tiff *const tiffdev = (gx_device_tiff *)pdev;
364
16.9k
    int width = gx_downscaler_scale(pdev->width, factor);
365
16.9k
    int height = gx_downscaler_scale(pdev->height, factor);
366
16.9k
    int xpi = gx_downscaler_scale((int)pdev->x_pixels_per_inch, factor);
367
16.9k
    int ypi = gx_downscaler_scale((int)pdev->y_pixels_per_inch, factor);
368
16.9k
    width = fax_adjusted_width(width, adjustWidth);
369
16.9k
    TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, width);
370
16.9k
    TIFFSetField(tif, TIFFTAG_IMAGELENGTH, height);
371
16.9k
    TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
372
16.9k
    TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
373
374
16.9k
    TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
375
16.9k
    TIFFSetField(tif, TIFFTAG_XRESOLUTION, (float)xpi);
376
16.9k
    TIFFSetField(tif, TIFFTAG_YRESOLUTION, (float)ypi);
377
378
16.9k
#ifndef CLUSTER
379
16.9k
    {
380
16.9k
        char revs[32];
381
50.9k
#define maxSoftware 40
382
16.9k
        char softwareValue[maxSoftware];
383
16.9k
        int revision = gs_revision_number();
384
16.9k
        int major = (int)(revision / 1000);
385
16.9k
        int minor = (int)(revision - (major * 1000)) / 10;
386
16.9k
        int patch =  revision % 10;
387
388
16.9k
        strncpy(softwareValue, gs_product, maxSoftware);
389
16.9k
        softwareValue[maxSoftware - 1] = 0;
390
16.9k
        gs_snprintf(revs, sizeof(revs), " %d.%02d.%d", major, minor, patch);
391
16.9k
        strncat(softwareValue, revs,
392
16.9k
                maxSoftware - strlen(softwareValue) - 1);
393
394
16.9k
        TIFFSetField(tif, TIFFTAG_SOFTWARE, softwareValue);
395
16.9k
    }
396
16.9k
#endif
397
16.9k
    if (writedatetime) {
398
16.9k
        struct tm tms;
399
16.9k
        time_t t;
400
16.9k
        char dateTimeValue[20];
401
402
#ifdef CLUSTER
403
        memset(&t, 0, sizeof(t));
404
        memset(&tms, 0, sizeof(tms));
405
#else
406
16.9k
        time(&t);
407
16.9k
        tms = *localtime(&t);
408
16.9k
#endif
409
16.9k
        gs_snprintf(dateTimeValue, sizeof(dateTimeValue), "%04d:%02d:%02d %02d:%02d:%02d",
410
16.9k
                tms.tm_year + 1900, tms.tm_mon + 1, tms.tm_mday,
411
16.9k
                tms.tm_hour, tms.tm_min, tms.tm_sec);
412
413
16.9k
        TIFFSetField(tif, TIFFTAG_DATETIME, dateTimeValue);
414
16.9k
    }
415
416
16.9k
    TIFFSetField(tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
417
16.9k
    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
16.9k
    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
16.9k
    return 0;
439
16.9k
}
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 **tifp,
530
                              gx_downscaler_params *params,
531
                              int aw, int bpc, int num_comps)
532
0
{
533
0
    TIFF *tif = *tifp;
534
0
    gx_device_tiff *const tfdev = (gx_device_tiff *)dev;
535
0
    int code = 0;
536
0
    byte *data = NULL;
537
0
    size_t size = gdev_mem_bytes_per_scan_line((gx_device *)dev);
538
0
    size_t max_size = max(size, TIFFScanlineSize(tif));
539
0
    int row;
540
0
    int factor = params->downscale_factor;
541
0
    int height = dev->height/factor;
542
0
    gx_downscaler_t ds;
543
544
0
    code = TIFFCheckpointDirectory(tif);
545
0
    if (code < 0)
546
0
        return code;
547
548
0
    if (tfdev->icclink == NULL) {
549
0
        code = gx_downscaler_init(&ds, (gx_device *)dev,
550
0
                                  8, bpc, num_comps,
551
0
                                  params,
552
0
                                  &fax_adjusted_width, aw);
553
0
    } else {
554
0
        code = gx_downscaler_init_cm(&ds, (gx_device *)dev,
555
0
                                     8, bpc, num_comps,
556
0
                                     params,
557
0
                                     &fax_adjusted_width, aw,
558
0
                                     tiff_chunky_post_cm, tfdev->icclink,
559
0
                                     tfdev->icclink->num_output);
560
0
    }
561
0
    if (code < 0)
562
0
        goto error;
563
564
0
    data = gs_alloc_bytes(dev->memory, max_size, "tiff_print_page(data)");
565
0
    if (data == NULL)
566
0
    {
567
0
        code = gs_note_error(gs_error_VMerror);
568
0
        goto error;
569
0
    }
570
571
0
    for (row = 0; row < height && code >= 0; row++) {
572
0
        code = gx_downscaler_getbits(&ds, data, row);
573
0
        if (code < 0)
574
0
            break;
575
576
0
        code = TIFFWriteScanline(tif, data, row, 0);
577
0
        if (code < 0)
578
0
            break;
579
0
    }
580
581
0
error:
582
0
    if (code >= 0)
583
0
        code = TIFFWriteDirectory(tif);
584
0
    else
585
0
    {
586
0
       TIFFClose(tif);
587
0
       *tifp = NULL;
588
0
    }
589
590
0
    gx_downscaler_fin(&ds);
591
0
    gs_free_object(dev->memory, data, "tiff_print_page(data)");
592
593
0
    return code;
594
0
}
595
596
597
static struct compression_string {
598
    uint16_t id;
599
    const char *str;
600
} compression_strings [] = {
601
    { COMPRESSION_NONE, "none" },
602
    { COMPRESSION_CCITTRLE, "crle" },
603
    { COMPRESSION_CCITTFAX3, "g3" },
604
    { COMPRESSION_CCITTFAX4, "g4" },
605
    { COMPRESSION_LZW, "lzw" },
606
    { COMPRESSION_PACKBITS, "pack" },
607
608
    { 0, NULL }
609
};
610
611
int
612
tiff_compression_param_string(gs_param_string *param, uint16_t id)
613
152k
{
614
152k
    struct compression_string *c;
615
608k
    for (c = compression_strings; c->str; c++)
616
608k
        if (id == c->id) {
617
152k
            param_string_from_string(*param, c->str);
618
152k
            return 0;
619
152k
        }
620
152k
    return_error(gs_error_undefined);
621
152k
}
622
623
int
624
tiff_compression_id(uint16_t *id, gs_param_string *param)
625
4.38k
{
626
4.38k
    struct compression_string *c;
627
17.5k
    for (c = compression_strings; c->str; c++)
628
17.5k
        if (!bytes_compare(param->data, param->size,
629
17.5k
                           (const byte *)c->str, strlen(c->str)))
630
4.38k
        {
631
4.38k
            *id = c->id;
632
4.38k
            return 0;
633
4.38k
        }
634
4.38k
    return_error(gs_error_undefined);
635
4.38k
}
636
637
int tiff_compression_allowed(uint16_t compression, byte depth)
638
4.38k
{
639
4.38k
    return ((depth == 1 && (compression == COMPRESSION_NONE ||
640
4.38k
                          compression == COMPRESSION_CCITTRLE ||
641
4.38k
                          compression == COMPRESSION_CCITTFAX3 ||
642
4.38k
                          compression == COMPRESSION_CCITTFAX4 ||
643
0
                          compression == COMPRESSION_LZW ||
644
0
                          compression == COMPRESSION_PACKBITS))
645
0
           || ((depth == 8 || depth == 16) && (compression == COMPRESSION_NONE ||
646
0
                          compression == COMPRESSION_LZW ||
647
0
                          compression == COMPRESSION_PACKBITS)));
648
649
4.38k
}