• 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
36typedef struct {
37 jas_image_t* image;
38
39 int cmptlut[MAXCMPTS];
40
41 jas_image_t* altimage;
42} gs_t;
43
44
45jas_image_t*
46read_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
91static bool
92convert_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
104static bool
105render_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
152static 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
188static 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
198TDE_EXPORT void
199kimgio_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
237static jas_image_t*
238create_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
267static bool
268write_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
300TDE_EXPORT void
301kimgio_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.4
This website is maintained by Timothy Pearson.