Enforce a limit of 400 million pixels, 2GB file size
This commit is contained in:
parent
11dbe1e6aa
commit
2f255c7aff
18
README.md
18
README.md
@ -7,8 +7,6 @@ the documentation.
|
|||||||
|
|
||||||
More info at https://phoboslab.org/log/2021/11/qoi-fast-lossless-image-compression
|
More info at https://phoboslab.org/log/2021/11/qoi-fast-lossless-image-compression
|
||||||
|
|
||||||
⚠️ Please note that this library is not yet ready to deal with untrusted input.
|
|
||||||
|
|
||||||
⚠️ 2021.11.30 – the file format is not yet finalized. We're still working to fix
|
⚠️ 2021.11.30 – the file format is not yet finalized. We're still working to fix
|
||||||
some smaller issues. The final specification will be announced on 2021.12.20.
|
some smaller issues. The final specification will be announced on 2021.12.20.
|
||||||
Thanks for your patience! The WIP file format specification can be found in
|
Thanks for your patience! The WIP file format specification can be found in
|
||||||
@ -30,6 +28,22 @@ converts between png <> qoi
|
|||||||
a simple wrapper to benchmark stbi, libpng and qoi
|
a simple wrapper to benchmark stbi, libpng and qoi
|
||||||
|
|
||||||
|
|
||||||
|
## Limitations
|
||||||
|
|
||||||
|
The QOI file format allows for huge images with up to 18 exa-pixels. A streaming
|
||||||
|
en-/decoder can handle these with minimal RAM requirements, assuming there is
|
||||||
|
enough storage space.
|
||||||
|
|
||||||
|
This particular implementation of QOI however is limited to images with a
|
||||||
|
maximum size of 400 million pixels. It will safely refuse to en-/decode anything
|
||||||
|
larger than that. This is not a streaming en-/decoder. It loads the whole image
|
||||||
|
file into RAM before doing any work and is not extensively optimized for
|
||||||
|
performance (but it's still very fast).
|
||||||
|
|
||||||
|
If this is a limitation for your use case, please look into any of the other
|
||||||
|
implementations listed below.
|
||||||
|
|
||||||
|
|
||||||
## Tools
|
## Tools
|
||||||
|
|
||||||
- https://github.com/floooh/qoiview
|
- https://github.com/floooh/qoiview
|
||||||
|
22
qoi.h
22
qoi.h
@ -168,8 +168,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
|
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
|
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.:
|
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)
|
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)
|
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,
|
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.
|
so "10 - 13" will result in 253, while "250 + 7" will result in 1.
|
||||||
@ -344,6 +344,12 @@ Implementation */
|
|||||||
#define QOI_HEADER_SIZE 14
|
#define QOI_HEADER_SIZE 14
|
||||||
#define QOI_PADDING 8
|
#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 {
|
typedef union {
|
||||||
struct { unsigned char r, g, b, a; } rgba;
|
struct { unsigned char r, g, b, a; } rgba;
|
||||||
unsigned int v;
|
unsigned int v;
|
||||||
@ -376,7 +382,8 @@ void *qoi_encode(const void *data, const qoi_desc *desc, int *out_len) {
|
|||||||
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 ||
|
||||||
desc->channels < 3 || desc->channels > 4 ||
|
desc->channels < 3 || desc->channels > 4 ||
|
||||||
desc->colorspace > 2
|
desc->colorspace > 2 ||
|
||||||
|
desc->height >= QOI_PIXELS_MAX / desc->width
|
||||||
) {
|
) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -502,7 +509,7 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||||||
unsigned char *pixels;
|
unsigned char *pixels;
|
||||||
qoi_rgba_t index[64];
|
qoi_rgba_t index[64];
|
||||||
qoi_rgba_t px;
|
qoi_rgba_t px;
|
||||||
int px_len, chunks_len, px_pos;
|
int px_len, chunks_len, px_pos;
|
||||||
int p = 0, run = 0;
|
int p = 0, run = 0;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -525,7 +532,8 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
|||||||
desc->width == 0 || desc->height == 0 ||
|
desc->width == 0 || desc->height == 0 ||
|
||||||
desc->channels < 3 || desc->channels > 4 ||
|
desc->channels < 3 || desc->channels > 4 ||
|
||||||
desc->colorspace > 2 ||
|
desc->colorspace > 2 ||
|
||||||
header_magic != QOI_MAGIC
|
header_magic != QOI_MAGIC ||
|
||||||
|
desc->height >= QOI_PIXELS_MAX / desc->width
|
||||||
) {
|
) {
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -636,6 +644,10 @@ void *qoi_read(const char *filename, qoi_desc *desc, int channels) {
|
|||||||
|
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
size = ftell(f);
|
size = ftell(f);
|
||||||
|
if (size <= 0) {
|
||||||
|
fclose(f);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
|
|
||||||
data = QOI_MALLOC(size);
|
data = QOI_MALLOC(size);
|
||||||
|
Loading…
Reference in New Issue
Block a user