Merge XFA to PDFium master at 4dc95e7 on 10/28/2014
[pdfium.git] / core / src / fxcodec / codec / fx_codec_tiff.cpp
1 // Copyright 2014 PDFium Authors. All rights reserved.\r
2 // Use of this source code is governed by a BSD-style license that can be\r
3 // found in the LICENSE file.\r
4 \r
5 // Original code copyright 2014 Foxit Software Inc. http://www.foxitsoftware.com\r
6 \r
7 #include "../../../include/fxcodec/fx_codec.h"\r
8 #include "../../../include/fxge/fx_dib.h"\r
9 #include "codec_int.h"\r
10 extern "C" {\r
11 #include "../fx_tiff/include/fx_tiffiop.h"\r
12 }\r
13 #if !defined(_FPDFAPI_MINI_)\r
14 void* IccLib_CreateTransform_sRGB(const unsigned char* pProfileData, unsigned int dwProfileSize, int nComponents, int intent, FX_DWORD dwSrcFormat = Icc_FORMAT_DEFAULT);\r
15 void IccLib_TranslateImage(void* pTransform, unsigned char* pDest, const unsigned char* pSrc, int pixels);\r
16 void IccLib_DestroyTransform(void* pTransform);\r
17 #endif\r
18 class CCodec_TiffContext : public CFX_Object\r
19 {\r
20 public:\r
21     CCodec_TiffContext();\r
22     ~CCodec_TiffContext();\r
23 \r
24     FX_BOOL     InitDecoder(IFX_FileRead* file_ptr);\r
25     void        GetFrames(FX_INT32& frames);\r
26     FX_BOOL     LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute);\r
27     FX_BOOL     Decode(CFX_DIBitmap* pDIBitmap);\r
28 \r
29     union {\r
30         IFX_FileRead*   in;\r
31         IFX_FileStream* out;\r
32     } io;\r
33 \r
34     FX_DWORD            offset;\r
35 \r
36     TIFF*                       tif_ctx;\r
37     void*                       icc_ctx;\r
38     FX_INT32            frame_num;\r
39     FX_INT32            frame_cur;\r
40     FX_BOOL                     isDecoder;\r
41 private:\r
42     FX_BOOL     isSupport(CFX_DIBitmap* pDIBitmap);\r
43     void        SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps);\r
44     FX_BOOL     Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);\r
45     FX_BOOL     Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);\r
46     FX_BOOL     Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp);\r
47 };\r
48 CCodec_TiffContext::CCodec_TiffContext()\r
49 {\r
50     offset = 0;\r
51     frame_num = 0;\r
52     frame_cur = 0;\r
53     io.in = NULL;\r
54     tif_ctx = NULL;\r
55     icc_ctx = NULL;\r
56     isDecoder = TRUE;\r
57 }\r
58 CCodec_TiffContext::~CCodec_TiffContext()\r
59 {\r
60 #if !defined(_FPDFAPI_MINI_)\r
61     if(icc_ctx) {\r
62         IccLib_DestroyTransform(icc_ctx);\r
63         icc_ctx = NULL;\r
64     }\r
65 #endif\r
66     if(tif_ctx) {\r
67         TIFFClose(tif_ctx);\r
68     }\r
69 }\r
70 static tsize_t _tiff_read(thandle_t context, tdata_t buf, tsize_t length)\r
71 {\r
72     CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;\r
73     FX_BOOL ret = FALSE;\r
74     if(pTiffContext->isDecoder) {\r
75         ret = pTiffContext->io.in->ReadBlock(buf, pTiffContext->offset, length);\r
76     } else {\r
77         ret = pTiffContext->io.out->ReadBlock(buf, pTiffContext->offset, length);\r
78     }\r
79     if(!ret) {\r
80         return 0;\r
81     }\r
82     pTiffContext->offset += (FX_DWORD)length;\r
83     return length;\r
84 }\r
85 static tsize_t _tiff_write(thandle_t context, tdata_t buf, tsize_t length)\r
86 {\r
87     CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;\r
88     ASSERT(!pTiffContext->isDecoder);\r
89     if(!pTiffContext->io.out->WriteBlock(buf, pTiffContext->offset, length)) {\r
90         return 0;\r
91     }\r
92     pTiffContext->offset += (FX_DWORD)length;\r
93     return length;\r
94 }\r
95 static toff_t _tiff_seek(thandle_t context, toff_t offset, int whence)\r
96 {\r
97     CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;\r
98     switch(whence) {\r
99         case 0:\r
100             pTiffContext->offset = (FX_DWORD)offset;\r
101             break;\r
102         case 1:\r
103             pTiffContext->offset += (FX_DWORD)offset;\r
104             break;\r
105         case 2:\r
106             if(pTiffContext->isDecoder) {\r
107                 if(pTiffContext->io.in->GetSize() < (FX_FILESIZE)offset) {\r
108                     return -1;\r
109                 }\r
110                 pTiffContext->offset = (FX_DWORD)(pTiffContext->io.in->GetSize() - offset);\r
111             } else {\r
112                 if(pTiffContext->io.out->GetSize() < (FX_FILESIZE)offset) {\r
113                     return -1;\r
114                 }\r
115                 pTiffContext->offset = (FX_DWORD)(pTiffContext->io.out->GetSize() - offset);\r
116             }\r
117             break;\r
118         default:\r
119             return -1;\r
120     }\r
121     ASSERT(pTiffContext->isDecoder ?\r
122            (pTiffContext->offset <= (FX_DWORD)pTiffContext->io.in->GetSize()) :\r
123            TRUE);\r
124     return pTiffContext->offset;\r
125 }\r
126 static int _tiff_close(thandle_t context)\r
127 {\r
128     return 0;\r
129 }\r
130 static toff_t _tiff_get_size(thandle_t context)\r
131 {\r
132     CCodec_TiffContext* pTiffContext = (CCodec_TiffContext*)context;\r
133     return pTiffContext->isDecoder ?\r
134            (toff_t)pTiffContext->io.in->GetSize() :\r
135            (toff_t)pTiffContext->io.out->GetSize();\r
136 }\r
137 static int _tiff_map(thandle_t context, tdata_t*, toff_t*)\r
138 {\r
139     return 0;\r
140 }\r
141 static void _tiff_unmap(thandle_t context, tdata_t, toff_t) {}\r
142 TIFF* _tiff_open(void* context, const char* mode)\r
143 {\r
144     TIFF* tif = TIFFClientOpen("Tiff Image", mode,\r
145                                (thandle_t)context,\r
146                                _tiff_read, _tiff_write, _tiff_seek, _tiff_close,\r
147                                _tiff_get_size, _tiff_map, _tiff_unmap);\r
148     if(tif)     {\r
149         tif->tif_fd = (int)(FX_INTPTR)context;\r
150     }\r
151     return tif;\r
152 }\r
153 void* _TIFFmalloc(tmsize_t size)\r
154 {\r
155     return FXMEM_DefaultAlloc(size, 0);\r
156 }\r
157 void _TIFFfree(void* ptr)\r
158 {\r
159     FXMEM_DefaultFree(ptr, 0);\r
160 }\r
161 void* _TIFFrealloc(void* ptr, tmsize_t size)\r
162 {\r
163     return FXMEM_DefaultRealloc(ptr, size, 0);\r
164 }\r
165 void _TIFFmemset(void* ptr, int val, tmsize_t size)\r
166 {\r
167     FXSYS_memset8(ptr, val, (size_t)size);\r
168 }\r
169 void _TIFFmemcpy(void* des, const void* src, tmsize_t size)\r
170 {\r
171     FXSYS_memcpy32(des, src, (size_t)size);\r
172 }\r
173 int _TIFFmemcmp(const void* ptr1, const void* ptr2, tmsize_t size)\r
174 {\r
175     return FXSYS_memcmp32(ptr1, ptr2, (size_t)size);\r
176 }\r
177 static void _tiff_warning_ext(thandle_t context, const char* module, const char* fmt, va_list ap)\r
178 {\r
179     if(module != NULL) {\r
180     }\r
181 }\r
182 TIFFErrorHandlerExt _TIFFwarningHandlerExt = _tiff_warning_ext;\r
183 static void _tiff_error_ext(thandle_t context, const char* module, const char* fmt, va_list ap)\r
184 {\r
185     if(module != NULL) {\r
186     }\r
187 }\r
188 TIFFErrorHandlerExt _TIFFerrorHandlerExt = _tiff_error_ext;\r
189 int TIFFCmyk2Rgb(thandle_t context, uint8 c, uint8 m, uint8 y, uint8 k, uint8* r, uint8* g, uint8* b)\r
190 {\r
191     if(context == NULL) {\r
192         return 0;\r
193     }\r
194     CCodec_TiffContext* p = (CCodec_TiffContext*)context;\r
195 #if !defined(_FPDFAPI_MINI_)\r
196     if(p->icc_ctx) {\r
197         unsigned char cmyk[4], bgr[3];\r
198         cmyk[0] = c, cmyk[1] = m, cmyk[2] = y, cmyk[3] = k;\r
199         IccLib_TranslateImage(p->icc_ctx, bgr, cmyk, 1);\r
200         *r = bgr[2], *g = bgr[1], *b = bgr[0];\r
201     } else {\r
202 #endif\r
203         AdobeCMYK_to_sRGB1(c, m, y, k, *r, *g, *b);\r
204 #if !defined(_FPDFAPI_MINI_)\r
205     }\r
206 #endif\r
207     return 1;\r
208 }\r
209 FX_BOOL CCodec_TiffContext::InitDecoder(IFX_FileRead* file_ptr)\r
210 {\r
211     io.in = file_ptr;\r
212     tif_ctx = _tiff_open(this, "r");\r
213     if(tif_ctx == NULL) {\r
214         return FALSE;\r
215     }\r
216     return TRUE;\r
217 }\r
218 void CCodec_TiffContext::GetFrames(FX_INT32& frames)\r
219 {\r
220     frames = frame_num = TIFFNumberOfDirectories(tif_ctx);\r
221 }\r
222 #define TIFF_EXIF_GETINFO(key, T, tag) {\\r
223         T val = (T)0;\\r
224         TIFFGetField(tif_ctx,tag,&val);\\r
225         if (val) {\\r
226             (key) = FX_Alloc(FX_BYTE,sizeof(T));\\r
227             if ((key)) {\\r
228                 T* ptr = (T*)(key);\\r
229                 *ptr = val;\\r
230                 pExif->m_TagVal.SetAt(tag,(key));}}}\\r
231     (key) = NULL;\r
232 #define TIFF_EXIF_GETSTRINGINFO(key, tag) {\\r
233         FX_DWORD size = 0;\\r
234         FX_LPBYTE buf = NULL;\\r
235         TIFFGetField(tif_ctx,tag,&size, &buf);\\r
236         if (size && buf) {\\r
237             (key) = FX_Alloc(FX_BYTE,size);\\r
238             if ((key)) {\\r
239                 FXSYS_memcpy32((key),buf,size);\\r
240                 pExif->m_TagVal.SetAt(tag,(key));}}}\\r
241     (key) = NULL;\r
242 template <class T>\r
243 static FX_BOOL Tiff_Exif_GetInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif)\r
244 {\r
245     FX_LPBYTE key = NULL;\r
246     T val = (T)0;\r
247     TIFFGetField(tif_ctx, tag, &val);\r
248     if (val) {\r
249         (key) = FX_Alloc(FX_BYTE, sizeof(T));\r
250         if ((key) == NULL) {\r
251             return FALSE;\r
252         }\r
253         T* ptr = (T*)(key);\r
254         *ptr = val;\r
255         pExif->m_TagVal.SetAt(tag, (key));\r
256         return TRUE;\r
257     }\r
258     return FALSE;\r
259 }\r
260 static void Tiff_Exif_GetStringInfo(TIFF* tif_ctx, ttag_t tag, CFX_DIBAttributeExif* pExif)\r
261 {\r
262     FX_LPSTR buf = NULL;\r
263     FX_LPBYTE key = NULL;\r
264     TIFFGetField(tif_ctx, tag, &buf);\r
265     if (buf) {\r
266         FX_INT32 size = (FX_INT32)FXSYS_strlen(buf);\r
267         (key) = FX_Alloc(FX_BYTE, size + 1);\r
268         if ((key) == NULL) {\r
269             return;\r
270         }\r
271         FXSYS_memcpy32((key), buf, size);\r
272         key[size] = 0;\r
273         pExif->m_TagVal.SetAt(tag, (key));\r
274     }\r
275 }\r
276 FX_BOOL CCodec_TiffContext::LoadFrameInfo(FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute)\r
277 {\r
278     if (!TIFFSetDirectory(tif_ctx, (uint16)frame))      {\r
279         return FALSE;\r
280     }\r
281     FX_WORD tif_cs;\r
282     FX_DWORD tif_icc_size = 0;\r
283     FX_LPBYTE tif_icc_buf = NULL;\r
284     FX_WORD tif_bpc = 0;\r
285     FX_WORD tif_cps;\r
286     FX_DWORD tif_rps;\r
287     width = height = comps = 0;\r
288     TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width);\r
289     TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height);\r
290     TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &comps);\r
291     TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &tif_bpc);\r
292     TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &tif_cs);\r
293     TIFFGetField(tif_ctx, TIFFTAG_COMPRESSION, &tif_cps);\r
294     TIFFGetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, &tif_rps);\r
295     TIFFGetField(tif_ctx, TIFFTAG_ICCPROFILE, &tif_icc_size, &tif_icc_buf);\r
296     if (pAttribute) {\r
297         pAttribute->m_wDPIUnit = FXCODEC_RESUNIT_INCH;\r
298         if (TIFFGetField(tif_ctx, TIFFTAG_RESOLUTIONUNIT, &pAttribute->m_wDPIUnit)) {\r
299             pAttribute->m_wDPIUnit -= 1;\r
300         }\r
301         CFX_DIBAttributeExif* pExif = (CFX_DIBAttributeExif*)pAttribute->m_pExif;\r
302         pExif->clear();\r
303         Tiff_Exif_GetInfo<FX_WORD>(tif_ctx, TIFFTAG_ORIENTATION, pExif);\r
304         if (Tiff_Exif_GetInfo<FX_FLOAT>(tif_ctx, TIFFTAG_XRESOLUTION, pExif)) {\r
305             FX_FLOAT fDpi = 0;\r
306             pExif->GetInfo(TIFFTAG_XRESOLUTION, &fDpi);\r
307             pAttribute->m_nXDPI = (FX_INT32)(fDpi + 0.5f);\r
308         }\r
309         if (Tiff_Exif_GetInfo<FX_FLOAT>(tif_ctx, TIFFTAG_YRESOLUTION, pExif)) {\r
310             FX_FLOAT fDpi = 0;\r
311             pExif->GetInfo(TIFFTAG_YRESOLUTION, &fDpi);\r
312             pAttribute->m_nYDPI = (FX_INT32)(fDpi + 0.5f);\r
313         }\r
314         Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_IMAGEDESCRIPTION, pExif);\r
315         Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MAKE, pExif);\r
316         Tiff_Exif_GetStringInfo(tif_ctx, TIFFTAG_MODEL, pExif);\r
317     }\r
318     bpc = tif_bpc;\r
319     if(tif_rps > height) {\r
320         TIFFSetField(tif_ctx, TIFFTAG_ROWSPERSTRIP, tif_rps = height);\r
321     }\r
322     return TRUE;\r
323 }\r
324 void _TiffBGRA2RGBA(FX_LPBYTE pBuf, FX_INT32 pixel, FX_INT32 spp)\r
325 {\r
326     register FX_BYTE tmp;\r
327     for (FX_INT32 n = 0; n < pixel; n++) {\r
328         tmp = pBuf[0];\r
329         pBuf[0] = pBuf[2];\r
330         pBuf[2] = tmp;\r
331         pBuf += spp;\r
332     }\r
333 }\r
334 FX_BOOL CCodec_TiffContext::isSupport(CFX_DIBitmap* pDIBitmap)\r
335 {\r
336     if (TIFFIsTiled(tif_ctx)) {\r
337         return FALSE;\r
338     }\r
339     FX_UINT16 photometric;\r
340     if (!TIFFGetField(tif_ctx, TIFFTAG_PHOTOMETRIC, &photometric)) {\r
341         return FALSE;\r
342     }\r
343     switch (pDIBitmap->GetBPP()) {\r
344         case 1:\r
345         case 8:\r
346             if (photometric != PHOTOMETRIC_PALETTE) {\r
347                 return FALSE;\r
348             }\r
349             break;\r
350         case 24:\r
351             if (photometric != PHOTOMETRIC_RGB) {\r
352                 return FALSE;\r
353             }\r
354             break;\r
355         default:\r
356             return FALSE;\r
357     }\r
358     FX_UINT16 planarconfig;\r
359     if (!TIFFGetFieldDefaulted(tif_ctx, TIFFTAG_PLANARCONFIG, &planarconfig)) {\r
360         return FALSE;\r
361     }\r
362     if (planarconfig == PLANARCONFIG_SEPARATE) {\r
363         return FALSE;\r
364     }\r
365     return TRUE;\r
366 }\r
367 void CCodec_TiffContext::SetPalette(CFX_DIBitmap* pDIBitmap, FX_UINT16 bps)\r
368 {\r
369     FX_UINT16 *red_orig, *green_orig, *blue_orig;\r
370     TIFFGetField(tif_ctx, TIFFTAG_COLORMAP, &red_orig, &green_orig, &blue_orig);\r
371     for (FX_INT32 i = (1L << bps) - 1; i >= 0; i--) {\r
372 #define CVT(x)          ((FX_UINT16)((x)>>8))\r
373         red_orig[i] = CVT(red_orig[i]);\r
374         green_orig[i] = CVT(green_orig[i]);\r
375         blue_orig[i] = CVT(blue_orig[i]);\r
376 #undef  CVT\r
377     }\r
378     FX_INT32 len = 1 << bps;\r
379     for(FX_INT32 index = 0; index < len; index++) {\r
380         FX_DWORD r = red_orig[index] & 0xFF;\r
381         FX_DWORD g = green_orig[index] & 0xFF;\r
382         FX_DWORD b = blue_orig[index] & 0xFF;\r
383         FX_DWORD color = (FX_UINT32)b | ((FX_UINT32)g << 8) | ((FX_UINT32)r << 16) | (((uint32)0xffL) << 24);\r
384         pDIBitmap->SetPaletteEntry(index, color);\r
385     }\r
386 }\r
387 FX_BOOL CCodec_TiffContext::Decode1bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)\r
388 {\r
389     if (pDIBitmap->GetBPP() != 1 || spp != 1 || bps != 1 || !isSupport(pDIBitmap)) {\r
390         return FALSE;\r
391     }\r
392     SetPalette(pDIBitmap, bps);\r
393     FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);\r
394     FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);\r
395     if (buf == NULL) {\r
396         TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");\r
397         return FALSE;\r
398     }\r
399     FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();\r
400     FX_DWORD pitch = pDIBitmap->GetPitch();\r
401     for(FX_INT32 row = 0; row < height; row++) {\r
402         TIFFReadScanline(tif_ctx, buf, row, 0);\r
403         for(FX_INT32 j = 0; j < size; j++) {\r
404             bitMapbuffer[row * pitch + j] = buf[j];\r
405         }\r
406     }\r
407     _TIFFfree(buf);\r
408     return TRUE;\r
409 }\r
410 FX_BOOL CCodec_TiffContext::Decode8bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)\r
411 {\r
412     if (pDIBitmap->GetBPP() != 8 || spp != 1 || (bps != 4 && bps != 8) || !isSupport(pDIBitmap)) {\r
413         return FALSE;\r
414     }\r
415     SetPalette(pDIBitmap, bps);\r
416     FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);\r
417     FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);\r
418     if (buf == NULL) {\r
419         TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");\r
420         return FALSE;\r
421     }\r
422     FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();\r
423     FX_DWORD pitch = pDIBitmap->GetPitch();\r
424     for(FX_INT32 row = 0; row < height; row++) {\r
425         TIFFReadScanline(tif_ctx, buf, row, 0);\r
426         for(FX_INT32 j = 0; j < size; j++) {\r
427             switch(bps) {\r
428                 case 4:\r
429                     bitMapbuffer[row * pitch + 2 * j + 0] = (buf[j] & 0xF0) >> 4;\r
430                     bitMapbuffer[row * pitch + 2 * j + 1] = (buf[j] & 0x0F) >> 0;\r
431                     break;\r
432                 case 8:\r
433                     bitMapbuffer[row * pitch + j] = buf[j];\r
434                     break;\r
435             }\r
436         }\r
437     }\r
438     _TIFFfree(buf);\r
439     return TRUE;\r
440 }\r
441 FX_BOOL CCodec_TiffContext::Decode24bppRGB(CFX_DIBitmap* pDIBitmap, FX_INT32 height, FX_INT32 width, FX_UINT16 bps, FX_UINT16 spp)\r
442 {\r
443     if (pDIBitmap->GetBPP() != 24 || !isSupport(pDIBitmap)) {\r
444         return FALSE;\r
445     }\r
446     FX_INT32 size = (FX_INT32)TIFFScanlineSize(tif_ctx);\r
447     FX_LPBYTE buf = (FX_LPBYTE)_TIFFmalloc(size);\r
448     if (buf == NULL) {\r
449         TIFFError(TIFFFileName(tif_ctx), "No space for scanline buffer");\r
450         return FALSE;\r
451     }\r
452     FX_LPBYTE bitMapbuffer = (FX_LPBYTE)pDIBitmap->GetBuffer();\r
453     FX_DWORD pitch = pDIBitmap->GetPitch();\r
454     for(FX_INT32 row = 0; row < height; row++) {\r
455         TIFFReadScanline(tif_ctx, buf, row, 0);\r
456         for(FX_INT32 j = 0; j < size - 2; j += 3) {\r
457             bitMapbuffer[row * pitch + j + 0] = buf[j + 2];\r
458             bitMapbuffer[row * pitch + j + 1] = buf[j + 1];\r
459             bitMapbuffer[row * pitch + j + 2] = buf[j + 0];\r
460         }\r
461     }\r
462     _TIFFfree(buf);\r
463     return TRUE;\r
464 }\r
465 FX_BOOL CCodec_TiffContext::Decode(CFX_DIBitmap* pDIBitmap)\r
466 {\r
467     FX_DWORD img_wid = pDIBitmap->GetWidth();\r
468     FX_DWORD img_hei = pDIBitmap->GetHeight();\r
469     FX_DWORD width = 0;\r
470     FX_DWORD height = 0;\r
471     TIFFGetField(tif_ctx, TIFFTAG_IMAGEWIDTH, &width);\r
472     TIFFGetField(tif_ctx, TIFFTAG_IMAGELENGTH, &height);\r
473     if (img_wid != width || img_hei != height) {\r
474         return FALSE;\r
475     }\r
476     if (pDIBitmap->GetBPP() == 32) {\r
477         FX_WORD rotation = ORIENTATION_TOPLEFT;\r
478         TIFFGetField(tif_ctx, TIFFTAG_ORIENTATION, &rotation);\r
479         if(TIFFReadRGBAImageOriented(tif_ctx, img_wid, img_hei,\r
480                                      (uint32*)pDIBitmap->GetBuffer(), rotation, 1)) {\r
481             for (FX_DWORD row = 0; row < img_hei; row++) {\r
482                 FX_LPBYTE row_buf = (FX_LPBYTE)pDIBitmap->GetScanline(row);\r
483                 _TiffBGRA2RGBA(row_buf, img_wid, 4);\r
484             }\r
485             return TRUE;\r
486         }\r
487     }\r
488     FX_UINT16 spp, bps;\r
489     TIFFGetField(tif_ctx, TIFFTAG_SAMPLESPERPIXEL, &spp);\r
490     TIFFGetField(tif_ctx, TIFFTAG_BITSPERSAMPLE, &bps);\r
491     FX_DWORD bpp = bps * spp;\r
492     if (bpp == 1) {\r
493         return Decode1bppRGB(pDIBitmap, height, width, bps, spp);\r
494     } else if (bpp <= 8) {\r
495         return Decode8bppRGB(pDIBitmap, height, width, bps, spp);\r
496     } else if (bpp <= 24) {\r
497         return Decode24bppRGB(pDIBitmap, height, width, bps, spp);\r
498     }\r
499     return FALSE;\r
500 }\r
501 FX_LPVOID CCodec_TiffModule::CreateDecoder(IFX_FileRead* file_ptr)\r
502 {\r
503     CCodec_TiffContext* pDecoder = FX_NEW CCodec_TiffContext;\r
504     if (pDecoder == NULL) {\r
505         return NULL;\r
506     }\r
507     if (!pDecoder->InitDecoder(file_ptr)) {\r
508         delete pDecoder;\r
509         return NULL;\r
510     }\r
511     return pDecoder;\r
512 }\r
513 void CCodec_TiffModule::GetFrames(FX_LPVOID ctx, FX_INT32& frames)\r
514 {\r
515     CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;\r
516     pDecoder->GetFrames(frames);\r
517 }\r
518 FX_BOOL CCodec_TiffModule::LoadFrameInfo(FX_LPVOID ctx, FX_INT32 frame, FX_DWORD& width, FX_DWORD& height, FX_DWORD& comps, FX_DWORD& bpc, CFX_DIBAttribute* pAttribute)\r
519 {\r
520     CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;\r
521     return pDecoder->LoadFrameInfo(frame, width, height, comps, bpc, pAttribute);\r
522 }\r
523 FX_BOOL CCodec_TiffModule::Decode(void* ctx, class CFX_DIBitmap* pDIBitmap)\r
524 {\r
525     CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;\r
526     return pDecoder->Decode(pDIBitmap);\r
527 }\r
528 void CCodec_TiffModule::DestroyDecoder(void* ctx)\r
529 {\r
530     CCodec_TiffContext* pDecoder = (CCodec_TiffContext*)ctx;\r
531     delete pDecoder;\r
532 }\r