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 =
reinterpret_cast<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 =
reinterpret_cast<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 =
reinterpret_cast<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 =
reinterpret_cast<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);
323 for (; l < _numrows; l++) {
327 _lengthtab =
new quint32[_numrows];
328 for (l = 0; !_stream.
atEnd() && l < _numrows; l++) {
329 _stream >> _lengthtab[l];
344 for (uint o = 0; o < _numrows; o++) {
346 if (_starttab[o] + _lengthtab[o] > (uint)_data.
size()) {
353 if (!readData(img)) {
365 for (
int i = 0; i <
size(); i++) {
370bool RLEData::operator<(
const RLEData &b)
const
374 for (
int i = 0; i < qMin(
size(), b.
size()); i++) {
384uint RLEMap::insert(
const uchar *d, uint l)
386 RLEData data = RLEData(d, l, _offset);
387 Iterator it =
find(data);
399 for (Iterator it =
begin(); it !=
end(); ++it) {
400 v.replace(it.value(), &it.key());
406uchar SGIImagePrivate::intensity(uchar c)
417uint SGIImagePrivate::compact(uchar *d, uchar *s)
423 uchar *
end = s + _xsize;
427 for (n = 0, t = src; t + 2 <
end && !(*t == t[1] && *t == t[2]); t++) {
432 i = n > 126 ? 126 : n;
445 for (n = 1; src <
end && *src == patt; src++) {
450 i = n > 126 ? 126 : n;
460bool SGIImagePrivate::scanData(
const QImage &img)
462 quint32 *
start = _starttab;
465 uchar *line = (uchar *)lineguard.data();
466 uchar *buf = (uchar *)bufguard.data();
472 for (y = 0; y < _ysize; y++) {
473 const int yPos = _ysize - y - 1;
474 if (yPos >= img.
height()) {
475 qWarning() <<
"Failed to get scanline for" << yPos;
479 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
481 for (x = 0; x < _xsize; x++) {
482 buf[x] = intensity(qRed(*c++));
484 len = compact(line, buf);
485 *
start++ = _rlemap.insert(line, len);
493 for (y = 0; y < _ysize; y++) {
494 const int yPos = _ysize - y - 1;
495 if (yPos >= img.
height()) {
496 qWarning() <<
"Failed to get scanline for" << yPos;
500 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
501 for (x = 0; x < _xsize; x++) {
502 buf[x] = intensity(qGreen(*c++));
504 len = compact(line, buf);
505 *
start++ = _rlemap.insert(line, len);
508 for (y = 0; y < _ysize; y++) {
509 const int yPos = _ysize - y - 1;
510 if (yPos >= img.
height()) {
511 qWarning() <<
"Failed to get scanline for" << yPos;
515 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
516 for (x = 0; x < _xsize; x++) {
517 buf[x] = intensity(qBlue(*c++));
519 len = compact(line, buf);
520 *
start++ = _rlemap.insert(line, len);
528 for (y = 0; y < _ysize; y++) {
529 const int yPos = _ysize - y - 1;
530 if (yPos >= img.
height()) {
531 qWarning() <<
"Failed to get scanline for" << yPos;
535 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(yPos));
536 for (x = 0; x < _xsize; x++) {
537 buf[x] = intensity(qAlpha(*c++));
539 len = compact(line, buf);
540 *
start++ = _rlemap.insert(line, len);
546bool SGIImagePrivate::isValid()
const
549 if (_magic != 0x01da) {
557 if (_bpc != 1 && _bpc != 2) {
561 if (_dim < 1 || _dim > 3) {
571bool SGIImagePrivate::isSupported()
const
576 if (_colormap != NORMAL) {
585bool SGIImagePrivate::peekHeader(
QIODevice *device)
588 return SGIImagePrivate::readHeader(ds,
this) && isValid();
591QSize SGIImagePrivate::size()
const
593 return QSize(_xsize, _ysize);
598 if (_zsize == 2 || _zsize == 4) {
604bool SGIImagePrivate::readHeader()
606 return readHeader(_stream,
this);
609bool SGIImagePrivate::readHeader(
QDataStream &ds, SGIImagePrivate *sgi)
623 ds >> sgi->_xsize >> sgi->_ysize >> sgi->_zsize >> sgi->_pixmin >> sgi->_pixmax >> sgi->_unused32;
627 sgi->_imagename[79] =
'\0';
629 ds >> sgi->_colormap;
631 for (
size_t i = 0; i <
sizeof(_unused); i++) {
632 ds >> sgi->_unused[i];
638bool SGIImagePrivate::writeHeader()
641 _stream << _rle << _bpc << _dim;
642 _stream << _xsize << _ysize << _zsize;
643 _stream << _pixmin << _pixmax;
644 _stream << _unused32;
646 for (
int i = 0; i < 80; i++) {
647 _imagename[i] =
'\0';
651 _stream << _colormap;
652 for (
size_t i = 0; i <
sizeof(_unused); i++) {
653 _stream << _unused[i];
658bool SGIImagePrivate::writeRle()
662 if (!writeHeader()) {
669 for (i = 0; i < _numrows; i++) {
670 _stream << quint32(_rlevector[_starttab[i]]->offset());
674 for (i = 0; i < _numrows; i++) {
675 _stream << quint32(_rlevector[_starttab[i]]->size());
679 for (i = 0; (int)i < _rlevector.
size(); i++) {
680 const_cast<RLEData *
>(_rlevector[i])->write(_stream);
686bool SGIImagePrivate::writeVerbatim(
const QImage &img)
689 if (!writeHeader()) {
697 for (y = 0; y < _ysize; y++) {
698 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
699 for (x = 0; x < _xsize; x++) {
700 _stream << quint8(qRed(*c++));
709 for (y = 0; y < _ysize; y++) {
710 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
711 for (x = 0; x < _xsize; x++) {
712 _stream << quint8(qGreen(*c++));
716 for (y = 0; y < _ysize; y++) {
717 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
718 for (x = 0; x < _xsize; x++) {
719 _stream << quint8(qBlue(*c++));
728 for (y = 0; y < _ysize; y++) {
729 c =
reinterpret_cast<const QRgb *
>(img.
scanLine(_ysize - y - 1));
730 for (x = 0; x < _xsize; x++) {
731 _stream << quint8(qAlpha(*c++));
738bool SGIImagePrivate::writeImage(
const QImage &image)
743 _dim = 2, _zsize = 1;
745 _dim = 3, _zsize = 3;
753#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0)
755 if (cs.isValid() && cs.colorModel() == QColorSpace::ColorModel::Cmyk && image.
format() == QImage::Format_CMYK8888) {
770 const int w = img.
width();
771 const int h = img.
height();
773 if (w > 65535 || h > 65535) {
784 _numrows = _ysize * _zsize;
785 _starttab =
new quint32[_numrows];
786 _rlemap.setBaseOffset(512 + _numrows * 2 *
sizeof(quint32));
788 if (!scanData(img)) {
793 _rlevector = _rlemap.vector();
795 long verbatim_size = _numrows * _xsize;
796 long rle_size = _numrows * 2 *
sizeof(quint32);
797 for (
int i = 0; i < _rlevector.
size(); i++) {
798 rle_size += _rlevector[i]->
size();
801 if (verbatim_size <= rle_size) {
802 return writeVerbatim(img);
809RGBHandler::RGBHandler()
811 , d(new SGIImagePrivate)
815bool RGBHandler::canRead()
const
817 if (canRead(device())) {
824bool RGBHandler::read(
QImage *outImage)
827 return d->readImage(*outImage);
830bool RGBHandler::write(
const QImage &image)
832 d->setDevice(device());
833 return d->writeImage(image);
836bool RGBHandler::supportsOption(ImageOption option)
const
847QVariant RGBHandler::option(ImageOption option)
const
853 if (sgi->isSupported()) {
855 }
else if (
auto dev = device()) {
856 if (d->peekHeader(dev) && sgi->isSupported()) {
864 if (sgi->isSupported()) {
866 }
else if (
auto dev = device()) {
867 if (d->peekHeader(dev) && sgi->isSupported()) {
876bool RGBHandler::canRead(
QIODevice *device)
879 qWarning(
"RGBHandler::canRead() called with no device");
884 return sgi.peekHeader(device) && sgi.isSupported();
891 if (format ==
"rgb" || format ==
"rgba" || format ==
"bw" || format ==
"sgi") {
902 if (device->
isReadable() && RGBHandler::canRead(device)) {
919#include "moc_rgb_p.cpp"
Q_SCRIPTABLE Q_NOREPLY void start()
QFlags< Capability > Capabilities
QAction * end(const QObject *recvr, const char *slot, QObject *parent)
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
QColorSpace colorSpace() const const
QImage convertedToColorSpace(const QColorSpace &colorSpace) 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)