00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 #ifdef EM_TIFF
00037
00038 #include "tifio.h"
00039 #include "util.h"
00040 #include "geometry.h"
00041 #include <tiffio.h>
00042 #include <climits>
00043
00044 using namespace EMAN;
00045
00046 namespace {
00047
00048 #define PCT(x) (((x)*255+127)/100)
00049 const int RED = PCT(30);
00050 const int GREEN = PCT(59);
00051 const int BLUE = PCT(11);
00052 }
00053
00054 TiffIO::TiffIO(string tiff_filename, IOMode rw)
00055 : filename(tiff_filename), rw_mode(rw), tiff_file(0),
00056 bitspersample(0), photometric(0), initialized(false),
00057 rendermin(0.0f), rendermax(0.0f)
00058 {
00059 is_big_endian = ByteOrder::is_host_big_endian();
00060 }
00061
00062
00063 TiffIO::~TiffIO()
00064 {
00065 if (tiff_file) {
00066 TIFFClose(tiff_file);
00067 tiff_file = 0;
00068 }
00069 }
00070
00071 void TiffIO::init()
00072 {
00073 ENTERFUNC;
00074 if (initialized) {
00075 return;
00076 }
00077 initialized = true;
00078
00079 bool is_new_file = false;
00080 FILE *tmp_in = sfopen(filename, rw_mode, &is_new_file, true);
00081 if (!tmp_in) {
00082 throw ImageReadException(filename, "open TIFF");
00083 }
00084
00085 if( !is_new_file ) {
00086 char buf[64];
00087 if (fread(buf, sizeof(buf), 1, tmp_in) != 1) {
00088 throw ImageReadException(filename, "first block");
00089 }
00090
00091 if (!is_valid(&buf)) {
00092 throw ImageReadException(filename, "invalid TIFF");
00093 }
00094
00095 if (buf[0] == TIFF_BIG_ENDIAN) {
00096 is_big_endian = true;
00097 }
00098 else {
00099 is_big_endian = false;
00100 }
00101 }
00102
00103 fclose(tmp_in);
00104 tmp_in = 0;
00105
00106 TIFFSetWarningHandler(0);
00107
00108 if( rw_mode == ImageIO::READ_ONLY ) {
00109 tiff_file = TIFFOpen(filename.c_str(), "r");
00110
00111 if (!tiff_file) {
00112 throw ImageReadException(filename, "open TIFF");
00113 }
00114
00115 TIFFGetField(tiff_file, TIFFTAG_BITSPERSAMPLE, &bitspersample);
00116
00117 if (bitspersample != CHAR_BIT &&
00118 bitspersample != (CHAR_BIT * sizeof(short)) &&
00119 bitspersample != (CHAR_BIT * sizeof(float)) ) {
00120 char desc[256];
00121 sprintf(desc, "invalid %d bits. only %d-bit and %d-bit TIFF are supported",
00122 bitspersample, CHAR_BIT, (int)(CHAR_BIT * sizeof(short)));
00123 throw ImageReadException(filename, desc);
00124 }
00125 }
00126 else {
00127 tiff_file = TIFFOpen(filename.c_str(), "w");
00128 if (!tiff_file) {
00129 throw ImageReadException(filename, "open TIFF");
00130 }
00131 }
00132
00133 EXITFUNC;
00134 }
00135
00136 bool TiffIO::is_valid(const void *first_block)
00137 {
00138 ENTERFUNC;
00139 bool result = false;
00140
00141 if (!first_block) {
00142 result = false;
00143 }
00144 else {
00145 const char *data = static_cast < const char *>(first_block);
00146
00147 if ((data[0] == data[1]) && (data[0] == TIFF_LITTLE_ENDIAN || data[1] == TIFF_BIG_ENDIAN)) {
00148 result = true;
00149 }
00150 }
00151 EXITFUNC;
00152 return result;
00153 }
00154
00155 int TiffIO::read_header(Dict & dict, int image_index, const Region * area, bool)
00156 {
00157 ENTERFUNC;
00158
00159 init();
00160
00161
00162 if(image_index == -1) {
00163 image_index = 0;
00164 }
00165
00166 if(image_index != 0) {
00167 throw ImageReadException(filename, "no stack allowed for MRC image. For take 2D slice out of 3D image, read the 3D image first, then use get_clip().");
00168 }
00169
00170 int nx = 0;
00171 int ny = 0;
00172 TIFFGetField(tiff_file, TIFFTAG_IMAGEWIDTH, &nx);
00173 TIFFGetField(tiff_file, TIFFTAG_IMAGELENGTH, &ny);
00174
00175 check_region(area, IntSize(nx, ny));
00176
00177 float min = 0;
00178 float max = 0;
00179 TIFFDataType data_type = TIFF_NOTYPE;
00180 float resolution_x = 0;
00181 float resolution_y = 0;
00182
00183 TIFFGetField(tiff_file, TIFFTAG_MINSAMPLEVALUE, &min);
00184 TIFFGetField(tiff_file, TIFFTAG_MAXSAMPLEVALUE, &max);
00185
00186 TIFFGetField(tiff_file, TIFFTAG_PHOTOMETRIC, &photometric);
00187
00188 TIFFGetField(tiff_file, TIFFTAG_SAMPLEFORMAT, &data_type);
00189 TIFFGetField(tiff_file, TIFFTAG_XRESOLUTION, &resolution_x);
00190 TIFFGetField(tiff_file, TIFFTAG_YRESOLUTION, &resolution_y);
00191
00192 int xlen = 0, ylen = 0;
00193 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00194
00195 dict["nx"] = xlen;
00196 dict["ny"] = ylen;
00197 dict["nz"] = 1;
00198
00199 dict["minimum"] = min;
00200 dict["maximum"] = max;
00201
00202 if (bitspersample == CHAR_BIT) {
00203 dict["datatype"] = EMUtil::EM_UCHAR;
00204 }
00205 else if (bitspersample == sizeof(unsigned short) * CHAR_BIT) {
00206 dict["datatype"] = EMUtil::EM_USHORT;
00207 }
00208 else if (bitspersample == sizeof(float) * CHAR_BIT) {
00209 dict["datatype"] = EMUtil::EM_FLOAT;
00210 }
00211
00212 dict["TIFF.bitspersample"] = bitspersample;
00213 dict["TIFF.resolution_x"] = resolution_x;
00214 dict["TIFF.resolution_y"] = resolution_y;
00215 EXITFUNC;
00216 return 0;
00217 }
00218
00219 int TiffIO::read_data(float *rdata, int image_index, const Region * area, bool)
00220 {
00221 ENTERFUNC;
00222
00223
00224 image_index = 0;
00225 check_read_access(image_index, rdata);
00226
00227 int nx = 0;
00228 int ny = 0;
00229 TIFFGetField(tiff_file, TIFFTAG_IMAGEWIDTH, &nx);
00230 TIFFGetField(tiff_file, TIFFTAG_IMAGELENGTH, &ny);
00231
00232 int err = 0;
00233
00234
00235
00236 if(photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK) {
00237 unsigned char *cdata;
00238
00239 if(TIFFIsTiled(tiff_file)) {
00240 tsize_t tileSize = TIFFTileSize(tiff_file);
00241 tsize_t tileMax = TIFFNumberOfTiles(tiff_file);
00242 tsize_t tileCount;
00243
00244 uint32 tileWidth, tileLength;
00245 TIFFGetField(tiff_file, TIFFTAG_TILEWIDTH, &tileWidth);
00246 TIFFGetField(tiff_file, TIFFTAG_TILELENGTH, &tileLength);
00247
00248 if((cdata=(unsigned char*)_TIFFmalloc(tileSize))==NULL){
00249 fprintf(stderr,"Error: Could not allocate enough memory\n");
00250 return(-1);
00251 }
00252
00253 int tilePerLine = nx/tileWidth + 1;
00254 int NX, NY;
00255 int xpos, ypos;
00256
00257 for(tileCount=0; tileCount<tileMax; tileCount++) {
00258 if(TIFFReadEncodedTile(tiff_file, tileCount, cdata, tileSize) == -1) {
00259 fprintf(stderr,"Error reading tiled image\n");return(-1);
00260 }
00261 else {
00262 NX = tileCount%tilePerLine;
00263 NY = tileCount/tilePerLine;
00264 uint32 i, j;
00265 for(i=0; i<tileLength; i++) {
00266 for(j=0; j<tileWidth; j++) {
00267 xpos = NX*tileWidth + j;
00268 ypos = NY*tileLength + i;
00269
00270 if(bitspersample == CHAR_BIT) {
00271 if(xpos<nx && ypos<ny) {
00272 photometric == PHOTOMETRIC_MINISWHITE ?
00273 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -(float) ((unsigned char*)cdata)[i*tileWidth+j] :
00274 rdata[nx*(ny-1)-(ypos*nx)+xpos] = (float) ((unsigned char*)cdata)[i*tileWidth+j];
00275 }
00276 }
00277 else if(bitspersample == sizeof(unsigned short) * CHAR_BIT) {
00278 if(xpos<nx && ypos<ny) {
00279 photometric == PHOTOMETRIC_MINISWHITE ?
00280 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -(float) ((unsigned short*)cdata)[i*tileWidth+j] :
00281 rdata[nx*(ny-1)-(ypos*nx)+xpos] = (float) ((unsigned short*)cdata)[i*tileWidth+j];
00282 }
00283 }
00284 else if (bitspersample == sizeof(float) * CHAR_BIT) {
00285 photometric == PHOTOMETRIC_MINISWHITE ?
00286 rdata[nx*(ny-1)-(ypos*nx)+xpos] = -((float*)cdata)[i*tileWidth+j] :
00287 rdata[nx*(ny-1)-(ypos*nx)+xpos] = ((float*)cdata)[i*tileWidth+j];
00288 }
00289 else {
00290 fprintf(stderr,"BAILING OUT:Allow only 8- or 16-bits image\n");
00291 return(-1);
00292 }
00293 }
00294 }
00295 }
00296 }
00297
00298 }
00299 else {
00300 check_region(area, IntSize(nx, ny));
00301 int xlen = 0, ylen = 0, x0 = 0, y0 = 0;
00302 EMUtil::get_region_dims(area, nx, &xlen, ny, &ylen);
00303 EMUtil::get_region_origins(area, &x0, &y0);
00304
00305 int strip_size = TIFFStripSize(tiff_file);
00306 uint32 num_strips = TIFFNumberOfStrips(tiff_file);
00307
00308 if((cdata = static_cast < unsigned char *>(_TIFFmalloc(strip_size)))==NULL) {
00309 fprintf(stderr,"Error: Could not allocate enough memory\n");
00310 return(-1);
00311 }
00312
00313 int k = 0;
00314 int num_read = 0;
00315 int mode_size = bitspersample / CHAR_BIT;
00316 int total_rows = 0;
00317
00318 for (uint32 i = 0; i < num_strips; i++) {
00319 if ((num_read = TIFFReadEncodedStrip(tiff_file, i, cdata, strip_size)) == -1) {
00320 LOGERR("reading stripped TiFF image '%s' failed", filename.c_str());
00321 err = 1;
00322 break;
00323 }
00324
00325 int nitems = num_read / mode_size;
00326 int nrows = nitems / nx;
00327 total_rows += nrows;
00328
00329 int y_start = 0;
00330 int y_end = nrows;
00331
00332 if (area) {
00333 if (total_rows >= y0 && total_rows < y0 + nrows) {
00334 y_start = nrows - (total_rows - y0);
00335 }
00336 else if (total_rows >= (y0 + ylen) && total_rows < (y0 + ylen + nrows)) {
00337 y_end = y0 + ylen - total_rows + nrows;
00338 }
00339 else if (total_rows >= (y0 + ylen + nrows)) {
00340 break;
00341 }
00342 }
00343
00344 for (int l = y_start; l < y_end; l++) {
00345 for (int j = x0; j < x0 + xlen; j++) {
00346 if (bitspersample == CHAR_BIT) {
00347 photometric == PHOTOMETRIC_MINISWHITE ?
00348 rdata[k] = -(float) ((unsigned char*)cdata)[l * nx + j] :
00349 rdata[k] = (float) ((unsigned char*)cdata)[l * nx + j];
00350 }
00351 else if (bitspersample == sizeof(unsigned short) * CHAR_BIT) {
00352 photometric == PHOTOMETRIC_MINISWHITE ?
00353 rdata[k] = -(float)((unsigned short*)cdata)[l * nx + j] :
00354 rdata[k] = (float)((unsigned short*)cdata)[l * nx + j];
00355 }
00356 else if (bitspersample == sizeof(float) * CHAR_BIT) {
00357 photometric == PHOTOMETRIC_MINISWHITE ?
00358 rdata[k] = -((float*)cdata)[l * nx + j] :
00359 rdata[k] = ((float*)cdata)[l * nx + j];
00360 }
00361 k++;
00362 }
00363 }
00364 }
00365 Util::flip_image(rdata, xlen, ylen);
00366 }
00367 _TIFFfree(cdata);
00368 }
00369 else {
00370 size_t npixels = nx * ny;
00371 uint32 * raster = (uint32*) _TIFFmalloc(npixels * sizeof(uint32));
00372 if(raster != NULL) {
00373 if(TIFFReadRGBAImage(tiff_file, nx, ny, raster, 0)) {
00374 int abgr = 0;
00375 int red=0, green=0, blue=0;
00376 for (int i=0; i<nx; ++i) {
00377 for (int j=0; j<ny; ++j) {
00378 abgr = raster[j+ny*i];
00379 red = TIFFGetR(abgr);
00380 green = TIFFGetG(abgr);
00381 blue = TIFFGetB(abgr);
00382 rdata[j+ny*i] = static_cast<float>(red*RED+green*GREEN+blue*BLUE);
00383 }
00384 }
00385 _TIFFfree(raster);
00386 }
00387 }
00388 }
00389
00390 EXITFUNC;
00391 return err;
00392 }
00393
00394
00395 int TiffIO::write_header(const Dict & dict, int image_index, const Region*, EMUtil::EMDataType datatype, bool)
00396 {
00397 ENTERFUNC;
00398
00399
00400 if(image_index == -1) {
00401 image_index = 0;
00402 }
00403 if(image_index != 0) {
00404 throw ImageWriteException(filename, "TIFF file does not support stack.");
00405 }
00406 check_write_access(rw_mode, image_index);
00407
00408 nx = (unsigned int) (int) dict["nx"];
00409 ny = (unsigned int) (int) dict["ny"];
00410 nz = (unsigned int) (int)dict["nz"];
00411 if (nz != 1) {
00412 LOGERR("Only support 2D TIFF file write");
00413 return 1;
00414 }
00415
00416
00417 if (datatype == EMUtil::EM_UCHAR) {
00418 bitspersample = CHAR_BIT;
00419 }
00420 else if(datatype == EMUtil::EM_USHORT) {
00421 bitspersample = CHAR_BIT * sizeof(short);
00422 }
00423 else if(datatype == EMUtil::EM_FLOAT) {
00424 bitspersample = CHAR_BIT * sizeof(float);
00425 }
00426 else {
00427 LOGWARN("Don't support data type '%s' in TIFF. Convert to '%s'.",
00428 EMUtil::get_datatype_string(datatype),
00429 EMUtil::get_datatype_string(EMUtil::EM_USHORT));
00430 bitspersample = CHAR_BIT * sizeof(short);
00431 }
00432 TIFFSetField(tiff_file, TIFFTAG_BITSPERSAMPLE, bitspersample);
00433 TIFFSetField(tiff_file, TIFFTAG_SAMPLESPERPIXEL, 1);
00434 TIFFSetField(tiff_file, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
00435 TIFFSetField(tiff_file, TIFFTAG_IMAGEWIDTH, nx);
00436 TIFFSetField(tiff_file, TIFFTAG_IMAGELENGTH, ny);
00437 TIFFSetField(tiff_file, TIFFTAG_ROWSPERSTRIP, ny);
00438 TIFFSetField(tiff_file, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
00439 TIFFSetField(tiff_file, TIFFTAG_SOFTWARE, "EMAN2" );
00440
00441
00442
00443 EXITFUNC;
00444 return 0;
00445 }
00446
00447 int TiffIO::write_data(float * data, int, const Region* , EMUtil::EMDataType, bool)
00448 {
00449 ENTERFUNC;
00450
00451
00452 EMUtil::getRenderMinMax(data, nx, ny, rendermin, rendermax);
00453
00454 if(bitspersample == CHAR_BIT) {
00455 unsigned char *cdata = new unsigned char[nx*ny];
00456
00457 int src_idx, dst_idx;
00458 for (unsigned int i = 0; i < ny; ++i) {
00459 for (unsigned int j = 0; j < nx; ++j) {
00460 src_idx = i*nx+j;
00461 dst_idx = nx*(ny-1) - (i*nx) +j;
00462 if(data[src_idx] < rendermin){
00463 cdata[dst_idx] = 0;
00464 }
00465 else if(data[src_idx] > rendermax) {
00466 cdata[dst_idx] = UCHAR_MAX;
00467 }
00468 else {
00469 cdata[dst_idx] = (unsigned char)((data[src_idx] - rendermin) / (rendermax - rendermin) * UCHAR_MAX);
00470 }
00471 }
00472 }
00473
00474 if(TIFFWriteEncodedStrip(tiff_file, 0, cdata, nx*ny) == -1)
00475 { printf("Fail to write tiff file.\n"); return -1; }
00476
00477 if( cdata ) { delete[] cdata; cdata = 0; }
00478 }
00479 else if(bitspersample == CHAR_BIT*sizeof(short)) {
00480 unsigned short *sdata = new unsigned short[nx*ny];
00481
00482 int src_idx, dst_idx;
00483 for (unsigned int i = 0; i < ny; ++i) {
00484 for (unsigned int j = 0; j < nx; ++j) {
00485 src_idx = i*nx+j;
00486 dst_idx = nx*(ny-1) - (i*nx) +j;
00487 if(data[src_idx] < rendermin){
00488 sdata[dst_idx] = 0;
00489 }
00490 else if(data[src_idx] > rendermax) {
00491 sdata[dst_idx] = USHRT_MAX;
00492 }
00493 else {
00494 sdata[dst_idx] = (unsigned short)((data[src_idx] - rendermin) / (rendermax - rendermin) * USHRT_MAX);
00495 }
00496 }
00497 }
00498
00499 if(TIFFWriteEncodedStrip(tiff_file, 0, sdata, nx*ny*sizeof(short)) == -1)
00500 { printf("Fail to write tiff file.\n"); return -1; }
00501
00502 if( sdata ) { delete[] sdata; sdata = 0; }
00503 }
00504 else if(bitspersample == CHAR_BIT*sizeof(float)) {
00505 float *fdata = new float[nx*ny];
00506
00507 int src_idx, dst_idx;
00508 for (unsigned int i = 0; i < ny; ++i) {
00509 for (unsigned int j = 0; j < nx; ++j) {
00510 src_idx = i*nx+j;
00511 dst_idx = nx*(ny-1) - (i*nx) +j;
00512 fdata[dst_idx] = data[src_idx];
00513 }
00514 }
00515
00516 if(TIFFWriteEncodedStrip(tiff_file, 0, fdata, nx*ny*sizeof(float)) == -1)
00517 { printf("Fail to write tiff file.\n"); return -1; }
00518
00519 if( fdata ) { delete[] fdata; fdata = 0; }
00520 }
00521 else {
00522 LOGWARN("TIFF in EMAN2 only support data type 8 bit, 16 bit or 32 bit.");
00523 }
00524
00525 EXITFUNC;
00526 return 0;
00527 }
00528
00529 void TiffIO::flush()
00530 {
00531 TIFFFlush(tiff_file);
00532 }
00533
00534 bool TiffIO::is_complex_mode()
00535 {
00536 return false;
00537 }
00538
00539 bool TiffIO::is_image_big_endian()
00540 {
00541 init();
00542 return is_big_endian;
00543 }
00544
00545
00546 #endif //EM_TIFF