| AWARE [SYSTEMS] | Imaging expertise for the Delphi developer | |||||||
![]() |
TIFF and LibTiff Mailing List Archive | |||||||
LibTiff Mailing List
TIFF and LibTiff Mailing List Archive Contact
The TIFF Mailing List Homepage |
Thread2009.04.14 15:52 "Re: writing in-memory tiffs", by Christian HenningThanks Jason, for your answer. Most of my ideas I took from the libtiff tutorial on the IBM site: http://www.ibm.com/developerworks/linux/library/l-libtiff2/ At the very bottom there is some code for writing in-memory tiff images. They also don't implement the the size procedure. Just returning the offset value. Their seek procedure also looks wrongs. Now. I finally realized that tif_stream.cxx already implements my procedures. I think Bob, pointed that out a while ago but I didn't pick that one up. I finally have something running for writing in-memory images using stringstream. I have attached my code below. I believe there are two bugs in tif_stream.cxx. For some reasons libtiff is try to seek before writing anything. This has two ramifications: 1. _tiffosSeekProc: The seek will fail and wont be recovered by the workaround. Meaning the following write will fail. I put an if statement fixing the problem. Please see below in my seek proc. 2. _tiffosWriteProc: When writing to an empty buffer ( pos is -1 ). The return value is incorrect ( os->tellp() - pos ). I fix that with another if statement, as you can see below. The newest beta of libtiff4 still doesn't work. The console output is as follows: seek: 0 write: 8 seek: 0 error: Maximum TIFF file size exceeded Regards, Christian #include <stdio.h> #include <cassert> #include <iostream> #include <sstream> #include <fstream> #include <vector> extern "C" { #include "tiff.h" #include "tiffio.h" } using namespace std; static ostream* get_ostream( thandle_t handle ) { return reinterpret_cast< ostream* >( handle ); } static tsize_t read_proc( thandle_t fd , tdata_t buf , tsize_t size ) { return 0; } static tsize_t write_proc( thandle_t handle , tdata_t buf , tsize_t size ) { cout << "write: " << size << endl; ostream* os = get_ostream( handle ); ios::pos_type pos = os->tellp(); os->write( reinterpret_cast< const char* >( buf ) , static_cast<streamsize>( size ) ); // Bug Fix if( static_cast< streamsize >( pos ) == -1 ) { return size; } else { return static_cast< tsize_t >( os->tellp() - pos ); } } static toff_t seek_proc( thandle_t handle , toff_t off , int way ) { cout << "seek: " << off << endl; ostream* os = get_ostream( handle ); if( os->fail() ) return static_cast< toff_t >( -1 ); // Bug Fix if( static_cast< streamsize >( os->tellp() ) == -1 ) return static_cast< toff_t >( 0 ); os->seekp( off , way == SEEK_SET ? ios::beg : ( way == SEEK_CUR ? ios::cur : ios::end ) ); if( os->fail() ) { ios::iostate old_state; ios::pos_type origin; old_state = os->rdstate(); // reset the fail bit or else tellp() won't work below os->clear(os->rdstate() & ~ios::failbit); switch( way ) { case SEEK_SET: { origin = 0; break; } case SEEK_CUR: { origin = os->tellp(); break; } case SEEK_END: { os->seekp( 0, ios::end ); origin = os->tellp(); break; } } // restore original stream state os->clear( old_state ); if( ( static_cast< size_t >( origin ) + off ) > 0 ) { os->clear( os->rdstate() & ~ios::failbit ); os->seekp( 0, ios::end ); size_t num_fill = static_cast< size_t >( origin ) + off - os->tellp(); for( size_t i = 0; i < num_fill; i++ ) { os->put( '\0' ); } os->seekp( static_cast< toff_t >( origin ) + off, ios::beg ); } } return static_cast< toff_t >( os->tellp() ); } static int close_proc( thandle_t handle ) { // Our stream was not allocated by us, // so it shouldn't be closed by us. return 0; } static toff_t size_proc( thandle_t handle ) { ostream* os = get_ostream( handle ); ios::pos_type pos = os->tellp(); ios::pos_type len; os->seekp( 0, ios::end ); len = os->tellp(); os->seekp( pos ); return static_cast< toff_t >( len ); } static void tiff_error( const char* module, const char* fmt, va_list ap ) { char buf[1000]; sprintf(buf, fmt, ap); cout << "error: " << buf << endl; } static void tiff_warning( char const *module, char const *fmt, va_list ap ) { char buf[1000]; sprintf(buf, fmt, ap); cout << "warning: " << fmt << endl; } int main() { stringstream ss( ios_base::in | ios_base::out | ios_base::binary ); TIFFSetErrorHandler ( tiff_error ); TIFFSetWarningHandler( tiff_warning ); TIFF* tiff = TIFFClientOpen( "dummy" , "w" , &ss , read_proc , write_proc , seek_proc , close_proc , size_proc , NULL , NULL ); TIFFSetField( tiff, TIFFTAG_IMAGEWIDTH , 100 ); TIFFSetField( tiff, TIFFTAG_IMAGELENGTH , 1 ); TIFFSetField( tiff, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG ); TIFFSetField( tiff, TIFFTAG_SAMPLESPERPIXEL, 1 ); TIFFSetField( tiff, TIFFTAG_BITSPERSAMPLE, 8 ); TIFFSetField( tiff, TIFFTAG_SAMPLEFORMAT, PHOTOMETRIC_RGB ); TIFFSetField( tiff, TIFFTAG_COMPRESSION, COMPRESSION_NONE ); vector< unsigned char > buffer( 300 ); fill( buffer.begin(), buffer.end(), 0 ); TIFFWriteScanline( tiff, &buffer.front(), 0, 0 ); TIFFClose( tiff ); ofstream out( "c:\\in-memory.tiff", ios_base::binary ); out << ss.rdbuf(); return 0; } |
|||||||