- // This library is distributed under the conditions of the GNU LGPL.
- #include "config.h"
-
- #ifdef HAVE_SYS_TYPES_H
- #include <sys/types.h>
- #endif
-
- #ifdef HAVE_JASPER
-
- #include "jp2.h"
-
- #ifdef HAVE_STDINT_H
- #include <stdint.h>
- #endif
- #include <tdetempfile.h>
- #include <tqcolor.h>
- #include <tqcstring.h>
- #include <tqfile.h>
- #include <tqimage.h>
-
- // dirty, but avoids a warning because jasper.h includes jas_config.h.
- #undef PACKAGE
- #undef VERSION
- #include <jasper/jasper.h>
-
- // code taken in parts from JasPer's jiv.c
-
- #define DEFAULT_RATE 0.10
- #define MAXCMPTS 256
-
-
- typedef struct {
- jas_image_t* image;
-
- int cmptlut[MAXCMPTS];
-
- jas_image_t* altimage;
- } gs_t;
-
-
- jas_image_t*
- read_image( const TQImageIO* io )
- {
- jas_stream_t* in = 0;
- // for QIODevice's other than TQFile, a temp. file is used.
- KTempFile* tempf = 0;
-
- TQFile* qf = 0;
- if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
- // great, it's a TQFile. Let's just take the filename.
- in = jas_stream_fopen( TQFile::encodeName( qf->name() ), "rb" );
- } else {
- // not a TQFile. Copy the whole data to a temp. file.
- tempf = new KTempFile();
- if( tempf->status() != 0 ) {
- delete tempf;
- return 0;
- } // if
- tempf->setAutoDelete( true );
- TQFile* out = tempf->file();
- // 4096 (=4k) is a common page size.
- TQByteArray b( 4096 );
- TQ_LONG size;
- // 0 or -1 is EOF / error
- while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
- // in case of a write error, still give the decoder a try
- if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
- } // while
- // flush everything out to disk
- out->flush();
-
- in = jas_stream_fopen( TQFile::encodeName( tempf->name() ), "rb" );
- } // else
- if( !in ) {
- delete tempf;
- return 0;
- } // if
-
- jas_image_t* image = jas_image_decode( in, -1, 0 );
- jas_stream_close( in );
- delete tempf;
-
- // image may be 0, but that's Ok
- return image;
- } // read_image
-
- static bool
- convert_colorspace( gs_t& gs )
- {
- jas_cmprof_t *outprof = jas_cmprof_createfromclrspc( JAS_CLRSPC_SRGB );
- if( !outprof ) return false;
-
- gs.altimage = jas_image_chclrspc( gs.image, outprof,
- JAS_CMXFORM_INTENT_PER );
- if( !gs.altimage ) return false;
-
- return true;
- } // convert_colorspace
-
- static bool
- render_view( gs_t& gs, TQImage& qti )
- {
- if((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
- JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
- (gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
- JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
- (gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
- JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
- return false;
- } // if
-
- const int* cmptlut = gs.cmptlut;
- int v[3];
-
- // check that all components have the same size.
- const int width = jas_image_cmptwidth( gs.altimage, cmptlut[0] );
- const int height = jas_image_cmptheight( gs.altimage, cmptlut[0] );
- for( int i = 1; i < 3; ++i ) {
- if (jas_image_cmptwidth( gs.altimage, cmptlut[i] ) != width ||
- jas_image_cmptheight( gs.altimage, cmptlut[i] ) != height)
- return false;
- } // for
-
- if( !qti.create( jas_image_width( gs.altimage ),
- jas_image_height( gs.altimage ), 32 ) )
- return false;
-
- uint32_t* data = (uint32_t*)qti.bits();
-
- for( int y = 0; y < height; ++y ) {
- for( int x = 0; x < width; ++x ) {
- for( int k = 0; k < 3; ++k ) {
- v[k] = jas_image_readcmptsample( gs.altimage, cmptlut[k], x, y );
- // if the precision of the component is too small, increase
- // it to use the complete value range.
- v[k] <<= 8 - jas_image_cmptprec( gs.altimage, cmptlut[k] );
-
- if( v[k] < 0 ) v[k] = 0;
- else if( v[k] > 255 ) v[k] = 255;
- } // for k
-
- *data++ = tqRgb( v[0], v[1], v[2] );
- } // for x
- } // for y
- return true;
- } // render_view
-
-
- KDE_EXPORT void
- kimgio_jp2_read( TQImageIO* io )
- {
- if( jas_init() ) return;
-
- gs_t gs;
- if( !(gs.image = read_image( io )) ) return;
-
- if( !convert_colorspace( gs ) ) return;
-
- TQImage image;
- render_view( gs, image );
-
- if( gs.image ) jas_image_destroy( gs.image );
- if( gs.altimage ) jas_image_destroy( gs.altimage );
-
- io->setImage( image );
- io->setStatus( 0 );
- } // kimgio_jp2_read
-
-
- static jas_image_t*
- create_image( const TQImage& qi )
- {
- // prepare the component parameters
- jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
-
- for ( int i = 0; i < 3; ++i ) {
- // x and y offset
- cmptparms[i].tlx = 0;
- cmptparms[i].tly = 0;
-
- // the resulting image will be hstep*width x vstep*height !
- cmptparms[i].hstep = 1;
- cmptparms[i].vstep = 1;
- cmptparms[i].width = qi.width();
- cmptparms[i].height = qi.height();
-
- // we write everything as 24bit truecolor ATM
- cmptparms[i].prec = 8;
- cmptparms[i].sgnd = false;
- }
-
- jas_image_t* ji = jas_image_create( 3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN );
- delete[] cmptparms;
-
- // returning 0 is ok
- return ji;
- } // create_image
-
-
- static bool
- write_components( jas_image_t* ji, const TQImage& qi )
- {
- const unsigned height = qi.height();
- const unsigned width = qi.width();
-
- jas_matrix_t* m = jas_matrix_create( height, width );
- if( !m ) return false;
-
- jas_image_setclrspc( ji, JAS_CLRSPC_SRGB );
-
- jas_image_setcmpttype( ji, 0, JAS_IMAGE_CT_RGB_R );
- for( uint y = 0; y < height; ++y )
- for( uint x = 0; x < width; ++x )
- jas_matrix_set( m, y, x, tqRed( qi.pixel( x, y ) ) );
- jas_image_writecmpt( ji, 0, 0, 0, width, height, m );
-
- jas_image_setcmpttype( ji, 1, JAS_IMAGE_CT_RGB_G );
- for( uint y = 0; y < height; ++y )
- for( uint x = 0; x < width; ++x )
- jas_matrix_set( m, y, x, tqGreen( qi.pixel( x, y ) ) );
- jas_image_writecmpt( ji, 1, 0, 0, width, height, m );
-
- jas_image_setcmpttype( ji, 2, JAS_IMAGE_CT_RGB_B );
- for( uint y = 0; y < height; ++y )
- for( uint x = 0; x < width; ++x )
- jas_matrix_set( m, y, x, tqBlue( qi.pixel( x, y ) ) );
- jas_image_writecmpt( ji, 2, 0, 0, width, height, m );
- jas_matrix_destroy( m );
-
- return true;
- } // write_components
-
- KDE_EXPORT void
- kimgio_jp2_write( TQImageIO* io )
- {
- if( jas_init() ) return;
-
- // open the stream. we write directly to the file if possible, to a
- // temporary file otherwise.
- jas_stream_t* stream = 0;
-
- TQFile* qf = 0;
- KTempFile* ktempf = 0;
- if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
- // jas_stream_fdopen works here, but not when reading...
- stream = jas_stream_fdopen( dup( qf->handle() ), "w" );
- } else {
- ktempf = new KTempFile;
- ktempf->setAutoDelete( true );
- stream = jas_stream_fdopen( dup( ktempf->handle()), "w" );
- } // else
-
-
- // by here, a jas_stream_t is open
- if( !stream ) return;
-
- jas_image_t* ji = create_image( io->image() );
- if( !ji ) {
- delete ktempf;
- jas_stream_close( stream );
- return;
- } // if
-
- if( !write_components( ji, io->image() ) ) {
- delete ktempf;
- jas_stream_close( stream );
- jas_image_destroy( ji );
- return;
- } // if
-
- // optstr:
- // - rate=#B => the resulting file size is about # bytes
- // - rate=0.0 .. 1.0 => the resulting file size is about the factor times
- // the uncompressed size
- TQString rate;
- TQTextStream ts( &rate, IO_WriteOnly );
- ts << "rate="
- << ( (io->quality() < 0) ? DEFAULT_RATE : io->quality() / 100.0F );
- int i = jp2_encode( ji, stream, rate.utf8().data() );
-
- jas_image_destroy( ji );
- jas_stream_close( stream );
-
- if( i != 0 ) { delete ktempf; return; }
-
- if( ktempf ) {
- // We've written to a tempfile. Copy the data to the final destination.
- TQFile* in = ktempf->file();
-
- TQByteArray b( 4096 );
- TQ_LONG size;
-
- // seek to the beginning of the file.
- if( !in->at( 0 ) ) { delete ktempf; return; }
-
- // 0 or -1 is EOF / error
- while( ( size = in->readBlock( b.data(), 4096 ) ) > 0 ) {
- if( ( io->ioDevice()->writeBlock( b.data(), size ) ) == -1 ) {
- delete ktempf;
- return;
- } // if
- } // while
- io->ioDevice()->flush();
- delete ktempf;
-
- // see if we've left the while loop due to an error.
- if( size == -1 ) return;
- } // if
-
-
- // everything went fine
- io->setStatus( IO_Ok );
- } // kimgio_jp2_write
-
- #endif // HAVE_JASPER
-
|