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

KImgIO

  • sources
  • kde-4.12
  • kdelibs
  • kimgio
rgb.cpp
Go to the documentation of this file.
1 // kimgio module for SGI images
2 //
3 // Copyright (C) 2004 Melchior FRANZ <mfranz@kde.org>
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the Lesser GNU General Public License as
7 // published by the Free Software Foundation; either version 2 of the
8 // License, or (at your option) any later version.
9 
10 
11 /* this code supports:
12  * reading:
13  * everything, except images with 1 dimension or images with
14  * mapmode != NORMAL (e.g. dithered); Images with 16 bit
15  * precision or more than 4 layers are stripped down.
16  * writing:
17  * Run Length Encoded (RLE) or Verbatim (uncompressed)
18  * (whichever is smaller)
19  *
20  * Please report if you come across rgb/rgba/sgi/bw files that aren't
21  * recognized. Also report applications that can't deal with images
22  * saved by this filter.
23  */
24 
25 
26 #include "rgb.h"
27 #include <QtGui/QImage>
28 #include <kdebug.h>
29 
30 
31 SGIImage::SGIImage(QIODevice *io) :
32  _starttab(0),
33  _lengthtab(0)
34 {
35  _dev = io;
36  _stream.setDevice(_dev);
37 }
38 
39 
40 SGIImage::~SGIImage()
41 {
42  delete[] _starttab;
43  delete[] _lengthtab;
44 }
45 
46 
48 
49 
50 bool SGIImage::getRow(uchar *dest)
51 {
52  int n, i;
53  if (!_rle) {
54  for (i = 0; i < _xsize; i++) {
55  if (_pos >= _data.end())
56  return false;
57  dest[i] = uchar(*_pos);
58  _pos += _bpc;
59  }
60  return true;
61  }
62 
63  for (i = 0; i < _xsize;) {
64  if (_bpc == 2)
65  _pos++;
66  n = *_pos & 0x7f;
67  if (!n)
68  break;
69 
70  if (*_pos++ & 0x80) {
71  for (; i < _xsize && n--; i++) {
72  *dest++ = *_pos;
73  _pos += _bpc;
74  }
75  } else {
76  for (; i < _xsize && n--; i++)
77  *dest++ = *_pos;
78 
79  _pos += _bpc;
80  }
81  }
82  return i == _xsize;
83 }
84 
85 
86 bool SGIImage::readData(QImage& img)
87 {
88  QRgb *c;
89  quint32 *start = _starttab;
90  QByteArray lguard(_xsize, 0);
91  uchar *line = (uchar *)lguard.data();
92  unsigned x, y;
93 
94  if (!_rle)
95  _pos = _data.begin();
96 
97  for (y = 0; y < _ysize; y++) {
98  if (_rle)
99  _pos = _data.begin() + *start++;
100  if (!getRow(line))
101  return false;
102  c = (QRgb *)img.scanLine(_ysize - y - 1);
103  for (x = 0; x < _xsize; x++, c++)
104  *c = qRgb(line[x], line[x], line[x]);
105  }
106 
107  if (_zsize == 1)
108  return true;
109 
110  if (_zsize != 2) {
111  for (y = 0; y < _ysize; y++) {
112  if (_rle)
113  _pos = _data.begin() + *start++;
114  if (!getRow(line))
115  return false;
116  c = (QRgb *)img.scanLine(_ysize - y - 1);
117  for (x = 0; x < _xsize; x++, c++)
118  *c = qRgb(qRed(*c), line[x], line[x]);
119  }
120 
121  for (y = 0; y < _ysize; y++) {
122  if (_rle)
123  _pos = _data.begin() + *start++;
124  if (!getRow(line))
125  return false;
126  c = (QRgb *)img.scanLine(_ysize - y - 1);
127  for (x = 0; x < _xsize; x++, c++)
128  *c = qRgb(qRed(*c), qGreen(*c), line[x]);
129  }
130 
131  if (_zsize == 3)
132  return true;
133  }
134 
135  for (y = 0; y < _ysize; y++) {
136  if (_rle)
137  _pos = _data.begin() + *start++;
138  if (!getRow(line))
139  return false;
140  c = (QRgb *)img.scanLine(_ysize - y - 1);
141  for (x = 0; x < _xsize; x++, c++)
142  *c = qRgba(qRed(*c), qGreen(*c), qBlue(*c), line[x]);
143  }
144 
145  return true;
146 }
147 
148 
149 bool SGIImage::readImage(QImage& img)
150 {
151  qint8 u8;
152  qint16 u16;
153  qint32 u32;
154 
155  kDebug(399) << "reading rgb ";
156 
157  // magic
158  _stream >> u16;
159  if (u16 != 0x01da)
160  return false;
161 
162  // verbatim/rle
163  _stream >> _rle;
164  kDebug(399) << (_rle ? "RLE" : "verbatim");
165  if (_rle > 1)
166  return false;
167 
168  // bytes per channel
169  _stream >> _bpc;
170  kDebug(399) << "bytes per channel: " << int(_bpc);
171  if (_bpc == 1)
172  ;
173  else if (_bpc == 2)
174  kDebug(399) << "dropping least significant byte";
175  else
176  return false;
177 
178  // number of dimensions
179  _stream >> _dim;
180  kDebug(399) << "dimensions: " << _dim;
181  if (_dim < 1 || _dim > 3)
182  return false;
183 
184  _stream >> _xsize >> _ysize >> _zsize >> _pixmin >> _pixmax >> u32;
185  kDebug(399) << "x: " << _xsize;
186  kDebug(399) << "y: " << _ysize;
187  kDebug(399) << "z: " << _zsize;
188 
189  // name
190  _stream.readRawData(_imagename, 80);
191  _imagename[79] = '\0';
192 
193  _stream >> _colormap;
194  kDebug(399) << "colormap: " << _colormap;
195  if (_colormap != NORMAL)
196  return false; // only NORMAL supported
197 
198  for (int i = 0; i < 404; i++)
199  _stream >> u8;
200 
201  if (_dim == 1) {
202  kDebug(399) << "1-dimensional images aren't supported yet";
203  return false;
204  }
205 
206  if( _stream.atEnd())
207  return false;
208 
209  _numrows = _ysize * _zsize;
210 
211  img = QImage( _xsize, _ysize, QImage::Format_RGB32 );
212 
213  if (_zsize == 2 || _zsize == 4)
214  img = img.convertToFormat(QImage::Format_ARGB32);
215  else if (_zsize > 4)
216  kDebug(399) << "using first 4 of " << _zsize << " channels";
217 
218  if (_rle) {
219  uint l;
220  _starttab = new quint32[_numrows];
221  for (l = 0; !_stream.atEnd() && l < _numrows; l++) {
222  _stream >> _starttab[l];
223  _starttab[l] -= 512 + _numrows * 2 * sizeof(quint32);
224  }
225 
226  _lengthtab = new quint32[_numrows];
227  for (l = 0; l < _numrows; l++)
228  _stream >> _lengthtab[l];
229  }
230 
231  _data = _dev->readAll();
232 
233  // sanity check
234  if (_rle)
235  for (uint o = 0; o < _numrows; o++)
236  // don't change to greater-or-equal!
237  if (_starttab[o] + _lengthtab[o] > (uint)_data.size()) {
238  kDebug(399) << "image corrupt (sanity check failed)";
239  return false;
240  }
241 
242  if (!readData(img)) {
243  kDebug(399) << "image corrupt (incomplete scanline)";
244  return false;
245  }
246 
247  return true;
248 }
249 
250 
252 
253 
254 void RLEData::write(QDataStream& s)
255 {
256  for (int i = 0; i < size(); i++)
257  s << at(i);
258 }
259 
260 
261 bool RLEData::operator<(const RLEData& b) const
262 {
263  uchar ac, bc;
264  for (int i = 0; i < qMin(size(), b.size()); i++) {
265  ac = at(i);
266  bc = b[i];
267  if (ac != bc)
268  return ac < bc;
269  }
270  return size() < b.size();
271 }
272 
273 
274 uint RLEMap::insert(const uchar *d, uint l)
275 {
276  RLEData data = RLEData(d, l, _offset);
277  Iterator it = find(data);
278  if (it != end())
279  return it.value();
280 
281  _offset += l;
282  return QMap<RLEData, uint>::insert(data, _counter++).value();
283 }
284 
285 
286 QVector<const RLEData*> RLEMap::vector()
287 {
288  QVector<const RLEData*> v(size());
289  for (Iterator it = begin(); it != end(); ++it)
290  v.replace(it.value(), &it.key());
291 
292  return v;
293 }
294 
295 
296 uchar SGIImage::intensity(uchar c)
297 {
298  if (c < _pixmin)
299  _pixmin = c;
300  if (c > _pixmax)
301  _pixmax = c;
302  return c;
303 }
304 
305 
306 uint SGIImage::compact(uchar *d, uchar *s)
307 {
308  uchar *dest = d, *src = s, patt, *t, *end = s + _xsize;
309  int i, n;
310  while (src < end) {
311  for (n = 0, t = src; t + 2 < end && !(*t == t[1] && *t == t[2]); t++)
312  n++;
313 
314  while (n) {
315  i = n > 126 ? 126 : n;
316  n -= i;
317  *dest++ = 0x80 | i;
318  while (i--)
319  *dest++ = *src++;
320  }
321 
322  if (src == end)
323  break;
324 
325  patt = *src++;
326  for (n = 1; src < end && *src == patt; src++)
327  n++;
328 
329  while (n) {
330  i = n > 126 ? 126 : n;
331  n -= i;
332  *dest++ = i;
333  *dest++ = patt;
334  }
335  }
336  *dest++ = 0;
337  return dest - d;
338 }
339 
340 
341 bool SGIImage::scanData(const QImage& img)
342 {
343  quint32 *start = _starttab;
344  QByteArray lineguard(_xsize * 2, 0);
345  QByteArray bufguard(_xsize, 0);
346  uchar *line = (uchar *)lineguard.data();
347  uchar *buf = (uchar *)bufguard.data();
348  const QRgb *c;
349  unsigned x, y;
350  uint len;
351 
352  for (y = 0; y < _ysize; y++) {
353  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
354  for (x = 0; x < _xsize; x++)
355  buf[x] = intensity(qRed(*c++));
356  len = compact(line, buf);
357  *start++ = _rlemap.insert(line, len);
358  }
359 
360  if (_zsize == 1)
361  return true;
362 
363  if (_zsize != 2) {
364  for (y = 0; y < _ysize; y++) {
365  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
366  for (x = 0; x < _xsize; x++)
367  buf[x] = intensity(qGreen(*c++));
368  len = compact(line, buf);
369  *start++ = _rlemap.insert(line, len);
370  }
371 
372  for (y = 0; y < _ysize; y++) {
373  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
374  for (x = 0; x < _xsize; x++)
375  buf[x] = intensity(qBlue(*c++));
376  len = compact(line, buf);
377  *start++ = _rlemap.insert(line, len);
378  }
379 
380  if (_zsize == 3)
381  return true;
382  }
383 
384  for (y = 0; y < _ysize; y++) {
385  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
386  for (x = 0; x < _xsize; x++)
387  buf[x] = intensity(qAlpha(*c++));
388  len = compact(line, buf);
389  *start++ = _rlemap.insert(line, len);
390  }
391 
392  return true;
393 }
394 
395 
396 void SGIImage::writeHeader()
397 {
398  _stream << quint16(0x01da);
399  _stream << _rle << _bpc << _dim;
400  _stream << _xsize << _ysize << _zsize;
401  _stream << _pixmin << _pixmax;
402  _stream << quint32(0);
403 
404  for (int i = 0; i < 80; i++)
405  _imagename[i] = '\0';
406  _stream.writeRawData(_imagename, 80);
407 
408  _stream << _colormap;
409  for (int i = 0; i < 404; i++)
410  _stream << quint8(0);
411 }
412 
413 
414 void SGIImage::writeRle()
415 {
416  _rle = 1;
417  kDebug(399) << "writing RLE data";
418  writeHeader();
419  uint i;
420 
421  // write start table
422  for (i = 0; i < _numrows; i++)
423  _stream << quint32(_rlevector[_starttab[i]]->offset());
424 
425  // write length table
426  for (i = 0; i < _numrows; i++)
427  _stream << quint32(_rlevector[_starttab[i]]->size());
428 
429  // write data
430  for (i = 0; (int)i < _rlevector.size(); i++)
431  const_cast<RLEData*>(_rlevector[i])->write(_stream);
432 }
433 
434 
435 void SGIImage::writeVerbatim(const QImage& img)
436 {
437  _rle = 0;
438  kDebug(399) << "writing verbatim data";
439  writeHeader();
440 
441  const QRgb *c;
442  unsigned x, y;
443 
444  for (y = 0; y < _ysize; y++) {
445  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
446  for (x = 0; x < _xsize; x++)
447  _stream << quint8(qRed(*c++));
448  }
449 
450  if (_zsize == 1)
451  return;
452 
453  if (_zsize != 2) {
454  for (y = 0; y < _ysize; y++) {
455  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
456  for (x = 0; x < _xsize; x++)
457  _stream << quint8(qGreen(*c++));
458  }
459 
460  for (y = 0; y < _ysize; y++) {
461  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
462  for (x = 0; x < _xsize; x++)
463  _stream << quint8(qBlue(*c++));
464  }
465 
466  if (_zsize == 3)
467  return;
468  }
469 
470  for (y = 0; y < _ysize; y++) {
471  c = reinterpret_cast<const QRgb *>(img.scanLine(_ysize - y - 1));
472  for (x = 0; x < _xsize; x++)
473  _stream << quint8(qAlpha(*c++));
474  }
475 }
476 
477 
478 bool SGIImage::writeImage(const QImage& image)
479 {
480  kDebug(399) << "writing "; // TODO add filename
481  QImage img = image;
482  if (img.allGray())
483  _dim = 2, _zsize = 1;
484  else
485  _dim = 3, _zsize = 3;
486 
487  if (img.format() == QImage::Format_ARGB32)
488  _dim = 3, _zsize++;
489 
490  img = img.convertToFormat(QImage::Format_RGB32);
491  if (img.isNull()) {
492  kDebug(399) << "can't convert image to depth 32";
493  return false;
494  }
495 
496  _bpc = 1;
497  _xsize = img.width();
498  _ysize = img.height();
499  _pixmin = ~0u;
500  _pixmax = 0;
501  _colormap = NORMAL;
502  _numrows = _ysize * _zsize;
503  _starttab = new quint32[_numrows];
504  _rlemap.setBaseOffset(512 + _numrows * 2 * sizeof(quint32));
505 
506  if (!scanData(img)) {
507  kDebug(399) << "this can't happen";
508  return false;
509  }
510 
511  _rlevector = _rlemap.vector();
512 
513  long verbatim_size = _numrows * _xsize;
514  long rle_size = _numrows * 2 * sizeof(quint32);
515  for (int i = 0; i < _rlevector.size(); i++)
516  rle_size += _rlevector[i]->size();
517 
518  kDebug(399) << "minimum intensity: " << _pixmin;
519  kDebug(399) << "maximum intensity: " << _pixmax;
520  kDebug(399) << "saved scanlines: " << _numrows - _rlemap.size();
521  kDebug(399) << "total savings: " << (verbatim_size - rle_size) << " bytes";
522  kDebug(399) << "compression: " << (rle_size * 100.0 / verbatim_size) << '%';
523 
524  if (verbatim_size <= rle_size)
525  writeVerbatim(img);
526  else
527  writeRle();
528  return true;
529 }
530 
531 
533 
534 
535 RGBHandler::RGBHandler()
536 {
537 }
538 
539 
540 bool RGBHandler::canRead() const
541 {
542  if (canRead(device())) {
543  setFormat("rgb");
544  return true;
545  }
546  return false;
547 }
548 
549 
550 bool RGBHandler::read(QImage *outImage)
551 {
552  SGIImage sgi(device());
553  return sgi.readImage(*outImage);
554 }
555 
556 
557 bool RGBHandler::write(const QImage &image)
558 {
559  SGIImage sgi(device());
560  return sgi.writeImage(image);
561 }
562 
563 
564 QByteArray RGBHandler::name() const
565 {
566  return "rgb";
567 }
568 
569 
570 bool RGBHandler::canRead(QIODevice *device)
571 {
572  if (!device) {
573  qWarning("RGBHandler::canRead() called with no device");
574  return false;
575  }
576 
577  qint64 oldPos = device->pos();
578  QByteArray head = device->readLine(64);
579  int readBytes = head.size();
580 
581  if (device->isSequential()) {
582  while (readBytes > 0)
583  device->ungetChar(head[readBytes-- - 1]);
584 
585  } else {
586  device->seek(oldPos);
587  }
588 
589  const QRegExp regexp("^\x01\xda\x01[\x01\x02]");
590  QString data(head);
591 
592  return data.contains(regexp);
593 }
594 
595 
597 
598 
599 class RGBPlugin : public QImageIOPlugin
600 {
601 public:
602  QStringList keys() const;
603  Capabilities capabilities(QIODevice *device, const QByteArray &format) const;
604  QImageIOHandler *create(QIODevice *device, const QByteArray &format = QByteArray()) const;
605 };
606 
607 
608 QStringList RGBPlugin::keys() const
609 {
610  return QStringList() << "rgb" << "RGB" << "rgba" << "RGBA" << "bw" << "BW" << "sgi" << "SGI";
611 }
612 
613 
614 QImageIOPlugin::Capabilities RGBPlugin::capabilities(QIODevice *device, const QByteArray &format) const
615 {
616  if (format == "rgb" || format == "RGB" || format == "rgba" || format == "RGBA"
617  || format == "bw" || format == "BW" || format == "sgi" || format == "SGI")
618  return Capabilities(CanRead|CanWrite);
619 
620  if (!format.isEmpty())
621  return 0;
622  if (!device->isOpen())
623  return 0;
624 
625  Capabilities cap;
626  if (device->isReadable() && RGBHandler::canRead(device))
627  cap |= CanRead;
628  if (device->isWritable())
629  cap |= CanWrite;
630  return cap;
631 }
632 
633 
634 QImageIOHandler *RGBPlugin::create(QIODevice *device, const QByteArray &format) const
635 {
636  QImageIOHandler *handler = new RGBHandler;
637  handler->setDevice(device);
638  handler->setFormat(format);
639  return handler;
640 }
641 
642 
643 Q_EXPORT_STATIC_PLUGIN(RGBPlugin)
644 Q_EXPORT_PLUGIN2(rgb, RGBPlugin)
645 
RLEMap::insert
uint insert(const uchar *d, uint l)
Definition: rgb.cpp:274
RLEData::write
void write(QDataStream &s)
Definition: rgb.cpp:254
RGBHandler
Definition: rgb.h:19
QVector
RGBHandler::read
bool read(QImage *image)
Definition: rgb.cpp:550
rgb.h
RGBHandler::name
QByteArray name() const
Definition: rgb.cpp:564
SGIImage
Definition: rgb.h:61
RLEData
Definition: rgb.h:32
SGIImage::SGIImage
SGIImage(QIODevice *device)
Definition: rgb.cpp:31
RLEMap::vector
QVector< const RLEData * > vector()
Definition: rgb.cpp:286
RGBHandler::write
bool write(const QImage &image)
Definition: rgb.cpp:557
RLEMap::setBaseOffset
void setBaseOffset(uint o)
Definition: rgb.h:53
uchar
quint8 uchar
Definition: dds.cpp:38
QImageIOHandler
SGIImage::~SGIImage
~SGIImage()
Definition: rgb.cpp:40
RGBHandler::canRead
bool canRead() const
Definition: rgb.cpp:540
RGBHandler::RGBHandler
RGBHandler()
Definition: rgb.cpp:535
qRgba
QRgb qRgba(const QRgb &rgb, int a)
Change a QRgb value's alpha only.
Definition: xcf.cpp:67
uint
quint32 uint
Definition: dds.cpp:36
RLEData::operator<
bool operator<(const RLEData &) const
Definition: rgb.cpp:261
SGIImage::writeImage
bool writeImage(const QImage &)
Definition: rgb.cpp:478
SGIImage::readImage
bool readImage(QImage &)
Definition: rgb.cpp:149
QMap
This file is part of the KDE documentation.
Documentation copyright © 1996-2014 The KDE developers.
Generated on Tue Oct 14 2014 22:47:50 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
  • kjsembed
  •   WTF
  • KNewStuff
  • KParts
  • KPty
  • Kross
  • KUnitConversion
  • KUtils
  • Nepomuk
  • Nepomuk-Core
  • 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