1 /*
2 *
3 * Copyright (C) 2001-2020, OFFIS e.V.
4 * All rights reserved. See COPYRIGHT file for details.
5 *
6 * This software and supporting documentation were developed by
7 *
8 * OFFIS e.V.
9 * R&D Division Health
10 * Escherweg 2
11 * D-26121 Oldenburg, Germany
12 *
13 *
14 * Module: dcmjpeg
15 *
16 * Author: Marco Eichelberg
17 *
18 * Purpose: Implements TIFF interface for plugable image formats
19 *
20 */
21
22
23 #include "dcmtk/config/osconfig.h"
24
25 #ifdef WITH_LIBTIFF
26
27 #include "dcmtk/dcmdata/dctypes.h"
28 #include "dcmtk/dcmimgle/diimage.h"
29 #include "dcmtk/dcmimage/dipitiff.h"
30 #include "dcmtk/dcmdata/dcuid.h" /* for dcmtk version */
31
32 BEGIN_EXTERN_C
33 #include <tiffio.h>
34
35 #ifdef HAVE_WINDOWS_H
36 #include <io.h> /* for _get_osfhandle() */
37 #endif
38 END_EXTERN_C
39
40
DiTIFFPlugin()41 DiTIFFPlugin::DiTIFFPlugin()
42 : DiPluginFormat()
43 , compressionType(E_tiffLZWCompression)
44 , predictor(E_tiffLZWPredictorDefault)
45 , rowsPerStrip(0)
46 {
47 }
48
49
~DiTIFFPlugin()50 DiTIFFPlugin::~DiTIFFPlugin()
51 {
52 }
53
54
write(DiImage * image,FILE * stream,const unsigned long frame) const55 int DiTIFFPlugin::write(
56 DiImage *image,
57 FILE *stream,
58 const unsigned long frame) const
59 {
60 int result = 0;
61 if ((image != NULL) && (stream != NULL))
62 {
63 int stream_fd = fileno(stream);
64
65
66 #ifdef HAVE_WINDOWS_H
67
68 #if TIFFLIB_VERSION < 20050912
69 #error TIFF library versions prior to 3.7.4 are not supported by DCMTK on Win32 - critical API change!
70 #endif
71
72 /* Older versions of libtiff expected a Win32 HANDLE when compiled on Windows
73 * instead of a file descriptor. The code below was needed to make that work.
74 * Libtiff version 3.7.4 and newer are known to use a file descriptor instead,
75 * but it is not completely clear at which libtiff release the API change happened.
76 *
77 * #ifdef __CYGWIN__
78 * stream_fd = OFstatic_cast(int, get_osfhandle(stream_fd));
79 * #else
80 * stream_fd =OFstatic_cast(int, _get_osfhandle(stream_fd));
81 * #endif
82 */
83
84 #elif TIFFLIB_VERSION < 20041016
85 #error TIFF library versions prior to 3.7.0 are not supported by DCMTK - TIFFCleanup is missing!
86 #endif
87
88 /* create bitmap with 8 bits per sample */
89 void *data = OFconst_cast(void *, image->getOutputData(frame, 8 /*bits*/, 0 /*planar*/));
90 if (data != NULL)
91 {
92 OFBool isMono = (image->getInternalColorModel() == EPI_Monochrome1) || (image->getInternalColorModel() == EPI_Monochrome2);
93 Uint16 rows = image->getRows();
94 Uint16 cols = image->getColumns();
95
96 short photometric = isMono ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB;
97 short samplesperpixel = isMono ? 1 : 3;
98 unsigned long bytesperrow = cols * samplesperpixel;
99 if (bytesperrow > 0)
100 {
101 short opt_predictor = 0;
102 switch (predictor)
103 {
104 case E_tiffLZWPredictorDefault:
105 opt_predictor = 0;
106 break;
107 case E_tiffLZWPredictorNoPrediction:
108 opt_predictor = 1;
109 break;
110 case E_tiffLZWPredictorHDifferencing:
111 opt_predictor = 2;
112 break;
113 }
114
115 unsigned short opt_compression = COMPRESSION_NONE;
116 switch (compressionType)
117 {
118 case E_tiffLZWCompression:
119 opt_compression = COMPRESSION_LZW;
120 break;
121 case E_tiffPackBitsCompression:
122 opt_compression = COMPRESSION_PACKBITS;
123 break;
124 case E_tiffNoCompression:
125 opt_compression = COMPRESSION_NONE;
126 break;
127 }
128
129 long opt_rowsperstrip = OFstatic_cast(long, rowsPerStrip);
130 if (opt_rowsperstrip <= 0) opt_rowsperstrip = 8192 / bytesperrow;
131 if (opt_rowsperstrip == 0) opt_rowsperstrip++;
132
133 OFBool OK = OFTrue;
134 unsigned char *bytedata = OFstatic_cast(unsigned char *, data);
135 TIFF *tif = TIFFFdOpen(stream_fd, "TIFF", "w");
136 if (tif)
137 {
138 /* Set TIFF parameters. */
139 TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, cols);
140 TIFFSetField(tif, TIFFTAG_IMAGELENGTH, rows);
141 TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, 8);
142 TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT);
143 TIFFSetField(tif, TIFFTAG_COMPRESSION, opt_compression);
144 if (opt_compression == COMPRESSION_LZW && opt_predictor != 0)
145 TIFFSetField(tif, TIFFTAG_PREDICTOR, opt_predictor);
146 TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, photometric);
147 TIFFSetField(tif, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
148 TIFFSetField(tif, TIFFTAG_DOCUMENTNAME, "unnamed");
149 TIFFSetField(tif, TIFFTAG_IMAGEDESCRIPTION, "Converted DICOM Image");
150 TIFFSetField(tif, TIFFTAG_SOFTWARE, "OFFIS DCMTK " OFFIS_DCMTK_VERSION);
151 TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, samplesperpixel);
152 TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, opt_rowsperstrip);
153 /* TIFFSetField(tif, TIFFTAG_STRIPBYTECOUNTS, rows / opt_rowsperstrip); */
154 TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
155
156 /* Now write the TIFF data. */
157 unsigned long offset = 0;
158 for (Uint16 i=0; (i < rows) && OK; i++)
159 {
160 if (TIFFWriteScanline(tif, bytedata + offset, i, 0) < 0) OK = OFFalse;
161 offset += bytesperrow;
162 }
163 TIFFFlushData(tif);
164 /* Clean up internal structures and free memory.
165 * However, the file will be closed by the caller, therefore
166 * TIFFClose(tif) is not called.
167 */
168 TIFFCleanup(tif);
169 }
170 if (OK) result = 1;
171 }
172 }
173
174 /* delete pixel data */
175 image->deleteOutputData();
176 }
177 return result;
178 }
179
180
setCompressionType(DiTIFFCompression ctype)181 void DiTIFFPlugin::setCompressionType(DiTIFFCompression ctype)
182 {
183 compressionType = ctype;
184 }
185
setLZWPredictor(DiTIFFLZWPredictor pred)186 void DiTIFFPlugin::setLZWPredictor(DiTIFFLZWPredictor pred)
187 {
188 predictor = pred;
189 }
190
setRowsPerStrip(unsigned long rows)191 void DiTIFFPlugin::setRowsPerStrip(unsigned long rows)
192 {
193 rowsPerStrip = rows;
194 }
195
getLibraryVersionString()196 OFString DiTIFFPlugin::getLibraryVersionString()
197 {
198 /* use first line only, omit copyright information */
199 OFString versionStr = TIFFGetVersion();
200 const size_t pos = versionStr.find('\n');
201 if (pos != OFString_npos)
202 versionStr.erase(pos);
203 return versionStr;
204 }
205
206 #else /* WITH_LIBTIFF */
207
208 int dipitiff_cc_dummy_to_keep_linker_from_moaning = 0;
209
210 #endif
211