-
Couldn't load subscription status.
- Fork 353
Description
Saying that I'm surprised by the amount of attention this is getting would be an understatement. There's lots of discussion going on about how the data format and compression could be improved and what features could be added.
I want to give my views here and discuss how to go forward.
First and foremost, I want QOI to be simple. Please keep this in mind. I consider the general compression scheme to be done. There's lots of interesting ideas on how to improve compression. I want to tinker with these ideas - but not for QOI.
QOI will not be versioned. There will only be one version of QOI's data format. I'm hoping we will be able to strictly define what exactly that is in the coming days.
QOI will only support 24bit RGB and 32bit RGBA data. I acknowledge there's some need for fewer or more channels and also for higher bit depths or paletted color - QOI will not serve these needs.
So, with all that said, there's some breaking changes that are probably worthwhile. I want to discuss if and how to implement those.
Proposed changes
-
width,heightandsizein the header should be stored as big endian for consistency with the rest of the format (this change already happened in c03edb2) -
Color differences (
QOI_DIFF_*) shouldbe storedhave the same range as two's-complement. That means:
- 2bit:
-2..1instead of the current range-1..2 - 4bit:
-8..7instead of the current range-7..8 - 5bit:
-16..15instead of the current range-15..16
- The header should accommodate some more info. Currently there's demand for
3a) number of channels ( The number of channels should be encoded in the QOI header #16)
3b) the colorspace (Consider adding a sRGB flag to the header #25 and this huge discussion on HN)
3c) un-/premultiplied alpha (Clarify that RGBA means non-premultiplied alpha #13)
3d) user-defined values
So, 1) is already implemented; 2) seems like the right thing to do (any objections?); 3) is imho worth discussing.
3a) Storing the number of channels (3 or 4) in the header would allow a user of this library to omit if they want RGB or RGBA and files would be more descriptive of their contents. You would still be able to enforce 3 or 4 channels when loading. This is consistent to what stbi_load does
int x,y,n;
unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
// ... process data if not NULL ...
// ... x = width, y = height, n = # 8-bit components per pixel ...
// ... replace '0' with '1'..'4' to force that many components per pixel
// ... but 'n' will always be the number that it would have been if you said 0It is my opinion that the channels header value should be purely informative. Meaning, en-/decoder will do exactly the same, regardless of the number of channels. The extra 5bit for alpha in QOI_DIFF_24 will still be wasted for RGB files.
3b) I don't understand enough about the colorspace issue to gauge the significance. If we implement this however, I would suggest to give this a full byte in the header, where 0 = sRGB and any non-zero value is another, user-defined(?) colorspace.
3c) I'm against an option for premultiplied alpha, because it puts more burden on any QOI implementation to decode in the right pixel format. We should just specify that QOI images have un-premultiplied alpha.
3d) For simplicity's sake I'd like to put 3a) and 3b) as one byte each into the header. I'm uncertain if we then should "pad" the u32 size in the header with two more bytes. This would make the size 4byte aligned again, but there's probably no need for it!? A u16 unused could also cause more confusion when other QOI libraries suddenly specify any of these bits to mean something.
With all this, the header would then be the following 16 bytes:
struct qoi_header_t {
char [4]; // magic bytes "qoif"
u16 width; // image width in pixels (BE)
u16 height; // image height in pixels (BE)
u8 channels; // must be 3 (RGB) or 4 (RGBA)
u8 colorspace; // 0 = sRGB (other values currently undefined)
u16 unused; // free for own use
u32 size; // number of data bytes following this header (BE)
};The one issue I have with this, is how to give these extra header value to the user of this library. qoi_read("file.qoi", &w, &h, &channels_in_file, &colorspace, want_channels) looks like an ugly API. So maybe that would rather be implemented as qoi_read_ex() and qoi_read() stays as it is. I'm still not sure if I want that extended header...
What's the opinion of the other library authors?