00001
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
00022 #undef PACKAGE
00023 #undef VERSION
00024 #include <jasper/jasper.h>
00025
00026
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
00046 KTempFile* tempf = 0;
00047
00048 QFile* qf = 0;
00049 if( ( qf = dynamic_cast<QFile*>( io->ioDevice() ) ) ) {
00050
00051 in = jas_stream_fopen( QFile::encodeName( qf->name() ), "rb" );
00052 } else {
00053
00054 tempf = new KTempFile();
00055 if( tempf->status() != 0 ) {
00056 delete tempf;
00057 return 0;
00058 }
00059 tempf->setAutoDelete( true );
00060 QFile* out = tempf->file();
00061
00062 QByteArray b( 4096 );
00063 Q_LONG size;
00064
00065 while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
00066
00067 if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
00068 }
00069
00070 out->flush();
00071
00072 in = jas_stream_fopen( QFile::encodeName( tempf->name() ), "rb" );
00073 }
00074 if( !in ) {
00075 delete tempf;
00076 return 0;
00077 }
00078
00079 jas_image_t* image = jas_image_decode( in, -1, 0 );
00080 jas_stream_close( in );
00081 delete tempf;
00082
00083
00084 return image;
00085 }
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 }
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 }
00111
00112 const int* cmptlut = gs.cmptlut;
00113 int v[3];
00114
00115
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 }
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
00135
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 }
00141
00142 *data++ = qRgb( v[0], v[1], v[2] );
00143 }
00144 }
00145 return true;
00146 }
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 }
00168
00169
00170 static jas_image_t*
00171 create_image( const QImage& qi )
00172 {
00173
00174 jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
00175
00176 for ( int i = 0; i < 3; ++i ) {
00177
00178 cmptparms[i].tlx = 0;
00179 cmptparms[i].tly = 0;
00180
00181
00182 cmptparms[i].hstep = 1;
00183 cmptparms[i].vstep = 1;
00184 cmptparms[i].width = qi.width();
00185 cmptparms[i].height = qi.height();
00186
00187
00188 cmptparms[i].prec = 8;
00189 cmptparms[i].sgnd = false;
00190 }
00191
00192 jas_image_t* ji = jas_image_create( 3 , cmptparms, JAS_CLRSPC_UNKNOWN );
00193 delete[] cmptparms;
00194
00195
00196 return ji;
00197 }
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 }
00232
00233 KDE_EXPORT void
00234 kimgio_jp2_write( QImageIO* io )
00235 {
00236 if( jas_init() ) return;
00237
00238
00239
00240 jas_stream_t* stream = 0;
00241
00242 QFile* qf = 0;
00243 KTempFile* ktempf = 0;
00244 if( ( qf = dynamic_cast<QFile*>( io->ioDevice() ) ) ) {
00245
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 }
00252
00253
00254
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 }
00263
00264 if( !write_components( ji, io->image() ) ) {
00265 delete ktempf;
00266 jas_stream_close( stream );
00267 jas_image_destroy( ji );
00268 return;
00269 }
00270
00271
00272
00273
00274
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
00288 QFile* in = ktempf->file();
00289
00290 QByteArray b( 4096 );
00291 Q_LONG size;
00292
00293
00294 if( !in->at( 0 ) ) { delete ktempf; return; }
00295
00296
00297 while( ( size = in->readBlock( b.data(), 4096 ) ) > 0 ) {
00298 if( ( io->ioDevice()->writeBlock( b.data(), size ) ) == -1 ) {
00299 delete ktempf;
00300 return;
00301 }
00302 }
00303 io->ioDevice()->flush();
00304 delete ktempf;
00305
00306
00307 if( size == -1 ) return;
00308 }
00309
00310
00311
00312 io->setStatus( IO_Ok );
00313 }
00314
00315 #endif // HAVE_JASPER
00316