libdraw: fix unloadimage() for wide images, libmemdraw: work arround width limit by outputting uncompressed image in writememimage() if compressed blocksize exceeds chunk limit

This commit is contained in:
cinap_lenrek 2011-09-04 23:51:14 +02:00
parent 0bc540a495
commit b5bbc62dda
3 changed files with 51 additions and 31 deletions

View file

@ -5,8 +5,8 @@
int int
unloadimage(Image *i, Rectangle r, uchar *data, int ndata) unloadimage(Image *i, Rectangle r, uchar *data, int ndata)
{ {
int bpl, n, ntot, dy; int bpl, n, chunk, dx, dy;
uchar *a; uchar *a, *start;
Display *d; Display *d;
if(!rectinrect(r, i->r)){ if(!rectinrect(r, i->r)){
@ -18,36 +18,41 @@ unloadimage(Image *i, Rectangle r, uchar *data, int ndata)
werrstr("unloadimage: buffer too small"); werrstr("unloadimage: buffer too small");
return -1; return -1;
} }
start = data;
d = i->display; d = i->display;
chunk = d->bufsize;
flushimage(d, 0); /* make sure subsequent flush is for us only */ flushimage(d, 0); /* make sure subsequent flush is for us only */
ntot = 0;
while(r.min.y < r.max.y){ while(r.min.y < r.max.y){
dx = Dx(r);
dy = chunk/bpl;
if(dy <= 0){
dy = 1;
dx = ((chunk*dx)/bpl) & ~7;
n = bytesperline(Rect(r.min.x, r.min.y, r.min.x+dx, r.min.y+dy), i->depth);
if(unloadimage(i, Rect(r.min.x+dx, r.min.y, r.max.x, r.min.y+dy), data+n, bpl-n) < 0)
return -1;
} else {
if(dy > Dy(r))
dy = Dy(r);
n = bpl*dy;
}
a = bufimage(d, 1+4+4*4); a = bufimage(d, 1+4+4*4);
if(a == 0){ if(a == 0){
werrstr("unloadimage: %r"); werrstr("unloadimage: %r");
return -1; return -1;
} }
dy = 8000/bpl;
if(dy <= 0){
werrstr("unloadimage: image too wide");
return -1;
}
if(dy > Dy(r))
dy = Dy(r);
a[0] = 'r'; a[0] = 'r';
BPLONG(a+1, i->id); BPLONG(a+1, i->id);
BPLONG(a+5, r.min.x); BPLONG(a+5, r.min.x);
BPLONG(a+9, r.min.y); BPLONG(a+9, r.min.y);
BPLONG(a+13, r.max.x); BPLONG(a+13, r.min.x+dx);
BPLONG(a+17, r.min.y+dy); BPLONG(a+17, r.min.y+dy);
if(flushimage(d, 0) < 0) if(flushimage(d, 0) < 0)
return -1; return -1;
n = read(d->fd, data+ntot, ndata-ntot); if(read(d->fd, data, n) < 0)
if(n < 0) return -1;
return n; data += bpl*dy;
ntot += n;
r.min.y += dy; r.min.y += dy;
} }
return ntot; return data - start;
} }

View file

@ -85,10 +85,6 @@ readmemimage(int fd)
dy = maxy - miny; dy = maxy - miny;
if(dy*l > chunk) if(dy*l > chunk)
dy = chunk/l; dy = chunk/l;
if(dy <= 0){
werrstr("readmemimage: image too wide for buffer");
goto Err;
}
n = dy*l; n = dy*l;
m = readn(fd, tmp, n); m = readn(fd, tmp, n);
if(m != n){ if(m != n){

View file

@ -43,26 +43,45 @@ writememimage(int fd, Memimage *i)
bpl = bytesperline(r, i->depth); bpl = bytesperline(r, i->depth);
n = Dy(r)*bpl; n = Dy(r)*bpl;
data = malloc(n); data = malloc(n);
ncblock = _compblocksize(r, i->depth); if(data == 0){
outbuf = malloc(ncblock); ErrOut0:
hash = malloc(NHASH*sizeof(Hlist));
chain = malloc(NMEM*sizeof(Hlist));
if(data == 0 || outbuf == 0 || hash == 0 || chain == 0){
ErrOut:
free(data); free(data);
free(outbuf);
free(hash);
free(chain);
return -1; return -1;
} }
for(miny = r.min.y; miny != r.max.y; miny += dy){ for(miny = r.min.y; miny != r.max.y; miny += dy){
dy = r.max.y-miny; dy = r.max.y-miny;
if(dy*bpl > CHUNK) if(dy*bpl > CHUNK)
dy = CHUNK/bpl; dy = CHUNK/bpl;
if(dy <= 0)
dy = 1;
nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy), nb = unloadmemimage(i, Rect(r.min.x, miny, r.max.x, miny+dy),
data+(miny-r.min.y)*bpl, dy*bpl); data+(miny-r.min.y)*bpl, dy*bpl);
if(nb != dy*bpl) if(nb != dy*bpl)
goto ErrOut; goto ErrOut0;
}
ncblock = _compblocksize(r, i->depth);
if(ncblock > CHUNK){
sprint(hdr, "%11s %11d %11d %11d %11d ",
chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);
if(write(fd, hdr, 5*12) != 5*12)
goto ErrOut0;
if(write(fd, data, n) != n)
goto ErrOut0;
free(data);
return 0;
}
outbuf = malloc(ncblock);
hash = malloc(NHASH*sizeof(Hlist));
chain = malloc(NMEM*sizeof(Hlist));
if(outbuf == 0 || hash == 0 || chain == 0){
ErrOut:
free(outbuf);
free(hash);
free(chain);
goto ErrOut0;
} }
sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ",
chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y); chantostr(cbuf, i->chan), r.min.x, r.min.y, r.max.x, r.max.y);