1//========================================================================
2//
3// TiffWriter.cc
4//
5// This file is licensed under the GPLv2 or later
6//
7// Copyright (C) 2010, 2012 William Bader <williambader@hotmail.com>
8// Copyright (C) 2012, 2021, 2022 Albert Astals Cid <aacid@kde.org>
9// Copyright (C) 2012, 2017 Adrian Johnson <ajohnson@redneon.com>
10// Copyright (C) 2012 Pino Toscano <pino@kde.org>
11// Copyright (C) 2014 Steven Lee <roc.sky@gmail.com>
12//
13//========================================================================
14
15#include "TiffWriter.h"
16
17#ifdef ENABLE_LIBTIFF
18
19# include <cstring>
20
21# ifdef _WIN32
22# include <io.h>
23# endif
24
25extern "C" {
26# include <tiffio.h>
27}
28
29# include <cstdint>
30
31struct TiffWriterPrivate
32{
33 TIFF *f; // LibTiff file context
34 int numRows; // number of rows in the image
35 int curRow; // number of rows written
36 const char *compressionString; // compression type
37 TiffWriter::Format format; // format of image data
38};
39
40TiffWriter::~TiffWriter()
41{
42 delete priv;
43}
44
45TiffWriter::TiffWriter(Format formatA)
46{
47 priv = new TiffWriterPrivate;
48 priv->f = nullptr;
49 priv->numRows = 0;
50 priv->curRow = 0;
51 priv->compressionString = nullptr;
52 priv->format = formatA;
53}
54
55// Set the compression type
56
57void TiffWriter::setCompressionString(const char *compressionStringArg)
58{
59 priv->compressionString = compressionStringArg;
60}
61
62// Write a TIFF file.
63
64bool TiffWriter::init(FILE *openedFile, int width, int height, double hDPI, double vDPI)
65{
66 unsigned int compression;
67 uint16_t photometric = 0;
68 uint32_t rowsperstrip = (uint32_t)-1;
69 int bitspersample;
70 uint16_t samplesperpixel = 0;
71 const struct compression_name_tag
72 {
73 const char *compressionName; // name of the compression option from the command line
74 unsigned int compressionCode; // internal libtiff code
75 const char *compressionDescription; // descriptive name
76 } compressionList[] = { { .compressionName: "none", COMPRESSION_NONE, .compressionDescription: "no compression" },
77 { .compressionName: "ccittrle", COMPRESSION_CCITTRLE, .compressionDescription: "CCITT modified Huffman RLE" },
78 { .compressionName: "ccittfax3", COMPRESSION_CCITTFAX3, .compressionDescription: "CCITT Group 3 fax encoding" },
79 { .compressionName: "ccittt4", COMPRESSION_CCITT_T4, .compressionDescription: "CCITT T.4 (TIFF 6 name)" },
80 { .compressionName: "ccittfax4", COMPRESSION_CCITTFAX4, .compressionDescription: "CCITT Group 4 fax encoding" },
81 { .compressionName: "ccittt6", COMPRESSION_CCITT_T6, .compressionDescription: "CCITT T.6 (TIFF 6 name)" },
82 { .compressionName: "lzw", COMPRESSION_LZW, .compressionDescription: "Lempel-Ziv & Welch" },
83 { .compressionName: "ojpeg", COMPRESSION_OJPEG, .compressionDescription: "!6.0 JPEG" },
84 { .compressionName: "jpeg", COMPRESSION_JPEG, .compressionDescription: "%JPEG DCT compression" },
85 { .compressionName: "next", COMPRESSION_NEXT, .compressionDescription: "NeXT 2-bit RLE" },
86 { .compressionName: "packbits", COMPRESSION_PACKBITS, .compressionDescription: "Macintosh RLE" },
87 { .compressionName: "ccittrlew", COMPRESSION_CCITTRLEW, .compressionDescription: "CCITT modified Huffman RLE w/ word alignment" },
88 { .compressionName: "deflate", COMPRESSION_DEFLATE, .compressionDescription: "Deflate compression" },
89 { .compressionName: "adeflate", COMPRESSION_ADOBE_DEFLATE, .compressionDescription: "Deflate compression, as recognized by Adobe" },
90 { .compressionName: "dcs", COMPRESSION_DCS, .compressionDescription: "Kodak DCS encoding" },
91 { .compressionName: "jbig", COMPRESSION_JBIG, .compressionDescription: "ISO JBIG" },
92 { .compressionName: "jp2000", COMPRESSION_JP2000, .compressionDescription: "Leadtools JPEG2000" },
93 { .compressionName: nullptr, .compressionCode: 0, .compressionDescription: nullptr } };
94
95 // Initialize
96
97 priv->f = nullptr;
98 priv->curRow = 0;
99
100 // Store the number of rows
101
102 priv->numRows = height;
103
104 // Set the compression
105
106 compression = COMPRESSION_NONE;
107
108 if (priv->compressionString == nullptr || strcmp(s1: priv->compressionString, s2: "") == 0) {
109 compression = COMPRESSION_NONE;
110 } else {
111 int i;
112 for (i = 0; compressionList[i].compressionName != nullptr; i++) {
113 if (strcmp(s1: priv->compressionString, s2: compressionList[i].compressionName) == 0) {
114 compression = compressionList[i].compressionCode;
115 break;
116 }
117 }
118 if (compressionList[i].compressionName == nullptr) {
119 fprintf(stderr, format: "TiffWriter: Unknown compression type '%.10s', using 'none'.\n", priv->compressionString);
120 fprintf(stderr, format: "Known compression types (the tiff library might not support every type)\n");
121 for (i = 0; compressionList[i].compressionName != nullptr; i++) {
122 fprintf(stderr, format: "%10s %s\n", compressionList[i].compressionName, compressionList[i].compressionDescription);
123 }
124 }
125 }
126
127 // Set bits per sample, samples per pixel, and photometric type from format
128
129 bitspersample = (priv->format == MONOCHROME ? 1 : 8);
130
131 switch (priv->format) {
132 case MONOCHROME:
133 case GRAY:
134 samplesperpixel = 1;
135 photometric = PHOTOMETRIC_MINISBLACK;
136 break;
137
138 case RGB:
139 samplesperpixel = 3;
140 photometric = PHOTOMETRIC_RGB;
141 break;
142
143 case RGBA_PREMULTIPLIED:
144 samplesperpixel = 4;
145 photometric = PHOTOMETRIC_RGB;
146 break;
147
148 case CMYK:
149 samplesperpixel = 4;
150 photometric = PHOTOMETRIC_SEPARATED;
151 break;
152
153 case RGB48:
154 samplesperpixel = 3;
155 bitspersample = 16;
156 photometric = PHOTOMETRIC_RGB;
157 break;
158 }
159
160 // Open the file
161
162 if (openedFile == nullptr) {
163 fprintf(stderr, format: "TiffWriter: No output file given.\n");
164 return false;
165 }
166
167# ifdef _WIN32
168 // Convert C Library handle to Win32 Handle
169 priv->f = TIFFFdOpen(_get_osfhandle(fileno(openedFile)), "-", "w");
170# else
171 priv->f = TIFFFdOpen(fileno(stream: openedFile), "-", "w");
172# endif
173
174 if (!priv->f) {
175 return false;
176 }
177
178 // Set TIFF tags
179
180 TIFFSetField(priv->f, TIFFTAG_IMAGEWIDTH, width);
181 TIFFSetField(priv->f, TIFFTAG_IMAGELENGTH, height);
182 TIFFSetField(priv->f, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
183 TIFFSetField(priv->f, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
184 TIFFSetField(priv->f, TIFFTAG_BITSPERSAMPLE, bitspersample);
185 TIFFSetField(priv->f, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
186 TIFFSetField(priv->f, TIFFTAG_PHOTOMETRIC, photometric);
187 TIFFSetField(priv->f, TIFFTAG_COMPRESSION, (uint16_t)compression);
188 TIFFSetField(priv->f, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif: priv->f, request: rowsperstrip));
189 TIFFSetField(priv->f, TIFFTAG_XRESOLUTION, hDPI);
190 TIFFSetField(priv->f, TIFFTAG_YRESOLUTION, vDPI);
191 TIFFSetField(priv->f, TIFFTAG_RESOLUTIONUNIT, RESUNIT_INCH);
192
193 if (priv->format == RGBA_PREMULTIPLIED) {
194 uint16_t extra = EXTRASAMPLE_ASSOCALPHA;
195 TIFFSetField(priv->f, TIFFTAG_EXTRASAMPLES, 1, &extra);
196 }
197
198 if (priv->format == CMYK) {
199 TIFFSetField(priv->f, TIFFTAG_INKSET, INKSET_CMYK);
200 TIFFSetField(priv->f, TIFFTAG_NUMBEROFINKS, 4);
201 }
202
203 return true;
204}
205
206bool TiffWriter::writePointers(unsigned char **rowPointers, int rowCount)
207{
208 // Write all rows to the file
209
210 for (int row = 0; row < rowCount; row++) {
211 if (TIFFWriteScanline(tif: priv->f, buf: rowPointers[row], row, sample: 0) < 0) {
212 fprintf(stderr, format: "TiffWriter: Error writing tiff row %d\n", row);
213 return false;
214 }
215 }
216
217 return true;
218}
219
220bool TiffWriter::writeRow(unsigned char **rowData)
221{
222 // Add a single row
223
224 if (TIFFWriteScanline(tif: priv->f, buf: *rowData, row: priv->curRow, sample: 0) < 0) {
225 fprintf(stderr, format: "TiffWriter: Error writing tiff row %d\n", priv->curRow);
226 return false;
227 }
228
229 priv->curRow++;
230
231 return true;
232}
233
234bool TiffWriter::close()
235{
236 // Close the file
237
238 TIFFClose(tif: priv->f);
239
240 return true;
241}
242
243#endif
244

source code of poppler/goo/TiffWriter.cc