make qoi.h build using c89 compilers.
also add a QOI_ZEROARR macro, wrapping around memset by default.
This commit is contained in:
parent
6a95206e35
commit
2aaba8da96
93
qoi.h
93
qoi.h
@ -77,6 +77,9 @@ QOI_NO_STDIO before including this library.
|
|||||||
This library uses malloc() and free(). To supply your own malloc implementation
|
This library uses malloc() and free(). To supply your own malloc implementation
|
||||||
you can define QOI_MALLOC and QOI_FREE before including this library.
|
you can define QOI_MALLOC and QOI_FREE before including this library.
|
||||||
|
|
||||||
|
This library uses memset() to zero arrayb. To supply your own implementation
|
||||||
|
you can define QOI_ZEROARR before including this library.
|
||||||
|
|
||||||
|
|
||||||
-- Data Format
|
-- Data Format
|
||||||
|
|
||||||
@ -315,11 +318,15 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels);
|
|||||||
|
|
||||||
#ifdef QOI_IMPLEMENTATION
|
#ifdef QOI_IMPLEMENTATION
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#ifndef QOI_MALLOC
|
#ifndef QOI_MALLOC
|
||||||
#define QOI_MALLOC(sz) malloc(sz)
|
#define QOI_MALLOC(sz) malloc(sz)
|
||||||
#define QOI_FREE(p) free(p)
|
#define QOI_FREE(p) free(p)
|
||||||
#endif
|
#endif
|
||||||
|
#ifndef QOI_ZEROARR
|
||||||
|
# define QOI_ZEROARR(_arr) memset((_arr),0,sizeof(_arr))
|
||||||
|
#endif
|
||||||
|
|
||||||
#define QOI_OP_INDEX 0x00 // 00xxxxxx
|
#define QOI_OP_INDEX 0x00 // 00xxxxxx
|
||||||
#define QOI_OP_DIFF 0x40 // 01xxxxxx
|
#define QOI_OP_DIFF 0x40 // 01xxxxxx
|
||||||
@ -358,6 +365,13 @@ unsigned int qoi_read_32(const unsigned char *bytes, int *p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
||||||
|
int i, max_size, p, run;
|
||||||
|
int px_len, px_end, px_pos, channels;
|
||||||
|
unsigned char *bytes;
|
||||||
|
const unsigned char *pixels;
|
||||||
|
qoi_rgba_t index[64];
|
||||||
|
qoi_rgba_t px, px_prev;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
data == NULL || out_len == NULL || desc == NULL ||
|
data == NULL || out_len == NULL || desc == NULL ||
|
||||||
desc->width == 0 || desc->height == 0 ||
|
desc->width == 0 || desc->height == 0 ||
|
||||||
@ -367,12 +381,12 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int max_size =
|
max_size =
|
||||||
desc->width * desc->height * (desc->channels + 1) +
|
desc->width * desc->height * (desc->channels + 1) +
|
||||||
QOI_HEADER_SIZE + QOI_PADDING;
|
QOI_HEADER_SIZE + QOI_PADDING;
|
||||||
|
|
||||||
int p = 0;
|
p = 0;
|
||||||
unsigned char *bytes = QOI_MALLOC(max_size);
|
bytes = (unsigned char *) QOI_MALLOC(max_size);
|
||||||
if (!bytes) {
|
if (!bytes) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -384,19 +398,22 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
bytes[p++] = desc->colorspace;
|
bytes[p++] = desc->colorspace;
|
||||||
|
|
||||||
|
|
||||||
const unsigned char *pixels = (const unsigned char *)data;
|
pixels = (const unsigned char *)data;
|
||||||
|
|
||||||
qoi_rgba_t index[64] = {0};
|
QOI_ZEROARR(index);
|
||||||
|
|
||||||
int run = 0;
|
run = 0;
|
||||||
qoi_rgba_t px_prev = {.rgba = {.r = 0, .g = 0, .b = 0, .a = 255}};
|
px_prev.rgba.r = 0;
|
||||||
qoi_rgba_t px = px_prev;
|
px_prev.rgba.g = 0;
|
||||||
|
px_prev.rgba.b = 0;
|
||||||
|
px_prev.rgba.a = 255;
|
||||||
|
px = px_prev;
|
||||||
|
|
||||||
int px_len = desc->width * desc->height * desc->channels;
|
px_len = desc->width * desc->height * desc->channels;
|
||||||
int px_end = px_len - desc->channels;
|
px_end = px_len - desc->channels;
|
||||||
int channels = desc->channels;
|
channels = desc->channels;
|
||||||
|
|
||||||
for (int px_pos = 0; px_pos < px_len; px_pos += channels) {
|
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
|
||||||
if (channels == 4) {
|
if (channels == 4) {
|
||||||
px = *(qoi_rgba_t *)(pixels + px_pos);
|
px = *(qoi_rgba_t *)(pixels + px_pos);
|
||||||
}
|
}
|
||||||
@ -414,12 +431,14 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
int index_pos;
|
||||||
|
|
||||||
if (run > 0) {
|
if (run > 0) {
|
||||||
bytes[p++] = QOI_OP_RUN | (run - 1);
|
bytes[p++] = QOI_OP_RUN | (run - 1);
|
||||||
run = 0;
|
run = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int index_pos = QOI_COLOR_HASH(px) % 64;
|
index_pos = QOI_COLOR_HASH(px) % 64;
|
||||||
|
|
||||||
if (index[index_pos].v == px.v) {
|
if (index[index_pos].v == px.v) {
|
||||||
bytes[p++] = QOI_OP_INDEX | index_pos;
|
bytes[p++] = QOI_OP_INDEX | index_pos;
|
||||||
@ -469,7 +488,7 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
px_prev = px;
|
px_prev = px;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < QOI_PADDING; i++) {
|
for (i = 0; i < QOI_PADDING; i++) {
|
||||||
bytes[p++] = 0;
|
bytes[p++] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -478,6 +497,14 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
||||||
|
const unsigned char *bytes;
|
||||||
|
unsigned int header_magic;
|
||||||
|
unsigned char *pixels;
|
||||||
|
qoi_rgba_t index[64];
|
||||||
|
qoi_rgba_t px;
|
||||||
|
int px_len, chunks_len, px_pos;
|
||||||
|
int p = 0, run = 0;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
data == NULL || desc == NULL ||
|
data == NULL || desc == NULL ||
|
||||||
(channels != 0 && channels != 3 && channels != 4) ||
|
(channels != 0 && channels != 3 && channels != 4) ||
|
||||||
@ -486,10 +513,9 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char *bytes = (const unsigned char *)data;
|
bytes = (const unsigned char *)data;
|
||||||
int p = 0;
|
|
||||||
|
|
||||||
unsigned int header_magic = qoi_read_32(bytes, &p);
|
header_magic = qoi_read_32(bytes, &p);
|
||||||
desc->width = qoi_read_32(bytes, &p);
|
desc->width = qoi_read_32(bytes, &p);
|
||||||
desc->height = qoi_read_32(bytes, &p);
|
desc->height = qoi_read_32(bytes, &p);
|
||||||
desc->channels = bytes[p++];
|
desc->channels = bytes[p++];
|
||||||
@ -508,18 +534,20 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||||||
channels = desc->channels;
|
channels = desc->channels;
|
||||||
}
|
}
|
||||||
|
|
||||||
int px_len = desc->width * desc->height * channels;
|
px_len = desc->width * desc->height * channels;
|
||||||
unsigned char *pixels = QOI_MALLOC(px_len);
|
pixels = (unsigned char *) QOI_MALLOC(px_len);
|
||||||
if (!pixels) {
|
if (!pixels) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
qoi_rgba_t px = {.rgba = {.r = 0, .g = 0, .b = 0, .a = 255}};
|
QOI_ZEROARR(index);
|
||||||
qoi_rgba_t index[64] = {0};
|
px.rgba.r = 0;
|
||||||
|
px.rgba.g = 0;
|
||||||
|
px.rgba.b = 0;
|
||||||
|
px.rgba.a = 255;
|
||||||
|
|
||||||
int run = 0;
|
chunks_len = size - QOI_PADDING;
|
||||||
int chunks_len = size - QOI_PADDING;
|
for (px_pos = 0; px_pos < px_len; px_pos += channels) {
|
||||||
for (int px_pos = 0; px_pos < px_len; px_pos += channels) {
|
|
||||||
if (run > 0) {
|
if (run > 0) {
|
||||||
run--;
|
run--;
|
||||||
}
|
}
|
||||||
@ -577,12 +605,14 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||||||
|
|
||||||
int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
|
int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
|
||||||
FILE *f = fopen(filename, "wb");
|
FILE *f = fopen(filename, "wb");
|
||||||
|
int size;
|
||||||
|
void *encoded;
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int size;
|
encoded = qoi_encode(data, desc, &size);
|
||||||
void *encoded = qoi_encode(data, desc, &size);
|
|
||||||
if (!encoded) {
|
if (!encoded) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return 0;
|
return 0;
|
||||||
@ -597,24 +627,27 @@ int qoi_write(const char *filename, const void *data, const qoi_desc *desc) {
|
|||||||
|
|
||||||
void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
|
void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
|
int size, bytes_read;
|
||||||
|
void *pixels, *data;
|
||||||
|
|
||||||
if (!f) {
|
if (!f) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
int size = ftell(f);
|
size = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
void *data = QOI_MALLOC(size);
|
data = QOI_MALLOC(size);
|
||||||
if (!data) {
|
if (!data) {
|
||||||
fclose(f);
|
fclose(f);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int bytes_read = fread(data, 1, size, f);
|
bytes_read = fread(data, 1, size, f);
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
void *pixels = qoi_decode(data, bytes_read, desc, channels);
|
pixels = qoi_decode(data, bytes_read, desc, channels);
|
||||||
QOI_FREE(data);
|
QOI_FREE(data);
|
||||||
return pixels;
|
return pixels;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user