TDE core libraries
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

jp2.cpp 8.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316
  1. // This library is distributed under the conditions of the GNU LGPL.
  2. #include "config.h"
  3. #ifdef HAVE_SYS_TYPES_H
  4. #include <sys/types.h>
  5. #endif
  6. #ifdef HAVE_JASPER
  7. #include "jp2.h"
  8. #ifdef HAVE_STDINT_H
  9. #include <stdint.h>
  10. #endif
  11. #include <tdetempfile.h>
  12. #include <tqcolor.h>
  13. #include <tqcstring.h>
  14. #include <tqfile.h>
  15. #include <tqimage.h>
  16. // dirty, but avoids a warning because jasper.h includes jas_config.h.
  17. #undef PACKAGE
  18. #undef VERSION
  19. #include <jasper/jasper.h>
  20. // code taken in parts from JasPer's jiv.c
  21. #define DEFAULT_RATE 0.10
  22. #define MAXCMPTS 256
  23. typedef struct {
  24. jas_image_t* image;
  25. int cmptlut[MAXCMPTS];
  26. jas_image_t* altimage;
  27. } gs_t;
  28. jas_image_t*
  29. read_image( const TQImageIO* io )
  30. {
  31. jas_stream_t* in = 0;
  32. // for QIODevice's other than TQFile, a temp. file is used.
  33. KTempFile* tempf = 0;
  34. TQFile* qf = 0;
  35. if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
  36. // great, it's a TQFile. Let's just take the filename.
  37. in = jas_stream_fopen( TQFile::encodeName( qf->name() ), "rb" );
  38. } else {
  39. // not a TQFile. Copy the whole data to a temp. file.
  40. tempf = new KTempFile();
  41. if( tempf->status() != 0 ) {
  42. delete tempf;
  43. return 0;
  44. } // if
  45. tempf->setAutoDelete( true );
  46. TQFile* out = tempf->file();
  47. // 4096 (=4k) is a common page size.
  48. TQByteArray b( 4096 );
  49. TQ_LONG size;
  50. // 0 or -1 is EOF / error
  51. while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
  52. // in case of a write error, still give the decoder a try
  53. if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
  54. } // while
  55. // flush everything out to disk
  56. out->flush();
  57. in = jas_stream_fopen( TQFile::encodeName( tempf->name() ), "rb" );
  58. } // else
  59. if( !in ) {
  60. delete tempf;
  61. return 0;
  62. } // if
  63. jas_image_t* image = jas_image_decode( in, -1, 0 );
  64. jas_stream_close( in );
  65. delete tempf;
  66. // image may be 0, but that's Ok
  67. return image;
  68. } // read_image
  69. static bool
  70. convert_colorspace( gs_t& gs )
  71. {
  72. jas_cmprof_t *outprof = jas_cmprof_createfromclrspc( JAS_CLRSPC_SRGB );
  73. if( !outprof ) return false;
  74. gs.altimage = jas_image_chclrspc( gs.image, outprof,
  75. JAS_CMXFORM_INTENT_PER );
  76. if( !gs.altimage ) return false;
  77. return true;
  78. } // convert_colorspace
  79. static bool
  80. render_view( gs_t& gs, TQImage& qti )
  81. {
  82. if((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
  83. JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
  84. (gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
  85. JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
  86. (gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
  87. JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
  88. return false;
  89. } // if
  90. const int* cmptlut = gs.cmptlut;
  91. int v[3];
  92. // check that all components have the same size.
  93. const int width = jas_image_cmptwidth( gs.altimage, cmptlut[0] );
  94. const int height = jas_image_cmptheight( gs.altimage, cmptlut[0] );
  95. for( int i = 1; i < 3; ++i ) {
  96. if (jas_image_cmptwidth( gs.altimage, cmptlut[i] ) != width ||
  97. jas_image_cmptheight( gs.altimage, cmptlut[i] ) != height)
  98. return false;
  99. } // for
  100. if( !qti.create( jas_image_width( gs.altimage ),
  101. jas_image_height( gs.altimage ), 32 ) )
  102. return false;
  103. uint32_t* data = (uint32_t*)qti.bits();
  104. for( int y = 0; y < height; ++y ) {
  105. for( int x = 0; x < width; ++x ) {
  106. for( int k = 0; k < 3; ++k ) {
  107. v[k] = jas_image_readcmptsample( gs.altimage, cmptlut[k], x, y );
  108. // if the precision of the component is too small, increase
  109. // it to use the complete value range.
  110. v[k] <<= 8 - jas_image_cmptprec( gs.altimage, cmptlut[k] );
  111. if( v[k] < 0 ) v[k] = 0;
  112. else if( v[k] > 255 ) v[k] = 255;
  113. } // for k
  114. *data++ = tqRgb( v[0], v[1], v[2] );
  115. } // for x
  116. } // for y
  117. return true;
  118. } // render_view
  119. KDE_EXPORT void
  120. kimgio_jp2_read( TQImageIO* io )
  121. {
  122. if( jas_init() ) return;
  123. gs_t gs;
  124. if( !(gs.image = read_image( io )) ) return;
  125. if( !convert_colorspace( gs ) ) return;
  126. TQImage image;
  127. render_view( gs, image );
  128. if( gs.image ) jas_image_destroy( gs.image );
  129. if( gs.altimage ) jas_image_destroy( gs.altimage );
  130. io->setImage( image );
  131. io->setStatus( 0 );
  132. } // kimgio_jp2_read
  133. static jas_image_t*
  134. create_image( const TQImage& qi )
  135. {
  136. // prepare the component parameters
  137. jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
  138. for ( int i = 0; i < 3; ++i ) {
  139. // x and y offset
  140. cmptparms[i].tlx = 0;
  141. cmptparms[i].tly = 0;
  142. // the resulting image will be hstep*width x vstep*height !
  143. cmptparms[i].hstep = 1;
  144. cmptparms[i].vstep = 1;
  145. cmptparms[i].width = qi.width();
  146. cmptparms[i].height = qi.height();
  147. // we write everything as 24bit truecolor ATM
  148. cmptparms[i].prec = 8;
  149. cmptparms[i].sgnd = false;
  150. }
  151. jas_image_t* ji = jas_image_create( 3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN );
  152. delete[] cmptparms;
  153. // returning 0 is ok
  154. return ji;
  155. } // create_image
  156. static bool
  157. write_components( jas_image_t* ji, const TQImage& qi )
  158. {
  159. const unsigned height = qi.height();
  160. const unsigned width = qi.width();
  161. jas_matrix_t* m = jas_matrix_create( height, width );
  162. if( !m ) return false;
  163. jas_image_setclrspc( ji, JAS_CLRSPC_SRGB );
  164. jas_image_setcmpttype( ji, 0, JAS_IMAGE_CT_RGB_R );
  165. for( uint y = 0; y < height; ++y )
  166. for( uint x = 0; x < width; ++x )
  167. jas_matrix_set( m, y, x, tqRed( qi.pixel( x, y ) ) );
  168. jas_image_writecmpt( ji, 0, 0, 0, width, height, m );
  169. jas_image_setcmpttype( ji, 1, JAS_IMAGE_CT_RGB_G );
  170. for( uint y = 0; y < height; ++y )
  171. for( uint x = 0; x < width; ++x )
  172. jas_matrix_set( m, y, x, tqGreen( qi.pixel( x, y ) ) );
  173. jas_image_writecmpt( ji, 1, 0, 0, width, height, m );
  174. jas_image_setcmpttype( ji, 2, JAS_IMAGE_CT_RGB_B );
  175. for( uint y = 0; y < height; ++y )
  176. for( uint x = 0; x < width; ++x )
  177. jas_matrix_set( m, y, x, tqBlue( qi.pixel( x, y ) ) );
  178. jas_image_writecmpt( ji, 2, 0, 0, width, height, m );
  179. jas_matrix_destroy( m );
  180. return true;
  181. } // write_components
  182. KDE_EXPORT void
  183. kimgio_jp2_write( TQImageIO* io )
  184. {
  185. if( jas_init() ) return;
  186. // open the stream. we write directly to the file if possible, to a
  187. // temporary file otherwise.
  188. jas_stream_t* stream = 0;
  189. TQFile* qf = 0;
  190. KTempFile* ktempf = 0;
  191. if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
  192. // jas_stream_fdopen works here, but not when reading...
  193. stream = jas_stream_fdopen( dup( qf->handle() ), "w" );
  194. } else {
  195. ktempf = new KTempFile;
  196. ktempf->setAutoDelete( true );
  197. stream = jas_stream_fdopen( dup( ktempf->handle()), "w" );
  198. } // else
  199. // by here, a jas_stream_t is open
  200. if( !stream ) return;
  201. jas_image_t* ji = create_image( io->image() );
  202. if( !ji ) {
  203. delete ktempf;
  204. jas_stream_close( stream );
  205. return;
  206. } // if
  207. if( !write_components( ji, io->image() ) ) {
  208. delete ktempf;
  209. jas_stream_close( stream );
  210. jas_image_destroy( ji );
  211. return;
  212. } // if
  213. // optstr:
  214. // - rate=#B => the resulting file size is about # bytes
  215. // - rate=0.0 .. 1.0 => the resulting file size is about the factor times
  216. // the uncompressed size
  217. TQString rate;
  218. TQTextStream ts( &rate, IO_WriteOnly );
  219. ts << "rate="
  220. << ( (io->quality() < 0) ? DEFAULT_RATE : io->quality() / 100.0F );
  221. int i = jp2_encode( ji, stream, rate.utf8().data() );
  222. jas_image_destroy( ji );
  223. jas_stream_close( stream );
  224. if( i != 0 ) { delete ktempf; return; }
  225. if( ktempf ) {
  226. // We've written to a tempfile. Copy the data to the final destination.
  227. TQFile* in = ktempf->file();
  228. TQByteArray b( 4096 );
  229. TQ_LONG size;
  230. // seek to the beginning of the file.
  231. if( !in->at( 0 ) ) { delete ktempf; return; }
  232. // 0 or -1 is EOF / error
  233. while( ( size = in->readBlock( b.data(), 4096 ) ) > 0 ) {
  234. if( ( io->ioDevice()->writeBlock( b.data(), size ) ) == -1 ) {
  235. delete ktempf;
  236. return;
  237. } // if
  238. } // while
  239. io->ioDevice()->flush();
  240. delete ktempf;
  241. // see if we've left the while loop due to an error.
  242. if( size == -1 ) return;
  243. } // if
  244. // everything went fine
  245. io->setStatus( IO_Ok );
  246. } // kimgio_jp2_write
  247. #endif // HAVE_JASPER