-
2009.03.27 23:57 "Re: [Tiff] TIFFOpen throws access error", by Bob Friesenhahn
- 2009.03.30 18:26 "Re: [Tiff] TIFFOpen throws access error", by
-
2009.04.07 13:44 "Re: [Tiff] Writing tiff to in-memory buffer", by Christian Henning
- 2009.04.06 15:35 "[Tiff] Writing tiff to in-memory buffer", by Christian Henning
- 2009.04.07 14:13 "Re: [Tiff] Writing tiff to in-memory buffer", by Edward Lam
- 2009.04.07 15:35 "Re: [Tiff] Writing tiff to in-memory buffer", by Bob Friesenhahn
- 2009.04.08 20:56 "[Tiff] writing in-memory tiffs", by Christian Henning
- 2009.03.28 01:03 "Re: [Tiff] TIFFOpen throws access error", by Toby Thain
2009.04.14 15:52 "Re: [Tiff] writing in-memory tiffs", by Christian Henning
Thanks 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:
- _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.
- _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;
}