Remove the requirement to specify sizes for PNG files

This commit is contained in:
Kovid Goyal 2017-09-29 06:52:53 +05:30
parent 9e5dbb45d4
commit 4f98d10caa
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
3 changed files with 24 additions and 16 deletions

View File

@ -79,17 +79,15 @@ bytes.
=== PNG data
In this format any PNG image can be transmitted directly. The size of the PNG data
**must** be specified in the control data. For example:
In this format any PNG image can be transmitted directly. For example:
```
<ESC>_Gf=100,S=4897;<payload><ESC>\
<ESC>_Gf=100;<payload><ESC>\
```
Here the size (in bytes) of the PNG file is specified using the `S` key and the
PNG format is specified using the `f` key. The pixel data must therefore be
`S=4897` bytes.
The PNG format is specified using the `f=100` key. The width and height of
the image will be read from the PNG data itself.
=== Compression
@ -127,7 +125,7 @@ and can take the values:
First let us consider the local client techniques (files and shared memory). Some examples:
```
<ESC>_Gf=100,S=3567,t=f;<encoded /path/to/file.png><ESC>\
<ESC>_Gf=100,t=f;<encoded /path/to/file.png><ESC>\
```
Here we tell the terminal emulator to read PNG data from the specified file of

View File

@ -281,6 +281,7 @@ add_trim_predicate(Image *img) {
static bool
handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_t *payload) {
#define ABRT(code, ...) { set_add_response(#code, __VA_ARGS__); self->loading_image = 0; return false; }
#define MAX_DATA_SZ (4 * 100000000)
bool existing, init_img = true;
Image *img;
unsigned char tt = g->transmission_type ? g->transmission_type : 'd';
@ -302,10 +303,9 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
img->width = g->data_width; img->height = g->data_height;
switch(fmt) {
case PNG:
if (!g->data_sz) ABRT(EINVAL, "Must provide a data size with the PNG format");
if (g->data_sz > 4 * 100000000) ABRT(EINVAL, "PNG data size too large");
if (g->data_sz > MAX_DATA_SZ) ABRT(EINVAL, "PNG data size too large");
img->load_data.is_4byte_aligned = true;
img->load_data.data_sz = g->data_sz;
img->load_data.data_sz = g->data_sz ? g->data_sz : 1024 * 100;
break;
case RGB:
case RGBA:
@ -319,9 +319,12 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
if (tt == 'd') {
if (g->more) self->loading_image = img->internal_id;
img->load_data.buf_capacity = img->load_data.data_sz + (g->compressed ? 1024 : 10); // compression header
img->load_data.buf = malloc(img->load_data.buf_capacity + 4);
if (img->load_data.buf == NULL) fatal("Out of memory while allocating image load data buffer");
img->load_data.buf = malloc(img->load_data.buf_capacity);
img->load_data.buf_used = 0;
if (img->load_data.buf == NULL) {
ABRT(ENOMEM, "Out of memory");
img->load_data.buf_capacity = 0; img->load_data.buf_used = 0;
}
}
} else {
img = img_by_internal_id(self, self->loading_image);
@ -334,8 +337,14 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
static char fname[2056] = {0};
switch(tt) {
case 'd': // direct
if (g->payload_sz >= img->load_data.buf_capacity - img->load_data.buf_used) {
ABRT(EFBIG, "Too much data transmitted");
if (img->load_data.buf_capacity - img->load_data.buf_used < g->payload_sz) {
if (img->load_data.buf_used + g->payload_sz > MAX_DATA_SZ || fmt != PNG) ABRT(EFBIG, "Too much data");
img->load_data.buf_capacity = MIN(2 * img->load_data.buf_capacity, MAX_DATA_SZ);
img->load_data.buf = realloc(img->load_data.buf, img->load_data.buf_capacity);
if (img->load_data.buf == NULL) {
ABRT(ENOMEM, "Out of memory");
img->load_data.buf_capacity = 0; img->load_data.buf_used = 0;
}
}
memcpy(img->load_data.buf + img->load_data.buf_used, payload, g->payload_sz);
img->load_data.buf_used += g->payload_sz;
@ -409,6 +418,7 @@ handle_add_command(GraphicsManager *self, const GraphicsCommand *g, const uint8_
}
}
return img->data_loaded;
#undef MAX_DATA_SZ
#undef ABRT
}

View File

@ -133,10 +133,10 @@ class TestGraphics(BaseTest):
for mode in 'RGBA RGB P'.split():
data = png(mode)
sl(data, f=100, S=len(data), expecting_data=rgba_data)
sl(data, f=100, expecting_data=rgba_data)
img = img.convert('L')
rgba_data = img.convert('RGBA').tobytes()
data = png('L')
sl(data, f=100, S=len(data), expecting_data=rgba_data)
sl(data, f=100, expecting_data=rgba_data)
self.ae(l(b'a' * 20, f=100, S=20).partition(':')[0], 'EBADPNG')