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
|
||||
|
||||
⚠️ 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
|
||||
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
|
||||
@ -30,6 +28,22 @@ converts between png <> 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
|
||||
|
||||
- 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
|
||||
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.
|
||||
@ -344,6 +344,12 @@ Implementation */
|
||||
#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;
|
||||
@ -376,7 +382,8 @@ 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 > 2 ||
|
||||
desc->height >= QOI_PIXELS_MAX / desc->width
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
@ -502,7 +509,7 @@ 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 (
|
||||
@ -525,7 +532,8 @@ void *qoi_decode(const void *data, int size, qoi_desc *desc, int channels) {
|
||||
desc->width == 0 || desc->height == 0 ||
|
||||
desc->channels < 3 || desc->channels > 4 ||
|
||||
desc->colorspace > 2 ||
|
||||
header_magic != QOI_MAGIC
|
||||
header_magic != QOI_MAGIC ||
|
||||
desc->height >= QOI_PIXELS_MAX / desc->width
|
||||
) {
|
||||
return NULL;
|
||||
}
|
||||
@ -636,6 +644,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);
|
||||
|
Loading…
Reference in New Issue
Block a user