]>
Commit | Line | Data |
---|---|---|
8414a40c VZ |
1 | #include "StdAfx.h" |
2 | ||
3 | //#define STRICT | |
4 | #include <windows.h> | |
5 | #include <windowsx.h> | |
6 | #include <commdlg.h> | |
7 | #include <stdlib.h> // MAX_ constants | |
8 | #include "diblib.h" | |
9 | ||
10 | /*-------------------------------------------------------------------- | |
11 | READ TIFF | |
12 | Load the TIFF data from the file into memory. Return | |
13 | a pointer to a valid DIB (or NULL for errors). | |
14 | Uses the TIFFRGBA interface to libtiff.lib to convert | |
15 | most file formats to a useable form. We just keep the 32 bit | |
16 | form of the data to display, rather than optimizing for the | |
17 | display. | |
18 | ||
19 | Main entry points: | |
20 | ||
21 | int ChkTIFF ( LPCTSTR lpszPath ) | |
22 | PVOID ReadTIFF ( LPCTSTR lpszPath ) | |
23 | ||
24 | RETURN | |
25 | A valid DIB pointer for success; NULL for failure. | |
26 | ||
27 | --------------------------------------------------------------------*/ | |
28 | ||
29 | #include "TiffLib/tiff.h" | |
30 | #include "TiffLib/tiffio.h" | |
31 | #include <assert.h> | |
32 | #include <stdio.h> | |
33 | ||
34 | ||
35 | // piggyback some data on top of the RGBA Image | |
36 | struct TIFFDibImage { | |
37 | TIFFRGBAImage tif; | |
38 | int dibinstalled; | |
39 | } ; | |
40 | ||
41 | ||
42 | HANDLE LoadTIFFinDIB(LPCTSTR lpFileName); | |
43 | HANDLE TIFFRGBA2DIB(TIFFDibImage* dib, uint32* raster) ; | |
44 | ||
45 | static void | |
46 | MyWarningHandler(const char* module, const char* fmt, va_list ap) | |
47 | { | |
48 | // ignore all warnings (unused tags, etc) | |
49 | return; | |
50 | } | |
51 | ||
52 | static void | |
53 | MyErrorHandler(const char* module, const char* fmt, va_list ap) | |
54 | { | |
55 | return; | |
56 | } | |
57 | ||
58 | // Turn off the error and warning handlers to check if a valid file. | |
59 | // Necessary because of the way that the Doc loads images and restart files. | |
60 | int ChkTIFF ( LPCTSTR lpszPath ) | |
61 | { | |
62 | int rtn = 0; | |
63 | ||
64 | TIFFErrorHandler eh; | |
65 | TIFFErrorHandler wh; | |
66 | ||
67 | eh = TIFFSetErrorHandler(NULL); | |
68 | wh = TIFFSetWarningHandler(NULL); | |
69 | ||
70 | TIFF* tif = TIFFOpen(lpszPath, "r"); | |
71 | if (tif) { | |
72 | rtn = 1; | |
73 | TIFFClose(tif); | |
74 | } | |
75 | ||
76 | TIFFSetErrorHandler(eh); | |
77 | TIFFSetWarningHandler(wh); | |
78 | ||
79 | return rtn; | |
80 | } | |
81 | ||
82 | void DibInstallHack(TIFFDibImage* img) ; | |
83 | ||
84 | PVOID ReadTIFF ( LPCTSTR lpszPath ) | |
85 | { | |
86 | void* pDIB = 0; | |
87 | TIFFErrorHandler wh; | |
88 | ||
89 | wh = TIFFSetWarningHandler(MyWarningHandler); | |
90 | ||
91 | if (ChkTIFF(lpszPath)) { | |
92 | TIFF* tif = TIFFOpen(lpszPath, "r"); | |
93 | if (tif) { | |
94 | char emsg[1024]; | |
95 | ||
96 | if (TIFFRGBAImageOK(tif, emsg)) { | |
97 | TIFFDibImage img; | |
98 | char emsg[1024]; | |
99 | ||
100 | if (TIFFRGBAImageBegin(&img.tif, tif, -1, emsg)) { | |
101 | size_t npixels; | |
102 | uint32* raster; | |
103 | ||
104 | DibInstallHack(&img); | |
105 | ||
106 | npixels = img.tif.width * img.tif.height; | |
107 | raster = (uint32*) _TIFFmalloc(npixels * sizeof (uint32)); | |
108 | if (raster != NULL) { | |
109 | if (TIFFRGBAImageGet(&img.tif, raster, img.tif.width, img.tif.height)) { | |
110 | pDIB = TIFFRGBA2DIB(&img, raster); | |
111 | } | |
112 | } | |
113 | _TIFFfree(raster); | |
114 | } | |
115 | TIFFRGBAImageEnd(&img.tif); | |
116 | } | |
117 | else { | |
118 | TRACE("Unable to open image(%s): %s\n", lpszPath, emsg ); | |
119 | } | |
120 | TIFFClose(tif); | |
121 | } | |
122 | } | |
123 | ||
124 | TIFFSetWarningHandler(wh); | |
125 | ||
126 | return pDIB; | |
127 | } | |
128 | ||
129 | ||
130 | ||
131 | HANDLE TIFFRGBA2DIB(TIFFDibImage* dib, uint32* raster) | |
132 | { | |
133 | void* pDIB = 0; | |
134 | TIFFRGBAImage* img = &dib->tif; | |
135 | ||
136 | uint32 imageLength; | |
137 | uint32 imageWidth; | |
138 | uint16 BitsPerSample; | |
139 | uint16 SamplePerPixel; | |
140 | uint32 RowsPerStrip; | |
141 | uint16 PhotometricInterpretation; | |
142 | ||
143 | BITMAPINFOHEADER bi; | |
144 | int dwDIBSize ; | |
145 | ||
146 | TIFFGetField(img->tif, TIFFTAG_IMAGEWIDTH, &imageWidth); | |
147 | TIFFGetField(img->tif, TIFFTAG_IMAGELENGTH, &imageLength); | |
148 | TIFFGetField(img->tif, TIFFTAG_BITSPERSAMPLE, &BitsPerSample); | |
149 | TIFFGetField(img->tif, TIFFTAG_ROWSPERSTRIP, &RowsPerStrip); | |
150 | TIFFGetField(img->tif, TIFFTAG_SAMPLESPERPIXEL, &SamplePerPixel); | |
151 | TIFFGetField(img->tif, TIFFTAG_PHOTOMETRIC, &PhotometricInterpretation); | |
152 | ||
153 | if ( BitsPerSample == 1 && SamplePerPixel == 1 && dib->dibinstalled ) { // bilevel | |
154 | bi.biSize = sizeof(BITMAPINFOHEADER); | |
155 | bi.biWidth = imageWidth; | |
156 | bi.biHeight = imageLength; | |
157 | bi.biPlanes = 1; // always | |
158 | bi.biBitCount = 1; | |
159 | bi.biCompression = BI_RGB; | |
160 | bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; | |
161 | bi.biXPelsPerMeter = 0; | |
162 | bi.biYPelsPerMeter = 0; | |
163 | bi.biClrUsed = 0; // must be zero for RGB compression (none) | |
164 | bi.biClrImportant = 0; // always | |
165 | ||
166 | // Get the size of the DIB | |
167 | dwDIBSize = GetDIBSize( &bi ); | |
168 | ||
169 | // Allocate for the BITMAPINFO structure and the color table. | |
170 | pDIB = GlobalAllocPtr( GHND, dwDIBSize ); | |
171 | if (pDIB == 0) { | |
172 | return( NULL ); | |
173 | } | |
174 | ||
175 | // Copy the header info | |
176 | *((BITMAPINFOHEADER*)pDIB) = bi; | |
177 | ||
178 | // Get a pointer to the color table | |
179 | RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); | |
180 | ||
181 | pRgbq[0].rgbRed = 0; | |
182 | pRgbq[0].rgbBlue = 0; | |
183 | pRgbq[0].rgbGreen = 0; | |
184 | pRgbq[0].rgbReserved = 0; | |
185 | pRgbq[1].rgbRed = 255; | |
186 | pRgbq[1].rgbBlue = 255; | |
187 | pRgbq[1].rgbGreen = 255; | |
188 | pRgbq[1].rgbReserved = 255; | |
189 | ||
190 | // Pointers to the bits | |
191 | //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); | |
192 | // | |
193 | // In the BITMAPINFOHEADER documentation, it appears that | |
194 | // there should be no color table for 32 bit images, but | |
195 | // experience shows that the image is off by 3 words if it | |
196 | // is not included. So here it is. | |
197 | PVOID pbiBits = GetDIBImagePtr((BITMAPINFOHEADER*)pDIB); //(LPSTR)pRgbq + 3 * sizeof(RGBQUAD); | |
198 | ||
199 | int sizeWords = bi.biSizeImage/4; | |
200 | RGBQUAD* rgbDib = (RGBQUAD*)pbiBits; | |
201 | long* rgbTif = (long*)raster; | |
202 | ||
203 | _TIFFmemcpy(pbiBits, raster, bi.biSizeImage); | |
204 | } | |
205 | ||
206 | // For now just always default to the RGB 32 bit form. // save as 32 bit for simplicity | |
207 | else if ( true /*BitsPerSample == 8 && SamplePerPixel == 3*/ ) { // 24 bit color | |
208 | ||
209 | bi.biSize = sizeof(BITMAPINFOHEADER); | |
210 | bi.biWidth = imageWidth; | |
211 | bi.biHeight = imageLength; | |
212 | bi.biPlanes = 1; // always | |
213 | bi.biBitCount = 32; | |
214 | bi.biCompression = BI_RGB; | |
215 | bi.biSizeImage = WIDTHBYTES(bi.biWidth * bi.biBitCount) * bi.biHeight; | |
216 | bi.biXPelsPerMeter = 0; | |
217 | bi.biYPelsPerMeter = 0; | |
218 | bi.biClrUsed = 0; // must be zero for RGB compression (none) | |
219 | bi.biClrImportant = 0; // always | |
220 | ||
221 | // Get the size of the DIB | |
222 | dwDIBSize = GetDIBSize( &bi ); | |
223 | ||
224 | // Allocate for the BITMAPINFO structure and the color table. | |
225 | pDIB = GlobalAllocPtr( GHND, dwDIBSize ); | |
226 | if (pDIB == 0) { | |
227 | return( NULL ); | |
228 | } | |
229 | ||
230 | // Copy the header info | |
231 | *((BITMAPINFOHEADER*)pDIB) = bi; | |
232 | ||
233 | // Get a pointer to the color table | |
234 | RGBQUAD *pRgbq = (RGBQUAD *)((LPSTR)pDIB + sizeof(BITMAPINFOHEADER)); | |
235 | ||
236 | // Pointers to the bits | |
237 | //PVOID pbiBits = (LPSTR)pRgbq + bi.biClrUsed * sizeof(RGBQUAD); | |
238 | // | |
239 | // In the BITMAPINFOHEADER documentation, it appears that | |
240 | // there should be no color table for 32 bit images, but | |
241 | // experience shows that the image is off by 3 words if it | |
242 | // is not included. So here it is. | |
243 | PVOID pbiBits = (LPSTR)pRgbq + 3 * sizeof(RGBQUAD); | |
244 | ||
245 | int sizeWords = bi.biSizeImage/4; | |
246 | RGBQUAD* rgbDib = (RGBQUAD*)pbiBits; | |
247 | long* rgbTif = (long*)raster; | |
248 | ||
249 | // Swap the byte order while copying | |
250 | for ( int i = 0 ; i < sizeWords ; ++i ) | |
251 | { | |
252 | rgbDib[i].rgbRed = TIFFGetR(rgbTif[i]); | |
253 | rgbDib[i].rgbBlue = TIFFGetB(rgbTif[i]); | |
254 | rgbDib[i].rgbGreen = TIFFGetG(rgbTif[i]); | |
255 | rgbDib[i].rgbReserved = 0; | |
256 | } | |
257 | } | |
258 | ||
259 | return pDIB; | |
260 | } | |
261 | ||
262 | ||
263 | ||
264 | ||
265 | /////////////////////////////////////////////////////////////// | |
266 | // | |
267 | // Hacked from tif_getimage.c in libtiff in v3.5.7 | |
268 | // | |
269 | // | |
270 | typedef unsigned char u_char; | |
271 | ||
272 | ||
273 | #define DECLAREContigPutFunc(name) \ | |
274 | static void name(\ | |
275 | TIFFRGBAImage* img, \ | |
276 | uint32* cp, \ | |
277 | uint32 x, uint32 y, \ | |
278 | uint32 w, uint32 h, \ | |
279 | int32 fromskew, int32 toskew, \ | |
280 | u_char* pp \ | |
281 | ) | |
282 | ||
283 | #define DECLARESepPutFunc(name) \ | |
284 | static void name(\ | |
285 | TIFFRGBAImage* img,\ | |
286 | uint32* cp,\ | |
287 | uint32 x, uint32 y, \ | |
288 | uint32 w, uint32 h,\ | |
289 | int32 fromskew, int32 toskew,\ | |
290 | u_char* r, u_char* g, u_char* b, u_char* a\ | |
291 | ) | |
292 | ||
293 | DECLAREContigPutFunc(putContig1bitTile); | |
294 | static int getStripContig1Bit(TIFFRGBAImage* img, uint32* uraster, uint32 w, uint32 h); | |
295 | ||
296 | //typdef struct TIFFDibImage { | |
297 | // TIFFRGBAImage tif; | |
298 | // dibinstalled; | |
299 | //} TIFFDibImage ; | |
300 | ||
301 | void DibInstallHack(TIFFDibImage* dib) { | |
302 | TIFFRGBAImage* img = &dib->tif; | |
303 | dib->dibinstalled = false; | |
304 | switch (img->photometric) { | |
305 | case PHOTOMETRIC_MINISWHITE: | |
306 | case PHOTOMETRIC_MINISBLACK: | |
307 | switch (img->bitspersample) { | |
308 | case 1: | |
309 | img->put.contig = putContig1bitTile; | |
310 | img->get = getStripContig1Bit; | |
311 | dib->dibinstalled = true; | |
312 | break; | |
313 | } | |
314 | break; | |
315 | } | |
316 | } | |
317 | ||
318 | /* | |
319 | * 1-bit packed samples => 1-bit | |
320 | * | |
321 | * Override to just copy the data | |
322 | */ | |
323 | DECLAREContigPutFunc(putContig1bitTile) | |
324 | { | |
325 | int samplesperpixel = img->samplesperpixel; | |
326 | ||
327 | (void) y; | |
328 | fromskew *= samplesperpixel; | |
329 | int wb = WIDTHBYTES(w); | |
330 | u_char* ucp = (u_char*)cp; | |
331 | ||
332 | /* Conver 'w' to bytes from pixels (rounded up) */ | |
333 | w = (w+7)/8; | |
334 | ||
335 | while (h-- > 0) { | |
336 | _TIFFmemcpy(ucp, pp, w); | |
337 | /* | |
338 | for (x = wb; x-- > 0;) { | |
339 | *cp++ = rgbi(Map[pp[0]], Map[pp[1]], Map[pp[2]]); | |
340 | pp += samplesperpixel; | |
341 | } | |
342 | */ | |
343 | ucp += (wb + toskew); | |
344 | pp += (w + fromskew); | |
345 | } | |
346 | } | |
347 | ||
348 | /* | |
349 | * Hacked from the tif_getimage.c file. | |
350 | */ | |
351 | static uint32 | |
352 | setorientation(TIFFRGBAImage* img, uint32 h) | |
353 | { | |
354 | TIFF* tif = img->tif; | |
355 | uint32 y; | |
356 | ||
357 | switch (img->orientation) { | |
358 | case ORIENTATION_BOTRIGHT: | |
359 | case ORIENTATION_RIGHTBOT: /* XXX */ | |
360 | case ORIENTATION_LEFTBOT: /* XXX */ | |
361 | TIFFWarning(TIFFFileName(tif), "using bottom-left orientation"); | |
362 | img->orientation = ORIENTATION_BOTLEFT; | |
363 | /* fall thru... */ | |
364 | case ORIENTATION_BOTLEFT: | |
365 | y = 0; | |
366 | break; | |
367 | case ORIENTATION_TOPRIGHT: | |
368 | case ORIENTATION_RIGHTTOP: /* XXX */ | |
369 | case ORIENTATION_LEFTTOP: /* XXX */ | |
370 | default: | |
371 | TIFFWarning(TIFFFileName(tif), "using top-left orientation"); | |
372 | img->orientation = ORIENTATION_TOPLEFT; | |
373 | /* fall thru... */ | |
374 | case ORIENTATION_TOPLEFT: | |
375 | y = h-1; | |
376 | break; | |
377 | } | |
378 | return (y); | |
379 | } | |
380 | ||
381 | /* | |
382 | * Get a strip-organized image that has | |
383 | * PlanarConfiguration contiguous if SamplesPerPixel > 1 | |
384 | * or | |
385 | * SamplesPerPixel == 1 | |
386 | * | |
387 | * Hacked from the tif_getimage.c file. | |
388 | * | |
389 | * This is set up to allow us to just copy the data to the raster | |
390 | * for 1-bit bitmaps | |
391 | */ | |
392 | static int | |
393 | getStripContig1Bit(TIFFRGBAImage* img, uint32* raster, uint32 w, uint32 h) | |
394 | { | |
395 | TIFF* tif = img->tif; | |
396 | tileContigRoutine put = img->put.contig; | |
397 | uint16 orientation; | |
398 | uint32 row, y, nrow, rowstoread; | |
399 | uint32 pos; | |
400 | u_char* buf; | |
401 | uint32 rowsperstrip; | |
402 | uint32 imagewidth = img->width; | |
403 | tsize_t scanline; | |
404 | int32 fromskew, toskew; | |
405 | tstrip_t strip; | |
406 | tsize_t stripsize; | |
407 | u_char* braster = (u_char*)raster; // byte wide raster | |
408 | uint32 wb = WIDTHBYTES(w); | |
409 | int ret = 1; | |
410 | ||
411 | buf = (u_char*) _TIFFmalloc(TIFFStripSize(tif)); | |
412 | if (buf == 0) { | |
413 | TIFFErrorExt(tif->tif_clientdata, TIFFFileName(tif), "No space for strip buffer"); | |
414 | return (0); | |
415 | } | |
416 | y = setorientation(img, h); | |
417 | orientation = img->orientation; | |
418 | toskew = -(int32) (orientation == ORIENTATION_TOPLEFT ? wb+wb : wb-wb); | |
419 | TIFFGetFieldDefaulted(tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); | |
420 | scanline = TIFFScanlineSize(tif); | |
421 | fromskew = (w < imagewidth ? imagewidth - w : 0)/8; | |
422 | for (row = 0; row < h; row += nrow) | |
423 | { | |
424 | rowstoread = rowsperstrip - (row + img->row_offset) % rowsperstrip; | |
425 | nrow = (row + rowstoread > h ? h - row : rowstoread); | |
426 | strip = TIFFComputeStrip(tif,row+img->row_offset, 0); | |
427 | stripsize = ((row + img->row_offset)%rowsperstrip + nrow) * scanline; | |
428 | if (TIFFReadEncodedStrip(tif, strip, buf, stripsize ) < 0 | |
429 | && img->stoponerr) | |
430 | { | |
431 | ret = 0; | |
432 | break; | |
433 | } | |
434 | ||
435 | pos = ((row + img->row_offset) % rowsperstrip) * scanline; | |
436 | (*put)(img, (uint32*)(braster+y*wb), 0, y, w, nrow, fromskew, toskew, buf + pos); | |
437 | y += (orientation == ORIENTATION_TOPLEFT ?-(int32) nrow : (int32) nrow); | |
438 | } | |
439 | _TIFFfree(buf); | |
440 | return (ret); | |
441 | } | |
442 |