afrantzis / pixel-format-guide

Pixel Format Guide
https://afrantzis.github.io/pixel-format-guide
GNU Lesser General Public License v2.1
68 stars 10 forks source link

QImage::Format_ARGB8555_Premultiplied #7

Open fdwr opened 2 years ago

fdwr commented 2 years ago

From https://afrantzis.com/pixel-format-guide/qt.html:

"The pixel is represented by a 24-bit value, with the most significant bit unused, A in bits 15-22, R in bits 10-14, G in bits 5-9 and B in bits 0-4..."

Looking into Qt source code, it appears the alpha byte actually comes first aligned to a whole byte, and the unused bit is just beyond red (yeah, this format is rather inconsistent with Qt's other names 😑).

Bit stream layout

byte |[      0      ] [      1      ] [      2      ]|
bit  |0 1 2 3 4 5 6 7|0 1 2 3 4|5 6 7 0 1|2 3 4 5 6|7|
     |[   alpha     ]|[ blue  ]|[ green ]|[  red  ]|0|

Motivation

I'm working on a generic pixel format viewer, supporting formats declaratively rather than hard-coded code (and so your project has been quite useful ☺ - thanks). e.g.

Qt_QImage_Format_ARGB8555_Premultiplied:{
    alphaPremulUnorm8
    blueUnorm5
    greenUnorm5
    redUnorm5
    unused1
    notes:{
        "The image is stored using a premultiplied 24-bit ARGB format (8,5,5,5,_)."
        "The documentation and actual code mismatch, as the alpha byte actually comes first, despite what the format name would imply."
    }
}

References

https://github.com/openwebos/qt/blob/master/src/gui/painting/qdrawhelper_p.h#L1121

{
    v = quint32p(v);
    data[0] = qAlpha(v);
    const int r = qRed(v);
    const int g = qGreen(v);
    const int b = qBlue(v);
    data[1] = ((g << 2) & 0xe0) | (b >> 3);
    data[2] = ((r >> 1) & 0x7c) | (g >> 6);
}

https://github.com/openwebos/qt/blob/master/src/gui/image/qimage.cpp#L5018

        for (int i = 0; i < d->height; i++) {
            const quint8 *p = constScanLine(i);
            quint8 *q = res.scanLine(i);
            const quint8 *end = p + d->width * sizeof(qargb8555);
            while (p < end) {
                q[0] = p[0];
                q[1] = (p[1] & 0xe0) | (p[2] >> 2);
                q[2] = (p[2] & 0x03) | ((p[1] << 2) & 0x7f);
                p += sizeof(qargb8555);
                q += sizeof(qargb8555);
            }
        }

This applies to qargb8565 too:

https://github.com/openwebos/qt/blob/master/src/gui/painting/qdrawhelper_p.h#L822

Want me to create a PR?