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