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