45 constexpr int PCT(
int x) {
return (
x*255+127)/100;}
46 const int RED = PCT(30);
47 const int GREEN = PCT(59);
48 const int BLUE = PCT(11);
51TiffIO::TiffIO(
const string & fname, IOMode rw)
52:
ImageIO(fname, rw), tiff_file(0),
53 bitspersample(0), photometric(0),
54 rendermin(0.0), rendermax(0.0), renderbits(16), nimg(1),
55 is_big_endian(
ByteOrder::is_host_big_endian())
76 bool is_new_file =
false;
78 FILE * tmp_in = sfopen(filename, rw_mode, & is_new_file,
true);
87 if (fread(buf,
sizeof(buf), 1, tmp_in) != 1) {
91 if (!is_valid(&buf)) {
95 is_big_endian = (buf[0] == TIFF_BIG_ENDIAN);
101 TIFFSetWarningHandler(0);
103 if (rw_mode == ImageIO::READ_ONLY) {
104 tiff_file = TIFFOpen(filename.c_str(),
"r");
110 TIFFGetField(tiff_file, TIFFTAG_BITSPERSAMPLE, &bitspersample);
112 if (bitspersample != CHAR_BIT &&
113 bitspersample != (CHAR_BIT *
sizeof(
short)) &&
114 bitspersample != (CHAR_BIT *
sizeof(
float)) ) {
117 sprintf(desc,
"invalid %d bits. only %d-bit and %d-bit TIFF are supported",
118 bitspersample, CHAR_BIT, (
int)(CHAR_BIT *
sizeof(
short)));
123 tiff_file = TIFFOpen(filename.c_str(),
"w");
135 }
while (TIFFReadDirectory(tiff_file));
141bool TiffIO::is_valid(
const void *first_block)
150 const char *data =
static_cast < const char *
>(first_block);
152 if ((data[0] == data[1]) && (data[0] == TIFF_LITTLE_ENDIAN ||
153 data[1] == TIFF_BIG_ENDIAN)) {
162int TiffIO::get_nimg()
169int TiffIO::read_header(
Dict & dict,
int image_index,
const Region * area,
bool)
175 if (image_index == -1) {
179 TIFFSetDirectory(tiff_file, image_index);
184 TIFFGetField(tiff_file, TIFFTAG_IMAGEWIDTH, &nx);
185 TIFFGetField(tiff_file, TIFFTAG_IMAGELENGTH, &ny);
187 check_region(area,
IntSize(nx, ny));
192 TIFFDataType data_type = TIFF_NOTYPE;
194 float resolution_x = 0;
195 float resolution_y = 0;
197 TIFFGetField(tiff_file, TIFFTAG_MINSAMPLEVALUE, &min);
198 TIFFGetField(tiff_file, TIFFTAG_MAXSAMPLEVALUE, &max);
200 TIFFGetField(tiff_file, TIFFTAG_PHOTOMETRIC, &photometric);
202 TIFFGetField(tiff_file, TIFFTAG_SAMPLEFORMAT, &data_type);
203 TIFFGetField(tiff_file, TIFFTAG_XRESOLUTION, &resolution_x);
204 TIFFGetField(tiff_file, TIFFTAG_YRESOLUTION, &resolution_y);
206 int xlen = 0, ylen = 0;
208 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
215 dict[
"minimum"] = min;
216 dict[
"maximum"] = max;
218 if (bitspersample == CHAR_BIT) {
219 dict[
"datatype"] = EMUtil::EM_UCHAR;
221 else if (bitspersample ==
sizeof(
unsigned short) * CHAR_BIT) {
222 dict[
"datatype"] = EMUtil::EM_USHORT;
224 else if (bitspersample ==
sizeof(
float) * CHAR_BIT) {
225 dict[
"datatype"] = EMUtil::EM_FLOAT;
228 dict[
"TIFF.bitspersample"] = bitspersample;
229 dict[
"TIFF.resolution_x"] = resolution_x;
230 dict[
"TIFF.resolution_y"] = resolution_y;
240 check_read_access(image_index,
rdata);
242 TIFFSetDirectory(tiff_file, image_index);
247 TIFFGetField(tiff_file, TIFFTAG_IMAGEWIDTH, & nx);
248 TIFFGetField(tiff_file, TIFFTAG_IMAGELENGTH, & ny);
255 if (photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK) {
256 unsigned char *cdata;
258 if (TIFFIsTiled(tiff_file)) {
259 tsize_t tileSize = TIFFTileSize(tiff_file);
260 tsize_t tileMax = TIFFNumberOfTiles(tiff_file);
263 uint32 tileWidth, tileLength;
264 TIFFGetField(tiff_file, TIFFTAG_TILEWIDTH, &tileWidth);
265 TIFFGetField(tiff_file, TIFFTAG_TILELENGTH, &tileLength);
267 if ((cdata=(
unsigned char*)_TIFFmalloc(tileSize))==NULL){
268 fprintf(stderr,
"Error: Could not allocate enough memory\n");
272 int tilePerLine = nx/tileWidth + 1;
276 for (tileCount=0; tileCount<tileMax; tileCount++) {
277 if (TIFFReadEncodedTile(tiff_file, tileCount, cdata, tileSize) == -1) {
278 fprintf(stderr,
"Error reading tiled image\n");
282 NX = tileCount%tilePerLine;
283 NY = tileCount/tilePerLine;
286 for (i=0; i<tileLength; i++) {
287 for (j=0; j<tileWidth; j++) {
288 xpos = NX*tileWidth + j;
289 ypos = NY*tileLength + i;
291 if (bitspersample == CHAR_BIT) {
292 if (xpos<nx && ypos<ny) {
293 photometric == PHOTOMETRIC_MINISWHITE ?
294 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -(float) ((
unsigned char*)cdata)[i*tileWidth+j] :
295 rdata[nx*(ny-1)-(ypos*nx)+xpos] = (
float) ((
unsigned char*)cdata)[i*tileWidth+j];
298 else if (bitspersample ==
sizeof(
unsigned short) * CHAR_BIT) {
299 if(xpos<nx && ypos<ny) {
300 photometric == PHOTOMETRIC_MINISWHITE ?
301 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -(float) ((
unsigned short*)cdata)[i*tileWidth+j] :
302 rdata[nx*(ny-1)-(ypos*nx)+xpos] = (
float) ((
unsigned short*)cdata)[i*tileWidth+j];
305 else if (bitspersample ==
sizeof(
float) * CHAR_BIT) {
306 photometric == PHOTOMETRIC_MINISWHITE ?
307 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -((
float*)cdata)[i*tileWidth+j] :
308 rdata[nx*(ny-1)-(ypos*nx)+xpos] = ((
float*)cdata)[i*tileWidth+j];
311 fprintf(stderr,
"BAILING OUT:Allow only 8- or 16-bits image\n");
321 check_region(area,
IntSize(nx, ny));
322 int xlen = 0, ylen = 0, x0 = 0, y0 = 0;
324 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
325 EMUtil::get_region_origins(area, &x0, &y0);
327 int strip_size = TIFFStripSize(tiff_file);
328 uint32 num_strips = TIFFNumberOfStrips(tiff_file);
330 if ((cdata =
static_cast < unsigned char *
>(_TIFFmalloc(strip_size)))==NULL) {
331 fprintf(stderr,
"Error: Could not allocate enough memory\n");
337 int mode_size = bitspersample / CHAR_BIT;
340 for (uint32 i = 0; i < num_strips; i++) {
341 if ((num_read = TIFFReadEncodedStrip(tiff_file, i, cdata, strip_size)) == -1) {
342 LOGERR(
"reading stripped TiFF image '%s' failed", filename.c_str());
347 int nitems = num_read / mode_size;
348 int nrows = nitems / nx;
355 if (total_rows >= y0 && total_rows < y0 + nrows) {
356 y_start = nrows - (total_rows - y0);
358 else if (total_rows >= (y0 + ylen) && total_rows < (y0 + ylen + nrows)) {
359 y_end = y0 + ylen - total_rows + nrows;
361 else if (total_rows >= (y0 + ylen + nrows)) {
366 for (
int l = y_start; l < y_end; l++) {
367 for (
int j = x0; j < x0 + xlen; j++) {
368 if (bitspersample == CHAR_BIT) {
369 photometric == PHOTOMETRIC_MINISWHITE ?
370 rdata[k] = -(float) ((
unsigned char*)cdata)[l * nx + j] :
371 rdata[k] = (
float) ((
unsigned char*)cdata)[l * nx + j];
373 else if (bitspersample ==
sizeof(
unsigned short) * CHAR_BIT) {
374 photometric == PHOTOMETRIC_MINISWHITE ?
375 rdata[k] = -(float)((
unsigned short*)cdata)[l * nx + j] :
376 rdata[k] = (
float)((
unsigned short*)cdata)[l * nx + j];
378 else if (bitspersample ==
sizeof(
float) * CHAR_BIT) {
379 photometric == PHOTOMETRIC_MINISWHITE ?
380 rdata[k] = -((
float*)cdata)[l * nx + j] :
381 rdata[k] = ((
float*)cdata)[l * nx + j];
388 Util::flip_image(
rdata, xlen, ylen);
394 size_t npixels = nx * ny;
395 uint32 * raster = (uint32*) _TIFFmalloc(npixels *
sizeof(uint32));
397 if (raster != NULL) {
398 if (TIFFReadRGBAImage(tiff_file, nx, ny, raster, 0)) {
400 int red=0, green=0, blue=0;
402 for (
int i=0; i<nx; ++i) {
403 for (
int j=0; j<ny; ++j) {
404 abgr = raster[j+ny*i];
405 red = TIFFGetR(abgr);
406 green = TIFFGetG(abgr);
407 blue = TIFFGetB(abgr);
408 rdata[j+ny*i] =
static_cast<float>(red*RED+green*GREEN+blue*BLUE);
421int TiffIO::write_header(
const Dict & dict,
int image_index,
const Region *,
428 if (image_index == -1) {
434 check_write_access(rw_mode, image_index);
436 nx = (
unsigned int) (
int) dict[
"nx"];
437 ny = (
unsigned int) (
int) dict[
"ny"];
438 nz = (
unsigned int) (
int)dict[
"nz"];
441 LOGERR(
"Only support 2D TIFF file write");
447 if (datatype == EMUtil::EM_UCHAR) {
448 bitspersample = CHAR_BIT;
450 else if (datatype == EMUtil::EM_USHORT) {
451 bitspersample = CHAR_BIT *
sizeof(short);
453 else if (datatype == EMUtil::EM_FLOAT) {
454 bitspersample = CHAR_BIT *
sizeof(float);
457 LOGWARN(
"Don't support data type '%s' in TIFF. Convert to '%s'.",
458 EMUtil::get_datatype_string(datatype),
459 EMUtil::get_datatype_string(EMUtil::EM_USHORT));
460 bitspersample = CHAR_BIT *
sizeof(short);
463 TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, bitspersample);
464 TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
465 TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
466 TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, nx);
467 TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, ny);
468 TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, ny);
469 TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
470 TIFFSetField(tiff_file, TIFFTAG_SOFTWARE,
"EMAN2" );
475 EMUtil::getRenderLimits(dict, rendermin, rendermax, renderbits);
492 int truebits=bitspersample;
493 if (renderbits==0 || renderbits>truebits) renderbits=truebits;
495 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax, renderbits);
497 if (bitspersample == CHAR_BIT) {
498 vector<unsigned char> cdata(nx*ny);
500 int src_idx, dst_idx;
502 for (
unsigned int i = 0; i < ny; ++i) {
503 for (
unsigned int j = 0; j < nx; ++j) {
505 dst_idx = nx*(ny-1) - (i*nx) +j;
507 if (data[src_idx] < rendermin){
510 else if (data[src_idx] > rendermax) {
511 cdata[dst_idx] = UCHAR_MAX;
514 cdata[dst_idx] = (
unsigned char)((data[src_idx] - rendermin) /
515 (rendermax - rendermin) * UCHAR_MAX);
520 if (TIFFWriteEncodedStrip(tiff_file, 0, cdata.data(), nx*ny) == -1) {
521 printf(
"Fail to write tiff file.\n");
526 else if (bitspersample == CHAR_BIT*
sizeof(
short)) {
527 vector<unsigned short> sdata(nx*ny);
529 int src_idx, dst_idx;
531 for (
unsigned int i = 0; i < ny; ++i) {
532 for (
unsigned int j = 0; j < nx; ++j) {
534 dst_idx = nx*(ny-1) - (i*nx) +j;
536 if (data[src_idx] < rendermin){
539 else if (data[src_idx] > rendermax) {
540 sdata[dst_idx] = USHRT_MAX;
543 sdata[dst_idx] = (
unsigned short)((data[src_idx] - rendermin) /
544 (rendermax - rendermin) * USHRT_MAX);
549 if (TIFFWriteEncodedStrip(tiff_file, 0, sdata.data(), nx*ny*
sizeof(short)) == -1) {
550 printf(
"Fail to write tiff file.\n");
555 else if (bitspersample == CHAR_BIT*
sizeof(
float)) {
556 vector<float> fdata(nx*ny);
558 int src_idx, dst_idx;
560 for (
unsigned int i = 0; i < ny; ++i) {
561 for (
unsigned int j = 0; j < nx; ++j) {
563 dst_idx = nx*(ny-1) - (i*nx) +j;
564 fdata[dst_idx] = data[src_idx];
568 if (TIFFWriteEncodedStrip(tiff_file, 0, fdata.data(), nx*ny*
sizeof(
float)) == -1) {
569 printf(
"Fail to write tiff file.\n");
575 LOGWARN(
"TIFF in EMAN2 only support data type 8 bit, 16 bit or 32 bit.");
584 TIFFFlush(tiff_file);
587bool TiffIO::is_complex_mode()
592bool TiffIO::is_image_big_endian()
595 return is_big_endian;
ByteOrder defines functions to work on big/little endian byte orders.
Dict is a dictionary to store <string, EMObject> pair.
EMDataType
Image pixel data type used in EMAN.
ImageIO classes are designed for reading/writing various electron micrography image formats,...
IntSize is used to describe a 1D, 2D or 3D rectangular size in integers.
Region defines a 2D or 3D rectangular region specified by its origin coordinates and all edges' sizes...
#define ImageReadException(filename, desc)