AWARE [SYSTEMS] Imaging expertise for the Delphi developer
AWare Systems, Imaging expertise for the Delphi developer, Home TIFF and LibTiff Mailing List Archive

LibTiff Mailing List

TIFF and LibTiff Mailing List Archive
April 2009

Previous Thread
Next Thread

Previous by Thread
Next by Thread

Previous by Date
Next by Date

Contact

The TIFF Mailing List Homepage
This list is run by Frank Warmerdam
Archive maintained by AWare Systems



Valid HTML 4.01!



Thread

2009.04.08 20:56 "writing in-memory tiffs", by Christian Henning
2009.04.13 14:50 "Re: writing in-memory tiffs", by Christian Henning
2009.04.13 16:08 "Re: writing in-memory tiffs", by Jason Summers
2009.04.14 15:52 "Re: writing in-memory tiffs", by Christian Henning
2009.04.14 16:42 "Re: writing in-memory tiffs", by Bob Friesenhahn

2009.04.14 15:52 "Re: 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:

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;
}