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