diff options
Diffstat (limited to 'saltoqd/msolimageiohandler.cpp')
-rw-r--r-- | saltoqd/msolimageiohandler.cpp | 162 |
1 files changed, 162 insertions, 0 deletions
diff --git a/saltoqd/msolimageiohandler.cpp b/saltoqd/msolimageiohandler.cpp new file mode 100644 index 0000000..bd0b23c --- /dev/null +++ b/saltoqd/msolimageiohandler.cpp @@ -0,0 +1,162 @@ +#include <QtCore/QtEndian> +#include <QtCore/QVariant> +#include <QtCore/QDebug> +#include <QtGui/QImage> + +#include "msolimageiohandler.h" + +static const int header_size = 16; + +namespace +{ + +static inline uchar encode_color(QRgb c) +{ + return (qRed(c) & 0xC0) | ((qBlue(c) & 0xC0) >> 2) | ((qGreen(c) & 0xC0) >> 4) | 3; +} + +static inline QRgb decode_color(uchar p, uchar a = 255) +{ + return qRgba(p & 0xC0, (p & 0x30) << 2, (p & 0x0C) << 4, a); +} + +} + +MSOLImageIOHandler::MSOLImageIOHandler() : QImageIOHandler() +{ +} + +bool MSOLImageIOHandler::canRead() const +{ + char header[header_size]; + if (device()->peek(header, header_size) != header_size) { + return false; + } + + return strncmp(&header[0], "MSOL ", 6) == 0; +} + +bool MSOLImageIOHandler::read(QImage *image) +{ + QIODevice *dev = device(); + + uchar header[header_size]; + if (dev->read(reinterpret_cast<char*>(header), header_size) != header_size) { + return false; + } + + if (strncmp(reinterpret_cast<char*>(&header[0]), "MSOL ", 6) != 0) { + return false; + } + + const bool alpha = header[6]; + const int width = qFromLittleEndian<quint16>(&header[8]); + const int height = qFromLittleEndian<quint16>(&header[10]); + const int pixel_size = alpha ? 2 : 1; + const int line_size = width * pixel_size; + + if (alpha) { + *image = QImage(width, height, QImage::Format_ARGB32); + } else { + *image = QImage(width, height, QImage::Format_RGB32); + } + + Q_ASSERT(image->depth() == sizeof(QRgb) * 8); + + for (int y = 0; y < height; y++) { + QRgb *dst = reinterpret_cast<QRgb*>(image->scanLine(y)); + uchar src[line_size]; + if (dev->read(reinterpret_cast<char*>(src), line_size) != line_size) { + qDebug() << "Could not read image line" << y; + return false; + } + for (int x = 0; x < width; x++) { + if (alpha) { + dst[x] = decode_color(src[x * pixel_size]); + } else { + dst[x] = decode_color(src[x * pixel_size], src[(x * pixel_size) + 1]); + } + } + } + + return true; +} + +bool MSOLImageIOHandler::write(const QImage &image) +{ + QIODevice *dev = device(); + const int height = image.height(); + const int width = image.width(); + const bool alpha = image.hasAlphaChannel(); + const int pixel_size = alpha ? 2 : 1; + const int line_size = width * pixel_size; + + QImage img = image.convertToFormat(alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32); + + uchar header[header_size] = { 0 }; + strcpy(reinterpret_cast<char*>(&header[0]), "MSOL "); + if (alpha) header[6] = 0x80; + header[7] = 8; + + qToLittleEndian<quint16>(width, &header[8]); + qToLittleEndian<quint16>(height, &header[10]); + + if (dev->write(reinterpret_cast<char*>(header), header_size) != header_size) { + qDebug() << "Could not write header"; + return false; + } + + Q_ASSERT(img.depth() == sizeof(QRgb) * 8); + + for (int y = 0; y < height; y++) { + uchar dst[line_size]; + const QRgb *src = reinterpret_cast<const QRgb*>(img.constScanLine(y)); + for (int x = 0; x < width; x++) { + dst[x * pixel_size] = encode_color(src[x]); + if (alpha) { + dst[(x * pixel_size) + 1] = qAlpha(src[x]); + } + } + if (dev->write(reinterpret_cast<char*>(dst), line_size) != line_size) { + qDebug() << "Could not write image line " << y; + return false; + } + } + + return true; +} + +bool MSOLImageIOHandler::supportsOption(ImageOption option) const +{ + switch (option) { + case Size: + return true; + default: + return false; + } +} + +QVariant MSOLImageIOHandler::option(ImageOption option) const +{ + char header[header_size]; + + switch (option) { + case Size: + if (device()->peek(header, header_size) == header_size) { + const QSize size(qFromLittleEndian<quint16>(reinterpret_cast<uchar*>(&header[8])), + qFromLittleEndian<quint16>(reinterpret_cast<uchar*>(&header[10]))); + return QVariant::fromValue(size); + } else { + qDebug() << "Cannot read from device: " << device()->errorString(); + } + default: + break; + } + + return QVariant(); +} + +void MSOLImageIOHandler::setOption(ImageOption option, const QVariant &value) +{ + +} |