qoi2-bikeshed icon indicating copy to clipboard operation
qoi2-bikeshed copied to clipboard

There are a lot of unreachable combinations of bits and ways to copy the previous color to the current pixel

Open rmn20 opened this issue 3 years ago • 6 comments

I believe QOI_RLE_8 is the best way to copy the previous pixel, but there are many other ways to do that.

QOI_INDEX always has the previous color, although we don't need it. Maybe we can put the colors in the table with a one chunk delay to fix this?

QOI_DIFF_8, QOI_DIFF_16 and QOI_DIFF_24 all have 000 diffs bit combinations. Maybe if 2 channels are equal to 0, we can expand the range of another one channel? For example, if channels g and b are 0, then we can change the range of channel r from [-8, 7] to [-8, 1]U[1, 8]. One of the problems is that we can't choose which channel we want to expand, so we need to choose a fixed one. I believe that channels r or g are more preferable to expand this way than channel b.

QOI_COLOR has a similar issue too, we can choose 0 channels to writte.

rmn20 avatar Nov 29 '21 18:11 rmn20

The expansion in QOI_DIFF_24 is a bit tricky, we can expand R if all the other channels are 0, but there are actually a more clever way to expand channels than just by checking if all the other channels are equal to zero.

For example, we have 544 RGB deltas in QOI_DIFF_16 and 5555 RGBA deltas in QOI_DIFF_24, and if A channel is 0 in QOI_DIFF_24, it doesn't make sense to store the G and B channels in the 4-bit range, since we could just use QOI_DIFF_16 for that. So this way we can extend one of the channels (R channel), but not only from [-16, 15] to [-16, 16]/{0}, if I'm right, we can extend it up to [-32, -17]U[16, 31]...

Oh god, I just get it, we can actually do the same trick in QOI_DIFF_16 if both channels R, G and B deltas are in 2-bit range... The expansion won't be so giant here, since we only have 2 bits, but we still can change the R channel range from [-16, 15] to [-18, -17]U[16, 17].

rmn20 avatar Nov 29 '21 18:11 rmn20

The downside of this idea is that it will be a non-negligable encoding and decoding slowdown. I think the easier approach is to use QOI_INDEX to store runs of length 2, and shift the range of QOI_RLE up by 1.

oscardssmith avatar Nov 29 '21 19:11 oscardssmith

Hmm, to be honest, I thought an 8 bit rle with stacking would be enough... I mean, when you compress 65536 pixels, it doesn't matter if they end up in 1 or 2 bytes, it's a strong compression anyway.. To be honest, I don't think many images have such large areas of repeating color anyway.

rmn20 avatar Nov 29 '21 20:11 rmn20

The place where it's a bigger change is if we increase the tag size of QOI_RLE (which might help fit other opcodes in). I think 4 bits for RLE is probably the sweet-spot, at which point the difference between 17 and 18 might be noticeable.

oscardssmith avatar Nov 29 '21 20:11 oscardssmith

sorry lol

rmn20 avatar Nov 30 '21 11:11 rmn20

Actually the same thing exists in 16-bit QOI_COLOR too, but I can't find the proper way to use it.. I mean, we never use QOI_COLOR with an R, G or B channel when the delta with the previous color can be encoded in QOI_DIFF_16, so 32 or 16 values are unused in 16-bit QOI_COLOR channel, or 1 bit is not used. I was thinking about adding an alpha channel here, but 1 bit is just a joke, it's really useless. (upd: I was wrong, there is no that 1 bit)

rmn20 avatar Nov 30 '21 17:11 rmn20