Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

tifio.cpp

Go to the documentation of this file.
00001 
00005 /*
00006  * Author: Steven Ludtke, 04/10/2003 (sludtke@bcm.edu)
00007  * Copyright (c) 2000-2006 Baylor College of Medicine
00008  *
00009  * This software is issued under a joint BSD/GNU license. You may use the
00010  * source code in this file under either license. However, note that the
00011  * complete EMAN2 and SPARX software packages have some GPL dependencies,
00012  * so you are responsible for compliance with the licenses of these packages
00013  * if you opt to use BSD licensing. The warranty disclaimer below holds
00014  * in either instance.
00015  *
00016  * This complete copyright notice must be included in any revised version of the
00017  * source code. Additional authorship citations may be added, but existing
00018  * author citations must be preserved.
00019  *
00020  * This program is free software; you can redistribute it and/or modify
00021  * it under the terms of the GNU General Public License as published by
00022  * the Free Software Foundation; either version 2 of the License, or
00023  * (at your option) any later version.
00024  *
00025  * This program is distributed in the hope that it will be useful,
00026  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00027  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00028  * GNU General Public License for more details.
00029  *
00030  * You should have received a copy of the GNU General Public License
00031  * along with this program; if not, write to the Free Software
00032  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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         /* x% weighting -> fraction of full color */
00048         #define PCT(x)  (((x)*255+127)/100)
00049         const int RED = PCT(30);                /* 30% */
00050         const int GREEN = PCT(59);              /* 59% */
00051         const int BLUE = PCT(11);               /* 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         //single image format, index can only be zero
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         //single image format, index can only be zero
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         /* for grey scale image, use TIFFReadEncodedStrip() and TIFFReadEncodedTile()
00235          * because the reading of strip image is twice time faster than TIFFReadRGBAImage -Grant*/
00236         if(photometric == PHOTOMETRIC_MINISWHITE || photometric == PHOTOMETRIC_MINISBLACK) {
00237                 unsigned char *cdata;   //buffer for strip or tile
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;     //(NX, NY) is the cordinates of tile
00255                         int xpos, ypos; //(xpos, ypos) is the actual coordinates of pixel (j,i) in image
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) {        //discard those pixel in tile which is out of actual image's boundary
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) {        //discard those pixel in tile which is out of actual image's boundary
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 {  //process color image, convert to greyscale
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;   //raw ABGR pixel value
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         //support single image TIFF only, index must be zero
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 //      EMUtil::EMDataType datatype = (EMUtil::EMDataType) (int) dict["datatype"];
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         //TIFFSetField(tiff_file, TIFFTAG_COMPRESSION, NO_COMPRESSION);
00441         //TIFFSetField(tiff_file, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB);
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         // If we didn't get any parameters in 'render_min' or 'render_max', we need to find some good ones
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

Generated on Tue Jun 11 13:46:19 2013 for EMAN2 by  doxygen 1.3.9.1