33class RLEData :
public QList<uchar>
39 RLEData(
const uchar *d, uint l, uint o)
42 for (uint i = 0; i < l; i++) {
46 bool operator<(
const RLEData &)
const;
57class RLEMap :
public QMap<RLEData, uint>
65 uint insert(
const uchar *d, uint l);
67 void setBaseOffset(uint o)
84 bool writeImage(
const QImage &);
87 bool isSupported()
const;
116 quint32 _colormap = 0;
118 quint32 _unused32 = 0;
123 QByteArray::Iterator _pos;
129 bool getRow(uchar *dest);
132 static bool readHeader(
QDataStream &ds, SGIImagePrivate *sgi);
136 bool writeVerbatim(
const QImage &);
137 bool scanData(
const QImage &);
138 uint compact(uchar *, uchar *);
139 uchar intensity(uchar);
142SGIImagePrivate::SGIImagePrivate()
145 , _lengthtab(nullptr)
147 std::memset(_imagename, 0,
sizeof(_imagename));
148 std::memset(_unused, 0,
sizeof(_unused));
151SGIImagePrivate::~SGIImagePrivate()
159void SGIImagePrivate::setDevice(
QIODevice *device)
165bool SGIImagePrivate::getRow(uchar *dest)
170 for (i = 0; i < _xsize; i++) {
171 if (_pos >= _data.
end()) {
174 dest[i] = uchar(*_pos);
180 for (i = 0; i < _xsize;) {
184 if (_pos >= _data.
end()) {
192 if (*_pos++ & 0x80) {
193 for (; i < _xsize && _pos < _data.
end() && n--; i++) {
198 for (; i < _xsize && n--; i++) {
208bool SGIImagePrivate::readData(
QImage &img)
211 quint32 *
start = _starttab;
213 uchar *line = (uchar *)lguard.data();
218 _pos = _data.
begin();
221 for (y = 0; y < _ysize; y++) {
228 c = (QRgb *)img.
scanLine(_ysize - y - 1);
229 for (x = 0; x < _xsize; x++, c++) {
230 *c = qRgb(line[x], line[x], line[x]);
239 for (y = 0; y < _ysize; y++) {
246 c = (QRgb *)img.
scanLine(_ysize - y - 1);
247 for (x = 0; x < _xsize; x++, c++) {
248 *c = qRgb(qRed(*c), line[x], line[x]);
252 for (y = 0; y < _ysize; y++) {
259 c = (QRgb *)img.
scanLine(_ysize - y - 1);
260 for (x = 0; x < _xsize; x++, c++) {
261 *c = qRgb(qRed(*c), qGreen(*c), line[x]);
270 for (y = 0; y < _ysize; y++) {
277 c = (QRgb *)img.
scanLine(_ysize - y - 1);
278 for (x = 0; x < _xsize; x++, c++) {
279 *c = qRgba(qRed(*c), qGreen(*c), qBlue(*c), line[x]);
286bool SGIImagePrivate::readImage(
QImage &img)
288 if (!readHeader() || !isSupported()) {
292 if (_stream.
atEnd()) {
296 img = imageAlloc(size(), format());
298 qWarning() <<
"Failed to allocate image, invalid dimensions?" <<
QSize(_xsize, _ysize);
306 if (_ysize > std::numeric_limits<int>::max() / _zsize) {
311 _numrows = _ysize * _zsize;
315 _starttab =
new quint32[_numrows];
316 for (l = 0; !_stream.
atEnd() && l < _numrows; l++) {
317 _stream >> _starttab[l];
318 _starttab[l] -= 512 + _numrows * 2 *
sizeof(quint32);
320 for (; l < _numrows; l++) {
324 _lengthtab =
new quint32[_numrows];
325 for (l = 0; !_stream.
atEnd() && l < _numrows; l++) {
326 _stream >> _lengthtab[l];
338 for (uint o = 0; o < _numrows; o++) {
340 if (_starttab[o] + _lengthtab[o] > (uint)_data.
size()) {
347 if (!readData(img)) {
359 for (
int i = 0; i <
size(); i++) {
364bool RLEData::operator<(
const RLEData &b)
const
368 for (
int i = 0; i < qMin(
size(), b.
size()); i++) {
378uint RLEMap::insert(
const uchar *d, uint l)
380 RLEData data = RLEData(d, l, _offset);
381 Iterator it =
find(data);
393 for (Iterator it =
begin(); it !=
end(); ++it) {
394 v.replace(it.value(), &it.key());
400uchar SGIImagePrivate::intensity(uchar c)
411uint SGIImagePrivate::compact(uchar *d, uchar *s)
417 uchar *
end = s + _xsize;
421 for (n = 0, t = src; t + 2 <
end && !(*t == t[1] && *t == t[2]); t++) {
426 i = n > 126 ? 126 : n;
439 for (n = 1; src <
end && *src == patt; src++) {
444 i = n > 126 ? 126 : n;
454bool SGIImagePrivate::scanData(
const QImage &img)
456 quint32 *
start = _starttab;
459 uchar *line = (uchar *)lineguard.data();
460 uchar *buf = (uchar *)bufguard.data();
466 for (y = 0; y < _ysize; y++) {
467 const int yPos = _ysize - y - 1;
468 if (yPos >= img.
height()) {
469 qWarning() <<
"Failed to get scanline for" << yPos;
473 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
475 for (x = 0; x < _xsize; x++) {
476 buf[x] = intensity(qRed(*c++));
478 len = compact(line, buf);
479 *
start++ = _rlemap.insert(line, len);
487 for (y = 0; y < _ysize; y++) {
488 const int yPos = _ysize - y - 1;
489 if (yPos >= img.
height()) {
490 qWarning() <<
"Failed to get scanline for" << yPos;
494 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
495 for (x = 0; x < _xsize; x++) {
496 buf[x] = intensity(qGreen(*c++));
498 len = compact(line, buf);
499 *
start++ = _rlemap.insert(line, len);
502 for (y = 0; y < _ysize; y++) {
503 const int yPos = _ysize - y - 1;
504 if (yPos >= img.
height()) {
505 qWarning() <<
"Failed to get scanline for" << yPos;
509 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
510 for (x = 0; x < _xsize; x++) {
511 buf[x] = intensity(qBlue(*c++));
513 len = compact(line, buf);
514 *
start++ = _rlemap.insert(line, len);
522 for (y = 0; y < _ysize; y++) {
523 const int yPos = _ysize - y - 1;
524 if (yPos >= img.
height()) {
525 qWarning() <<
"Failed to get scanline for" << yPos;
529 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
530 for (x = 0; x < _xsize; x++) {
531 buf[x] = intensity(qAlpha(*c++));
533 len = compact(line, buf);
534 *
start++ = _rlemap.insert(line, len);
540bool SGIImagePrivate::isValid()
const
543 if (_magic != 0x01da) {
551 if (_bpc != 1 && _bpc != 2) {
555 if (_dim < 1 || _dim > 3) {
565bool SGIImagePrivate::isSupported()
const
570 if (_colormap != NORMAL) {
579bool SGIImagePrivate::peekHeader(
QIODevice *device)
582 return SGIImagePrivate::readHeader(ds,
this) && isValid();
585QSize SGIImagePrivate::size()
const
587 return QSize(_xsize, _ysize);
592 if (_zsize == 2 || _zsize == 4) {
598bool SGIImagePrivate::readHeader()
600 return readHeader(_stream,
this);
603bool SGIImagePrivate::readHeader(
QDataStream &ds, SGIImagePrivate *sgi)
617 ds >> sgi->_xsize >> sgi->_ysize >> sgi->_zsize >> sgi->_pixmin >> sgi->_pixmax >> sgi->_unused32;
621 sgi->_imagename[79] =
'\0';
623 ds >> sgi->_colormap;
625 for (
size_t i = 0; i <
sizeof(_unused); i++) {
626 ds >> sgi->_unused[i];
632bool SGIImagePrivate::writeHeader()
635 _stream << _rle << _bpc << _dim;
636 _stream << _xsize << _ysize << _zsize;
637 _stream << _pixmin << _pixmax;
638 _stream << _unused32;
640 for (
int i = 0; i < 80; i++) {
641 _imagename[i] =
'\0';
645 _stream << _colormap;
646 for (
size_t i = 0; i <
sizeof(_unused); i++) {
647 _stream << _unused[i];
652bool SGIImagePrivate::writeRle()
656 if (!writeHeader()) {
663 for (i = 0; i < _numrows; i++) {
664 _stream << quint32(_rlevector[_starttab[i]]->offset());
668 for (i = 0; i < _numrows; i++) {
669 _stream << quint32(_rlevector[_starttab[i]]->size());
673 for (i = 0; (int)i < _rlevector.
size(); i++) {
674 const_cast<RLEData *
>(_rlevector[i])->write(_stream);
680bool SGIImagePrivate::writeVerbatim(
const QImage &img)
683 if (!writeHeader()) {
691 for (y = 0; y < _ysize; y++) {
692 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
693 for (x = 0; x < _xsize; x++) {
694 _stream << quint8(qRed(*c++));
703 for (y = 0; y < _ysize; y++) {
704 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
705 for (x = 0; x < _xsize; x++) {
706 _stream << quint8(qGreen(*c++));
710 for (y = 0; y < _ysize; y++) {
711 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
712 for (x = 0; x < _xsize; x++) {
713 _stream << quint8(qBlue(*c++));
722 for (y = 0; y < _ysize; y++) {
723 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
724 for (x = 0; x < _xsize; x++) {
725 _stream << quint8(qAlpha(*c++));
732bool SGIImagePrivate::writeImage(
const QImage &image)
737 _dim = 2, _zsize = 1;
739 _dim = 3, _zsize = 3;
757 const int w = img.
width();
758 const int h = img.
height();
760 if (w > 65535 || h > 65535) {
771 _numrows = _ysize * _zsize;
772 _starttab =
new quint32[_numrows];
773 _rlemap.setBaseOffset(512 + _numrows * 2 *
sizeof(quint32));
775 if (!scanData(img)) {
780 _rlevector = _rlemap.vector();
782 long verbatim_size = _numrows * _xsize;
783 long rle_size = _numrows * 2 *
sizeof(quint32);
784 for (
int i = 0; i < _rlevector.
size(); i++) {
785 rle_size += _rlevector[i]->
size();
788 if (verbatim_size <= rle_size) {
789 return writeVerbatim(img);
796RGBHandler::RGBHandler()
798 , d(new SGIImagePrivate)
802bool RGBHandler::canRead()
const
804 if (canRead(device())) {
811bool RGBHandler::read(
QImage *outImage)
814 return d->readImage(*outImage);
817bool RGBHandler::write(
const QImage &image)
819 d->setDevice(device());
820 return d->writeImage(image);
823bool RGBHandler::supportsOption(ImageOption option)
const
834QVariant RGBHandler::option(ImageOption option)
const
840 if (sgi->isSupported()) {
842 }
else if (
auto dev = device()) {
843 if (d->peekHeader(dev) && sgi->isSupported()) {
851 if (sgi->isSupported()) {
853 }
else if (
auto dev = device()) {
854 if (d->peekHeader(dev) && sgi->isSupported()) {
863bool RGBHandler::canRead(
QIODevice *device)
866 qWarning(
"RGBHandler::canRead() called with no device");
871 return sgi.peekHeader(device) && sgi.isSupported();
878 if (format ==
"rgb" || format ==
"rgba" || format ==
"bw" || format ==
"sgi") {
889 if (device->
isReadable() && RGBHandler::canRead(device)) {
906#include "moc_rgb_p.cpp"
Q_SCRIPTABLE Q_NOREPLY void start()
QFlags< Capability > Capabilities
const QList< QKeySequence > & end()
bool isEmpty() const const
qsizetype size() const const
int readRawData(char *s, int len)
void setDevice(QIODevice *d)
Status status() const const
int writeRawData(const char *s, int len)
bool allGray() const const
bool hasAlphaChannel() const const
bool isNull() const const
void setDevice(QIODevice *device)
bool isOpen() const const
bool isReadable() const const
bool isWritable() const const
QByteArray peek(qint64 maxSize)
void append(QList< T > &&value)
const_reference at(qsizetype i) const const
qsizetype size() const const
iterator find(const Key &key)
iterator insert(const Key &key, const T &value)
size_type size() const const
QVariant fromValue(T &&value)