summaryrefslogtreecommitdiff
path: root/saltoqd/msolimageiohandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'saltoqd/msolimageiohandler.cpp')
-rw-r--r--saltoqd/msolimageiohandler.cpp162
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)
+{
+
+}