Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

The QOI File Format Specification #37

Closed
phoboslab opened this issue Nov 27, 2021 · 12 comments
Closed

The QOI File Format Specification #37

phoboslab opened this issue Nov 27, 2021 · 12 comments

Comments

@phoboslab
Copy link
Owner

phoboslab commented Nov 27, 2021

After a discussion in #28, the QOI data format changes to accommodate some of the concerns. This will serve as the basis for final specification for QOI.

These changes are not yet reflected in the code of this repository. I'm working on it! The code in qoi.h now implements all these changes.

Changes from the original implementation

  • all values are encoded in big-endian byte order (already happened in c03edb2)
  • the range of QOI_DIFF will shift -1, to be consistent with the range of a two's complement int
  • QOI_DIFF will explicitly allow to wrap around. Whether the encoder makes use of this is outside of the spec. The decoder must account for this wrapping.
  • the size field in the header will be removed
  • width and height in the header will be widened to 32bit
  • a channels field will be added to the header. This is purely informative and will not change the behavior of the en-/decoder
  • a colorspace bitmap will be added to the header. This is purely informative and will not change the behavior of the en-/decoder.
  • the spec will mandate that the alpha channel is un-premultiplied

The header then looks like this:

struct qoi_header_t {
    char [4];       // magic bytes "qoif"
    u32 width;      // image width in pixels (BE)
    u32 height;     // image height in pixels (BE)
     u8 channels;   // must be 3 (RGB) or 4 (RGBA)
     u8 colorspace; // a bitmap 0000rgba where 
                    //   - a zero bit indicates sRGBA, 
                    //   - a one bit indicates linear (user interpreted)
                    //   colorspace for each channel
};

The ranges for QOI_DIFF change to:

  • 2bit: -2..1 instead of the original range -1..2
  • 4bit: -8..7 instead of the original range -7..8
  • 5bit: -16..15 instead of the original range -15..16

The channels field in the header serves only as a hint to the user on how to handle this image. It is valid for a QOI image to still encode alpha changes in a file with a header that denotes 3 channels. It is not the responsibility of the decoder to mask off alpha values. The color hash will always be computed as r^g^b^a, irregardless of the number of channels denoted in the header.

@phoboslab phoboslab pinned this issue Nov 27, 2021
@ThomasMertes
Copy link

I think that omitting the size field is a bad idea. I wrote about this here:

I have seen several file formats without size and it always looked like a bad idea.

The Entropy Coded Segment of JPEG is such an example. All other JPEG segments have a length. The ECS (Entropy Coded Segment) does not. The ECS segment ends if a 0xff byte is not followed by 0 byte. In decoding the byte sequence 0xff 0 needs to be converted to 0xff. Every other JPEG segment can be skipped easily, because it has a length. An ECS must be processed byte by byte to find its end. This is absolutely crazy.

If the size is missing you need to process everything to get to the end of the data. The size opens the opportunity to have other information afterwards. E.g.: Another header with another image. Or meta information. With a size field you can just jump to the information after the image without processing it. The size can also be used as redundant information (afterwards the file must end). I now think that the "channels" field is not needed, but a "size" field definitive makes sense.

@aldanor
Copy link
Contributor

aldanor commented Nov 27, 2021

QOI_DIFF will explicitly allow to wrap around. Whether the encoder makes use of this is outside of the spec. The decoder must account for this wrapping.

Does it match what's suggested in #28 (comment)?

@jmi2k
Copy link

jmi2k commented Nov 27, 2021

At the risk of being repetitive, I want to point to my issue again (#29). In particular, I prefer that the compression scheme remains independent from the data inside the header. It looks like that's the way QOI is taking (making colorspace and channels purely informative and allowing the encoder to encode alpha regardless of its presence in the channel attribute), but I think being explicit about it is a good idea. Right now I'm making an FPGA implementation of QOI compression scheme, ignoring the header, and I think calling the format QOI could be misleading (as people would look for the header, which doesn't exist anywhere).

Just my 2 cents, opinions welcome!

@Ansraer
Copy link

Ansraer commented Nov 27, 2021

I noticed that this file format doesnt support custom user data. Could we add a u16 user_data_length to the header, that can be used to reserve x bytes directly after the header for custom data. This way people could encode whatever custom data they want in the file, and the en- and decoder could just skip it.

@phoboslab
Copy link
Owner Author

phoboslab commented Nov 27, 2021

With the last few commits, the code in qoi.h is now in line with this specification.

I will work on improving the documentation and fix any remaining bugs in the en-/decoder, but

The data format is now fixed!

I will not merge any pull requests that will change the data format. QOIs initial goal was to be simple and I want it to stay this way.

Edit: some things should still be looked into: #48

There's still a lot of interesting discussion about how to change the en-/decoding scheme to improve performance or compression ratio or to add more features. You are free to present and discuss your ideas here, but ultimately they will need to find a new home... in a Quite Good Image Format, maybe? :)

@oscardssmith
Copy link

do you want to host qgif or should someone else?

@phoboslab
Copy link
Owner Author

Someone else should lead that effort. I don't think "management" is my strong suit.

@awakecoding
Copy link

If someone wants to take the lead and create a repository meant to define a more elaborate and flexible header format for QOI, please tag me so I can comment on it. I'm watching the development of QOI with interest, and in the past I have worked a lot on GFWX.

There are a lot of things from GFWX that could be applied to QOI. I have also had to define my own replacement header format for GFWX because the original one wasn't good enough, so I can bring ideas on the design of a clean QOI header format.

@nigeltao
Copy link

The data format is now fixed!

Let's move the bikeshedding to:
https://github.com/nigeltao/qoi2-bikeshed/issues

Note that GitHub is having some server issues right now.

@SeaBee63
Copy link

Very interesting, but using C bit fields for storage makes the file format potentially unportable on some platforms (bit and byte order may vary, compiler implementation defined according to the standard). The most portable way for file storage is to manage byte-by-byte using bit masks and shifts (then, no dependency on little/big endian and bits order, only possible problem: CHAR_BIT != 8 (very specific, assume file transfer manage the missing bit).

@JD557
Copy link

JD557 commented Nov 28, 2021

Now that the format is fixed, WDYT about adding some example images in this repo (maybe in an examples folder)?

@phoboslab
Copy link
Owner Author

phoboslab commented Nov 28, 2021

some example images

Edit: please discuss here: #20

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

10 participants