• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdelibs API Reference
  • KDE Home
  • Contact Us
 

KImgIO

  • sources
  • kde-4.14
  • kdelibs
  • kimgio
jp2.cpp
Go to the documentation of this file.
1 
8 #include "jp2.h"
9 
10 #include <config.h>
11 
12 #ifdef HAVE_SYS_TYPES_H
13 #include <sys/types.h>
14 #endif
15 
16 #ifdef HAVE_STDINT_H
17 #include <stdint.h>
18 #endif
19 
20 #include <QImage>
21 #include <QVariant>
22 #include <QTextStream>
23 
24 // dirty, but avoids a warning because jasper.h includes jas_config.h.
25 #undef PACKAGE
26 #undef VERSION
27 #include <jasper/jasper.h>
28 
29 // code taken in parts from JasPer's jiv.c
30 
31 #define DEFAULT_RATE 0.10
32 #define MAXCMPTS 256
33 
34 
35 /************************* JasPer QIODevice stream ***********************/
36 
37 //unfortunately this is declared as static in JasPer libraries
38 static jas_stream_t *jas_stream_create()
39 {
40  jas_stream_t *stream;
41 
42  if (!(stream = (jas_stream_t*)jas_malloc(sizeof(jas_stream_t)))) {
43  return 0;
44  }
45  stream->openmode_ = 0;
46  stream->bufmode_ = 0;
47  stream->flags_ = 0;
48  stream->bufbase_ = 0;
49  stream->bufstart_ = 0;
50  stream->bufsize_ = 0;
51  stream->ptr_ = 0;
52  stream->cnt_ = 0;
53  stream->ops_ = 0;
54  stream->obj_ = 0;
55  stream->rwcnt_ = 0;
56  stream->rwlimit_ = -1;
57 
58  return stream;
59 }
60 
61 //unfortunately this is declared as static in JasPer libraries
62 static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf,
63  int bufsize)
64 {
65  /* If this function is being called, the buffer should not have been
66  initialized yet. */
67  assert(!stream->bufbase_);
68 
69  if (bufmode != JAS_STREAM_UNBUF) {
70  /* The full- or line-buffered mode is being employed. */
71  if (!buf) {
72  /* The caller has not specified a buffer to employ, so allocate
73  one. */
74  if ((stream->bufbase_ = (unsigned char*)jas_malloc(JAS_STREAM_BUFSIZE +
75  JAS_STREAM_MAXPUTBACK))) {
76  stream->bufmode_ |= JAS_STREAM_FREEBUF;
77  stream->bufsize_ = JAS_STREAM_BUFSIZE;
78  } else {
79  /* The buffer allocation has failed. Resort to unbuffered
80  operation. */
81  stream->bufbase_ = stream->tinybuf_;
82  stream->bufsize_ = 1;
83  }
84  } else {
85  /* The caller has specified a buffer to employ. */
86  /* The buffer must be large enough to accommodate maximum
87  putback. */
88  assert(bufsize > JAS_STREAM_MAXPUTBACK);
89  stream->bufbase_ = JAS_CAST(uchar *, buf);
90  stream->bufsize_ = bufsize - JAS_STREAM_MAXPUTBACK;
91  }
92  } else {
93  /* The unbuffered mode is being employed. */
94  /* A buffer should not have been supplied by the caller. */
95  assert(!buf);
96  /* Use a trivial one-character buffer. */
97  stream->bufbase_ = stream->tinybuf_;
98  stream->bufsize_ = 1;
99  }
100  stream->bufstart_ = &stream->bufbase_[JAS_STREAM_MAXPUTBACK];
101  stream->ptr_ = stream->bufstart_;
102  stream->cnt_ = 0;
103  stream->bufmode_ |= bufmode & JAS_STREAM_BUFMODEMASK;
104 }
105 
106 static int qiodevice_read(jas_stream_obj_t *obj, char *buf, int cnt)
107 {
108  QIODevice *io = (QIODevice*) obj;
109  return io->read(buf, cnt);
110 }
111 
112 static int qiodevice_write(jas_stream_obj_t *obj, char *buf, int cnt)
113 {
114  QIODevice *io = (QIODevice*) obj;
115  return io->write(buf, cnt);
116 }
117 
118 static long qiodevice_seek(jas_stream_obj_t *obj, long offset, int origin)
119 {
120  QIODevice *io = (QIODevice*) obj;
121  long newpos;
122 
123  switch (origin) {
124  case SEEK_SET:
125  newpos = offset;
126  break;
127  case SEEK_END:
128  newpos = io->size() - offset;
129  break;
130  case SEEK_CUR:
131  newpos = io->pos() + offset;
132  break;
133  default:
134  return -1;
135  }
136  if (newpos < 0) {
137  return -1;
138  }
139  if ( io->seek(newpos) )
140  return newpos;
141  else
142  return -1;
143 }
144 
145 static int qiodevice_close(jas_stream_obj_t *)
146 {
147  return 0;
148 }
149 
150 static jas_stream_ops_t jas_stream_qiodeviceops = {
151  qiodevice_read,
152  qiodevice_write,
153  qiodevice_seek,
154  qiodevice_close
155 };
156 
157 static jas_stream_t *jas_stream_qiodevice(QIODevice *iodevice)
158 {
159  jas_stream_t *stream;
160 
161  if ( !iodevice ) return 0;
162  if (!(stream = jas_stream_create())) {
163  return 0;
164  }
165 
166  /* A stream associated with a memory buffer is always opened
167  for both reading and writing in binary mode. */
168  stream->openmode_ = JAS_STREAM_READ | JAS_STREAM_WRITE | JAS_STREAM_BINARY;
169 
170  jas_stream_initbuf(stream, JAS_STREAM_FULLBUF, 0, 0);
171 
172  /* Select the operations for a memory stream. */
173  stream->obj_ = (void *)iodevice;
174  stream->ops_ = &jas_stream_qiodeviceops;
175 
176  return stream;
177 }
178 
179 /************************ End of JasPer QIODevice stream ****************/
180 
181 typedef struct {
182  jas_image_t* image;
183 
184  int cmptlut[MAXCMPTS];
185 
186  jas_image_t* altimage;
187 } gs_t;
188 
189 
190 static jas_image_t*
191 read_image( QIODevice* io )
192 {
193  jas_stream_t* in = 0;
194 
195  in = jas_stream_qiodevice( io );
196 
197  if( !in ) return 0;
198 
199  jas_image_t* image = jas_image_decode( in, -1, 0 );
200  jas_stream_close( in );
201 
202  // image may be 0, but that's Ok
203  return image;
204 } // read_image
205 
206 static bool
207 convert_colorspace( gs_t& gs )
208 {
209  jas_cmprof_t *outprof = jas_cmprof_createfromclrspc( JAS_CLRSPC_SRGB );
210  if( !outprof ) return false;
211 
212  gs.altimage = jas_image_chclrspc( gs.image, outprof,
213  JAS_CMXFORM_INTENT_PER );
214  if( !gs.altimage ) return false;
215 
216  return true;
217 } // convert_colorspace
218 
219 static bool
220 render_view( gs_t& gs, QImage* outImage )
221 {
222  if ( !gs.altimage ) return false;
223  QImage qti;
224  if((gs.cmptlut[0] = jas_image_getcmptbytype(gs.altimage,
225  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_R))) < 0 ||
226  (gs.cmptlut[1] = jas_image_getcmptbytype(gs.altimage,
227  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_G))) < 0 ||
228  (gs.cmptlut[2] = jas_image_getcmptbytype(gs.altimage,
229  JAS_IMAGE_CT_COLOR(JAS_CLRSPC_CHANIND_RGB_B))) < 0) {
230  return false;
231  } // if
232 
233  const int* cmptlut = gs.cmptlut;
234  int v[3];
235 
236  // check that all components have the same size.
237  const int width = jas_image_cmptwidth( gs.altimage, cmptlut[0] );
238  const int height = jas_image_cmptheight( gs.altimage, cmptlut[0] );
239  for( int i = 1; i < 3; ++i ) {
240  if (jas_image_cmptwidth( gs.altimage, cmptlut[i] ) != width ||
241  jas_image_cmptheight( gs.altimage, cmptlut[i] ) != height)
242  return false;
243  } // for
244 
245  jas_matrix_t *cmptmatrix[3];
246  jas_seqent_t *buf[3];
247  int prec[3];
248 
249  for (int k = 0; k < 3; ++k ) {
250  prec[k] = jas_image_cmptprec(gs.altimage, cmptlut[k]);
251  if (!(cmptmatrix[k] = jas_matrix_create(1, width))) {
252  return false;
253  }
254  }
255 
256  qti = QImage( jas_image_width( gs.altimage ), jas_image_height( gs.altimage ),
257  QImage::Format_RGB32 );
258  if (qti.isNull()) {
259  return false;
260  }
261  uint32_t* data = (uint32_t*)qti.bits();
262 
263  for( int y = 0; y < height; ++y ) {
264  for( int k = 0; k < 3; ++k ) {
265  if (jas_image_readcmpt(gs.altimage, cmptlut[k], 0, y, width, 1, cmptmatrix[k])) {
266  return false;
267  }
268  buf[k] = jas_matrix_getref(cmptmatrix[k], 0, 0);
269  }
270  for( int x = 0; x < width; ++x ) {
271  for( int k = 0; k < 3; ++k ) {
272  v[k] = *buf[k];
273  // if the precision of the component is too small, increase
274  // it to use the complete value range.
275  v[k] <<= 8 - prec[k];
276 
277  if( v[k] < 0 ) v[k] = 0;
278  else if( v[k] > 255 ) v[k] = 255;
279  ++buf[k];
280  } // for k
281 
282  *data++ = qRgb( v[0], v[1], v[2] );
283  } // for x
284  } // for y
285 
286  for (int k = 0; k < 3; ++k ) {
287  if (cmptmatrix[k]) {
288  jas_matrix_destroy(cmptmatrix[k]);
289  }
290  }
291 
292  *outImage = qti;
293  return true;
294 } // render_view
295 
296 
297 static jas_image_t*
298 create_image( const QImage& qi )
299 {
300  // prepare the component parameters
301  jas_image_cmptparm_t* cmptparms = new jas_image_cmptparm_t[ 3 ];
302 
303  for ( int i = 0; i < 3; ++i ) {
304  // x and y offset
305  cmptparms[i].tlx = 0;
306  cmptparms[i].tly = 0;
307 
308  // the resulting image will be hstep*width x vstep*height !
309  cmptparms[i].hstep = 1;
310  cmptparms[i].vstep = 1;
311  cmptparms[i].width = qi.width();
312  cmptparms[i].height = qi.height();
313 
314  // we write everything as 24bit truecolor ATM
315  cmptparms[i].prec = 8;
316  cmptparms[i].sgnd = false;
317  }
318 
319  jas_image_t* ji = jas_image_create( 3 /* number components */, cmptparms, JAS_CLRSPC_UNKNOWN );
320  delete[] cmptparms;
321 
322  // returning 0 is ok
323  return ji;
324 } // create_image
325 
326 
327 static bool
328 write_components( jas_image_t* ji, const QImage& qi )
329 {
330  const unsigned height = qi.height();
331  const unsigned width = qi.width();
332 
333  jas_matrix_t* m = jas_matrix_create( height, width );
334  if( !m ) return false;
335 
336  jas_image_setclrspc( ji, JAS_CLRSPC_SRGB );
337 
338  jas_image_setcmpttype( ji, 0, JAS_IMAGE_CT_RGB_R );
339  for( uint y = 0; y < height; ++y )
340  for( uint x = 0; x < width; ++x )
341  jas_matrix_set( m, y, x, qRed( qi.pixel( x, y ) ) );
342  jas_image_writecmpt( ji, 0, 0, 0, width, height, m );
343 
344  jas_image_setcmpttype( ji, 1, JAS_IMAGE_CT_RGB_G );
345  for( uint y = 0; y < height; ++y )
346  for( uint x = 0; x < width; ++x )
347  jas_matrix_set( m, y, x, qGreen( qi.pixel( x, y ) ) );
348  jas_image_writecmpt( ji, 1, 0, 0, width, height, m );
349 
350  jas_image_setcmpttype( ji, 2, JAS_IMAGE_CT_RGB_B );
351  for( uint y = 0; y < height; ++y )
352  for( uint x = 0; x < width; ++x )
353  jas_matrix_set( m, y, x, qBlue( qi.pixel( x, y ) ) );
354  jas_image_writecmpt( ji, 2, 0, 0, width, height, m );
355  jas_matrix_destroy( m );
356 
357  return true;
358 } // write_components
359 
360 static bool
361 write_image( const QImage &image, QIODevice* io, int quality )
362 {
363  jas_stream_t* stream = 0;
364  stream = jas_stream_qiodevice( io );
365 
366  // by here, a jas_stream_t is open
367  if( !stream ) return false;
368 
369  jas_image_t* ji = create_image( image );
370  if( !ji ) {
371  jas_stream_close( stream );
372  return false;
373  } // if
374 
375  if( !write_components( ji, image ) ) {
376  jas_stream_close( stream );
377  jas_image_destroy( ji );
378  return false;
379  } // if
380 
381  // optstr:
382  // - rate=#B => the resulting file size is about # bytes
383  // - rate=0.0 .. 1.0 => the resulting file size is about the factor times
384  // the uncompressed size
385  // use sprintf for locale-aware string
386  char rateBuffer[16];
387  sprintf(rateBuffer, "rate=%.2g\n", (quality < 0) ? DEFAULT_RATE : quality / 100.0);
388  int i = jp2_encode( ji, stream, rateBuffer);
389 
390  jas_image_destroy( ji );
391  jas_stream_close( stream );
392 
393  if( i != 0 ) return false;
394 
395  return true;
396 }
397 
398 JP2Handler::JP2Handler()
399 {
400  quality = 75;
401  jas_init();
402 }
403 
404 JP2Handler::~JP2Handler()
405 {
406  jas_cleanup();
407 }
408 
409 bool JP2Handler::canRead() const
410 {
411  if (canRead(device())) {
412  setFormat("jp2");
413  return true;
414  }
415  return false;
416 }
417 
418 bool JP2Handler::canRead(QIODevice *device)
419 {
420  if (!device) {
421  return false;
422  }
423  return device->peek(6) == QByteArray("\x00\x00\x00\x0C\x6A\x50", 6);
424 }
425 
426 bool JP2Handler::read(QImage *image)
427 {
428  if (!canRead()) return false;
429 
430  gs_t gs;
431  if( !(gs.image = read_image( device() )) ) return false;
432 
433  if( !convert_colorspace( gs ) ) return false;
434 
435  render_view( gs, image );
436 
437  if( gs.image ) jas_image_destroy( gs.image );
438  if( gs.altimage ) jas_image_destroy( gs.altimage );
439  return true;
440 
441 }
442 
443 bool JP2Handler::write(const QImage &image)
444 {
445  return write_image(image, device(),quality);
446 }
447 
448 bool JP2Handler::supportsOption(ImageOption option) const
449 {
450  return option == Quality;
451 }
452 
453 QVariant JP2Handler::option(ImageOption option) const
454 {
455  if (option == Quality)
456  return quality;
457  return QVariant();
458 }
459 
460 void JP2Handler::setOption(ImageOption option, const QVariant &value)
461 {
462  if (option == Quality)
463  quality = qBound(-1, value.toInt(), 100);
464 }
465 
466 QByteArray JP2Handler::name() const
467 {
468  return "jp2";
469 }
470 
471 class JP2Plugin : public QImageIOPlugin
472 {
473 public:
474  QStringList keys() const;
475  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
476  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
477 };
478 
479 QStringList JP2Plugin::keys() const
480 {
481  return QStringList() << "jp2";
482 }
483 
484 QImageIOPlugin::Capabilities JP2Plugin::capabilities(QIODevice *device, const QByteArray &format) const
485 {
486  if (format == "jp2")
487  return Capabilities(CanRead | CanWrite);
488  if (!format.isEmpty())
489  return 0;
490  if (!device->isOpen())
491  return 0;
492 
493  Capabilities cap;
494  if (device->isReadable() && JP2Handler::canRead(device))
495  cap |= CanRead;
496  if (device->isWritable())
497  cap |= CanWrite;
498  return cap;
499 }
500 
501 QImageIOHandler *JP2Plugin::create(QIODevice *device, const QByteArray &format) const
502 {
503  QImageIOHandler *handler = new JP2Handler;
504  handler->setDevice(device);
505  handler->setFormat(format);
506  return handler;
507 }
508 
509 Q_EXPORT_STATIC_PLUGIN(JP2Plugin)
510 Q_EXPORT_PLUGIN2(jp2, JP2Plugin)
511 
512 
QIODevice
JP2Handler::setOption
void setOption(ImageOption option, const QVariant &value)
Definition: jp2.cpp:460
QImageIOPlugin::Capabilities
typedef Capabilities
QIODevice::isWritable
bool isWritable() const
QImageIOPlugin::create
virtual QImageIOHandler * create(QIODevice *device, const QByteArray &format) const =0
QImageIOHandler::device
QIODevice * device() const
QIODevice::seek
virtual bool seek(qint64 pos)
QByteArray
jas_stream_create
static jas_stream_t * jas_stream_create()
Definition: jp2.cpp:38
qiodevice_close
static int qiodevice_close(jas_stream_obj_t *)
Definition: jp2.cpp:145
QByteArray::isEmpty
bool isEmpty() const
JP2Handler::read
bool read(QImage *image)
Definition: jp2.cpp:426
QImage::isNull
bool isNull() const
QIODevice::isReadable
bool isReadable() const
jas_stream_initbuf
static void jas_stream_initbuf(jas_stream_t *stream, int bufmode, char *buf, int bufsize)
Definition: jp2.cpp:62
JP2Handler
QImageIO Routines to read/write JPEG2000 images.
Definition: jp2.h:12
QIODevice::pos
virtual qint64 pos() const
read_image
static jas_image_t * read_image(QIODevice *io)
Definition: jp2.cpp:191
QIODevice::peek
qint64 peek(char *data, qint64 maxSize)
create_image
static jas_image_t * create_image(const QImage &qi)
Definition: jp2.cpp:298
qiodevice_write
static int qiodevice_write(jas_stream_obj_t *obj, char *buf, int cnt)
Definition: jp2.cpp:112
QImage::pixel
QRgb pixel(int x, int y) const
write_components
static bool write_components(jas_image_t *ji, const QImage &qi)
Definition: jp2.cpp:328
QIODevice::size
virtual qint64 size() const
QVariant::toInt
int toInt(bool *ok) const
render_view
static bool render_view(gs_t &gs, QImage *outImage)
Definition: jp2.cpp:220
JP2Handler::name
QByteArray name() const
Definition: jp2.cpp:466
QImage::width
int width() const
jp2.h
JP2Handler::canRead
bool canRead() const
Definition: jp2.cpp:409
QImageIOHandler::setDevice
void setDevice(QIODevice *device)
JP2Handler::JP2Handler
JP2Handler()
Definition: jp2.cpp:398
qiodevice_read
static int qiodevice_read(jas_stream_obj_t *obj, char *buf, int cnt)
Definition: jp2.cpp:106
QIODevice::read
qint64 read(char *data, qint64 maxSize)
QIODevice::isOpen
bool isOpen() const
JP2Handler::supportsOption
bool supportsOption(ImageOption option) const
Definition: jp2.cpp:448
QImageIOPlugin::capabilities
virtual Capabilities capabilities(QIODevice *device, const QByteArray &format) const =0
write_image
static bool write_image(const QImage &image, QIODevice *io, int quality)
Definition: jp2.cpp:361
QImageIOPlugin
QStringList
QImageIOHandler
MAXCMPTS
#define MAXCMPTS
Definition: jp2.cpp:32
jas_stream_qiodeviceops
static jas_stream_ops_t jas_stream_qiodeviceops
Definition: jp2.cpp:150
JP2Handler::write
bool write(const QImage &image)
Definition: jp2.cpp:443
jas_stream_qiodevice
static jas_stream_t * jas_stream_qiodevice(QIODevice *iodevice)
Definition: jp2.cpp:157
convert_colorspace
static bool convert_colorspace(gs_t &gs)
Definition: jp2.cpp:207
uchar
quint8 uchar
Definition: dds.cpp:38
QImage
JP2Handler::option
QVariant option(ImageOption option) const
Definition: jp2.cpp:453
QImageIOPlugin::keys
virtual QStringList keys() const =0
JP2Handler::~JP2Handler
virtual ~JP2Handler()
Definition: jp2.cpp:404
QImage::bits
uchar * bits()
QIODevice::write
qint64 write(const char *data, qint64 maxSize)
QImageIOHandler::setFormat
void setFormat(const QByteArray &format)
QImage::height
int height() const
DEFAULT_RATE
#define DEFAULT_RATE
QImageIO Routines to read/write JPEG2000 images.
Definition: jp2.cpp:31
uint
quint32 uint
Definition: dds.cpp:36
qiodevice_seek
static long qiodevice_seek(jas_stream_obj_t *obj, long offset, int origin)
Definition: jp2.cpp:118
QVariant
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:22:49 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

KImgIO

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

kdelibs API Reference

Skip menu "kdelibs API Reference"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDEWebKit
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • kio
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Plasma
  • Solid
  • Sonnet
  • ThreadWeaver

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal