void TifReader::readLine(char *buffer, int x0, int x1, int shrink) { if (this->m_info.m_bitsPerSample == 16 && this->m_info.m_samplePerPixel >= 3) { std::vector<short> app(4 * (m_info.m_lx)); readLine(&app[0], x0, x1, shrink); TPixel64 *pixin = (TPixel64 *)&app[0]; TPixel32 *pixout = (TPixel32 *)buffer; for (int j = 0; j < x0; j++) { pixout++; pixin++; } for (int i = 0; i < (x1 - x0) + 1; i++) *pixout++ = PixelConverter<TPixel32>::from(*pixin++); return; } assert(shrink > 0); const int pixelSize = 4; int stripRowSize = m_rowLength * pixelSize; if (m_row < m_info.m_y0 || m_row > m_info.m_y1) { memset(buffer, 0, (x1 - x0 + 1) * pixelSize); m_row++; return; } int stripIndex = m_row / m_rowsPerStrip; if (m_stripIndex != stripIndex) { m_stripIndex = stripIndex; if (TIFFIsTiled(m_tiff)) { uint32 tileWidth = 0, tileHeight = 0; TIFFGetField(m_tiff, TIFFTAG_TILEWIDTH, &tileWidth); TIFFGetField(m_tiff, TIFFTAG_TILELENGTH, &tileHeight); assert(tileWidth > 0 && tileHeight > 0); int tileSize = tileWidth * tileHeight; std::unique_ptr<uint32[]> tile(new uint32[tileSize]); int x = 0; int y = tileHeight * m_stripIndex; int lastTy = std::min((int)tileHeight, m_info.m_ly - y); while (x < m_info.m_lx) { int ret = TIFFReadRGBATile(m_tiff, x, y, tile.get()); assert(ret); int tileRowSize = std::min((int)tileWidth, (int)(m_info.m_lx - x)) * pixelSize; for (int ty = 0; ty < lastTy; ++ty) { memcpy( m_stripBuffer + (ty * m_rowLength + x) * pixelSize, (UCHAR *)tile.get() + ty * tileWidth * pixelSize, tileRowSize); } x += tileWidth; } } else { int y = m_rowsPerStrip * m_stripIndex; int ok = TIFFReadRGBAStrip(m_tiff, y, (uint32 *)m_stripBuffer); assert(ok); } } uint16 orient = ORIENTATION_TOPLEFT; TIFFGetField(m_tiff, TIFFTAG_ORIENTATION, &orient); int r = m_rowsPerStrip - 1 - (m_row % m_rowsPerStrip); switch (orient) // Pretty weak check for top/bottom orientation { case ORIENTATION_TOPLEFT: case ORIENTATION_TOPRIGHT: case ORIENTATION_LEFTTOP: case ORIENTATION_RIGHTTOP: // We have to invert the fixed BOTTOM-UP returned by TIFF functions - since this function is // supposed to ignore orientation issues (which are managed outside). // The last tiles row will actually start at the END OF THE IMAGE (not necessarily at // m_rowsPerStrip multiples). So, we must adjust for that. r = std::min(m_rowsPerStrip, m_info.m_ly - m_rowsPerStrip * m_stripIndex) - 1 - (m_row % m_rowsPerStrip); break; case ORIENTATION_BOTRIGHT: case ORIENTATION_BOTLEFT: case ORIENTATION_RIGHTBOT: case ORIENTATION_LEFTBOT: r = m_row % m_rowsPerStrip; break; } TPixel32 *pix = (TPixel32 *)buffer; uint32 *v = (uint32 *)(m_stripBuffer + r * stripRowSize); pix += x0; v += x0; int width = (x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1; for (int i = 0; i < width; i++) { uint32 c = *v; pix->r = (UCHAR)TIFFGetR(c); pix->g = (UCHAR)TIFFGetG(c); pix->b = (UCHAR)TIFFGetB(c); pix->m = (UCHAR)TIFFGetA(c); v += shrink; pix += shrink; } m_row++; }
void TifReader::open(FILE *file) { int fd = fileno(file); #if 0 m_tiff = TIFFFdOpenNoCloseProc(fd, "", "rb"); #else m_tiff = TIFFFdOpen(dup(fd), "", "rb"); #endif if (!m_tiff) { std::string str("Tiff file closed"); throw(str); } uint32 w = 0, h = 0, rps = 0; uint16 bps = 0, spp = 0; uint32 tileWidth = 0, tileLength = 0; //TIFFSetDirectory(m_tiff,1); //TIFFGetField(m_tiff, TIFFTAG_PAGENUMBER, &pn); //int pn = TIFFNumberOfDirectories(m_tiff); //TIFFSetDirectory(m_tiff,1); TIFFGetField(m_tiff, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(m_tiff, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(m_tiff, TIFFTAG_BITSPERSAMPLE, &bps); TIFFGetField(m_tiff, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetField(m_tiff, TIFFTAG_ROWSPERSTRIP, &rps); //int stripCount = TIFFNumberOfStrips(m_tiff); //int tileCount = TIFFNumberOfTiles(m_tiff); TIFFGetField(m_tiff, TIFFTAG_TILEWIDTH, &tileWidth); TIFFGetField(m_tiff, TIFFTAG_TILELENGTH, &tileLength); Tiio::TifWriterProperties *prop = new Tiio::TifWriterProperties(); m_info.m_properties = prop; uint16 orient = Tiio::TOP2BOTTOM; if (TIFFGetField(m_tiff, TIFFTAG_ORIENTATION, &orient)) { switch (orient) { case ORIENTATION_TOPLEFT: /* row 0 top, col 0 lhs */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_TOPLEFT); m_rowOrder = Tiio::TOP2BOTTOM; break; case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_TOPRIGHT); m_rowOrder = Tiio::TOP2BOTTOM; break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_LEFTTOP); m_rowOrder = Tiio::TOP2BOTTOM; break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_RIGHTTOP); m_rowOrder = Tiio::TOP2BOTTOM; break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_BOTRIGHT); m_rowOrder = Tiio::BOTTOM2TOP; break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_BOTLEFT); m_rowOrder = Tiio::BOTTOM2TOP; break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_RIGHTBOT); m_rowOrder = Tiio::BOTTOM2TOP; break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ prop->m_orientation.setValue(TNZ_INFO_ORIENT_LEFTBOT); m_rowOrder = Tiio::BOTTOM2TOP; break; default: prop->m_orientation.setValue(TNZ_INFO_ORIENT_NONE); m_rowOrder = Tiio::TOP2BOTTOM; break; } } USHORT compression; TIFFGetField(m_tiff, TIFFTAG_COMPRESSION, &compression); switch (compression) { case COMPRESSION_LZW: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_LZW); break; case COMPRESSION_PACKBITS: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_PACKBITS); break; case COMPRESSION_THUNDERSCAN: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_THUNDERSCAN); break; case COMPRESSION_CCITTFAX3: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_CCITTFAX3); break; case COMPRESSION_CCITTFAX4: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_CCITTFAX4); break; case COMPRESSION_CCITTRLE: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_CCITTRLE); break; case COMPRESSION_JPEG: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_JPEG); break; case COMPRESSION_OJPEG: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_OJPEG); break; case COMPRESSION_NONE: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_NONE); break; case COMPRESSION_SGILOG: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_SGILOG); break; case COMPRESSION_SGILOG24: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_SGILOG24); break; case COMPRESSION_ADOBE_DEFLATE: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_ADOBE_DEFLATE); break; case COMPRESSION_DEFLATE: prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_DEFLATE); break; /*default : prop->m_compressionType.setValue(TNZ_INFO_COMPRESS_UNKNOWN); break;*/ default: assert(0); } float xdpi = 0, ydpi = 0; TIFFGetField(m_tiff, TIFFTAG_XRESOLUTION, &xdpi); TIFFGetField(m_tiff, TIFFTAG_YRESOLUTION, &ydpi); bool swapxy = false; // orient == ORIENTATION_RIGHTTOP; if (swapxy) { tswap(w, h); tswap(xdpi, ydpi); } m_xdpi = xdpi; m_ydpi = ydpi; m_info.m_lx = w; m_info.m_ly = h; m_info.m_dpix = xdpi; m_info.m_dpiy = ydpi; m_info.m_samplePerPixel = spp; if (bps == 64 && spp == 3) bps = 16; //immagine con bpp = 192 uint16 photometric; //codice di controllo TIFFGetField(m_tiff, TIFFTAG_PHOTOMETRIC, &photometric); if (photometric == 3 && (bps == 2 || bps == 4)) //immagini con PHOTOMATRIC_PALETTE bps = 8; if (photometric == 1 && (bps == 12 || bps == 24)) bps = 16; if (bps == 6) bps = 4; //immagini con bps = 6 if (bps == 10 || bps == 12 || bps == 14) //immagini con bps = 10 , 12 , 14 , 24 , 32 bps = 8; if (bps == 24 || bps == 32) bps = 16; m_info.m_bitsPerSample = bps; if (bps == 8) switch (spp) { case 1: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L" 8(GREYTONES)"); break; case 3: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"24(RGB)"); break; case 4: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; } else if (bps == 16) switch (spp) { case 1: /* row 0 top, col 0 lhs */ //prop->m_bitsPerPixel.setValue(L"16(GREYTONES)"); break; case 3: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"48(RGB)"); break; case 4: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"64(RGBM)"); break; } else if (bps == 2) switch (spp) { case 1: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; case 3: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; case 4: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; } else if (bps == 1) switch (spp) { case 1: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L" 1(BW)"); break; case 3: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; case 4: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; } else if (bps == 4) switch (spp) { case 1: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L" 8(GREYTONES)"); break; case 3: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; case 4: /* row 0 top, col 0 lhs */ prop->m_bitsPerPixel.setValue(L"32(RGBM)"); break; } else if (bps == 64 && spp == 3) prop->m_bitsPerPixel.setValue(L"64(RGBM)"); else assert(false); if (TIFFIsTiled(m_tiff)) { m_rowsPerStrip = tileLength; int tilesPerRow = (w + tileWidth - 1) / tileWidth; //m_rowLength = tileWidth * tilesPerRow; m_rowLength = m_info.m_lx; int pixelSize = bps == 16 ? 8 : 4; int stripSize = m_rowsPerStrip * m_rowLength * pixelSize; m_tmpRas = TRasterGR8P(stripSize, 1); m_tmpRas->lock(); m_stripBuffer = m_tmpRas->getRawData(); } else { m_rowsPerStrip = rps; //if(m_rowsPerStrip<=0) m_rowsPerStrip = 1; //potrei mettere qualsiasi valore //purchè sia lo stesso in tif_getimage.c linea 2512 //if(m_rowsPerStrip==-1) assert(0); if (m_rowsPerStrip <= 0) m_rowsPerStrip = m_info.m_ly; int stripSize = m_rowsPerStrip * w * 4; // + 4096; TIFFStripSize(m_tiff); if (bps == 16) stripSize *= 2; m_tmpRas = TRasterGR8P(stripSize, 1); m_tmpRas->lock(); m_stripBuffer = m_tmpRas->getRawData(); m_rowLength = m_info.m_lx; //w; } /* int TIFFTileRowSize(m_tiff); m_rowsPerStrip = 0; if(TIFFGetField(m_tiff, TIFFTAG_ROWSPERSTRIP, &rps) ) { int stripSize = TIFFStripSize(m_tiff); if(stripSize>0) { } } */ if (m_isTzi) { USHORT risCount = 0; USHORT *risArray = 0; if (TIFFGetField(m_tiff, TIFFTAG_TOONZWINDOW, &risCount, &risArray)) { if (m_info.m_lx == risArray[2] && m_info.m_ly == risArray[3]) //se sono diverse, la lettura tif crasha.... { //m_info.m_lx = risArray[2]; //m_info.m_ly = risArray[3]; m_info.m_x0 = risArray[0]; m_info.m_y0 = risArray[1]; } // USHORT extraMask = risArray[4]; //bool isEduFile = risArray[TOONZWINDOW_COUNT - 1] & 1; } else { m_info.m_x0 = 0; m_info.m_y0 = 0; } if (swapxy) { tswap(m_info.m_x0, m_info.m_y0); tswap(m_info.m_lx, m_info.m_ly); } m_info.m_x1 = m_info.m_x0 + w; m_info.m_y1 = m_info.m_y0 + h; } else { m_info.m_x0 = m_info.m_y0 = 0; m_info.m_x1 = m_info.m_x0 + m_info.m_lx - 1; m_info.m_y1 = m_info.m_y0 + m_info.m_ly - 1; } }
static int tiffcp(TIFF* in, TIFF* out) { uint16 bitspersample, samplesperpixel, compression, shortv, *shortav; uint32 w, l; float floatv; char *stringv; uint32 longv; CopyField(TIFFTAG_SUBFILETYPE, longv); CopyField(TIFFTAG_TILEWIDTH, w); CopyField(TIFFTAG_TILELENGTH, l); CopyField(TIFFTAG_IMAGEWIDTH, w); CopyField(TIFFTAG_IMAGELENGTH, l); CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample); CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); CopyField(TIFFTAG_COMPRESSION, compression); if (compression == COMPRESSION_JPEG) { uint32 count = 0; void *table = NULL; if (TIFFGetField(in, TIFFTAG_JPEGTABLES, &count, &table) && count > 0 && table) { TIFFSetField(out, TIFFTAG_JPEGTABLES, count, table); } } CopyField(TIFFTAG_PHOTOMETRIC, shortv); CopyField(TIFFTAG_PREDICTOR, shortv); CopyField(TIFFTAG_THRESHHOLDING, shortv); CopyField(TIFFTAG_FILLORDER, shortv); CopyField(TIFFTAG_ORIENTATION, shortv); CopyField(TIFFTAG_MINSAMPLEVALUE, shortv); CopyField(TIFFTAG_MAXSAMPLEVALUE, shortv); CopyField(TIFFTAG_XRESOLUTION, floatv); CopyField(TIFFTAG_YRESOLUTION, floatv); CopyField(TIFFTAG_GROUP3OPTIONS, longv); CopyField(TIFFTAG_GROUP4OPTIONS, longv); CopyField(TIFFTAG_RESOLUTIONUNIT, shortv); CopyField(TIFFTAG_PLANARCONFIG, shortv); CopyField(TIFFTAG_ROWSPERSTRIP, longv); CopyField(TIFFTAG_XPOSITION, floatv); CopyField(TIFFTAG_YPOSITION, floatv); CopyField(TIFFTAG_IMAGEDEPTH, longv); CopyField(TIFFTAG_TILEDEPTH, longv); CopyField(TIFFTAG_SAMPLEFORMAT, shortv); CopyField2(TIFFTAG_EXTRASAMPLES, shortv, shortav); { uint16 *red, *green, *blue; CopyField3(TIFFTAG_COLORMAP, red, green, blue); } { uint16 shortv2; CopyField2(TIFFTAG_PAGENUMBER, shortv, shortv2); } CopyField(TIFFTAG_ARTIST, stringv); CopyField(TIFFTAG_IMAGEDESCRIPTION, stringv); CopyField(TIFFTAG_MAKE, stringv); CopyField(TIFFTAG_MODEL, stringv); CopyField(TIFFTAG_SOFTWARE, stringv); CopyField(TIFFTAG_DATETIME, stringv); CopyField(TIFFTAG_HOSTCOMPUTER, stringv); CopyField(TIFFTAG_PAGENAME, stringv); CopyField(TIFFTAG_DOCUMENTNAME, stringv); CopyField(TIFFTAG_BADFAXLINES, longv); CopyField(TIFFTAG_CLEANFAXDATA, longv); CopyField(TIFFTAG_CONSECUTIVEBADFAXLINES, longv); CopyField(TIFFTAG_FAXRECVPARAMS, longv); CopyField(TIFFTAG_FAXRECVTIME, longv); CopyField(TIFFTAG_FAXSUBADDRESS, stringv); CopyField(TIFFTAG_FAXDCS, stringv); if (TIFFIsTiled(in)) return (cpTiles(in, out)); else return (cpStrips(in, out)); }
int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ssize_t bytes) { TIFFSTATE *clientstate = (TIFFSTATE *)state->context; char *filename = "tempfile.tif"; char *mode = "r"; TIFF *tiff; /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ TRACE(("in decoder: bytes %d\n", bytes)); TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, state->x, state->y, state->ystep)); TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, state->xoff, state->yoff)); TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes)); TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3])); TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3])); TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n", im->mode, im->type, im->bands, im->xsize, im->ysize)); TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n", im->image8, im->image32, im->image, im->block)); TRACE(("Image: pixelsize: %d, linesize %d \n", im->pixelsize, im->linesize)); dump_state(clientstate); clientstate->size = bytes; clientstate->eof = clientstate->size; clientstate->loc = 0; clientstate->data = (tdata_t)buffer; clientstate->flrealloc = 0; dump_state(clientstate); TIFFSetWarningHandler(NULL); TIFFSetWarningHandlerExt(NULL); if (clientstate->fp) { TRACE(("Opening using fd: %d\n",clientstate->fp)); lseek(clientstate->fp,0,SEEK_SET); // Sometimes, I get it set to the end. tiff = TIFFFdOpen(clientstate->fp, filename, mode); } else { TRACE(("Opening from string\n")); tiff = TIFFClientOpen(filename, mode, (thandle_t) clientstate, _tiffReadProc, _tiffWriteProc, _tiffSeekProc, _tiffCloseProc, _tiffSizeProc, _tiffMapProc, _tiffUnmapProc); } if (!tiff){ TRACE(("Error, didn't get the tiff\n")); state->errcode = IMAGING_CODEC_BROKEN; return -1; } if (clientstate->ifd){ int rv; uint32 ifdoffset = clientstate->ifd; TRACE(("reading tiff ifd %u\n", ifdoffset)); rv = TIFFSetSubDirectory(tiff, ifdoffset); if (!rv){ TRACE(("error in TIFFSetSubDirectory")); return -1; } } if (TIFFIsTiled(tiff)) { UINT32 x, y, tile_y, row_byte_size; UINT32 tile_width, tile_length, current_tile_width; UINT8 *new_data; TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tile_length); // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size row_byte_size = (tile_width * state->bits + 7) / 8; state->bytes = row_byte_size * tile_length; /* overflow check for malloc */ if (state->bytes > INT_MAX - 1) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } /* realloc to fit whole tile */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } state->buffer = new_data; TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { for (x = state->xoff; x < state->xsize; x += tile_width) { if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) { TRACE(("Decode Error, Tile at %dx%d\n", x, y)); state->errcode = IMAGING_CODEC_BROKEN; TIFFClose(tiff); return -1; } TRACE(("Read tile at %dx%d; \n\n", x, y)); current_tile_width = min(tile_width, state->xsize - x); // iterate over each line in the tile and stuff data into image for (tile_y = 0; tile_y < min(tile_length, state->ysize - y); tile_y++) { TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); // UINT8 * bbb = state->buffer + tile_y * row_byte_size; // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize, state->buffer + tile_y * row_byte_size, current_tile_width ); } } } } else { UINT32 strip_row, row_byte_size; UINT8 *new_data; UINT32 rows_per_strip; TIFFGetField(tiff, TIFFTAG_ROWSPERSTRIP, &rows_per_strip); TRACE(("RowsPerStrip: %u \n", rows_per_strip)); // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size row_byte_size = (state->xsize * state->bits + 7) / 8; state->bytes = rows_per_strip * row_byte_size; TRACE(("StripSize: %d \n", state->bytes)); /* realloc to fit whole strip */ new_data = realloc (state->buffer, state->bytes); if (!new_data) { state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; } state->buffer = new_data; for (; state->y < state->ysize; state->y += rows_per_strip) { if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); state->errcode = IMAGING_CODEC_BROKEN; TIFFClose(tiff); return -1; } TRACE(("Decoded strip for row %d \n", state->y)); // iterate over each row in the strip and stuff data into image for (strip_row = 0; strip_row < min(rows_per_strip, state->ysize - state->y); strip_row++) { TRACE(("Writing data into line %d ; \n", state->y + strip_row)); // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] + state->xoff * im->pixelsize, state->buffer + strip_row * row_byte_size, state->xsize); } } } TIFFClose(tiff); TRACE(("Done Decoding, Returning \n")); // Returning -1 here to force ImageFile.load to break, rather than // even think about looping back around. return -1; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(uint32_t)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; uint8_t *bits; //pointer to source data uint8_t *bits2; //pointer to destination data cx_try { //check if it's a tiff file if (!m_tif) cx_throw("Error encountered while opening TIFF file"); // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) cx_throw("Error: page not present in TIFF file"); //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; info.dwType = CXIMAGE_FORMAT_TIF; cx_throw("output dimensions returned"); } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((int32_t)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (int32_t)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (int32_t)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height) { rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = /*(bitspersample >= 8) && (VK: it is possible so for RGB to have < 8 bpp!)*/ (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB) { head.biBitCount=24; } else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)||(photometric==PHOTOMETRIC_PALETTE)) { if (bitspersample == 1) { head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } if ((bitspersample > 8) && (photometric==PHOTOMETRIC_PALETTE)) // + VK + (BIG palette! => convert to RGB) { head.biBitCount=24; head.biClrUsed =0; } } if (info.nEscape) cx_throw("Cancelled"); // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) cx_throw("CxImageTIF can't create image"); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) cx_throw("No space for raster buffer"); // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); cx_throw("Corrupted TIFF file!"); } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape) { // <vho> - cancel decoding _TIFFfree(raster); cx_throw("Cancelled"); } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (uint8_t)TIFFGetB(row[x]); *bits++ = (uint8_t)TIFFGetG(row[x]); *bits++ = (uint8_t)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(uint8_t)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { int32_t BIG_palette = (bitspersample > 8) && // + VK (photometric==PHOTOMETRIC_PALETTE); if (BIG_palette && (bitspersample > 24)) // + VK cx_throw("Too big palette to handle"); // + VK RGBQUAD *pal; pal=(RGBQUAD*)calloc(BIG_palette ? 1<<bitspersample : 256,sizeof(RGBQUAD)); // ! VK: it coasts nothing but more correct to use 256 as temp palette storage // ! VK: but for case of BIG palette it just copied if (pal==NULL) cx_throw("Unable to allocate TIFF palette"); int32_t bpp = bitspersample <= 8 ? bitspersample : 8; // + VK (to use instead of bitspersample for case of > 8) // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (int32_t i=0; i<(1<<bpp); i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(i*(255/((1<<bpp)-1))); } } else { for (int32_t i=0; i<(1<<bpp); i++) { pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (uint8_t)(255-i*(255/((1<<bpp)-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = /*FALSE*/ BIG_palette; if (!BIG_palette) { int32_t n= 1<<bpp; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } } // load the palette in the DIB for (int32_t i = (1 << ( BIG_palette ? bitspersample : bpp )) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(uint8_t) CVT(red[i]); pal[i].rgbGreen = (uint8_t) CVT(green[i]); pal[i].rgbBlue = (uint8_t) CVT(blue[i]); } else { pal[i].rgbRed = (uint8_t) red[i]; pal[i].rgbGreen = (uint8_t) green[i]; pal[i].rgbBlue = (uint8_t) blue[i]; } } break; } if (!BIG_palette) { // + VK (BIG palette is stored until image is ready) SetPalette(pal,/*head.biClrUsed*/ 1<<bpp); //palette assign // * VK free(pal); pal = NULL; } // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int32_t line = CalculateLine(width, bitspersample * samplesperpixel); int32_t bitsize = TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(int32_t)(head.biSizeImage*samplesperpixel)) bitsize = head.biSizeImage*samplesperpixel; if (bitsize<(int32_t)(info.dwEffWidth*rowsperstrip)) bitsize = info.dwEffWidth*rowsperstrip; if ((bitspersample > 8) && (bitspersample != 16)) // + VK (for bitspersample == 9..15,17..32..64 bitsize *= (bitspersample + 7)/8; int32_t tiled_image = TIFFIsTiled(m_tif); uint32 tw=0, tl=0; uint8_t* tilebuf=NULL; if (tiled_image) { TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int32_t)(1+width/tw); tilebuf = (uint8_t*)malloc(TIFFTileSize(m_tif)); } bits = (uint8_t*)malloc(bitspersample==16? bitsize*2 : bitsize); // * VK uint8_t * bits16 = NULL; // + VK int32_t line16 = 0; // + VK if (!tiled_image && bitspersample==16) { // + VK + line16 = line; line = CalculateLine(width, 8 * samplesperpixel); bits16 = bits; bits = (uint8_t*)malloc(bitsize); } if (bits==NULL) { if (bits16) free(bits16); // + VK if (pal) free(pal); // + VK if (tilebuf)free(tilebuf); // + VK cx_throw("CxImageTIF can't allocate memory"); } #ifdef FIX_16BPP_DARKIMG // + VK: for each line, store shift count bits used to fix it uint8_t* row_shifts = NULL; if (bits16) row_shifts = (uint8_t*)malloc(height); #endif for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape) { // <vho> - cancel decoding free(bits); cx_throw("Cancelled"); } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image) { uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int32_t iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0) { free(tilebuf); free(bits); cx_throw("Corrupted tiled TIFF file!"); } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), (bits16? bits16 : bits), nrow * (bits16 ? line16 : line)) == -1) { // * VK #ifdef NOT_IGNORE_CORRUPTED free(bits); if (bits16) free(bits16); // + VK cx_throw("Corrupted TIFF file!"); #else break; #endif } } for (y = 0; y < nrow; y++) { int32_t offset=(nrow-y-1)*line; if ((bitspersample==16) && !BIG_palette) { // * VK int32_t offset16 = (nrow-y-1)*line16; // + VK if (bits16) { // + VK + #ifdef FIX_16BPP_DARKIMG int32_t the_shift; uint8_t hi_byte, hi_max=0; uint32_t xi; for (xi=0; xi<(uint32)line; xi++) { hi_byte = bits16[xi*2+offset16+1]; if(hi_byte>hi_max) hi_max = hi_byte; } the_shift = (hi_max == 0) ? 8 : 0; if (!the_shift) while( ! (hi_max & 0x80) ) { the_shift++; hi_max <<= 1; } row_shifts[height-ys-nrow+y] = the_shift; the_shift = 8 - the_shift; for (xi=0; xi<(uint32)line; xi++) bits[xi+offset]= ((bits16[xi*2+offset16+1]<<8) | bits16[xi*2+offset16]) >> the_shift; #else for (uint32_t xi=0; xi<(uint32)line; xi++) bits[xi+offset]=bits16[xi*2+offset16+1]; #endif } else { for (uint32_t xi=0; xi<width; xi++) bits[xi+offset]=bits[xi*2+offset+1]; } } if (samplesperpixel==1) { if (BIG_palette) if (bits16) { int32_t offset16 = (nrow-y-1)*line16; // + VK MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits16 + offset16, width, bitspersample, pal ); } else MoveBitsPal( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample, pal ); else if ((bitspersample == head.biBitCount) || (bitspersample == 16)) //simple 8bpp, 4bpp image or 16bpp memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,min((unsigned)line, info.dwEffWidth)); else MoveBits( info.pImage + info.dwEffWidth * (height-ys-nrow+y), bits + offset, width, bitspersample ); } else if (samplesperpixel==2) { //8bpp image with alpha layer int32_t xi=0; int32_t ii=0; int32_t yi=height-ys-nrow+y; #if CXIMAGE_SUPPORT_ALPHA if (!pAlpha) AlphaCreate(); // + VK #endif //CXIMAGE_SUPPORT_ALPHA while (ii<line) { SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int32_t)width) { yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24) { //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int32_t xi=0; uint32 ii=0; int32_t yi=height-ys-nrow+y; RGBQUAD c; int32_t l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii</*line*/width) { // * VK bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(uint8_t)max(0,min(255,(int32_t)(cr*255))); c.rgbGreen=(uint8_t)max(0,min(255,(int32_t)(cg*255))); c.rgbBlue =(uint8_t)max(0,min(255,(int32_t)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int32_t)width) { yi--; xi=0; } } } } } free(bits); if (bits16) free(bits16); #ifdef FIX_16BPP_DARKIMG if (row_shifts && (samplesperpixel == 1) && (bitspersample==16) && !BIG_palette) { // 1. calculate maximum necessary shift int32_t min_row_shift = 8; for( y=0; y<height; y++ ) { if (min_row_shift > row_shifts[y]) min_row_shift = row_shifts[y]; } // 2. for rows having less shift value, correct such rows: for( y=0; y<height; y++ ) { if (min_row_shift < row_shifts[y]) { int32_t need_shift = row_shifts[y] - min_row_shift; uint8_t* data = info.pImage + info.dwEffWidth * y; for( x=0; x<width; x++, data++ ) *data >>= need_shift; } }
int read_image_striped(const char *name, uint32 width, uint32 length, uint32 rowsperstrip, uint16 compression, uint16 spp, uint16 bps, uint16 photometric, uint16 sampleformat, uint16 planarconfig, const tdata_t array, const tsize_t size) { TIFF *tif; uint16 value_u16; uint32 value_u32; /* Test whether we can read written values. */ tif = TIFFOpen(name, "r"); if (!tif) goto openfailure; if (TIFFIsTiled(tif)) { fprintf (stderr, "Can't read image %s, it is tiled.\n", name); goto failure; } if (!TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &value_u32) || value_u32 != width) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_IMAGEWIDTH); goto failure; } if (!TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &value_u32) || value_u32 != length) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_IMAGELENGTH); goto failure; } if (!TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &value_u16) || value_u16 != bps) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_BITSPERSAMPLE); goto failure; } if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &value_u16) || value_u16 != photometric) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_PHOTOMETRIC); goto failure; } if (!TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &value_u16) || value_u16 != spp) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_SAMPLESPERPIXEL); goto failure; } if (!TIFFGetField(tif, TIFFTAG_ROWSPERSTRIP, &value_u32) || value_u32 != rowsperstrip) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_ROWSPERSTRIP); goto failure; } if (!TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &value_u16) || value_u16 != planarconfig) { fprintf (stderr, "Can't get tag %d.\n", TIFFTAG_PLANARCONFIG); goto failure; } if (read_strips(tif, array, size) < 0) { fprintf (stderr, "Can't read image data.\n"); goto failure; } TIFFClose(tif); return 0; failure: TIFFClose(tif); openfailure: fprintf (stderr, "Can't read test TIFF file %s:\n" " ImageWidth=%u, ImageLength=%u, RowsPerStrip=%u, Compression=%d,\n" " BitsPerSample=%d, SamplesPerPixel=%d, SampleFormat=%d,\n" " PlanarConfiguration=%d, PhotometricInterpretation=%d.\n", name, width, length, rowsperstrip, compression, bps, spp, sampleformat, planarconfig, photometric); return -1; }
boolean TIFFRasterImpl::gt(u_long w, u_long h) { u_short minsamplevalue; u_short maxsamplevalue; u_short planarconfig; RGBvalue* Map = nil; if (!TIFFGetField(tif_, TIFFTAG_MINSAMPLEVALUE, &minsamplevalue)) { minsamplevalue = 0; } if (!TIFFGetField(tif_, TIFFTAG_MAXSAMPLEVALUE, &maxsamplevalue)) { maxsamplevalue = (1<<bitspersample_)-1; } switch (photometric_) { case PHOTOMETRIC_RGB: if (minsamplevalue == 0 && maxsamplevalue == 255) { break; } /* fall thru... */ case PHOTOMETRIC_MINISBLACK: case PHOTOMETRIC_MINISWHITE: { register int x, range; range = maxsamplevalue - minsamplevalue; Map = new RGBvalue[range + 1]; if (Map == nil) { TIFFError( TIFFFileName(tif_), "No space for photometric conversion table" ); return false; } if (photometric_ == PHOTOMETRIC_MINISWHITE) { for (x = 0; x <= range; x++) { Map[x] = ((range - x) * 255) / range; } } else { for (x = 0; x <= range; x++) { Map[x] = (x * 255) / range; } } if (photometric_ != PHOTOMETRIC_RGB && bitspersample_ != 8) { /* * Use photometric mapping table to construct * unpacking tables for samples < 8 bits. */ if (!makebwmap(Map)) { return false; } delete Map; /* no longer need Map, free it */ Map = nil; } break; } case PHOTOMETRIC_PALETTE: if (!TIFFGetField( tif_, TIFFTAG_COLORMAP, &redcmap_, &greencmap_, &bluecmap_) ) { TIFFError(TIFFFileName(tif_), "Missing required \"Colormap\" tag"); return (false); } /* * Convert 16-bit colormap to 8-bit (unless it looks * like an old-style 8-bit colormap). */ if ( checkcmap( 1 << bitspersample_, redcmap_, greencmap_, bluecmap_ ) == 16 ) { int i; for (i = (1 << bitspersample_) - 1; i > 0; i--) { #define CVT(x) (((x) * 255) / ((1L<<16)-1)) redcmap_[i] = (u_short) CVT(redcmap_[i]); greencmap_[i] = (u_short) CVT(greencmap_[i]); bluecmap_[i] = (u_short) CVT(bluecmap_[i]); } } if (bitspersample_ <= 8) { /* * Use mapping table and colormap to construct * unpacking tables for samples < 8 bits. */ if (!makecmap(redcmap_, greencmap_, bluecmap_)) { return false; } } break; } TIFFGetField(tif_, TIFFTAG_PLANARCONFIG, &planarconfig); boolean e; if (planarconfig == PLANARCONFIG_SEPARATE && samplesperpixel_ > 1) { e = TIFFIsTiled(tif_) ? gtTileSeparate(Map, h, w) : gtStripSeparate(Map, h, w); } else { e = TIFFIsTiled(tif_) ? gtTileContig(Map, h, w) : gtStripContig(Map, h, w); } delete Map; return e; }
TIFFOvrCache *TIFFCreateOvrCache( TIFF *hTIFF, int nDirOffset ) { TIFFOvrCache *psCache; uint32 nBaseDirOffset; psCache = (TIFFOvrCache *) _TIFFmalloc(sizeof(TIFFOvrCache)); psCache->nDirOffset = nDirOffset; psCache->hTIFF = hTIFF; /* -------------------------------------------------------------------- */ /* Get definition of this raster from the TIFF file itself. */ /* -------------------------------------------------------------------- */ nBaseDirOffset = TIFFCurrentDirOffset( psCache->hTIFF ); TIFFSetSubDirectory( hTIFF, nDirOffset ); TIFFGetField( hTIFF, TIFFTAG_IMAGEWIDTH, &(psCache->nXSize) ); TIFFGetField( hTIFF, TIFFTAG_IMAGELENGTH, &(psCache->nYSize) ); TIFFGetField( hTIFF, TIFFTAG_BITSPERSAMPLE, &(psCache->nBitsPerPixel) ); TIFFGetField( hTIFF, TIFFTAG_SAMPLESPERPIXEL, &(psCache->nSamples) ); TIFFGetField( hTIFF, TIFFTAG_PLANARCONFIG, &(psCache->nPlanarConfig) ); if( !TIFFIsTiled( hTIFF ) ) { TIFFGetField( hTIFF, TIFFTAG_ROWSPERSTRIP, &(psCache->nBlockYSize) ); psCache->nBlockXSize = psCache->nXSize; psCache->nBytesPerBlock = TIFFStripSize(hTIFF); psCache->bTiled = FALSE; } else { TIFFGetField( hTIFF, TIFFTAG_TILEWIDTH, &(psCache->nBlockXSize) ); TIFFGetField( hTIFF, TIFFTAG_TILELENGTH, &(psCache->nBlockYSize) ); psCache->nBytesPerBlock = TIFFTileSize(hTIFF); psCache->bTiled = TRUE; } /* -------------------------------------------------------------------- */ /* Compute some values from this. */ /* -------------------------------------------------------------------- */ psCache->nBlocksPerRow = (psCache->nXSize + psCache->nBlockXSize - 1) / psCache->nBlockXSize; psCache->nBlocksPerColumn = (psCache->nYSize + psCache->nBlockYSize - 1) / psCache->nBlockYSize; if (psCache->nPlanarConfig == PLANARCONFIG_SEPARATE) psCache->nBytesPerRow = psCache->nBytesPerBlock * psCache->nBlocksPerRow * psCache->nSamples; else psCache->nBytesPerRow = psCache->nBytesPerBlock * psCache->nBlocksPerRow; /* -------------------------------------------------------------------- */ /* Allocate and initialize the data buffers. */ /* -------------------------------------------------------------------- */ psCache->pabyRow1Blocks = (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); psCache->pabyRow2Blocks = (unsigned char *) _TIFFmalloc(psCache->nBytesPerRow); if( psCache->pabyRow1Blocks == NULL || psCache->pabyRow2Blocks == NULL ) { TIFFErrorExt( hTIFF->tif_clientdata, hTIFF->tif_name, "Can't allocate memory for overview cache." ); /* TODO: use of TIFFError is inconsistent with use of fprintf in addtiffo.c, sort out */ return NULL; } _TIFFmemset( psCache->pabyRow1Blocks, 0, psCache->nBytesPerRow ); _TIFFmemset( psCache->pabyRow2Blocks, 0, psCache->nBytesPerRow ); psCache->nBlockOffset = 0; TIFFSetSubDirectory( psCache->hTIFF, nBaseDirOffset ); return psCache; }
int PS_Lvl2page(FILE* fd, TIFF* tif, uint32 w, uint32 h) { uint16 fillorder; int use_rawdata, tiled_image, breaklen; uint32 chunk_no, num_chunks, *bc; unsigned char *buf_data, *cp; tsize_t chunk_size, byte_count; #if defined( EXP_ASCII85ENCODER ) int ascii85_l; /* Length, in bytes, of ascii85_p[] data */ uint8 * ascii85_p = 0; /* Holds ASCII85 encoded data */ #endif PS_Lvl2colorspace(fd, tif); use_rawdata = PS_Lvl2ImageDict(fd, tif, w, h); fputs("%%BeginData:\n", fd); fputs("exec\n", fd); tiled_image = TIFFIsTiled(tif); if (tiled_image) { num_chunks = TIFFNumberOfTiles(tif); TIFFGetField(tif, TIFFTAG_TILEBYTECOUNTS, &bc); } else { num_chunks = TIFFNumberOfStrips(tif); TIFFGetField(tif, TIFFTAG_STRIPBYTECOUNTS, &bc); } if (use_rawdata) { chunk_size = bc[0]; for (chunk_no = 1; chunk_no < num_chunks; chunk_no++) if (bc[chunk_no] > chunk_size) chunk_size = bc[chunk_no]; } else { if (tiled_image) chunk_size = TIFFTileSize(tif); else chunk_size = TIFFStripSize(tif); } buf_data = (unsigned char *)_TIFFmalloc(chunk_size); if (!buf_data) { TIFFError(filename, "Can't alloc %u bytes for %s.", chunk_size, tiled_image ? "tiles" : "strips"); return(FALSE); } #if defined( EXP_ASCII85ENCODER ) if ( ascii85 ) { /* * Allocate a buffer to hold the ASCII85 encoded data. Note * that it is allocated with sufficient room to hold the * encoded data (5*chunk_size/4) plus the EOD marker (+8) * and formatting line breaks. The line breaks are more * than taken care of by using 6*chunk_size/4 rather than * 5*chunk_size/4. */ ascii85_p = _TIFFmalloc( (chunk_size+(chunk_size/2)) + 8 ); if ( !ascii85_p ) { _TIFFfree( buf_data ); TIFFError( filename, "Cannot allocate ASCII85 encoding buffer." ); return ( FALSE ); } } #endif TIFFGetFieldDefaulted(tif, TIFFTAG_FILLORDER, &fillorder); for (chunk_no = 0; chunk_no < num_chunks; chunk_no++) { if (ascii85) Ascii85Init(); else breaklen = 36; if (use_rawdata) { if (tiled_image) byte_count = TIFFReadRawTile(tif, chunk_no, buf_data, chunk_size); else byte_count = TIFFReadRawStrip(tif, chunk_no, buf_data, chunk_size); if (fillorder == FILLORDER_LSB2MSB) TIFFReverseBits(buf_data, byte_count); } else { if (tiled_image) byte_count = TIFFReadEncodedTile(tif, chunk_no, buf_data, chunk_size); else byte_count = TIFFReadEncodedStrip(tif, chunk_no, buf_data, chunk_size); } if (byte_count < 0) { TIFFError(filename, "Can't read %s %d.", tiled_image ? "tile" : "strip", chunk_no); if (ascii85) Ascii85Put('\0', fd); } if (ascii85) { #if defined( EXP_ASCII85ENCODER ) ascii85_l = Ascii85EncodeBlock(ascii85_p, 1, buf_data, byte_count ); if ( ascii85_l > 0 ) fwrite( ascii85_p, ascii85_l, 1, fd ); #else for (cp = buf_data; byte_count > 0; byte_count--) Ascii85Put(*cp++, fd); #endif } else { for (cp = buf_data; byte_count > 0; byte_count--) { putc(hex[((*cp)>>4)&0xf], fd); putc(hex[(*cp)&0xf], fd); cp++; if (--breaklen <= 0) { putc('\n', fd); breaklen = 36; } } } if ( !ascii85 ) { if ( level2 ) putc( '>', fd ); putc('\n', fd); } #if !defined( EXP_ASCII85ENCODER ) else Ascii85Flush(fd); #endif } #if defined( EXP_ASCII85ENCODER ) if ( ascii85_p ) _TIFFfree( ascii85_p ); #endif _TIFFfree(buf_data); fputs("%%EndData\n", fd); return(TRUE); }
bool TiffDecoder::readData( Mat& img ) { bool result = false; bool color = img.channels() > 1; uchar* data = img.data; int step = img.step; if( m_tif && m_width && m_height ) { TIFF* tif = (TIFF*)m_tif; int tile_width0 = m_width, tile_height0 = 0; int x, y, i; int is_tiled = TIFFIsTiled(tif); if( (!is_tiled && TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 )) || (is_tiled && TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) && TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))) { if( tile_width0 <= 0 ) tile_width0 = m_width; if( tile_height0 <= 0 ) tile_height0 = m_height; AutoBuffer<uchar> _buffer(tile_height0*tile_width0*4); uchar* buffer = _buffer; for( y = 0; y < m_height; y += tile_height0, data += step*tile_height0 ) { int tile_height = tile_height0; if( y + tile_height > m_height ) tile_height = m_height - y; for( x = 0; x < m_width; x += tile_width0 ) { int tile_width = tile_width0, ok; if( x + tile_width > m_width ) tile_width = m_width - x; if( !is_tiled ) ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); else ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); if( !ok ) { close(); return false; } for( i = 0; i < tile_height; i++ ) if( color ) icvCvt_BGRA2BGR_8u_C4C3R( buffer + i*tile_width*4, 0, data + x*3 + step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); else icvCvt_BGRA2Gray_8u_C4C1R( buffer + i*tile_width*4, 0, data + x + step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); } } result = true; } } close(); return result; }
static int PS_Lvl2ImageDict(FILE* fd, TIFF* tif, uint32 w, uint32 h) { int use_rawdata; uint32 tile_width, tile_height; uint16 predictor, minsamplevalue, maxsamplevalue; int repeat_count; char im_h[64], im_x[64], im_y[64]; char * imageOp = "image"; if ( useImagemask && (bitspersample == 1) ) imageOp = "imagemask"; (void)strcpy(im_x, "0"); (void)sprintf(im_y, "%lu", (long) h); (void)sprintf(im_h, "%lu", (long) h); tile_width = w; tile_height = h; if (TIFFIsTiled(tif)) { repeat_count = TIFFNumberOfTiles(tif); TIFFGetField(tif, TIFFTAG_TILEWIDTH, &tile_width); TIFFGetField(tif, TIFFTAG_TILELENGTH, &tile_height); if (tile_width > w || tile_height > h || (w % tile_width) != 0 || (h % tile_height != 0)) { /* * The tiles does not fit image width and height. * Set up a clip rectangle for the image unit square. */ fputs("0 0 1 1 rectclip\n", fd); } if (tile_width < w) { fputs("/im_x 0 def\n", fd); (void)strcpy(im_x, "im_x neg"); } if (tile_height < h) { fputs("/im_y 0 def\n", fd); (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h); } } else { repeat_count = tf_numberstrips; tile_height = tf_rowsperstrip; if (tile_height > h) tile_height = h; if (repeat_count > 1) { fputs("/im_y 0 def\n", fd); fprintf(fd, "/im_h %lu def\n", (unsigned long) tile_height); (void)strcpy(im_h, "im_h"); (void)sprintf(im_y, "%lu im_y sub", (unsigned long) h); } } /* * Output start of exec block */ fputs("{ % exec\n", fd); if (repeat_count > 1) fprintf(fd, "%d { %% repeat\n", repeat_count); /* * Output filter options and image dictionary. */ if (ascii85) fputs(" /im_stream currentfile /ASCII85Decode filter def\n", fd); fputs(" <<\n", fd); fputs(" /ImageType 1\n", fd); fprintf(fd, " /Width %lu\n", (unsigned long) tile_width); fprintf(fd, " /Height %lu\n", (unsigned long) tile_height); if (planarconfiguration == PLANARCONFIG_SEPARATE && samplesperpixel > 1) fputs(" /MultipleDataSources true\n", fd); fprintf(fd, " /ImageMatrix [ %lu 0 0 %ld %s %s ]\n", (unsigned long) w, - (long)h, im_x, im_y); fprintf(fd, " /BitsPerComponent %d\n", bitspersample); fprintf(fd, " /Interpolate %s\n", interpolate ? "true" : "false"); switch (samplesperpixel) { case 1: switch (photometric) { case PHOTOMETRIC_MINISBLACK: fputs(" /Decode [0 1]\n", fd); break; case PHOTOMETRIC_MINISWHITE: switch (compression) { case COMPRESSION_CCITTRLE: case COMPRESSION_CCITTRLEW: case COMPRESSION_CCITTFAX3: case COMPRESSION_CCITTFAX4: /* * Manage inverting with /Blackis1 flag * since there migth be uncompressed parts */ fputs(" /Decode [0 1]\n", fd); break; default: /* * ERROR... */ fputs(" /Decode [1 0]\n", fd); break; } break; case PHOTOMETRIC_PALETTE: TIFFGetFieldDefaulted(tif, TIFFTAG_MINSAMPLEVALUE, &minsamplevalue); TIFFGetFieldDefaulted(tif, TIFFTAG_MAXSAMPLEVALUE, &maxsamplevalue); fprintf(fd, " /Decode [%u %u]\n", minsamplevalue, maxsamplevalue); break; default: /* * ERROR ? */ fputs(" /Decode [0 1]\n", fd); break; } break; case 3: switch (photometric) { case PHOTOMETRIC_RGB: fputs(" /Decode [0 1 0 1 0 1]\n", fd); break; case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: default: /* * ERROR?? */ fputs(" /Decode [0 1 0 1 0 1]\n", fd); break; } break; case 4: /* * ERROR?? */ fputs(" /Decode [0 1 0 1 0 1 0 1]\n", fd); break; } fputs(" /DataSource", fd); if (planarconfiguration == PLANARCONFIG_SEPARATE && samplesperpixel > 1) fputs(" [", fd); if (ascii85) fputs(" im_stream", fd); else fputs(" currentfile /ASCIIHexDecode filter", fd); use_rawdata = TRUE; switch (compression) { case COMPRESSION_NONE: /* 1: uncompressed */ break; case COMPRESSION_CCITTRLE: /* 2: CCITT modified Huffman RLE */ case COMPRESSION_CCITTRLEW: /* 32771: #1 w/ word alignment */ case COMPRESSION_CCITTFAX3: /* 3: CCITT Group 3 fax encoding */ case COMPRESSION_CCITTFAX4: /* 4: CCITT Group 4 fax encoding */ fputs("\n\t<<\n", fd); if (compression == COMPRESSION_CCITTFAX3) { uint32 g3_options; fputs("\t /EndOfLine true\n", fd); fputs("\t /EndOfBlock false\n", fd); if (!TIFFGetField(tif, TIFFTAG_GROUP3OPTIONS, &g3_options)) g3_options = 0; if (g3_options & GROUP3OPT_2DENCODING) fprintf(fd, "\t /K %s\n", im_h); if (g3_options & GROUP3OPT_UNCOMPRESSED) fputs("\t /Uncompressed true\n", fd); if (g3_options & GROUP3OPT_FILLBITS) fputs("\t /EncodedByteAlign true\n", fd); } if (compression == COMPRESSION_CCITTFAX4) { uint32 g4_options; fputs("\t /K -1\n", fd); TIFFGetFieldDefaulted(tif, TIFFTAG_GROUP4OPTIONS, &g4_options); if (g4_options & GROUP4OPT_UNCOMPRESSED) fputs("\t /Uncompressed true\n", fd); } if (!(tile_width == w && w == 1728U)) fprintf(fd, "\t /Columns %lu\n", (unsigned long) tile_width); fprintf(fd, "\t /Rows %s\n", im_h); if (compression == COMPRESSION_CCITTRLE || compression == COMPRESSION_CCITTRLEW) { fputs("\t /EncodedByteAlign true\n", fd); fputs("\t /EndOfBlock false\n", fd); } if (photometric == PHOTOMETRIC_MINISBLACK) fputs("\t /BlackIs1 true\n", fd); fprintf(fd, "\t>> /CCITTFaxDecode filter"); break; case COMPRESSION_LZW: /* 5: Lempel-Ziv & Welch */ TIFFGetFieldDefaulted(tif, TIFFTAG_PREDICTOR, &predictor); if (predictor == 2) { fputs("\n\t<<\n", fd); fprintf(fd, "\t /Predictor %u\n", predictor); fprintf(fd, "\t /Columns %lu\n", (unsigned long) tile_width); fprintf(fd, "\t /Colors %u\n", samplesperpixel); fprintf(fd, "\t /BitsPerComponent %u\n", bitspersample); fputs("\t>>", fd); } fputs(" /LZWDecode filter", fd); break; case COMPRESSION_PACKBITS: /* 32773: Macintosh RLE */ fputs(" /RunLengthDecode filter", fd); use_rawdata = TRUE; break; case COMPRESSION_OJPEG: /* 6: !6.0 JPEG */ case COMPRESSION_JPEG: /* 7: %JPEG DCT compression */ #ifdef notdef /* * Code not tested yet */ fputs(" /DCTDecode filter", fd); use_rawdata = TRUE; #else use_rawdata = FALSE; #endif break; case COMPRESSION_NEXT: /* 32766: NeXT 2-bit RLE */ case COMPRESSION_THUNDERSCAN: /* 32809: ThunderScan RLE */ case COMPRESSION_PIXARFILM: /* 32908: Pixar companded 10bit LZW */ case COMPRESSION_DEFLATE: /* 32946: Deflate compression */ case COMPRESSION_JBIG: /* 34661: ISO JBIG */ use_rawdata = FALSE; break; case COMPRESSION_SGILOG: /* 34676: SGI LogL or LogLuv */ case COMPRESSION_SGILOG24: /* 34677: SGI 24-bit LogLuv */ use_rawdata = FALSE; break; default: /* * ERROR... */ use_rawdata = FALSE; break; } if (planarconfiguration == PLANARCONFIG_SEPARATE && samplesperpixel > 1) { uint16 i; /* * NOTE: This code does not work yet... */ for (i = 1; i < samplesperpixel; i++) fputs(" dup", fd); fputs(" ]", fd); } fprintf( fd, "\n >> %s\n", imageOp ); if (ascii85) fputs(" im_stream status { im_stream flushfile } if\n", fd); if (repeat_count > 1) { if (tile_width < w) { fprintf(fd, " /im_x im_x %lu add def\n", (unsigned long) tile_width); if (tile_height < h) { fprintf(fd, " im_x %lu ge {\n", (unsigned long) w); fputs(" /im_x 0 def\n", fd); fprintf(fd, " /im_y im_y %lu add def\n", (unsigned long) tile_height); fputs(" } if\n", fd); } } if (tile_height < h) { if (tile_width >= w) { fprintf(fd, " /im_y im_y %lu add def\n", (unsigned long) tile_height); if (!TIFFIsTiled(tif)) { fprintf(fd, " /im_h %lu im_y sub", (unsigned long) h); fprintf(fd, " dup %lu gt { pop", (unsigned long) tile_height); fprintf(fd, " %lu } if def\n", (unsigned long) tile_height); } } } fputs("} repeat\n", fd); } /* * End of exec function */ fputs("}\n", fd); return(use_rawdata); }
static int tiffcp(TIFF* in, TIFF* out) { uint16 bitspersample, samplesperpixel, shortv; copyFunc cf; uint32 w, l; CopyField(TIFFTAG_IMAGEWIDTH, w); CopyField(TIFFTAG_IMAGELENGTH, l); if( convert_8_to_4 ) { TIFFSetField(out, TIFFTAG_BITSPERSAMPLE, 4); } else { CopyField(TIFFTAG_BITSPERSAMPLE, bitspersample); } if (compression != (uint16)-1) TIFFSetField(out, TIFFTAG_COMPRESSION, compression); else CopyField(TIFFTAG_COMPRESSION, compression); if (compression == COMPRESSION_JPEG && jpegcolormode == JPEGCOLORMODE_RGB) TIFFSetField(out, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_YCBCR); else CopyField(TIFFTAG_PHOTOMETRIC, shortv); if (fillorder != 0) TIFFSetField(out, TIFFTAG_FILLORDER, fillorder); else CopyField(TIFFTAG_FILLORDER, shortv); CopyField(TIFFTAG_SAMPLESPERPIXEL, samplesperpixel); /* * Choose tiles/strip for the output image according to * the command line arguments (-tiles, -strips) and the * structure of the input image. */ if (outtiled == -1) outtiled = TIFFIsTiled(in); if (outtiled) { /* * Setup output file's tile width&height. If either * is not specified, use either the value from the * input image or, if nothing is defined, use the * library default. */ if (tilewidth == (uint32) -1) TIFFGetField(in, TIFFTAG_TILEWIDTH, &tilewidth); if (tilelength == (uint32) -1) TIFFGetField(in, TIFFTAG_TILELENGTH, &tilelength); TIFFDefaultTileSize(out, &tilewidth, &tilelength); TIFFSetField(out, TIFFTAG_TILEWIDTH, tilewidth); TIFFSetField(out, TIFFTAG_TILELENGTH, tilelength); } else { /* * RowsPerStrip is left unspecified: use either the * value from the input image or, if nothing is defined, * use the library default. */ if (rowsperstrip == (uint32) -1) TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); rowsperstrip = TIFFDefaultStripSize(out, rowsperstrip); TIFFSetField(out, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } if (config != (uint16) -1) TIFFSetField(out, TIFFTAG_PLANARCONFIG, config); else CopyField(TIFFTAG_PLANARCONFIG, config); if (g3opts != (uint32) -1) TIFFSetField(out, TIFFTAG_GROUP3OPTIONS, g3opts); else CopyField(TIFFTAG_GROUP3OPTIONS, g3opts); if (samplesperpixel <= 4) { uint16 *tr, *tg, *tb, *ta; CopyField4(TIFFTAG_TRANSFERFUNCTION, tr, tg, tb, ta); } { uint16 *red, *green, *blue; if (TIFFGetField(in, TIFFTAG_COLORMAP, &red, &green, &blue)) { CheckAndCorrectColormap(in, 1<<bitspersample, red, green, blue); TIFFSetField(out, TIFFTAG_COLORMAP, red, green, blue); } } /* SMinSampleValue & SMaxSampleValue */ switch (compression) { case COMPRESSION_JPEG: TIFFSetField(out, TIFFTAG_JPEGQUALITY, quality); TIFFSetField(out, TIFFTAG_JPEGCOLORMODE, jpegcolormode); break; case COMPRESSION_LZW: case COMPRESSION_DEFLATE: if (predictor != (uint16)-1) TIFFSetField(out, TIFFTAG_PREDICTOR, predictor); else CopyField(TIFFTAG_PREDICTOR, predictor); break; } cpOtherTags(in, out); if (geofile || proj4_string ) InstallGeoTIFF(out); else CopyGeoTIFF(in,out); if( worldfile ) ApplyWorldFile( worldfile, out); cf = pickCopyFunc(in, out, bitspersample, samplesperpixel); return (cf ? (*cf)(in, out, l, w, samplesperpixel) : FALSE); }
int vglPrintTiffInfo(char* inFilename, char* msg){ if (msg){ printf("====== %s:\n", msg); } else { printf("====== vglPrintTiffInfo:\n"); } TIFF* tif = TIFFOpen(inFilename, "r"); if (tif == NULL){ fprintf(stderr, "%s:%s: Error: File %s not found.\n", __FILE__, __FUNCTION__, inFilename); return 1; } if (tif) { uint32 w, h; uint16 bps, spp, photo, config, pageNumber, numberPages; uint32 subfileType; tdir_t dirCount; tstrip_t stripMax; tstrip_t istrip; tsize_t stripSize; tsize_t npixels; tsize_t pixelSize; tdata_t raster; tsize_t result, offset; char* rasterc; uint32 iw, ih; int i; do{ TIFFPrintDirectory(tif, stdout, 255); } while(TIFFReadDirectory(tif)); printf("TIFFScanlineSize = %ld\n", (long int) TIFFScanlineSize(tif)); printf("TIFFRasterScanlineSize = %ld\n", (long int) TIFFRasterScanlineSize(tif)); printf("TIFFStripSize = %ld\n", (long int) TIFFStripSize(tif)); printf("TIFFNumberOfStrips = %d\n", TIFFNumberOfStrips(tif)); printf("TIFFVStripSize = %ld\n", (long int) TIFFVStripSize(tif,0)); printf("TIFFTileRowSize = %ld\n", (long int) TIFFTileRowSize(tif)); printf("TIFFTileSize = %ld\n", (long int) TIFFTileSize(tif)); printf("TIFFNumberOfTiles = %d\n", TIFFNumberOfTiles(tif)); printf("TIFFVTileSize = %ld\n", (long int) TIFFVTileSize(tif,0)); printf("TIFFDefaultStripSize = %d\n", TIFFDefaultStripSize(tif,0)); printf("TIFFFileno = %d\n", TIFFFileno(tif)); printf("TIFFGetMode = %d\n", TIFFGetMode(tif)); printf("TIFFIsTiled = %d\n", TIFFIsTiled(tif)); printf("TIFFIsByteSwapped = %d\n", TIFFIsByteSwapped(tif)); printf("TIFFRGBAImageOK = %d\n", TIFFRGBAImageOK(tif, (char*)"TIFFRGBAImageOK mesg\n")); TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &h); TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bps); TIFFGetField(tif, TIFFTAG_SAMPLESPERPIXEL, &spp); TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &photo); TIFFGetField(tif, TIFFTAG_PLANARCONFIG, &config); TIFFGetField(tif, TIFFTAG_PAGENUMBER, &pageNumber, &numberPages); TIFFGetField(tif, TIFFTAG_SUBFILETYPE, &subfileType); stripSize = TIFFStripSize(tif); stripMax = TIFFNumberOfStrips(tif); switch(bps){ case 8: pixelSize = 1; break; case 16: pixelSize = 2; break; default: pixelSize = 0; break; } dirCount = tif_DirCount(tif); printf("size = %lu, w = %d, h = %d, spp = %d, bps = %d, pixelSize = %ld\n", sizeof(w), w, h, spp, bps, (long int) pixelSize); printf("Page Number = %d\n", pageNumber); printf("Number Pages = %d\n", numberPages); printf("Photometric interpretation = %d\n", photo); printf("Planar configuration = %d\n", config); printf("stripSize = %ld, stripMax = %d\n", (long int) stripSize, stripMax); printf("Number of directories = %d\n", dirCount); printf("Subfile type = %d\n", subfileType); //printbin((char*)&w, sizeof(w)); //printbin((char*)&h, sizeof(h)); //raster = tif_ReadData(tif); //tif_PrintAsc(tif, raster, (char*)"ascimg.txt"); TIFFClose(tif); } return 0; }
void TIFF_ProcessFullResBlock( TIFF *hTIFF, int nPlanarConfig, int nOverviews, int * panOvList, int nBitsPerPixel, int nSamples, TIFFOvrCache ** papoRawBIs, int nSXOff, int nSYOff, unsigned char *pabySrcTile, int nBlockXSize, int nBlockYSize, int nSampleFormat, const char * pszResampling ) { int iOverview, iSample; for( iSample = 0; iSample < nSamples; iSample++ ) { /* * We have to read a tile/strip for each sample for * PLANARCONFIG_SEPARATE. Otherwise, we just read all the samples * at once when handling the first sample. */ if( nPlanarConfig == PLANARCONFIG_SEPARATE || iSample == 0 ) { if( TIFFIsTiled(hTIFF) ) { TIFFReadEncodedTile( hTIFF, TIFFComputeTile(hTIFF, nSXOff, nSYOff, 0, iSample ), pabySrcTile, TIFFTileSize(hTIFF)); } else { TIFFReadEncodedStrip( hTIFF, TIFFComputeStrip(hTIFF, nSYOff, iSample), pabySrcTile, TIFFStripSize(hTIFF) ); } } /* * Loop over destination overview layers */ for( iOverview = 0; iOverview < nOverviews; iOverview++ ) { TIFFOvrCache *poRBI = papoRawBIs[iOverview]; unsigned char *pabyOTile; int nTXOff, nTYOff, nOXOff, nOYOff, nOMult; int nOBlockXSize = poRBI->nBlockXSize; int nOBlockYSize = poRBI->nBlockYSize; int nSkewBits, nSampleByteOffset; /* * Fetch the destination overview tile */ nOMult = panOvList[iOverview]; nOXOff = (nSXOff/nOMult) / nOBlockXSize; nOYOff = (nSYOff/nOMult) / nOBlockYSize; pabyOTile = TIFFGetOvrBlock( poRBI, nOXOff, nOYOff, iSample ); /* * Establish the offset into this tile at which we should * start placing data. */ nTXOff = (nSXOff - nOXOff*nOMult*nOBlockXSize) / nOMult; nTYOff = (nSYOff - nOYOff*nOMult*nOBlockYSize) / nOMult; /* * Figure out the skew (extra space between ``our samples'') and * the byte offset to the first sample. */ assert( (nBitsPerPixel % 8) == 0 ); if( nPlanarConfig == PLANARCONFIG_SEPARATE ) { nSkewBits = 0; nSampleByteOffset = 0; } else { nSkewBits = nBitsPerPixel * (nSamples-1); nSampleByteOffset = (nBitsPerPixel/8) * iSample; } /* * Perform the downsampling. */ #ifdef DBMALLOC malloc_chain_check( 1 ); #endif TIFF_DownSample( pabySrcTile + nSampleByteOffset, nBlockXSize, nBlockYSize, nSkewBits, nBitsPerPixel, pabyOTile, poRBI->nBlockXSize, poRBI->nBlockYSize, nTXOff, nTYOff, nOMult, nSampleFormat, pszResampling ); #ifdef DBMALLOC malloc_chain_check( 1 ); #endif } } }
bool _openslide_try_aperio(openslide_t *osr, TIFF *tiff, struct _openslide_hash *quickhash1, GError **err) { int32_t level_count = 0; int32_t *levels = NULL; int32_t i = 0; if (!TIFFIsTiled(tiff)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FORMAT_NOT_SUPPORTED, "TIFF is not tiled"); goto FAIL; } char *tagval; int tiff_result; tiff_result = TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &tagval); if (!tiff_result || (strncmp(APERIO_DESCRIPTION, tagval, strlen(APERIO_DESCRIPTION)) != 0)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_FORMAT_NOT_SUPPORTED, "Not an Aperio slide"); goto FAIL; } /* * http://www.aperio.com/documents/api/Aperio_Digital_Slides_and_Third-party_data_interchange.pdf * page 14: * * The first image in an SVS file is always the baseline image (full * resolution). This image is always tiled, usually with a tile size * of 240 x 240 pixels. The second image is always a thumbnail, * typically with dimensions of about 1024 x 768 pixels. Unlike the * other slide images, the thumbnail image is always * stripped. Following the thumbnail there may be one or more * intermediate "pyramid" images. These are always compressed with * the same type of compression as the baseline image, and have a * tiled organization with the same tile size. * * Optionally at the end of an SVS file there may be a slide label * image, which is a low resolution picture taken of the slide’s * label, and/or a macro camera image, which is a low resolution * picture taken of the entire slide. The label and macro images are * always stripped. */ // for aperio, the tiled directories are the ones we want do { if (TIFFIsTiled(tiff)) { level_count++; } } while (TIFFReadDirectory(tiff)); levels = g_new(int32_t, level_count); TIFFSetDirectory(tiff, 0); i = 0; do { tdir_t dir = TIFFCurrentDirectory(tiff); if (TIFFIsTiled(tiff)) { levels[i++] = dir; //g_debug("tiled directory: %d", dir); } else { // associated image const char *name = (dir == 1) ? "thumbnail" : NULL; if (!add_associated_image(osr ? osr->associated_images : NULL, name, tiff, err)) { g_prefix_error(err, "Can't read associated image: "); goto FAIL; } //g_debug("associated image: %d", dir); } // check depth uint32_t depth; tiff_result = TIFFGetField(tiff, TIFFTAG_IMAGEDEPTH, &depth); if (tiff_result && depth != 1) { // we can't handle depth != 1 g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Cannot handle ImageDepth=%d", depth); goto FAIL; } // check compression uint16_t compression; if (!TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Can't read compression scheme"); goto FAIL; } if ((compression != APERIO_COMPRESSION_JP2K_YCBCR) && (compression != APERIO_COMPRESSION_JP2K_RGB) && !TIFFIsCODECConfigured(compression)) { g_set_error(err, OPENSLIDE_ERROR, OPENSLIDE_ERROR_BAD_DATA, "Unsupported TIFF compression: %u", compression); goto FAIL; } } while (TIFFReadDirectory(tiff)); // read properties if (osr) { TIFFSetDirectory(tiff, 0); TIFFGetField(tiff, TIFFTAG_IMAGEDESCRIPTION, &tagval); // XXX? should be safe, we just did it char **props = g_strsplit(tagval, "|", -1); add_properties(osr->properties, props); g_strfreev(props); } // special jpeg 2000 aperio thing (with fallback) _openslide_add_tiff_ops(osr, tiff, 0, 0, NULL, level_count, levels, aperio_tiff_tilereader, quickhash1); return true; FAIL: g_free(levels); return false; }
/** * Loads a TIFF file. * * * \param mem: Memory containing the TIFF file. * \param size: Size of the mem buffer. * \param flags: If flags has IB_test set then the file is not actually loaded, * but all other operations take place. * * \return: A newly allocated ImBuf structure if successful, otherwise NULL. */ ImBuf *imb_loadtiff(unsigned char *mem, size_t size, int flags, char colorspace[IM_MAX_SPACE]) { TIFF *image = NULL; ImBuf *ibuf = NULL, *hbuf; ImbTIFFMemFile memFile; uint32 width, height; char *format = NULL; int level; short spp; int ib_depth; /* check whether or not we have a TIFF file */ if (size < IMB_TIFF_NCB) { fprintf(stderr, "imb_loadtiff: size < IMB_TIFF_NCB\n"); return NULL; } if (imb_is_a_tiff(mem) == 0) return NULL; /* both 8 and 16 bit PNGs are default to standard byte colorspace */ colorspace_set_default_role(colorspace, IM_MAX_SPACE, COLOR_ROLE_DEFAULT_BYTE); image = imb_tiff_client_open(&memFile, mem, size); if (image == NULL) { printf("imb_loadtiff: could not open TIFF IO layer.\n"); return NULL; } /* allocate the image buffer */ TIFFGetField(image, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(image, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(image, TIFFTAG_SAMPLESPERPIXEL, &spp); ib_depth = (spp == 3) ? 24 : 32; ibuf = IMB_allocImBuf(width, height, ib_depth, 0); if (ibuf) { ibuf->ftype = TIF; } else { fprintf(stderr, "imb_loadtiff: could not allocate memory for TIFF " "image.\n"); TIFFClose(image); return NULL; } /* get alpha mode from file header */ if (flags & IB_alphamode_detect) { if (spp == 4) { unsigned short extra, *extraSampleTypes; TIFFGetField(image, TIFFTAG_EXTRASAMPLES, &extra, &extraSampleTypes); if (extraSampleTypes[0] == EXTRASAMPLE_ASSOCALPHA) ibuf->flags |= IB_alphamode_premul; } } /* if testing, we're done */ if (flags & IB_test) { TIFFClose(image); return ibuf; } /* detect if we are reading a tiled/mipmapped texture, in that case * we don't read pixels but leave it to the cache to load tiles */ if (flags & IB_tilecache) { format = NULL; TIFFGetField(image, TIFFTAG_PIXAR_TEXTUREFORMAT, &format); if (format && strcmp(format, "Plain Texture") == 0 && TIFFIsTiled(image)) { int numlevel = TIFFNumberOfDirectories(image); /* create empty mipmap levels in advance */ for (level = 0; level < numlevel; level++) { if (!TIFFSetDirectory(image, level)) break; if (level > 0) { width = (width > 1) ? width / 2 : 1; height = (height > 1) ? height / 2 : 1; hbuf = IMB_allocImBuf(width, height, 32, 0); hbuf->miplevel = level; hbuf->ftype = ibuf->ftype; ibuf->mipmap[level - 1] = hbuf; } else hbuf = ibuf; hbuf->flags |= IB_tilecache; TIFFGetField(image, TIFFTAG_TILEWIDTH, &hbuf->tilex); TIFFGetField(image, TIFFTAG_TILELENGTH, &hbuf->tiley); hbuf->xtiles = ceil(hbuf->x / (float)hbuf->tilex); hbuf->ytiles = ceil(hbuf->y / (float)hbuf->tiley); imb_addtilesImBuf(hbuf); ibuf->miptot++; } } } /* read pixels */ if (!(ibuf->flags & IB_tilecache) && !imb_read_tiff_pixels(ibuf, image)) { fprintf(stderr, "imb_loadtiff: Failed to read tiff image.\n"); TIFFClose(image); return NULL; } /* close the client layer interface to the in-memory file */ TIFFClose(image); /* return successfully */ return ibuf; }
void TIFFInput::readspec (bool read_meta) { uint32 width = 0, height = 0, depth = 0; unsigned short nchans = 1; TIFFGetField (m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField (m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetFieldDefaulted (m_tif, TIFFTAG_IMAGEDEPTH, &depth); TIFFGetFieldDefaulted (m_tif, TIFFTAG_SAMPLESPERPIXEL, &nchans); if (read_meta) { // clear the whole m_spec and start fresh m_spec = ImageSpec ((int)width, (int)height, (int)nchans); } else { // assume m_spec is valid, except for things that might differ // between MIP levels m_spec.width = (int)width; m_spec.height = (int)height; m_spec.depth = (int)depth; m_spec.full_x = 0; m_spec.full_y = 0; m_spec.full_z = 0; m_spec.full_width = (int)width; m_spec.full_height = (int)height; m_spec.full_depth = (int)depth; m_spec.nchannels = (int)nchans; } float x = 0, y = 0; TIFFGetField (m_tif, TIFFTAG_XPOSITION, &x); TIFFGetField (m_tif, TIFFTAG_YPOSITION, &y); m_spec.x = (int)x; m_spec.y = (int)y; m_spec.z = 0; // FIXME? - TIFF spec describes the positions as in resolutionunit. // What happens if this is not unitless pixels? Are we interpreting // it all wrong? if (TIFFGetField (m_tif, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &width) == 1 && width > 0) m_spec.full_width = width; if (TIFFGetField (m_tif, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &height) == 1 && height > 0) m_spec.full_height = height; if (TIFFIsTiled (m_tif)) { TIFFGetField (m_tif, TIFFTAG_TILEWIDTH, &m_spec.tile_width); TIFFGetField (m_tif, TIFFTAG_TILELENGTH, &m_spec.tile_height); TIFFGetFieldDefaulted (m_tif, TIFFTAG_TILEDEPTH, &m_spec.tile_depth); } else { m_spec.tile_width = 0; m_spec.tile_height = 0; m_spec.tile_depth = 0; } m_bitspersample = 8; TIFFGetField (m_tif, TIFFTAG_BITSPERSAMPLE, &m_bitspersample); m_spec.attribute ("oiio:BitsPerSample", (int)m_bitspersample); unsigned short sampleformat = SAMPLEFORMAT_UINT; TIFFGetFieldDefaulted (m_tif, TIFFTAG_SAMPLEFORMAT, &sampleformat); switch (m_bitspersample) { case 1: case 2: case 4: case 6: // Make 1, 2, 4, 6 bpp look like byte images case 8: if (sampleformat == SAMPLEFORMAT_UINT) m_spec.set_format (TypeDesc::UINT8); else if (sampleformat == SAMPLEFORMAT_INT) m_spec.set_format (TypeDesc::INT8); else m_spec.set_format (TypeDesc::UINT8); // punt break; case 10: case 12: case 14: // Make 10, 12, 14 bpp look like 16 bit images case 16: if (sampleformat == SAMPLEFORMAT_UINT) m_spec.set_format (TypeDesc::UINT16); else if (sampleformat == SAMPLEFORMAT_INT) m_spec.set_format (TypeDesc::INT16); else if (sampleformat == SAMPLEFORMAT_IEEEFP) m_spec.set_format (TypeDesc::HALF); // not to spec, but why not? else m_spec.set_format (TypeDesc::UNKNOWN); break; case 32: if (sampleformat == SAMPLEFORMAT_IEEEFP) m_spec.set_format (TypeDesc::FLOAT); else if (sampleformat == SAMPLEFORMAT_UINT) m_spec.set_format (TypeDesc::UINT32); else if (sampleformat == SAMPLEFORMAT_INT) m_spec.set_format (TypeDesc::INT32); else m_spec.set_format (TypeDesc::UNKNOWN); break; case 64: if (sampleformat == SAMPLEFORMAT_IEEEFP) m_spec.set_format (TypeDesc::DOUBLE); else m_spec.set_format (TypeDesc::UNKNOWN); break; default: m_spec.set_format (TypeDesc::UNKNOWN); break; } // If we've been instructed to skip reading metadata, because it is // guaranteed to be identical to what we already have in m_spec, // skip everything following. if (! read_meta) return; // Use the table for all the obvious things that can be mindlessly // shoved into the image spec. for (int i = 0; tiff_tag_table[i].name; ++i) find_tag (tiff_tag_table[i].tifftag, tiff_tag_table[i].tifftype, tiff_tag_table[i].name); // Now we need to get fields "by hand" for anything else that is less // straightforward... m_photometric = (m_spec.nchannels == 1 ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); TIFFGetField (m_tif, TIFFTAG_PHOTOMETRIC, &m_photometric); m_spec.attribute ("tiff:PhotometricInterpretation", (int)m_photometric); if (m_photometric == PHOTOMETRIC_PALETTE) { // Read the color map unsigned short *r = NULL, *g = NULL, *b = NULL; TIFFGetField (m_tif, TIFFTAG_COLORMAP, &r, &g, &b); ASSERT (r != NULL && g != NULL && b != NULL); m_colormap.clear (); m_colormap.insert (m_colormap.end(), r, r + (1 << m_bitspersample)); m_colormap.insert (m_colormap.end(), g, g + (1 << m_bitspersample)); m_colormap.insert (m_colormap.end(), b, b + (1 << m_bitspersample)); // Palette TIFF images are always 3 channels (to the client) m_spec.nchannels = 3; m_spec.default_channel_names (); // FIXME - what about palette + extra (alpha?) channels? Is that // allowed? And if so, ever encountered in the wild? } TIFFGetFieldDefaulted (m_tif, TIFFTAG_PLANARCONFIG, &m_planarconfig); m_separate = (m_planarconfig == PLANARCONFIG_SEPARATE && m_spec.nchannels > 1 && m_photometric != PHOTOMETRIC_PALETTE); m_spec.attribute ("tiff:PlanarConfiguration", (int)m_planarconfig); if (m_planarconfig == PLANARCONFIG_SEPARATE) m_spec.attribute ("planarconfig", "separate"); else m_spec.attribute ("planarconfig", "contig"); int compress = 0; TIFFGetFieldDefaulted (m_tif, TIFFTAG_COMPRESSION, &compress); m_spec.attribute ("tiff:Compression", compress); switch (compress) { case COMPRESSION_NONE : m_spec.attribute ("compression", "none"); break; case COMPRESSION_LZW : m_spec.attribute ("compression", "lzw"); break; case COMPRESSION_CCITTRLE : m_spec.attribute ("compression", "ccittrle"); break; case COMPRESSION_DEFLATE : case COMPRESSION_ADOBE_DEFLATE : m_spec.attribute ("compression", "zip"); break; case COMPRESSION_PACKBITS : m_spec.attribute ("compression", "packbits"); break; default: break; } int rowsperstrip = -1; if (! m_spec.tile_width) { TIFFGetField (m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); if (rowsperstrip > 0) m_spec.attribute ("tiff:RowsPerStrip", rowsperstrip); } // The libtiff docs say that only uncompressed images, or those with // rowsperstrip==1, support random access to scanlines. m_no_random_access = (compress != COMPRESSION_NONE && rowsperstrip != 1); short resunit = -1; TIFFGetField (m_tif, TIFFTAG_RESOLUTIONUNIT, &resunit); switch (resunit) { case RESUNIT_NONE : m_spec.attribute ("ResolutionUnit", "none"); break; case RESUNIT_INCH : m_spec.attribute ("ResolutionUnit", "in"); break; case RESUNIT_CENTIMETER : m_spec.attribute ("ResolutionUnit", "cm"); break; } get_matrix_attribute ("worldtocamera", TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA); get_matrix_attribute ("worldtoscreen", TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN); get_int_attribute ("tiff:subfiletype", TIFFTAG_SUBFILETYPE); // FIXME -- should subfiletype be "conventionized" and used for all // plugins uniformly? // Do we care about fillorder? No, the TIFF spec says, "We // recommend that FillOrder=2 (lsb-to-msb) be used only in // special-purpose applications". So OIIO will assume msb-to-lsb // convention until somebody finds a TIFF file in the wild that // breaks this assumption. // Special names for shadow maps char *s = NULL; TIFFGetField (m_tif, TIFFTAG_PIXAR_TEXTUREFORMAT, &s); if (s) m_emulate_mipmap = true; if (s && ! strcmp (s, "Shadow")) { for (int c = 0; c < m_spec.nchannels; ++c) m_spec.channelnames[c] = "z"; } unsigned short *sampleinfo = NULL; unsigned short extrasamples = 0; TIFFGetFieldDefaulted (m_tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); // std::cerr << "Extra samples = " << extrasamples << "\n"; bool alpha_is_unassociated = false; // basic assumption if (extrasamples) { // If the TIFF ExtraSamples tag was specified, use that to figure // out the meaning of alpha. int colorchannels = 3; if (m_photometric == PHOTOMETRIC_MINISWHITE || m_photometric == PHOTOMETRIC_MINISBLACK || m_photometric == PHOTOMETRIC_PALETTE || m_photometric == PHOTOMETRIC_MASK) colorchannels = 1; for (int i = 0, c = colorchannels; i < extrasamples && c < m_spec.nchannels; ++i, ++c) { // std::cerr << " extra " << i << " " << sampleinfo[i] << "\n"; if (sampleinfo[i] == EXTRASAMPLE_ASSOCALPHA) { // This is the alpha channel, associated as usual m_spec.alpha_channel = c; } else if (sampleinfo[i] == EXTRASAMPLE_UNASSALPHA) { // This is the alpha channel, but color is unassociated m_spec.alpha_channel = c; alpha_is_unassociated = true; m_spec.attribute ("oiio:UnassociatedAlpha", 1); } else { DASSERT (sampleinfo[i] == EXTRASAMPLE_UNSPECIFIED); // This extra channel is not alpha at all. Undo any // assumptions we previously made about this channel. if (m_spec.alpha_channel == c) { m_spec.channelnames[c] = Strutil::format("channel%d", c); m_spec.alpha_channel = -1; } } } if (m_spec.alpha_channel >= 0) m_spec.channelnames[m_spec.alpha_channel] = "A"; } // Will we need to do alpha conversions? m_convert_alpha = (m_spec.alpha_channel >= 0 && alpha_is_unassociated && ! m_keep_unassociated_alpha); // N.B. we currently ignore the following TIFF fields: // GrayResponseCurve GrayResponseUnit // MaxSampleValue MinSampleValue // NewSubfileType SubfileType(deprecated) // Colorimetry fields // Search for an EXIF IFD in the TIFF file, and if found, rummage // around for Exif fields. #if TIFFLIB_VERSION > 20050912 /* compat with old TIFF libs - skip Exif */ int exifoffset = 0; if (TIFFGetField (m_tif, TIFFTAG_EXIFIFD, &exifoffset) && TIFFReadEXIFDirectory (m_tif, exifoffset)) { for (int i = 0; exif_tag_table[i].name; ++i) find_tag (exif_tag_table[i].tifftag, exif_tag_table[i].tifftype, exif_tag_table[i].name); // I'm not sure what state TIFFReadEXIFDirectory leaves us. // So to be safe, close and re-seek. TIFFClose (m_tif); #ifdef _WIN32 std::wstring wfilename = Filesystem::path_to_windows_native (m_filename); m_tif = TIFFOpenW (wfilename.c_str(), "rm"); #else m_tif = TIFFOpen (m_filename.c_str(), "rm"); #endif TIFFSetDirectory (m_tif, m_subimage); // A few tidbits to look for ImageIOParameter *p; if ((p = m_spec.find_attribute ("Exif:ColorSpace", TypeDesc::INT))) { // Exif spec says that anything other than 0xffff==uncalibrated // should be interpreted to be sRGB. if (*(const int *)p->data() != 0xffff) m_spec.attribute ("oiio::ColorSpace", "sRGB"); } } #endif #if TIFFLIB_VERSION >= 20051230 // Search for IPTC metadata in IIM form -- but older versions of // libtiff botch the size, so ignore it for very old libtiff. int iptcsize = 0; const void *iptcdata = NULL; if (TIFFGetField (m_tif, TIFFTAG_RICHTIFFIPTC, &iptcsize, &iptcdata)) { std::vector<uint32> iptc ((uint32 *)iptcdata, (uint32 *)iptcdata+iptcsize); if (TIFFIsByteSwapped (m_tif)) TIFFSwabArrayOfLong ((uint32*)&iptc[0], iptcsize); decode_iptc_iim (&iptc[0], iptcsize*4, m_spec); } #endif // Search for an XML packet containing XMP (IPTC, Exif, etc.) int xmlsize = 0; const void *xmldata = NULL; if (TIFFGetField (m_tif, TIFFTAG_XMLPACKET, &xmlsize, &xmldata)) { // std::cerr << "Found XML data, size " << xmlsize << "\n"; if (xmldata && xmlsize) { std::string xml ((const char *)xmldata, xmlsize); decode_xmp (xml, m_spec); } } #if 0 // Experimental -- look for photoshop data int photoshopsize = 0; const void *photoshopdata = NULL; if (TIFFGetField (m_tif, TIFFTAG_PHOTOSHOP, &photoshopsize, &photoshopdata)) { std::cerr << "Found PHOTOSHOP data, size " << photoshopsize << "\n"; if (photoshopdata && photoshopsize) { // std::string photoshop ((const char *)photoshopdata, photoshopsize); // std::cerr << "PHOTOSHOP:\n" << photoshop << "\n---\n"; } } #endif }
bool TiffDecoder::readData( Mat& img ) { bool result = false; bool color = img.channels() > 1; uchar* data = img.data; if( img.depth() != CV_8U && img.depth() != CV_16U && img.depth() != CV_32F && img.depth() != CV_64F ) return false; if( m_tif && m_width && m_height ) { TIFF* tif = (TIFF*)m_tif; uint32 tile_width0 = m_width, tile_height0 = 0; int x, y, i; int is_tiled = TIFFIsTiled(tif); uint16 photometric; TIFFGetField( tif, TIFFTAG_PHOTOMETRIC, &photometric ); uint16 bpp = 8, ncn = photometric > 1 ? 3 : 1; TIFFGetField( tif, TIFFTAG_BITSPERSAMPLE, &bpp ); TIFFGetField( tif, TIFFTAG_SAMPLESPERPIXEL, &ncn ); const int bitsPerByte = 8; int dst_bpp = (int)(img.elemSize1() * bitsPerByte); if(dst_bpp == 8) { char errmsg[1024]; if(!TIFFRGBAImageOK( tif, errmsg )) { close(); return false; } } if( (!is_tiled) || (is_tiled && TIFFGetField( tif, TIFFTAG_TILEWIDTH, &tile_width0 ) && TIFFGetField( tif, TIFFTAG_TILELENGTH, &tile_height0 ))) { if(!is_tiled) TIFFGetField( tif, TIFFTAG_ROWSPERSTRIP, &tile_height0 ); if( tile_width0 <= 0 ) tile_width0 = m_width; if( tile_height0 <= 0 ) tile_height0 = m_height; AutoBuffer<uchar> _buffer( size_t(8) * tile_height0*tile_width0); uchar* buffer = _buffer; ushort* buffer16 = (ushort*)buffer; float* buffer32 = (float*)buffer; double* buffer64 = (double*)buffer; int tileidx = 0; for( y = 0; y < m_height; y += tile_height0, data += img.step*tile_height0 ) { int tile_height = tile_height0; if( y + tile_height > m_height ) tile_height = m_height - y; for( x = 0; x < m_width; x += tile_width0, tileidx++ ) { int tile_width = tile_width0, ok; if( x + tile_width > m_width ) tile_width = m_width - x; switch(dst_bpp) { case 8: { uchar * bstart = buffer; if( !is_tiled ) ok = TIFFReadRGBAStrip( tif, y, (uint32*)buffer ); else { ok = TIFFReadRGBATile( tif, x, y, (uint32*)buffer ); //Tiles fill the buffer from the bottom up bstart += (tile_height0 - tile_height) * tile_width0 * 4; } if( !ok ) { close(); return false; } for( i = 0; i < tile_height; i++ ) if( color ) icvCvt_BGRA2BGR_8u_C4C3R( bstart + i*tile_width0*4, 0, data + x*3 + img.step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); else icvCvt_BGRA2Gray_8u_C4C1R( bstart + i*tile_width0*4, 0, data + x + img.step*(tile_height - i - 1), 0, cvSize(tile_width,1), 2 ); break; } case 16: { if( !is_tiled ) ok = (int)TIFFReadEncodedStrip( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; else ok = (int)TIFFReadEncodedTile( tif, tileidx, (uint32*)buffer, (tsize_t)-1 ) >= 0; if( !ok ) { close(); return false; } for( i = 0; i < tile_height; i++ ) { if( color ) { if( ncn == 1 ) { icvCvt_Gray2BGR_16u_C1C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else if( ncn == 3 ) { icvCvt_RGB2BGR_16u_C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1) ); } else { icvCvt_BGRA2BGR_16u_C4C3R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x*3, 0, cvSize(tile_width,1), 2 ); } } else { if( ncn == 1 ) { memcpy((ushort*)(data + img.step*i)+x, buffer16 + i*tile_width0*ncn, tile_width*sizeof(buffer16[0])); } else { icvCvt_BGRA2Gray_16u_CnC1R(buffer16 + i*tile_width0*ncn, 0, (ushort*)(data + img.step*i) + x, 0, cvSize(tile_width,1), ncn, 2 ); } } } break; } case 32: case 64: { if( !is_tiled ) ok = (int)TIFFReadEncodedStrip( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; else ok = (int)TIFFReadEncodedTile( tif, tileidx, buffer, (tsize_t)-1 ) >= 0; if( !ok || ncn != 1 ) { close(); return false; } for( i = 0; i < tile_height; i++ ) { if(dst_bpp == 32) { memcpy((float*)(data + img.step*i)+x, buffer32 + i*tile_width0*ncn, tile_width*sizeof(buffer32[0])); } else { memcpy((double*)(data + img.step*i)+x, buffer64 + i*tile_width0*ncn, tile_width*sizeof(buffer64[0])); } } break; } default: { close(); return false; } } } } result = true; } } close(); return result; }
bool CxImageTIF::Decode(CxFile * hFile) { //Comment this line if you need more information on errors // TIFFSetErrorHandler(NULL); //<Patrick Hoffmann> //Open file and fill the TIFF structure // m_tif = TIFFOpen(imageFileName,"rb"); TIFF* m_tif = _TIFFOpenEx(hFile, "rb"); uint32 height=0; uint32 width=0; uint16 bitspersample=1; uint16 samplesperpixel=1; uint32 rowsperstrip=(DWORD)-1; uint16 photometric=0; uint16 compression=1; uint16 orientation=ORIENTATION_TOPLEFT; //<vho> uint16 res_unit; //<Trifon> uint32 x, y; float resolution, offset; BOOL isRGB; BYTE *bits; //pointer to source data BYTE *bits2; //pointer to destination data try{ //check if it's a tiff file if (!m_tif) throw "Error encountered while opening TIFF file"; // <Robert Abram> - 12/2002 : get NumFrames directly, instead of looping // info.nNumFrames=0; // while(TIFFSetDirectory(m_tif,(uint16)info.nNumFrames)) info.nNumFrames++; info.nNumFrames = TIFFNumberOfDirectories(m_tif); if (!TIFFSetDirectory(m_tif, (uint16)info.nFrame)) throw "Error: page not present in TIFF file"; //get image info TIFFGetField(m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField(m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetField(m_tif, TIFFTAG_SAMPLESPERPIXEL, &samplesperpixel); TIFFGetField(m_tif, TIFFTAG_BITSPERSAMPLE, &bitspersample); TIFFGetField(m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); TIFFGetField(m_tif, TIFFTAG_PHOTOMETRIC, &photometric); TIFFGetField(m_tif, TIFFTAG_ORIENTATION, &orientation); if (info.nEscape == -1) { // Return output dimensions only head.biWidth = width; head.biHeight = height; throw "output dimensions returned"; } TIFFGetFieldDefaulted(m_tif, TIFFTAG_RESOLUTIONUNIT, &res_unit); if (TIFFGetField(m_tif, TIFFTAG_XRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetXDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_YRESOLUTION, &resolution)) { if (res_unit == RESUNIT_CENTIMETER) resolution = (float)(resolution*2.54f + 0.5f); SetYDPI((long)resolution); } if (TIFFGetField(m_tif, TIFFTAG_XPOSITION, &offset)) info.xOffset = (long)offset; if (TIFFGetField(m_tif, TIFFTAG_YPOSITION, &offset)) info.yOffset = (long)offset; head.biClrUsed=0; info.nBkgndIndex =-1; if (rowsperstrip>height){ rowsperstrip=height; TIFFSetField(m_tif, TIFFTAG_ROWSPERSTRIP, rowsperstrip); } isRGB = (bitspersample >= 8) && (photometric == PHOTOMETRIC_RGB) || (photometric == PHOTOMETRIC_YCBCR) || (photometric == PHOTOMETRIC_SEPARATED) || (photometric == PHOTOMETRIC_LOGL) || (photometric == PHOTOMETRIC_LOGLUV); if (isRGB){ head.biBitCount=24; }else{ if ((photometric==PHOTOMETRIC_MINISBLACK)||(photometric==PHOTOMETRIC_MINISWHITE)){ if (bitspersample == 1){ head.biBitCount=1; //B&W image head.biClrUsed =2; } else if (bitspersample == 4) { head.biBitCount=4; //16 colors gray scale head.biClrUsed =16; } else { head.biBitCount=8; //gray scale head.biClrUsed =256; } } else if (bitspersample == 4) { head.biBitCount=4; // 16 colors head.biClrUsed=16; } else { head.biBitCount=8; //256 colors head.biClrUsed=256; } } if (info.nEscape) throw "Cancelled"; // <vho> - cancel decoding Create(width,height,head.biBitCount,CXIMAGE_FORMAT_TIF); //image creation if (!pDib) throw "CxImageTIF can't create image"; #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); //add alpha support for 32bpp tiffs if (samplesperpixel==2 && bitspersample==8) AlphaCreate(); //add alpha support for 8bpp + alpha #endif //CXIMAGE_SUPPORT_ALPHA TIFFGetField(m_tif, TIFFTAG_COMPRESSION, &compression); SetCodecOption(compression); // <DPR> save original compression type if (isRGB) { // Read the whole image into one big RGBA buffer using // the traditional TIFFReadRGBAImage() API that we trust. uint32* raster; // retrieve RGBA image uint32 *row; raster = (uint32*)_TIFFmalloc(width * height * sizeof (uint32)); if (raster == NULL) throw "No space for raster buffer"; // Read the image in one chunk into an RGBA array if(!TIFFReadRGBAImage(m_tif, width, height, raster, 1)) { _TIFFfree(raster); throw "Corrupted TIFF file!"; } // read the raster lines and save them in the DIB // with RGB mode, we have to change the order of the 3 samples RGB row = &raster[0]; bits2 = info.pImage; for (y = 0; y < height; y++) { if (info.nEscape){ // <vho> - cancel decoding _TIFFfree(raster); throw "Cancelled"; } bits = bits2; for (x = 0; x < width; x++) { *bits++ = (BYTE)TIFFGetB(row[x]); *bits++ = (BYTE)TIFFGetG(row[x]); *bits++ = (BYTE)TIFFGetR(row[x]); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(x,y,(BYTE)TIFFGetA(row[x])); #endif //CXIMAGE_SUPPORT_ALPHA } row += width; bits2 += info.dwEffWidth; } _TIFFfree(raster); } else { RGBQUAD *pal; pal=(RGBQUAD*)calloc(256,sizeof(RGBQUAD)); if (pal==NULL) throw "Unable to allocate TIFF palette"; // set up the colormap based on photometric switch(photometric) { case PHOTOMETRIC_MINISBLACK: // bitmap and greyscale image types case PHOTOMETRIC_MINISWHITE: if (bitspersample == 1) { // Monochrome image if (photometric == PHOTOMETRIC_MINISBLACK) { pal[1].rgbRed = pal[1].rgbGreen = pal[1].rgbBlue = 255; } else { pal[0].rgbRed = pal[0].rgbGreen = pal[0].rgbBlue = 255; } } else { // need to build the scale for greyscale images if (photometric == PHOTOMETRIC_MINISBLACK) { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(i*(255/(head.biClrUsed-1))); } } else { for (DWORD i=0; i<head.biClrUsed; i++){ pal[i].rgbRed = pal[i].rgbGreen = pal[i].rgbBlue = (BYTE)(255-i*(255/(head.biClrUsed-1))); } } } break; case PHOTOMETRIC_PALETTE: // color map indexed uint16 *red; uint16 *green; uint16 *blue; TIFFGetField(m_tif, TIFFTAG_COLORMAP, &red, &green, &blue); // Is the palette 16 or 8 bits ? BOOL Palette16Bits = FALSE; int n=1<<bitspersample; while (n-- > 0) { if (red[n] >= 256 || green[n] >= 256 || blue[n] >= 256) { Palette16Bits=TRUE; break; } } // load the palette in the DIB for (int i = (1 << bitspersample) - 1; i >= 0; i--) { if (Palette16Bits) { pal[i].rgbRed =(BYTE) CVT(red[i]); pal[i].rgbGreen = (BYTE) CVT(green[i]); pal[i].rgbBlue = (BYTE) CVT(blue[i]); } else { pal[i].rgbRed = (BYTE) red[i]; pal[i].rgbGreen = (BYTE) green[i]; pal[i].rgbBlue = (BYTE) blue[i]; } } break; } SetPalette(pal,head.biClrUsed); //palette assign free(pal); // read the tiff lines and save them in the DIB uint32 nrow; uint32 ys; int line = CalculateLine(width, bitspersample * samplesperpixel); long bitsize= TIFFStripSize(m_tif); //verify bitsize: could be wrong if StripByteCounts is missing. if (bitsize>(long)(head.biSizeImage*samplesperpixel)) bitsize=head.biSizeImage*samplesperpixel; int tiled_image = TIFFIsTiled(m_tif); uint32 tw, tl; BYTE* tilebuf; if (tiled_image){ TIFFGetField(m_tif, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(m_tif, TIFFTAG_TILELENGTH, &tl); rowsperstrip = tl; bitsize = TIFFTileSize(m_tif) * (int)(1+width/tw); tilebuf = (BYTE*)malloc(TIFFTileSize(m_tif)); } bits = (BYTE*)malloc(bitsize); if (bits==NULL){ throw "CxImageTIF can't allocate memory"; } for (ys = 0; ys < height; ys += rowsperstrip) { if (info.nEscape){ // <vho> - cancel decoding free(bits); throw "Cancelled"; } nrow = (ys + rowsperstrip > height ? height - ys : rowsperstrip); if (tiled_image){ uint32 imagew = TIFFScanlineSize(m_tif); uint32 tilew = TIFFTileRowSize(m_tif); int iskew = imagew - tilew; uint8* bufp = (uint8*) bits; uint32 colb = 0; for (uint32 col = 0; col < width; col += tw) { if (TIFFReadTile(m_tif, tilebuf, col, ys, 0, 0) < 0){ free(tilebuf); free(bits); throw "Corrupted tiled TIFF file!"; } if (colb + tw > imagew) { uint32 owidth = imagew - colb; uint32 oskew = tilew - owidth; TileToStrip(bufp + colb, tilebuf, nrow, owidth, oskew + iskew, oskew ); } else { TileToStrip(bufp + colb, tilebuf, nrow, tilew, iskew, 0); } colb += tilew; } } else { if (TIFFReadEncodedStrip(m_tif, TIFFComputeStrip(m_tif, ys, 0), bits, nrow * line) == -1) { free(bits); throw "Corrupted TIFF file!"; } } for (y = 0; y < nrow; y++) { long offset=(nrow-y-1)*line; if (bitspersample==16) for (DWORD xi=0;xi<width;xi++) bits[xi+offset]=bits[xi*2+offset+1]; if (samplesperpixel==1) { //simple 8bpp image memcpy(info.pImage+info.dwEffWidth*(height-ys-nrow+y),bits+offset,info.dwEffWidth); } else if (samplesperpixel==2) { //8bpp image with alpha layer int xi=0; int ii=0; int yi=height-ys-nrow+y; while (ii<line){ SetPixelIndex(xi,yi,bits[ii+offset]); #if CXIMAGE_SUPPORT_ALPHA AlphaSet(xi,yi,bits[ii+offset+1]); #endif //CXIMAGE_SUPPORT_ALPHA ii+=2; xi++; if (xi>=(int)width){ yi--; xi=0; } } } else { //photometric==PHOTOMETRIC_CIELAB if (head.biBitCount!=24){ //fix image Create(width,height,24,CXIMAGE_FORMAT_TIF); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaCreate(); #endif //CXIMAGE_SUPPORT_ALPHA } int xi=0; int ii=0; int yi=height-ys-nrow+y; RGBQUAD c; int l,a,b,bitsoffset; double p,cx,cy,cz,cr,cg,cb; while (ii<line){ bitsoffset = ii*samplesperpixel+offset; l=bits[bitsoffset]; a=bits[bitsoffset+1]; b=bits[bitsoffset+2]; if (a>127) a-=256; if (b>127) b-=256; // lab to xyz p = (l/2.55 + 16) / 116.0; cx = pow( p + a * 0.002, 3); cy = pow( p, 3); cz = pow( p - b * 0.005, 3); // white point cx*=0.95047; //cy*=1.000; cz*=1.0883; // xyz to rgb cr = 3.240479 * cx - 1.537150 * cy - 0.498535 * cz; cg = -0.969256 * cx + 1.875992 * cy + 0.041556 * cz; cb = 0.055648 * cx - 0.204043 * cy + 1.057311 * cz; if ( cr > 0.00304 ) cr = 1.055 * pow(cr,0.41667) - 0.055; else cr = 12.92 * cr; if ( cg > 0.00304 ) cg = 1.055 * pow(cg,0.41667) - 0.055; else cg = 12.92 * cg; if ( cb > 0.00304 ) cb = 1.055 * pow(cb,0.41667) - 0.055; else cb = 12.92 * cb; c.rgbRed =(BYTE)max(0,min(255,(int)(cr*255))); c.rgbGreen=(BYTE)max(0,min(255,(int)(cg*255))); c.rgbBlue =(BYTE)max(0,min(255,(int)(cb*255))); SetPixelColor(xi,yi,c); #if CXIMAGE_SUPPORT_ALPHA if (samplesperpixel==4) AlphaSet(xi,yi,bits[bitsoffset+3]); #endif //CXIMAGE_SUPPORT_ALPHA ii++; xi++; if (xi>=(int)width){ yi--; xi=0; } } } } } free(bits); if (tiled_image) free(tilebuf); switch(orientation){ case ORIENTATION_TOPRIGHT: /* row 0 top, col 0 rhs */ Mirror(); break; case ORIENTATION_BOTRIGHT: /* row 0 bottom, col 0 rhs */ Flip(); Mirror(); break; case ORIENTATION_BOTLEFT: /* row 0 bottom, col 0 lhs */ Flip(); break; case ORIENTATION_LEFTTOP: /* row 0 lhs, col 0 top */ RotateRight(); Mirror(); break; case ORIENTATION_RIGHTTOP: /* row 0 rhs, col 0 top */ RotateLeft(); break; case ORIENTATION_RIGHTBOT: /* row 0 rhs, col 0 bottom */ RotateLeft(); Mirror(); break; case ORIENTATION_LEFTBOT: /* row 0 lhs, col 0 bottom */ RotateRight(); break; } } } catch (char *message) { strncpy(info.szLastError,message,255); if (m_tif) TIFFClose(m_tif); if (info.nEscape==-1) return true; return false; } TIFFClose(m_tif); return true; }
int TIFFRGBAImageBegin(TIFFRGBAImage* img, TIFF* tif, int stop, char emsg[1024]) { uint16* sampleinfo; uint16 extrasamples; uint16 planarconfig; int colorchannels; img->tif = tif; img->stoponerr = stop; TIFFGetFieldDefaulted(tif, TIFFTAG_BITSPERSAMPLE, &img->bitspersample); switch (img->bitspersample) { case 1: case 2: case 4: case 8: case 16: break; default: sprintf(emsg, "Sorry, can not image with %d-bit samples", img->bitspersample); return (0); } img->alpha = 0; TIFFGetFieldDefaulted(tif, TIFFTAG_SAMPLESPERPIXEL, &img->samplesperpixel); TIFFGetFieldDefaulted(tif, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); if (extrasamples == 1) switch (sampleinfo[0]) { case EXTRASAMPLE_ASSOCALPHA: /* data is pre-multiplied */ case EXTRASAMPLE_UNASSALPHA: /* data is not pre-multiplied */ img->alpha = sampleinfo[0]; break; } colorchannels = img->samplesperpixel - extrasamples; TIFFGetFieldDefaulted(tif, TIFFTAG_PLANARCONFIG, &planarconfig); if (!TIFFGetField(tif, TIFFTAG_PHOTOMETRIC, &img->photometric)) { switch (colorchannels) { case 1: if (isCCITTCompression(tif)) img->photometric = PHOTOMETRIC_MINISWHITE; else img->photometric = PHOTOMETRIC_MINISBLACK; break; case 3: img->photometric = PHOTOMETRIC_RGB; break; default: sprintf(emsg, "Missing needed %s tag", photoTag); return (0); } } switch (img->photometric) { case PHOTOMETRIC_PALETTE: if (!TIFFGetField(tif, TIFFTAG_COLORMAP, &img->redcmap, &img->greencmap, &img->bluecmap)) { TIFFError(TIFFFileName(tif), "Missing required \"Colormap\" tag"); return (0); } /* fall thru... */ case PHOTOMETRIC_MINISWHITE: case PHOTOMETRIC_MINISBLACK: if (planarconfig == PLANARCONFIG_CONTIG && img->samplesperpixel != 1) { sprintf(emsg, "Sorry, can not handle contiguous data with %s=%d, and %s=%d", photoTag, img->photometric, "Samples/pixel", img->samplesperpixel); return (0); } break; case PHOTOMETRIC_YCBCR: if (planarconfig != PLANARCONFIG_CONTIG) { sprintf(emsg, "Sorry, can not handle YCbCr images with %s=%d", "Planarconfiguration", planarconfig); return (0); } /* It would probably be nice to have a reality check here. */ { uint16 compress; TIFFGetField(tif, TIFFTAG_COMPRESSION, &compress); if (compress == COMPRESSION_JPEG && planarconfig == PLANARCONFIG_CONTIG) { /* can rely on libjpeg to convert to RGB */ /* XXX should restore current state on exit */ TIFFSetField(tif, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB); img->photometric = PHOTOMETRIC_RGB; } } break; case PHOTOMETRIC_RGB: if (colorchannels < 3) { sprintf(emsg, "Sorry, can not handle RGB image with %s=%d", "Color channels", colorchannels); return (0); } break; case PHOTOMETRIC_SEPARATED: { uint16 inkset; TIFFGetFieldDefaulted(tif, TIFFTAG_INKSET, &inkset); if (inkset != INKSET_CMYK) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "InkSet", inkset); return (0); } if (img->samplesperpixel != 4) { sprintf(emsg, "Sorry, can not handle separated image with %s=%d", "Samples/pixel", img->samplesperpixel); return (0); } break; } default: sprintf(emsg, "Sorry, can not handle image with %s=%d", photoTag, img->photometric); return (0); } img->Map = NULL; img->BWmap = NULL; img->PALmap = NULL; img->ycbcr = NULL; TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &img->width); TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &img->height); TIFFGetFieldDefaulted(tif, TIFFTAG_ORIENTATION, &img->orientation); img->isContig = !(planarconfig == PLANARCONFIG_SEPARATE && colorchannels > 1); if (img->isContig) { img->get = TIFFIsTiled(tif) ? gtTileContig : gtStripContig; (void) pickTileContigCase(img); } else { img->get = TIFFIsTiled(tif) ? gtTileSeparate : gtStripSeparate; (void) pickTileSeparateCase(img); } return (1); }
static void* tiff_init(FILE *fp, char *filename, unsigned int page, struct ida_image_info *i, int thumbnail) { struct tiff_state *h; fclose(fp); h = malloc(sizeof(*h)); memset(h,0,sizeof(*h)); TIFFSetWarningHandler(NULL); h->tif = TIFFOpen(filename,"r"); if (NULL == h->tif) goto oops; /* Determine number of directories */ h->ndirs = 1; while (TIFFReadDirectory(h->tif)) h->ndirs++; i->npages = h->ndirs; /* Select requested directory (page) */ if (!TIFFSetDirectory(h->tif, (tdir_t)page)) goto oops; TIFFGetField(h->tif, TIFFTAG_IMAGEWIDTH, &h->width); TIFFGetField(h->tif, TIFFTAG_IMAGELENGTH, &h->height); TIFFGetField(h->tif, TIFFTAG_PLANARCONFIG, &h->config); TIFFGetField(h->tif, TIFFTAG_SAMPLESPERPIXEL, &h->nsamples); TIFFGetField(h->tif, TIFFTAG_BITSPERSAMPLE, &h->depth); TIFFGetField(h->tif, TIFFTAG_FILLORDER, &h->fillorder); TIFFGetField(h->tif, TIFFTAG_PHOTOMETRIC, &h->photometric); h->row = malloc(TIFFScanlineSize(h->tif)); if (debug) fprintf(stderr,"tiff: %" PRId32 "x%" PRId32 ", planar=%d, " "nsamples=%d, depth=%d fo=%d pm=%d scanline=%" PRId32 "\n", h->width,h->height,h->config,h->nsamples,h->depth, h->fillorder,h->photometric, TIFFScanlineSize(h->tif)); if (PHOTOMETRIC_PALETTE == h->photometric || PHOTOMETRIC_YCBCR == h->photometric || PHOTOMETRIC_SEPARATED == h->photometric || TIFFIsTiled(h->tif) || (1 != h->depth && 8 != h->depth)) { /* for the more difficuilt cases we let libtiff * do all the hard work. Drawback is that we lose * progressive loading and decode everything here */ if (debug) fprintf(stderr,"tiff: reading whole image [TIFFReadRGBAImage]\n"); h->image=malloc(4*h->width*h->height); TIFFReadRGBAImage(h->tif, h->width, h->height, h->image, 0); } else { if (debug) fprintf(stderr,"tiff: reading scanline by scanline\n"); h->row = malloc(TIFFScanlineSize(h->tif)); } i->width = h->width; i->height = h->height; if (TIFFGetField(h->tif, TIFFTAG_RESOLUTIONUNIT, &h->resunit) && TIFFGetField(h->tif, TIFFTAG_XRESOLUTION, &h->xres) && TIFFGetField(h->tif, TIFFTAG_YRESOLUTION, &h->yres)) { switch (h->resunit) { case RESUNIT_NONE: break; case RESUNIT_INCH: i->dpi = h->xres; break; case RESUNIT_CENTIMETER: i->dpi = res_cm_to_inch(h->xres); break; } } return h; oops: if (h->tif) TIFFClose(h->tif); free(h); return NULL; }
bool _openslide_try_generic_tiff(openslide_t *osr, TIFF *tiff, struct _openslide_hash *quickhash1) { GList *layer_list = NULL; int32_t layer_count = 0; int32_t *layers = NULL; int32_t current_layer = 0; if (!TIFFIsTiled(tiff)) { goto FAIL; // not tiled } if (osr) { g_hash_table_insert(osr->properties, g_strdup(OPENSLIDE_PROPERTY_NAME_VENDOR), g_strdup("generic-tiff")); } // accumulate tiled layers current_layer = 0; layer_count = 0; do { if (TIFFIsTiled(tiff)) { // get width uint32_t width; if (!TIFFGetField(tiff, TIFFTAG_IMAGEWIDTH, &width)) { // oh no continue; } // confirm it is either the first image, or reduced-resolution if (current_layer != 0) { uint32_t subfiletype; if (!TIFFGetField(tiff, TIFFTAG_SUBFILETYPE, &subfiletype)) { continue; } if (!(subfiletype & FILETYPE_REDUCEDIMAGE)) { continue; } } // verify that we can read this compression (hard fail if not) uint16_t compression; if (!TIFFGetField(tiff, TIFFTAG_COMPRESSION, &compression)) { g_warning("Can't read compression scheme"); goto FAIL; }; if (!TIFFIsCODECConfigured(compression)) { g_warning("Unsupported TIFF compression: %u", compression); goto FAIL; } // push into list struct layer *l = g_slice_new(struct layer); l->layer_number = current_layer; l->width = width; layer_list = g_list_prepend(layer_list, l); layer_count++; } current_layer++; } while (TIFFReadDirectory(tiff)); // sort tiled layers layer_list = g_list_sort(layer_list, width_compare); // copy layers in, while deleting the list layers = g_new(int32_t, layer_count); for (int i = 0; i < layer_count; i++) { struct layer *l = (struct layer *)layer_list->data; layer_list = g_list_delete_link(layer_list, layer_list); layers[i] = l->layer_number; g_slice_free(struct layer, l); } g_assert(layer_list == NULL); // all set, load up the TIFF-specific ops _openslide_add_tiff_ops(osr, tiff, 0, NULL, layer_count, layers, _openslide_generic_tiff_tilereader, quickhash1); return true; FAIL: // free the layer list for (GList *i = layer_list; i != NULL; i = g_list_delete_link(i, i)) { g_slice_free(struct layer, i->data); } return false; }
void TifReader::readLine(short *buffer, int x0, int x1, int shrink) { assert(shrink > 0); const int pixelSize = 8; int stripRowSize = m_rowLength * pixelSize; if (m_row < m_info.m_y0 || m_row > m_info.m_y1) { memset(buffer, 0, (x1 - x0 + 1) * pixelSize); m_row++; return; } int stripIndex = m_row / m_rowsPerStrip; if (m_stripIndex != stripIndex) { // Retrieve the strip holding current row. Please, observe that // TIFF functions will return the strip buffer in the BOTTOM-UP orientation, // no matter the internal tif's orientation storage m_stripIndex = stripIndex; if (TIFFIsTiled(m_tiff)) { // Retrieve tiles size uint32 tileWidth = 0, tileHeight = 0; TIFFGetField(m_tiff, TIFFTAG_TILEWIDTH, &tileWidth); TIFFGetField(m_tiff, TIFFTAG_TILELENGTH, &tileHeight); assert(tileWidth > 0 && tileHeight > 0); // Allocate a sufficient buffer to store a single tile int tileSize = tileWidth * tileHeight; std::unique_ptr<uint64[]> tile(new uint64[tileSize]); int x = 0; int y = tileHeight * m_stripIndex; // In case it's the last tiles row, the tile size might exceed the image bounds int lastTy = std::min((int)tileHeight, m_info.m_ly - y); // Traverse the tiles row while (x < m_info.m_lx) { int ret = TIFFReadRGBATile_64(m_tiff, x, y, tile.get()); assert(ret); int tileRowSize = std::min((int)tileWidth, m_info.m_lx - x) * pixelSize; // Copy the tile rows in the corresponding output strip rows for (int ty = 0; ty < lastTy; ++ty) { memcpy( m_stripBuffer + (ty * m_rowLength + x) * pixelSize, (UCHAR *)tile.get() + ty * tileWidth * pixelSize, tileRowSize); } x += tileWidth; } } else { int y = m_rowsPerStrip * m_stripIndex; int ok = TIFFReadRGBAStrip_64(m_tiff, y, (uint64 *)m_stripBuffer); assert(ok); } } uint16 orient = ORIENTATION_TOPLEFT; TIFFGetField(m_tiff, TIFFTAG_ORIENTATION, &orient); int r = m_rowsPerStrip - 1 - (m_row % m_rowsPerStrip); switch (orient) // Pretty weak check for top/bottom orientation { case ORIENTATION_TOPLEFT: case ORIENTATION_TOPRIGHT: case ORIENTATION_LEFTTOP: case ORIENTATION_RIGHTTOP: // We have to invert the fixed BOTTOM-UP returned by TIFF functions - since this function is // supposed to ignore orientation issues (which are managed outside). // The last tiles row will actually start at the END OF THE IMAGE (not necessarily at // m_rowsPerStrip multiples). So, we must adjust for that. r = std::min(m_rowsPerStrip, m_info.m_ly - m_rowsPerStrip * m_stripIndex) - 1 - (m_row % m_rowsPerStrip); break; case ORIENTATION_BOTRIGHT: case ORIENTATION_BOTLEFT: case ORIENTATION_RIGHTBOT: case ORIENTATION_LEFTBOT: r = m_row % m_rowsPerStrip; break; } // Finally, copy the strip row to the output row buffer TPixel64 *pix = (TPixel64 *)buffer; USHORT *v = (USHORT *)(m_stripBuffer + r * stripRowSize); pix += x0; v += 4 * x0; int width = (x1 < x0) ? (m_info.m_lx - 1) / shrink + 1 : (x1 - x0) / shrink + 1; for (int i = 0; i < width; i++) { USHORT c = *v++; pix->r = c; c = *v++; pix->g = c; c = *v++; pix->b = c; c = *v++; pix->m = c; pix += shrink; v += 4 * (shrink - 1); } m_row++; }
/* * Select the appropriate copy function to use. */ static copyFunc pickCopyFunc(TIFF* in, TIFF* out, uint16 bitspersample, uint16 samplesperpixel) { uint16 shortv; uint32 w, l, tw, tl; int bychunk; (void) TIFFGetField(in, TIFFTAG_PLANARCONFIG, &shortv); if (shortv != config && bitspersample != 8 && samplesperpixel > 1) { fprintf(stderr, "%s: Can not handle different planar configuration w/ bits/sample != 8\n", TIFFFileName(in)); return (NULL); } TIFFGetField(in, TIFFTAG_IMAGEWIDTH, &w); TIFFGetField(in, TIFFTAG_IMAGELENGTH, &l); if (TIFFIsTiled(out)) { if (!TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw)) tw = w; if (!TIFFGetField(in, TIFFTAG_TILELENGTH, &tl)) tl = l; bychunk = (tw == tilewidth && tl == tilelength); } else if (TIFFIsTiled(in)) { TIFFGetField(in, TIFFTAG_TILEWIDTH, &tw); TIFFGetField(in, TIFFTAG_TILELENGTH, &tl); bychunk = (tw == w && tl == rowsperstrip); } else { uint32 irps = (uint32) -1L; TIFFGetField(in, TIFFTAG_ROWSPERSTRIP, &irps); bychunk = (rowsperstrip == irps); } #define T 1 #define F 0 #define pack(a,b,c,d,e) ((long)(((a)<<11)|((b)<<3)|((c)<<2)|((d)<<1)|(e))) switch(pack(shortv,config,TIFFIsTiled(in),TIFFIsTiled(out),bychunk)) { /* Strips -> Tiles */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,T,T): return cpContigStrips2ContigTiles; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,T,T): return cpContigStrips2SeparateTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,T,T): return cpSeparateStrips2ContigTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,T,T): return cpSeparateStrips2SeparateTiles; /* Tiles -> Tiles */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,T,T): return cpContigTiles2ContigTiles; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,T,T): return cpContigTiles2SeparateTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,T,T): return cpSeparateTiles2ContigTiles; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,T,T): return cpSeparateTiles2SeparateTiles; /* Tiles -> Strips */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, T,F,T): return cpContigTiles2ContigStrips; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, T,F,T): return cpContigTiles2SeparateStrips; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, T,F,T): return cpSeparateTiles2ContigStrips; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, T,F,T): return cpSeparateTiles2SeparateStrips; /* Strips -> Strips */ case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,F): return cpContig2ContigByRow; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_CONTIG, F,F,T): return cpDecodedStrips; case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,F): case pack(PLANARCONFIG_CONTIG, PLANARCONFIG_SEPARATE, F,F,T): return cpContig2SeparateByRow; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_CONTIG, F,F,T): return cpSeparate2ContigByRow; case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,F): case pack(PLANARCONFIG_SEPARATE, PLANARCONFIG_SEPARATE, F,F,T): return cpSeparate2SeparateByRow; } #undef pack #undef F #undef T fprintf(stderr, "tiffcp: %s: Don't know how to copy/convert image.\n", TIFFFileName(in)); return (NULL); }
void TIFFInput::readspec () { uint32 width = 0, height = 0, depth = 0; unsigned short nchans = 1; TIFFGetField (m_tif, TIFFTAG_IMAGEWIDTH, &width); TIFFGetField (m_tif, TIFFTAG_IMAGELENGTH, &height); TIFFGetFieldDefaulted (m_tif, TIFFTAG_IMAGEDEPTH, &depth); TIFFGetFieldDefaulted (m_tif, TIFFTAG_SAMPLESPERPIXEL, &nchans); m_spec = ImageSpec ((int)width, (int)height, (int)nchans); float x = 0, y = 0; TIFFGetField (m_tif, TIFFTAG_XPOSITION, &x); TIFFGetField (m_tif, TIFFTAG_YPOSITION, &y); m_spec.x = (int)x; m_spec.y = (int)y; m_spec.z = 0; // FIXME? - TIFF spec describes the positions as in resolutionunit. // What happens if this is not unitless pixels? Are we interpreting // it all wrong? if (TIFFGetField (m_tif, TIFFTAG_PIXAR_IMAGEFULLWIDTH, &width) == 1 && width > 0) m_spec.full_width = width; if (TIFFGetField (m_tif, TIFFTAG_PIXAR_IMAGEFULLLENGTH, &height) == 1 && height > 0) m_spec.full_height = height; if (TIFFIsTiled (m_tif)) { TIFFGetField (m_tif, TIFFTAG_TILEWIDTH, &m_spec.tile_width); TIFFGetField (m_tif, TIFFTAG_TILELENGTH, &m_spec.tile_height); TIFFGetFieldDefaulted (m_tif, TIFFTAG_TILEDEPTH, &m_spec.tile_depth); } else { m_spec.tile_width = 0; m_spec.tile_height = 0; m_spec.tile_depth = 0; } m_bitspersample = 8; TIFFGetField (m_tif, TIFFTAG_BITSPERSAMPLE, &m_bitspersample); m_spec.attribute ("oiio:BitsPerSample", (int)m_bitspersample); unsigned short sampleformat = SAMPLEFORMAT_UINT; TIFFGetFieldDefaulted (m_tif, TIFFTAG_SAMPLEFORMAT, &sampleformat); switch (m_bitspersample) { case 1: case 2: case 4: // Make 1, 2, 4 bpp look like byte images case 8: if (sampleformat == SAMPLEFORMAT_UINT) m_spec.set_format (TypeDesc::UINT8); else if (sampleformat == SAMPLEFORMAT_INT) m_spec.set_format (TypeDesc::INT8); else m_spec.set_format (TypeDesc::UINT8); // punt break; case 16: if (sampleformat == SAMPLEFORMAT_UINT) m_spec.set_format (TypeDesc::UINT16); else if (sampleformat == SAMPLEFORMAT_INT) m_spec.set_format (TypeDesc::INT16); break; case 32: if (sampleformat == SAMPLEFORMAT_IEEEFP) m_spec.set_format (TypeDesc::FLOAT); break; case 64: if (sampleformat == SAMPLEFORMAT_IEEEFP) m_spec.set_format (TypeDesc::DOUBLE); break; default: m_spec.set_format (TypeDesc::UNKNOWN); break; } // Use the table for all the obvious things that can be mindlessly // shoved into the image spec. for (int i = 0; tiff_tag_table[i].name; ++i) find_tag (tiff_tag_table[i].tifftag, tiff_tag_table[i].tifftype, tiff_tag_table[i].name); // Now we need to get fields "by hand" for anything else that is less // straightforward... m_photometric = (m_spec.nchannels == 1 ? PHOTOMETRIC_MINISBLACK : PHOTOMETRIC_RGB); TIFFGetField (m_tif, TIFFTAG_PHOTOMETRIC, &m_photometric); m_spec.attribute ("tiff:PhotometricInterpretation", (int)m_photometric); if (m_photometric == PHOTOMETRIC_PALETTE) { // Read the color map unsigned short *r = NULL, *g = NULL, *b = NULL; TIFFGetField (m_tif, TIFFTAG_COLORMAP, &r, &g, &b); ASSERT (r != NULL && g != NULL && b != NULL); m_colormap.clear (); m_colormap.insert (m_colormap.end(), r, r + (1 << m_bitspersample)); m_colormap.insert (m_colormap.end(), g, g + (1 << m_bitspersample)); m_colormap.insert (m_colormap.end(), b, b + (1 << m_bitspersample)); // Palette TIFF images are always 3 channels (to the client) m_spec.nchannels = 3; m_spec.default_channel_names (); } TIFFGetFieldDefaulted (m_tif, TIFFTAG_PLANARCONFIG, &m_planarconfig); m_spec.attribute ("tiff:PlanarConfiguration", (int)m_planarconfig); if (m_planarconfig == PLANARCONFIG_SEPARATE) m_spec.attribute ("planarconfig", "separate"); else m_spec.attribute ("planarconfig", "contig"); int compress = 0; TIFFGetFieldDefaulted (m_tif, TIFFTAG_COMPRESSION, &compress); m_spec.attribute ("tiff:Compression", compress); switch (compress) { case COMPRESSION_NONE : m_spec.attribute ("compression", "none"); break; case COMPRESSION_LZW : m_spec.attribute ("compression", "lzw"); break; case COMPRESSION_CCITTRLE : m_spec.attribute ("compression", "ccittrle"); break; case COMPRESSION_DEFLATE : case COMPRESSION_ADOBE_DEFLATE : m_spec.attribute ("compression", "zip"); break; case COMPRESSION_PACKBITS : m_spec.attribute ("compression", "packbits"); break; default: break; } int rowsperstrip = -1; if (! m_spec.tile_width) { TIFFGetField (m_tif, TIFFTAG_ROWSPERSTRIP, &rowsperstrip); if (rowsperstrip > 0) m_spec.attribute ("tiff:RowsPerStrip", rowsperstrip); } // The libtiff docs say that only uncompressed images, or those with // rowsperstrip==1, support random access to scanlines. m_no_random_access = (compress != COMPRESSION_NONE && rowsperstrip != 1); short resunit = -1; TIFFGetField (m_tif, TIFFTAG_RESOLUTIONUNIT, &resunit); switch (resunit) { case RESUNIT_NONE : m_spec.attribute ("ResolutionUnit", "none"); break; case RESUNIT_INCH : m_spec.attribute ("ResolutionUnit", "in"); break; case RESUNIT_CENTIMETER : m_spec.attribute ("ResolutionUnit", "cm"); break; } get_matrix_attribute ("worldtocamera", TIFFTAG_PIXAR_MATRIX_WORLDTOCAMERA); get_matrix_attribute ("worldtoscreen", TIFFTAG_PIXAR_MATRIX_WORLDTOSCREEN); get_int_attribute ("tiff:subfiletype", TIFFTAG_SUBFILETYPE); // FIXME -- should subfiletype be "conventionized" and used for all // plugins uniformly? // FIXME: do we care about fillorder for 1-bit and 4-bit images? // Special names for shadow maps char *s = NULL; TIFFGetField (m_tif, TIFFTAG_PIXAR_TEXTUREFORMAT, &s); if (s) m_emulate_mipmap = true; if (s && ! strcmp (s, "Shadow")) { for (int c = 0; c < m_spec.nchannels; ++c) m_spec.channelnames[c] = "z"; } // N.B. we currently ignore the following TIFF fields: // ExtraSamples // GrayResponseCurve GrayResponseUnit // MaxSampleValue MinSampleValue // NewSubfileType SubfileType(deprecated) // Colorimetry fields // Search for an EXIF IFD in the TIFF file, and if found, rummage // around for Exif fields. #if TIFFLIB_VERSION > 20050912 /* compat with old TIFF libs - skip Exif */ int exifoffset = 0; if (TIFFGetField (m_tif, TIFFTAG_EXIFIFD, &exifoffset) && TIFFReadEXIFDirectory (m_tif, exifoffset)) { for (int i = 0; exif_tag_table[i].name; ++i) find_tag (exif_tag_table[i].tifftag, exif_tag_table[i].tifftype, exif_tag_table[i].name); // I'm not sure what state TIFFReadEXIFDirectory leaves us. // So to be safe, close and re-seek. TIFFClose (m_tif); m_tif = TIFFOpen (m_filename.c_str(), "rm"); TIFFSetDirectory (m_tif, m_subimage); // A few tidbits to look for ImageIOParameter *p; if ((p = m_spec.find_attribute ("Exif:ColorSpace", TypeDesc::INT))) { // Exif spec says that anything other than 0xffff==uncalibrated // should be interpreted to be sRGB. if (*(const int *)p->data() != 0xffff) m_spec.attribute ("oiio::ColorSpace", "sRGB"); } } #endif #if TIFFLIB_VERSION >= 20051230 // Search for IPTC metadata in IIM form -- but older versions of // libtiff botch the size, so ignore it for very old libtiff. int iptcsize = 0; const void *iptcdata = NULL; if (TIFFGetField (m_tif, TIFFTAG_RICHTIFFIPTC, &iptcsize, &iptcdata)) { std::vector<uint32> iptc ((uint32 *)iptcdata, (uint32 *)iptcdata+iptcsize); if (TIFFIsByteSwapped (m_tif)) TIFFSwabArrayOfLong ((uint32*)&iptc[0], iptcsize); decode_iptc_iim (&iptc[0], iptcsize*4, m_spec); } #endif // Search for an XML packet containing XMP (IPTC, Exif, etc.) int xmlsize = 0; const void *xmldata = NULL; if (TIFFGetField (m_tif, TIFFTAG_XMLPACKET, &xmlsize, &xmldata)) { // std::cerr << "Found XML data, size " << xmlsize << "\n"; if (xmldata && xmlsize) { std::string xml ((const char *)xmldata, xmlsize); decode_xmp (xml, m_spec); } } #if 0 // Experimental -- look for photoshop data int photoshopsize = 0; const void *photoshopdata = NULL; if (TIFFGetField (m_tif, TIFFTAG_PHOTOSHOP, &photoshopsize, &photoshopdata)) { std::cerr << "Found PHOTOSHOP data, size " << photoshopsize << "\n"; if (photoshopdata && photoshopsize) { // std::string photoshop ((const char *)photoshopdata, photoshopsize); // std::cerr << "PHOTOSHOP:\n" << photoshop << "\n---\n"; } } #endif }