• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • kimgio
 

kimgio

  • kimgio
jp2.cpp
1 // This library is distributed under the conditions of the GNU LGPL.
2 #include "config.h"
3 
4 #ifdef HAVE_JASPER
5 #include <unistd.h>
6 #include "jp2.h"
7 
8 #if !defined(__STDC_LIMIT_MACROS)
9 #define __STDC_LIMIT_MACROS
10 #endif
11 
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15 #ifdef HAVE_STDINT_H
16 #include <stdint.h>
17 #endif
18 #include <kdebug.h>
19 #include <tdetempfile.h>
20 #include <tqcolor.h>
21 #include <tqcstring.h>
22 #include <tqfile.h>
23 #include <tqimage.h>
24 
25 // dirty, but avoids a warning because jasper.h includes jas_config.h.
26 #undef PACKAGE
27 #undef VERSION
28 #include <jasper/jasper.h>
29 
30 // code taken in parts from JasPer's jiv.c
31 
32 #define DEFAULT_RATE 0.10
33 #define MAXCMPTS 256
34 
35 
36 typedef struct {
37  jas_image_t* image;
38 
39  int cmptlut[MAXCMPTS];
40 
41  jas_image_t* altimage;
42 } gs_t;
43 
44 
45 jas_image_t*
46 read_image( const TQImageIO* io )
47 {
48  jas_stream_t* in = 0;
49  // for TQIODevice's other than TQFile, a temp. file is used.
50  KTempFile* tempf = 0;
51 
52  TQFile* qf = 0;
53  if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
54  // great, it's a TQFile. Let's just take the filename.
55  in = jas_stream_fopen( TQFile::encodeName( qf->name() ), "rb" );
56  } else {
57  // not a TQFile. Copy the whole data to a temp. file.
58  tempf = new KTempFile();
59  if( tempf->status() != 0 ) {
60  delete tempf;
61  return nullptr;
62  } // if
63  tempf->setAutoDelete( true );
64  TQFile* out = tempf->file();
65  // 4096 (=4k) is a common page size.
66  TQByteArray b( 4096 );
67  TQ_LONG size;
68  // 0 or -1 is EOF / error
69  while( ( size = io->ioDevice()->readBlock( b.data(), 4096 ) ) > 0 ) {
70  // in case of a write error, still give the decoder a try
71  if( ( out->writeBlock( b.data(), size ) ) == -1 ) break;
72  } // while
73  // flush everything out to disk
74  out->flush();
75 
76  in = jas_stream_fopen( TQFile::encodeName( tempf->name() ), "rb" );
77  } // else
78  if( !in ) {
79  delete tempf;
80  return nullptr;
81  } // if
82 
83  jas_image_t* image = jas_image_decode( in, -1, 0 );
84  jas_stream_close( in );
85  delete tempf;
86 
87  // image may be 0, but that's Ok
88  return image;
89 } // read_image
90 
91 static bool
92 convert_colorspace( gs_t& gs )
93 {
94  jas_cmprof_t *outprof = jas_cmprof_createfromclrspc( JAS_CLRSPC_SRGB );
95  if( !outprof ) return false;
96 
97  gs.altimage = jas_image_chclrspc( gs.image, outprof,
98  JAS_CMXFORM_INTENT_PER );
99  if( !gs.altimage ) return false;
100 
101  return true;
102 } // convert_colorspace
103 
104 static bool
105 render_view( gs_t& gs, TQImage& qti )
106 {
107  if((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
108  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
109  (gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
110  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
111  (gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
112  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
113  return false;
114  } // if
115 
116  const int* cmptlut = gs.cmptlut;
117  int v[3];
118 
119  // check that all components have the same size.
120  const int width = jas_image_cmptwidth( gs.altimage, cmptlut[0] );
121  const int height = jas_image_cmptheight( gs.altimage, cmptlut[0] );
122  for( int i = 1; i < 3; ++i ) {
123  if (jas_image_cmptwidth( gs.altimage, cmptlut[i] ) != width ||
124  jas_image_cmptheight( gs.altimage, cmptlut[i] ) != height)
125  return false;
126  } // for
127 
128  if( !qti.create( jas_image_width( gs.altimage ),
129  jas_image_height( gs.altimage ), 32 ) )
130  return false;
131 
132  uint32_t* data = (uint32_t*)qti.bits();
133 
134  for( int y = 0; y < height; ++y ) {
135  for( int x = 0; x < width; ++x ) {
136  for( int k = 0; k < 3; ++k ) {
137  v[k] = jas_image_readcmptsample( gs.altimage, cmptlut[k], x, y );
138  // if the precision of the component is too small, increase
139  // it to use the complete value range.
140  v[k] <<= 8 - jas_image_cmptprec( gs.altimage, cmptlut[k] );
141 
142  if( v[k] < 0 ) v[k] = 0;
143  else if( v[k] > 255 ) v[k] = 255;
144  } // for k
145 
146  *data++ = tqRgb( v[0], v[1], v[2] );
147  } // for x
148  } // for y
149  return true;
150 } // render_view
151 
152 static bool initializeJasper()
153 {
154 #if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3)
155  jas_conf_clear();
156 
157  // Limit JasPer memory usage to at most 512 MB
158  size_t memoryLimit = (512 * 1024) * 1024;
159  size_t jasperTotalMemory = jas_get_total_mem_size();
160  if (!jasperTotalMemory)
161  {
162  jasperTotalMemory = JAS_DEFAULT_MAX_MEM_USAGE;
163  }
164  memoryLimit = memoryLimit < jasperTotalMemory ? memoryLimit : jasperTotalMemory;
165  jas_conf_set_max_mem_usage(memoryLimit);
166 
167  if (jas_init_library())
168  {
169  return false;
170  }
171 
172  if (jas_init_thread())
173  {
174  jas_cleanup_library();
175  return false;
176  }
177 
178 #else
179  if (jas_init())
180  {
181  return false;
182  }
183 #endif // defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3)
184 
185  return true;
186 }
187 
188 static void cleanupJasper()
189 {
190 #if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3)
191  jas_cleanup_thread();
192  jas_cleanup_library();
193 #endif
194 }
195 
196 
197 
198 TDE_EXPORT void
199 kimgio_jp2_read( TQImageIO* io )
200 {
201  if (!initializeJasper())
202  {
203  kdError(399) << "Failed to initialize JasPer library" << endl;
204  return;
205  }
206 
207  gs_t gs;
208  gs.image = read_image(io);
209 
210  if (!gs.image)
211  {
212  kdError(399) << "Failed to read JP2 image from IO." << endl;
213  cleanupJasper();
214  return;
215  }
216 
217  if (!convert_colorspace(gs))
218  {
219  kdError(399) << "Could not convert JP2 colorspace." << endl;
220  cleanupJasper();
221  return;
222  }
223 
224  TQImage image;
225  render_view( gs, image );
226 
227  if( gs.image ) jas_image_destroy( gs.image );
228  if( gs.altimage ) jas_image_destroy( gs.altimage );
229 
230  cleanupJasper();
231 
232  io->setImage( image );
233  io->setStatus( 0 );
234 } // kimgio_jp2_read
235 
236 
237 static jas_image_t*
238 create_image( const TQImage& qi )
239 {
240  // prepare the component parameters
241  jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
242 
243  for ( int i = 0; i < 3; ++i ) {
244  // x and y offset
245  cmptparms[i].tlx = 0;
246  cmptparms[i].tly = 0;
247 
248  // the resulting image will be hstep*width x vstep*height !
249  cmptparms[i].hstep = 1;
250  cmptparms[i].vstep = 1;
251  cmptparms[i].width = qi.width();
252  cmptparms[i].height = qi.height();
253 
254  // we write everything as 24bit truecolor ATM
255  cmptparms[i].prec = 8;
256  cmptparms[i].sgnd = false;
257  }
258 
259  jas_image_t* ji = jas_image_create( 3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN );
260  delete[] cmptparms;
261 
262  // returning 0 is ok
263  return ji;
264 } // create_image
265 
266 
267 static bool
268 write_components( jas_image_t* ji, const TQImage& qi )
269 {
270  const unsigned height = qi.height();
271  const unsigned width = qi.width();
272 
273  jas_matrix_t* m = jas_matrix_create( height, width );
274  if( !m ) return false;
275 
276  jas_image_setclrspc( ji, JAS_CLRSPC_SRGB );
277 
278  jas_image_setcmpttype( ji, 0, JAS_IMAGE_CT_RGB_R );
279  for( uint y = 0; y < height; ++y )
280  for( uint x = 0; x < width; ++x )
281  jas_matrix_set( m, y, x, tqRed( qi.pixel( x, y ) ) );
282  jas_image_writecmpt( ji, 0, 0, 0, width, height, m );
283 
284  jas_image_setcmpttype( ji, 1, JAS_IMAGE_CT_RGB_G );
285  for( uint y = 0; y < height; ++y )
286  for( uint x = 0; x < width; ++x )
287  jas_matrix_set( m, y, x, tqGreen( qi.pixel( x, y ) ) );
288  jas_image_writecmpt( ji, 1, 0, 0, width, height, m );
289 
290  jas_image_setcmpttype( ji, 2, JAS_IMAGE_CT_RGB_B );
291  for( uint y = 0; y < height; ++y )
292  for( uint x = 0; x < width; ++x )
293  jas_matrix_set( m, y, x, tqBlue( qi.pixel( x, y ) ) );
294  jas_image_writecmpt( ji, 2, 0, 0, width, height, m );
295  jas_matrix_destroy( m );
296 
297  return true;
298 } // write_components
299 
300 TDE_EXPORT void
301 kimgio_jp2_write( TQImageIO* io )
302 {
303  if (!initializeJasper())
304  {
305  kdError(399) << "Failed to initialize JasPer library." << endl;
306  return;
307  }
308 
309  // open the stream. we write directly to the file if possible, to a
310  // temporary file otherwise.
311  jas_stream_t* stream = 0;
312 
313  TQFile* qf = 0;
314  KTempFile* ktempf = 0;
315  if( ( qf = dynamic_cast<TQFile*>( io->ioDevice() ) ) ) {
316  // jas_stream_fdopen works here, but not when reading...
317  stream = jas_stream_fdopen( dup( qf->handle() ), "w" );
318  } else {
319  ktempf = new KTempFile;
320  ktempf->setAutoDelete( true );
321  stream = jas_stream_fdopen( dup( ktempf->handle()), "w" );
322  } // else
323 
324 
325  // by here, a jas_stream_t is open
326  if (!stream)
327  {
328  kdError(399)
329  << "Failed to create a stream to write JP2 image" << endl;
330  cleanupJasper();
331  return;
332  }
333 
334  jas_image_t* ji = create_image( io->image() );
335  if( !ji ) {
336  delete ktempf;
337  jas_stream_close( stream );
338  cleanupJasper();
339  return;
340  } // if
341 
342  if( !write_components( ji, io->image() ) ) {
343  delete ktempf;
344  jas_stream_close( stream );
345  jas_image_destroy( ji );
346  cleanupJasper();
347  return;
348  } // if
349 
350  // optstr:
351  // - rate=#B => the resulting file size is about # bytes
352  // - rate=0.0 .. 1.0 => the resulting file size is about the factor times
353  // the uncompressed size
354  TQString rate;
355  TQTextStream ts( &rate, IO_WriteOnly );
356  ts << "rate="
357  << ( (io->quality() < 0) ? DEFAULT_RATE : io->quality() / 100.0F );
358 # if defined(JAS_VERSION_MAJOR) && (JAS_VERSION_MAJOR >= 3)
359  const jas_image_fmtinfo_t *jp2_fmtinfo = jas_image_lookupfmtbyname("jp2");
360  int i = -1;
361  if (jp2_fmtinfo)
362  {
363  i = jas_image_encode(ji, stream, jp2_fmtinfo->id, rate.utf8().data());
364  }
365 # else
366  int i = jp2_encode( ji, stream, rate.utf8().data() );
367 # endif
368 
369  jas_image_destroy( ji );
370  jas_stream_close( stream );
371  cleanupJasper();
372 
373  if( i != 0 ) { delete ktempf; return; }
374 
375  if( ktempf ) {
376  // We've written to a tempfile. Copy the data to the final destination.
377  TQFile* in = ktempf->file();
378 
379  TQByteArray b( 4096 );
380  TQ_LONG size;
381 
382  // seek to the beginning of the file.
383  if( !in->at( 0 ) ) { delete ktempf; return; }
384 
385  // 0 or -1 is EOF / error
386  while( ( size = in->readBlock( b.data(), 4096 ) ) > 0 ) {
387  if( ( io->ioDevice()->writeBlock( b.data(), size ) ) == -1 ) {
388  delete ktempf;
389  return;
390  } // if
391  } // while
392  io->ioDevice()->flush();
393  delete ktempf;
394 
395  // see if we've left the while loop due to an error.
396  if( size == -1 ) return;
397  } // if
398 
399 
400  // everything went fine
401  io->setStatus( IO_Ok );
402 } // kimgio_jp2_write
403 
404 #endif // HAVE_JASPER
405 

kimgio

Skip menu "kimgio"
  • Main Page
  • File List
  • Related Pages

kimgio

Skip menu "kimgio"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for kimgio by doxygen 1.9.1
This website is maintained by Timothy Pearson.