summaryrefslogtreecommitdiff
path: root/saltoqd/msolimageiohandler.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'saltoqd/msolimageiohandler.cpp')
-rw-r--r--saltoqd/msolimageiohandler.cpp59
1 files changed, 58 insertions, 1 deletions
diff --git a/saltoqd/msolimageiohandler.cpp b/saltoqd/msolimageiohandler.cpp
index e6a9065..5a18ff6 100644
--- a/saltoqd/msolimageiohandler.cpp
+++ b/saltoqd/msolimageiohandler.cpp
@@ -21,6 +21,17 @@ static inline QRgb decode_color(uchar p, uchar a = 255)
return qRgba(p & 0xC0, (p & 0x30) << 2, (p & 0x0C) << 4, a);
}
+static inline uchar add_saturate(uchar val, int addend)
+{
+ int sum = val + addend;
+ return qMax(0, qMin(sum, 255));
+}
+
+static inline void add_saturate(uchar* val, int addend)
+{
+ *val = add_saturate(*val, addend);
+}
+
}
MSOLImageIOHandler::MSOLImageIOHandler() : QImageIOHandler()
@@ -93,6 +104,7 @@ bool MSOLImageIOHandler::write(const QImage &image)
const int line_size = width * pixel_size;
QImage img = image.convertToFormat(alpha ? QImage::Format_ARGB32 : QImage::Format_RGB32);
+ img = ditherForMsol(img);
uchar header[header_size] = { 0 };
strcpy(reinterpret_cast<char*>(&header[0]), "MSOL ");
@@ -159,7 +171,8 @@ QVariant MSOLImageIOHandler::option(ImageOption option) const
void MSOLImageIOHandler::setOption(ImageOption option, const QVariant &value)
{
-
+ Q_UNUSED(option);
+ Q_UNUSED(value);
}
QByteArray convertImageToMsol(const QImage &img)
@@ -186,3 +199,47 @@ QImage convertMsolToImage(const QByteArray &msol)
}
return img;
}
+
+QImage ditherForMsol(const QImage &src)
+{
+ Q_ASSERT(src.format() == QImage::Format_ARGB32 || src.format() == QImage::Format_RGB32);
+ const int width = src.width(), height = src.height();
+ const int bytesPerLine = src.bytesPerLine();
+
+ QImage dst(src);
+
+ // If we are on Big endian, then we must skip the first channel (=alpha).
+ // In LE, use the first three channels and skip the final one (=alpha).
+ const bool bigEndian = QSysInfo::ByteOrder == QSysInfo::BigEndian;
+ uchar *line = dst.bits() + (bigEndian ? 1 : 0);
+ for (int y = 0; y < height; y++) {
+ for (int x = 0; x < width; x++) {
+ for (int chan = 0; chan < 3; chan++) {
+ const uchar val = line[x * 4 + chan];
+ const uchar quant = add_saturate(val, 0x20) & 0xC0;
+ const int error = val - quant;
+
+ line[x * 4 + chan] = quant;
+
+ if (x + 1 < width)
+ add_saturate(&line[(x + 1) * 4 + chan], (error * 7) / 16);
+
+ if (y + 1 < height) {
+ uchar *nextLine = line + bytesPerLine;
+
+ if (x > 0)
+ add_saturate(&nextLine[(x - 1) * 4 + chan], (error * 3) / 16);
+
+ add_saturate(&nextLine[x * 4 + chan], (error * 5) / 16);
+
+ if (x + 1 < width)
+ add_saturate(&nextLine[(x + 1) * 4 + chan], (error * 1) / 16);
+ }
+ }
+ }
+
+ line += bytesPerLine;
+ }
+
+ return dst;
+}