Skip to content

Commit

Permalink
update qoi.h to latest from https://github.com/phoboslab/qoi.git
Browse files Browse the repository at this point in the history
  • Loading branch information
sezero committed Dec 17, 2021
1 parent 6fbce9f commit cc362ae
Showing 1 changed file with 31 additions and 15 deletions.
46 changes: 31 additions & 15 deletions qoi.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,8 @@ implementation you can define QOI_ZEROARR before including this library.
-- Data Format
A QOI file has a 14 byte header, followed by any number of data "chunks" and 8
zero-bytes to mark the end of the data stream.
A QOI file has a 14 byte header, followed by any number of data "chunks" and an
8-byte end marker.
struct qoi_header_t {
char magic[4]; // magic bytes "qoif"
Expand Down Expand Up @@ -120,7 +120,7 @@ values encoded in these data bits have the most significant bit on the left.
The 8-bit tags have precedence over the 2-bit tags. A decoder must check for the
presence of an 8-bit tag first.
The byte stream is padded with 8 zero-bytes at the end.
The byte stream's end is marked with 7 0x00 bytes followed a single 0x01 byte.
The possible chunks are:
Expand All @@ -135,6 +135,9 @@ The possible chunks are:
2-bit tag b00
6-bit index into the color index array: 0..63
A valid encoder must not issue 7 or more consecutive QOI_OP_INDEX chunks to the
index 0, to avoid confusion with the 8 byte end marker.
.- QOI_OP_DIFF -----------.
| Byte[0] |
Expand Down Expand Up @@ -168,8 +171,8 @@ Values are stored as unsigned integers with a bias of 2. E.g. -2 is stored as
The green channel is used to indicate the general direction of change and is
encoded in 6 bits. The red and green channels (dr and db) base their diffs off
of the green channel difference and are encoded in 4 bits. I.e.:
dr_dg = (last_px.r - cur_px.r) - (last_px.g - cur_px.g)
db_dg = (last_px.b - cur_px.b) - (last_px.g - cur_px.g)
dr_dg = (last_px.r - cur_px.r) - (last_px.g - cur_px.g)
db_dg = (last_px.b - cur_px.b) - (last_px.g - cur_px.g)
The difference to the current channel values are using a wraparound operation,
so "10 - 13" will result in 253, while "250 + 7" will result in 1.
Expand Down Expand Up @@ -342,13 +345,20 @@ Implementation */
(((unsigned int)'q') << 24 | ((unsigned int)'o') << 16 | \
((unsigned int)'i') << 8 | ((unsigned int)'f'))
#define QOI_HEADER_SIZE 14
#define QOI_PADDING 8

/* 2GB is the max file size that this implementation can safely handle. We guard
against anything larger than that, assuming the worst case with 5 bytes per
pixel, rounded down to a nice clean value. 400 million pixels ought to be
enough for anybody. */
#define QOI_PIXELS_MAX ((unsigned int)400000000)

typedef union {
struct { unsigned char r, g, b, a; } rgba;
unsigned int v;
} qoi_rgba_t;

static const unsigned char qoi_padding[8] = {0,0,0,0,0,0,0,1};

void qoi_write_32(unsigned char *bytes, int *p, unsigned int v) {
bytes[(*p)++] = (0xff000000 & v) >> 24;
bytes[(*p)++] = (0x00ff0000 & v) >> 16;
Expand Down Expand Up @@ -376,14 +386,15 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
data == NULL || out_len == NULL || desc == NULL ||
desc->width == 0 || desc->height == 0 ||
desc->channels < 3 || desc->channels > 4 ||
desc->colorspace > 2
desc->colorspace > 1 ||
desc->height >= QOI_PIXELS_MAX / desc->width
) {
return NULL;
}

max_size =
desc->width * desc->height * (desc->channels + 1) +
QOI_HEADER_SIZE + QOI_PADDING;
QOI_HEADER_SIZE + sizeof(qoi_padding);

p = 0;
bytes = (unsigned char *) QOI_MALLOC(max_size);
Expand Down Expand Up @@ -488,8 +499,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
px_prev = px;
}

for (i = 0; i < QOI_PADDING; i++) {
bytes[p++] = 0;
for (i = 0; i < (int)sizeof(qoi_padding); i++) {
bytes[p++] = qoi_padding[i];
}

*out_len = p;
Expand All @@ -502,13 +513,13 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
unsigned char *pixels;
qoi_rgba_t index[64];
qoi_rgba_t px;
int px_len, chunks_len, px_pos;
int px_len, chunks_len, px_pos;
int p = 0, run = 0;

if (
data == NULL || desc == NULL ||
(channels != 0 && channels != 3 && channels != 4) ||
size < QOI_HEADER_SIZE + QOI_PADDING
size < QOI_HEADER_SIZE + (int)sizeof(qoi_padding)
) {
return NULL;
}
Expand All @@ -524,8 +535,9 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
if (
desc->width == 0 || desc->height == 0 ||
desc->channels < 3 || desc->channels > 4 ||
desc->colorspace > 2 ||
header_magic != QOI_MAGIC
desc->colorspace > 1 ||
header_magic != QOI_MAGIC ||
desc->height >= QOI_PIXELS_MAX / desc->width
) {
return NULL;
}
Expand All @@ -546,7 +558,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
px.rgba.b = 0;
px.rgba.a = 255;

chunks_len = size - QOI_PADDING;
chunks_len = size - (int)sizeof(qoi_padding);
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
if (run > 0) {
run--;
Expand Down Expand Up @@ -636,6 +648,10 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {

fseek(f, 0, SEEK_END);
size = ftell(f);
if (size <= 0) {
fclose(f);
return NULL;
}
fseek(f, 0, SEEK_SET);

data = QOI_MALLOC(size);
Expand Down

0 comments on commit cc362ae

Please sign in to comment.