#include #include #include #include #include #include #include #include #include #include /**************************************************************************** * * Follows is code extracted from the simage library. Original Authors: * * Systems in Motion, * * * Peder Blekken * Morten Eriksen * Marius Bugge Monsen * * The original COPYING notice * * All files in this library are public domain, except simage_rgb.cpp which is * Copyright (c) Mark J Kilgard . I will contact Mark * very soon to hear if this source also can become public domain. * * Please send patches for bugs and new features to: . * * Peder Blekken * * * Ported into the OSG as a plugin, Robert Osfield Decemeber 2000. * Note, reference above to license of simage_rgb is not relevant to the OSG * as the OSG does not use it. Also for patches, bugs and new features * please send them direct to the OSG dev team rather than address above. * **********************************************************************/ #include #include #include #include #define ERR_NO_ERROR 0 #define ERR_OPEN 1 #define ERR_READ 2 #define ERR_MEM 3 #define ERR_UNSUPPORTED 4 #define ERR_TIFFLIB 5 /* Functions to read TIFF image from memory * */ tsize_t libtiffStreamReadProc(thandle_t fd, tdata_t buf, tsize_t size) { std::istream *fin = (std::istream*)fd; fin->read((char*)buf,size); if(fin->bad()) return -1; if(fin->gcount() < size) return 0; return size; } tsize_t libtiffStreamWriteProc(thandle_t, tdata_t, tsize_t) { return 0; } toff_t libtiffStreamSeekProc(thandle_t fd, toff_t off, int i) { std::istream *fin = (std::istream*)fd; toff_t ret; switch(i) { case SEEK_SET: fin->seekg(off,std::ios::beg); ret = fin->tellg(); if(fin->bad()) ret = 0; break; case SEEK_CUR: fin->seekg(off,std::ios::cur); ret = fin->tellg(); if(fin->bad()) ret = 0; break; case SEEK_END: fin->seekg(off,std::ios::end); ret = fin->tellg(); if(fin->bad()) ret = 0; break; default: ret = 0; break; } return ret; } int libtiffStreamCloseProc(thandle_t) { return 0; } toff_t libtiffStreamSizeProc(thandle_t fd) { std::istream *fin = (std::istream*)fd; std::streampos curPos = fin->tellg(); fin->seekg(0, std::ios::end); toff_t size = fin->tellg(); fin->seekg(curPos, std::ios::beg); return size; } int libtiffStreamMapProc(thandle_t, tdata_t*, toff_t*) { return 0; } void libtiffStreamUnmapProc(thandle_t, tdata_t, toff_t) { } /* Functions to write TIFF image from memory * */ tsize_t libtiffOStreamReadProc(thandle_t, tdata_t, tsize_t) { return 0; } tsize_t libtiffOStreamWriteProc(thandle_t fd, tdata_t buf, tsize_t size) { std::ostream *fout = (std::ostream*)fd; fout->write((const char*)buf,size); if(fout->bad()) { return -1; } return size; } toff_t libtiffOStreamSizeProc(thandle_t fd) { std::ostream *fout = (std::ostream*)fd; std::streampos curPos = fout->tellp(); fout->seekp(0, std::ios::end); toff_t size = fout->tellp(); fout->seekp(curPos, std::ios::beg); return size; } toff_t libtiffOStreamSeekProc(thandle_t fd, toff_t off, int i) { std::ostream *fout = (std::ostream*)fd; toff_t pos_required = 0; toff_t stream_end = 0; switch(i) { case SEEK_SET: { if (off==0) { std::streampos checkEmpty = fout->tellp(); if(checkEmpty < 0) { return 0; } } pos_required = off; fout->seekp(0, std::ios::end); stream_end = fout->tellp(); break; } case SEEK_CUR: { toff_t stream_curr = fout->tellp(); pos_required = stream_curr + off; fout->seekp(0, std::ios::end); stream_end = fout->tellp(); break; } case SEEK_END: { fout->seekp(0, std::ios::end); stream_end = fout->tellp(); pos_required = stream_end + off; break; } default: break; } if (pos_required>stream_end) { // position required past the end of the stream so we need to insert extra characters to // ensure the stream is big enough to encompass the new the position. fout->seekp(0, std::ios::end); for(toff_t i=stream_end; iput(char(0)); } } fout->seekp(pos_required,std::ios::beg); toff_t ret = fout->tellp(); if (fout->bad()) { ret = 0; } return ret; } static int tifferror = ERR_NO_ERROR; int simage_tiff_error(char * buffer, int buflen) { switch (tifferror) { case ERR_OPEN: strncpy(buffer, "TIFF loader: Error opening file", buflen); break; case ERR_READ: strncpy(buffer, "TIFF loader: Error reading/decoding file", buflen); break; case ERR_MEM: strncpy(buffer, "TIFF loader: Out of memory error", buflen); break; case ERR_UNSUPPORTED: strncpy(buffer, "TIFF loader: Unsupported image type", buflen); break; case ERR_TIFFLIB: strncpy(buffer, "TIFF loader: Illegal tiff file", buflen); break; default: strncpy(buffer, "TIFF loader: unknown error", buflen); break; } return tifferror; } /// Generates a std::string from a printf format string and a va_list. /// Took & adapted from the man page of printf. ///\todo Externalize this function to make is useable for all OSG? std::string doFormat(const char* fmt, va_list ap) { static const int MSG_BUFSIZE = 256; // Initial size of the buffer used for formatting static const int MAX_BUFSIZE = 256*1024; // Maximum size of the buffer used for formatting for(int size=MSG_BUFSIZE; size= 0 && n < size) { std::string res(p); delete[] p; return res; } /* Else try again with more space. */ if (n > 0) /* glibc 2.1 */ size = n+1; /* precisely what is needed */ else /* glibc 2.0 */ size *= 2; /* twice the old size */ delete[] p; } return std::string(fmt, fmt+MSG_BUFSIZE) + "..."; // Fallback: Message is not formatted and truncated, but that's better than no message } static void tiff_error(const char*, const char* fmt, va_list ap) { // values are (const char* module, const char* fmt, va_list list) /* FIXME: store error message ? */ OSG_WARN << "TIFF rader: " << doFormat(fmt, ap) << std::endl; } static void tiff_warn(const char*, const char* fmt, va_list ap) { // values are (const char* module, const char* fmt, va_list list) /* FIXME: notify? */ OSG_NOTICE << "TIFF rader: " << doFormat(fmt, ap) << std::endl; } static int checkcmap(int n, uint16* r, uint16* g, uint16* b) { while (n-- > 0) if (*r++ >= 256 || *g++ >= 256 || *b++ >= 256) return (16); /* Assuming 8-bit colormap */ return (8); } static void invert_row(unsigned char *ptr, unsigned char *data, int n, int invert, uint16 bitspersample) { // OSG_NOTICE<<"invert_row "<setImage(s,t,r, internalFormat, pixelFormat, dataType, imageData, osg::Image::USE_NEW_DELETE); return pOsgImage; } WriteResult::WriteStatus writeTIFStream(std::ostream& fout, const osg::Image& img, const osgDB::ReaderWriter::Options* options) const { int compressionType = COMPRESSION_PACKBITS; if (options) { std::istringstream iss(options->getOptionString()); std::string opt; while (iss >> opt) { opt = osgDB::convertToLowerCase(opt); std::size_t eqInd = opt.find("="); if (opt.substr(0, eqInd) == "tiff_compression") { std::string compressTypeOpt; compressTypeOpt = opt.substr(eqInd + 1); compressTypeOpt = osgDB::convertToLowerCase(compressTypeOpt); if (compressTypeOpt == "packbits") { compressionType = COMPRESSION_PACKBITS; } else if (compressTypeOpt == "lzw") { compressionType = COMPRESSION_LZW; } else if (compressTypeOpt == "jpeg") { compressionType = COMPRESSION_JPEG; } else if (compressTypeOpt == "none") { compressionType = COMPRESSION_NONE; } } } } //Code is based from the following article on CodeProject.com //http://www.codeproject.com/bitmap/BitmapsToTiffs.asp TIFF *image; int samplesPerPixel; int bitsPerSample; uint16 photometric; image = TIFFClientOpen("outputstream", "w", (thandle_t)&fout, libtiffOStreamReadProc, //Custom read function libtiffOStreamWriteProc, //Custom write function libtiffOStreamSeekProc, //Custom seek function libtiffStreamCloseProc, //Custom close function libtiffOStreamSizeProc, //Custom size function libtiffStreamMapProc, //Custom map function libtiffStreamUnmapProc); //Custom unmap function if(image == NULL) { return WriteResult::ERROR_IN_WRITING_FILE; } switch(img.getPixelFormat()) { case GL_DEPTH_COMPONENT: case GL_LUMINANCE: case GL_ALPHA: case GL_RED: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 1; break; case GL_LUMINANCE_ALPHA: case GL_RG: photometric = PHOTOMETRIC_MINISBLACK; samplesPerPixel = 2; break; case GL_RGB: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 3; break; case GL_RGBA: photometric = PHOTOMETRIC_RGB; samplesPerPixel = 4; break; default: return WriteResult::ERROR_IN_WRITING_FILE; break; } uint32 rowsperstrip = 0; switch(img.getDataType()){ case GL_FLOAT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_IEEEFP); rowsperstrip = 1; bitsPerSample = 32; break; case GL_SHORT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_INT); bitsPerSample = 16; break; case GL_UNSIGNED_SHORT: TIFFSetField(image, TIFFTAG_SAMPLEFORMAT, SAMPLEFORMAT_UINT); bitsPerSample = 16; break; default: bitsPerSample = 8; break; } TIFFSetField(image, TIFFTAG_IMAGEWIDTH,img.s()); TIFFSetField(image, TIFFTAG_IMAGELENGTH,img.t()); TIFFSetField(image, TIFFTAG_BITSPERSAMPLE,bitsPerSample); TIFFSetField(image, TIFFTAG_SAMPLESPERPIXEL,samplesPerPixel); TIFFSetField(image, TIFFTAG_PHOTOMETRIC, photometric); TIFFSetField(image, TIFFTAG_COMPRESSION, compressionType); TIFFSetField(image, TIFFTAG_FILLORDER, FILLORDER_MSB2LSB); TIFFSetField(image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); if (rowsperstrip==0) rowsperstrip = TIFFDefaultStripSize(image, 0); TIFFSetField(image, TIFFTAG_ROWSPERSTRIP, rowsperstrip); // Write the information to the file for(int i = 0; i < img.t(); ++i) { TIFFWriteScanline(image,(tdata_t)img.data(0,img.t()-i-1),i,0); } // Close the file TIFFClose(image); return WriteResult::FILE_SAVED; } virtual ReadResult readObject(std::istream& fin,const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(fin, options); } virtual ReadResult readObject(const std::string& file, const osgDB::ReaderWriter::Options* options =NULL) const { return readImage(file, options); } virtual ReadResult readImage(std::istream& fin,const osgDB::ReaderWriter::Options* =NULL) const { return readTIFStream(fin); } virtual ReadResult readImage(const std::string& file, const osgDB::ReaderWriter::Options* options) const { std::string ext = osgDB::getLowerCaseFileExtension(file); if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED; std::string fileName = osgDB::findDataFile( file, options ); if (fileName.empty()) return ReadResult::FILE_NOT_FOUND; osgDB::ifstream istream(fileName.c_str(), std::ios::in | std::ios::binary); if(!istream) return ReadResult::FILE_NOT_HANDLED; ReadResult rr = readTIFStream(istream); if(rr.validImage()) rr.getImage()->setFileName(file); return rr; } virtual WriteResult writeImage(const osg::Image& img,std::ostream& fout,const osgDB::ReaderWriter::Options* options) const { WriteResult::WriteStatus ws = writeTIFStream(fout,img, options); return ws; } virtual WriteResult writeImage(const osg::Image &img,const std::string& fileName, const osgDB::ReaderWriter::Options *options) const { std::string ext = osgDB::getFileExtension(fileName); if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED; osgDB::ofstream fout(fileName.c_str(), std::ios::out | std::ios::binary); if(!fout) return WriteResult::ERROR_IN_WRITING_FILE; return writeImage(img,fout,options); } }; // now register with Registry to instantiate the above // reader/writer. REGISTER_OSGPLUGIN(tiff, ReaderWriterTIFF)