• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • API Reference
  • Sitemap
  • Contact Us
 

KImgIO

jp2.cpp

Go to the documentation of this file.
00001 // This library is distributed under the conditions of the GNU LGPL.
00002 #include "config.h"
00003 
00004 #ifdef HAVE_SYS_TYPES_H
00005 #include <sys/types.h>
00006 #endif
00007 
00008 #ifdef HAVE_JASPER
00009 
00010 #include "jp2.h"
00011 
00012 #ifdef HAVE_STDINT_H
00013 #include <stdint.h>
00014 #endif
00015 #include <ktempfile.h>
00016 #include <qcolor.h>
00017 #include <qcstring.h>
00018 #include <qfile.h>
00019 #include <qimage.h>
00020 
00021 // dirty, but avoids a warning because jasper.h includes jas_config.h.
00022 #undef PACKAGE
00023 #undef VERSION
00024 #include <jasper/jasper.h>
00025 
00026 // code taken in parts from JasPer's jiv.c
00027 
00028 #define DEFAULT_RATE 0.10
00029 #define MAXCMPTS 256
00030 
00031 
00032 typedef struct {
00033     jas_image_t* image;
00034 
00035     int cmptlut[MAXCMPTS];
00036 
00037     jas_image_t* altimage;
00038 } gs_t;
00039 
00040 
00041 jas_image_t*
00042 read_image( const QImageIO* io )
00043 {
00044     jas_stream_t* in = 0;
00045     // for QIODevice's other than QFile, a temp. file is used.
00046     KTempFile* tempf = 0;
00047 
00048     QFile* qf = 0;
00049     if( ( qf = dynamic_cast<QFile*>( io->ioDevice() ) ) ) {
00050         // great, it's a QFile. Let's just take the filename.
00051         in = jas_stream_fopen( QFile::encodeName( qf->name() ), "rb" );
00052     } else {
00053         // not a QFile. Copy the whole data to a temp. file.
00054         tempf = new KTempFile();
00055         if( tempf->status() != 0 ) {
00056             delete tempf;
00057             return 0;
00058         } // if
00059         tempf->setAutoDelete( true );
00060         QFile* out = tempf->file();
00061         // 4096 (=4k) is a common page size.
00062         QByteArray b( 4096 );
00063         Q_LONG size;
00064         // 0 or -1 is EOF / error
00065         while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
00066             // in case of a write error, still give the decoder a try
00067             if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
00068         } // while
00069         // flush everything out to disk
00070         out->flush();
00071 
00072         in = jas_stream_fopen( QFile::encodeName( tempf->name() ), "rb" );
00073     } // else
00074     if( !in ) {
00075         delete tempf;
00076         return 0;
00077     } // if
00078 
00079     jas_image_t* image = jas_image_decode( in, -1, 0 );
00080     jas_stream_close( in );
00081     delete tempf;
00082 
00083     // image may be 0, but that's Ok
00084     return image;
00085 } // read_image
00086 
00087 static bool
00088 convert_colorspace( gs_t& gs )
00089 {
00090     jas_cmprof_t *outprof = jas_cmprof_createfromclrspc( JAS_CLRSPC_SRGB );
00091     if( !outprof ) return false;
00092 
00093     gs.altimage = jas_image_chclrspc( gs.image, outprof,
00094                                       JAS_CMXFORM_INTENT_PER );
00095     if( !gs.altimage ) return false;
00096 
00097     return true;
00098 } // convert_colorspace
00099 
00100 static bool
00101 render_view( gs_t& gs, QImage& qti )
00102 {
00103     if((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
00104                                                 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
00105        (gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
00106                                                 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
00107        (gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
00108                                                 JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
00109         return false;
00110     } // if
00111 
00112     const int* cmptlut = gs.cmptlut;
00113     int v[3];
00114 
00115     // check that all components have the same size.
00116     const int width = jas_image_cmptwidth( gs.altimage, cmptlut[0] );
00117     const int height = jas_image_cmptheight( gs.altimage, cmptlut[0] );
00118     for( int i = 1; i < 3; ++i ) {
00119         if (jas_image_cmptwidth( gs.altimage, cmptlut[i] ) != width ||
00120             jas_image_cmptheight( gs.altimage, cmptlut[i] ) != height)
00121             return false;
00122     } // for
00123 
00124     if( !qti.create( jas_image_width( gs.altimage ),
00125                      jas_image_height( gs.altimage ), 32 ) )
00126         return false;
00127 
00128     uint32_t* data = (uint32_t*)qti.bits();
00129 
00130     for( int y = 0; y < height; ++y ) {
00131         for( int x = 0; x < width; ++x ) {
00132             for( int k = 0; k < 3; ++k ) {
00133                 v[k] = jas_image_readcmptsample( gs.altimage, cmptlut[k], x, y );
00134                 // if the precision of the component is too small, increase
00135                 // it to use the complete value range.
00136                 v[k] <<= 8 - jas_image_cmptprec( gs.altimage, cmptlut[k] );
00137 
00138                 if( v[k] < 0 ) v[k] = 0;
00139                 else if( v[k] > 255 ) v[k] = 255;
00140             } // for k
00141 
00142             *data++ = qRgb( v[0], v[1], v[2] );
00143         } // for x
00144     } // for y
00145     return true;
00146 } // render_view
00147 
00148 
00149 KDE_EXPORT void
00150 kimgio_jp2_read( QImageIO* io )
00151 {
00152     if( jas_init() ) return;
00153 
00154     gs_t gs;
00155     if( !(gs.image = read_image( io )) ) return;
00156 
00157     if( !convert_colorspace( gs ) ) return;
00158 
00159     QImage image;
00160     render_view( gs, image );
00161 
00162     if( gs.image ) jas_image_destroy( gs.image );
00163     if( gs.altimage ) jas_image_destroy( gs.altimage );
00164 
00165     io->setImage( image );
00166     io->setStatus( 0 );
00167 } // kimgio_jp2_read
00168 
00169 
00170 static jas_image_t*
00171 create_image( const QImage& qi )
00172 {
00173     // prepare the component parameters
00174     jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
00175 
00176     for ( int i = 0; i < 3; ++i ) {
00177         // x and y offset
00178         cmptparms[i].tlx = 0;
00179         cmptparms[i].tly = 0;
00180 
00181         // the resulting image will be hstep*width x vstep*height !
00182         cmptparms[i].hstep = 1;
00183         cmptparms[i].vstep = 1;
00184         cmptparms[i].width = qi.width();
00185         cmptparms[i].height = qi.height();
00186 
00187         // we write everything as 24bit truecolor ATM
00188         cmptparms[i].prec = 8;
00189         cmptparms[i].sgnd = false;
00190     }
00191 
00192     jas_image_t* ji = jas_image_create( 3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN );
00193     delete[] cmptparms;
00194 
00195     // returning 0 is ok
00196     return ji;
00197 } // create_image
00198 
00199 
00200 static bool
00201 write_components( jas_image_t* ji, const QImage& qi )
00202 {
00203     const unsigned height = qi.height();
00204     const unsigned width = qi.width();
00205 
00206     jas_matrix_t* m = jas_matrix_create( height, width );
00207     if( !m ) return false;
00208 
00209     jas_image_setclrspc( ji, JAS_CLRSPC_SRGB );
00210 
00211     jas_image_setcmpttype( ji, 0, JAS_IMAGE_CT_RGB_R );
00212     for( uint y = 0; y < height; ++y )
00213         for( uint x = 0; x < width; ++x )
00214             jas_matrix_set( m, y, x, qRed( qi.pixel( x, y ) ) );
00215     jas_image_writecmpt( ji, 0, 0, 0, width, height, m );
00216 
00217     jas_image_setcmpttype( ji, 1, JAS_IMAGE_CT_RGB_G );
00218     for( uint y = 0; y < height; ++y )
00219         for( uint x = 0; x < width; ++x )
00220             jas_matrix_set( m, y, x, qGreen( qi.pixel( x, y ) ) );
00221     jas_image_writecmpt( ji, 1, 0, 0, width, height, m );
00222 
00223     jas_image_setcmpttype( ji, 2, JAS_IMAGE_CT_RGB_B );
00224     for( uint y = 0; y < height; ++y )
00225         for( uint x = 0; x < width; ++x )
00226             jas_matrix_set( m, y, x, qBlue( qi.pixel( x, y ) ) );
00227     jas_image_writecmpt( ji, 2, 0, 0, width, height, m );
00228     jas_matrix_destroy( m );
00229 
00230     return true;
00231 } // write_components
00232 
00233 KDE_EXPORT void
00234 kimgio_jp2_write( QImageIO* io )
00235 {
00236     if( jas_init() ) return;
00237 
00238     // open the stream. we write directly to the file if possible, to a
00239     // temporary file otherwise.
00240     jas_stream_t* stream = 0;
00241 
00242     QFile* qf = 0;
00243     KTempFile* ktempf = 0;
00244     if( ( qf = dynamic_cast<QFile*>( io->ioDevice() ) ) ) {
00245         // jas_stream_fdopen works here, but not when reading...
00246         stream = jas_stream_fdopen( dup( qf->handle() ), "w" );
00247     } else {
00248         ktempf = new KTempFile;
00249         ktempf->setAutoDelete( true );
00250         stream = jas_stream_fdopen( dup( ktempf->handle()), "w" );
00251     } // else
00252 
00253 
00254     // by here, a jas_stream_t is open
00255     if( !stream ) return;
00256 
00257     jas_image_t* ji = create_image( io->image() );
00258     if( !ji ) {
00259         delete ktempf;
00260         jas_stream_close( stream );
00261         return;
00262     } // if
00263 
00264     if( !write_components( ji, io->image() ) ) {
00265         delete ktempf;
00266         jas_stream_close( stream );
00267         jas_image_destroy( ji );
00268         return;
00269     } // if
00270 
00271     // optstr:
00272     // - rate=#B => the resulting file size is about # bytes
00273     // - rate=0.0 .. 1.0 => the resulting file size is about the factor times
00274     //                      the uncompressed size
00275     QString rate;
00276     QTextStream ts( &rate, IO_WriteOnly );
00277     ts << "rate="
00278         << ( (io->quality() < 0) ? DEFAULT_RATE : io->quality() / 100.0F );
00279     int i = jp2_encode( ji, stream, rate.utf8().data() );
00280 
00281     jas_image_destroy( ji );
00282     jas_stream_close( stream );
00283 
00284     if( i != 0 ) { delete ktempf; return; }
00285 
00286     if( ktempf ) {
00287         // We've written to a tempfile. Copy the data to the final destination.
00288         QFile* in = ktempf->file();
00289 
00290         QByteArray b( 4096 );
00291         Q_LONG size;
00292 
00293         // seek to the beginning of the file.
00294         if( !in->at( 0 ) ) { delete ktempf; return; }
00295 
00296         // 0 or -1 is EOF / error
00297         while( ( size = in->readBlock( b.data(), 4096 ) ) > 0 ) {
00298             if( ( io->ioDevice()->writeBlock( b.data(), size ) ) == -1 ) {
00299                 delete ktempf;
00300                 return;
00301             } // if
00302         } // while
00303         io->ioDevice()->flush();
00304         delete ktempf;
00305 
00306         // see if we've left the while loop due to an error.
00307         if( size == -1 ) return;
00308     } // if
00309 
00310 
00311     // everything went fine
00312     io->setStatus( IO_Ok );
00313 } // kimgio_jp2_write
00314 
00315 #endif // HAVE_JASPER
00316 

KImgIO

Skip menu "KImgIO"
  • Main Page
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Class Members
  • Related Pages

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal