gif: implement dispose method for animations, do composing offscreen for speed

This commit is contained in:
cinap_lenrek 2011-10-06 22:49:12 +02:00
parent 2fdb279101
commit 7e744bda2b

View file

@ -13,7 +13,6 @@ int threeflag = 0;
int output = 0;
ulong outchan = CMAP8;
Image **allims;
Image **allmasks;
int which;
int defaultcolor = 1;
@ -50,9 +49,7 @@ eresized(int new)
return;
r = imager();
border(screen, r, -Border, nil, ZP);
r.min.x += allims[which]->r.min.x - allims[0]->r.min.x;
r.min.y += allims[which]->r.min.y - allims[0]->r.min.y;
drawop(screen, r, allims[which], allmasks[which], allims[which]->r.min, SoverD);
draw(screen, r, allims[which], nil, allims[which]->r.min);
flushimage(display, 1);
}
@ -283,7 +280,8 @@ char*
show(int fd, char *name)
{
Rawimage **images, **rgbv;
Image **ims, **masks;
Image *tmp, *msk, *img, *dst, **ims;
Rectangle r;
int j, k, n, ch, nloop, loopcount, dt;
char *err;
char buf[32];
@ -295,16 +293,18 @@ show(int fd, char *name)
return "decode";
}
for(n=0; images[n]; n++)
;
if(n == 0)
r = images[n]->r;
else
combinerect(&r, images[n]->r);
tmp = nil;
ims = malloc((n+1)*sizeof(Image*));
masks = malloc((n+1)*sizeof(Image*));
rgbv = malloc((n+1)*sizeof(Rawimage*));
if(masks==nil || rgbv==nil || ims==nil){
if(rgbv==nil || ims==nil){
fprint(2, "gif: malloc of masks for %s failed: %r\n", name);
err = "malloc";
goto Return;
}
memset(masks, 0, (n+1)*sizeof(Image*));
memset(ims, 0, (n+1)*sizeof(Image*));
memset(rgbv, 0, (n+1)*sizeof(Rawimage*));
if(!dflag){
@ -331,26 +331,46 @@ show(int fd, char *name)
goto Return;
}
if(!dflag){
masks[k] = transparency(images[k], name);
msk = transparency(images[k], name);
if(rgbv[k]->chandesc == CY)
ims[k] = allocimage(display, rgbv[k]->r, GREY8, 0, 0);
img = allocimage(display, rgbv[k]->r, GREY8, 0, 0);
else
ims[k] = allocimage(display, rgbv[k]->r, outchan, 0, 0);
if(ims[k] == nil){
img = allocimage(display, rgbv[k]->r, outchan, 0, 0);
if(tmp == nil)
tmp = allocimage(display, r, img->chan, 0, DWhite);
ims[k]= dst = allocimage(display, r, tmp->chan, 0, DWhite);
if(tmp == nil || img == nil || dst == nil){
fprint(2, "gif: allocimage %s failed: %r\n", name);
err = "allocimage";
goto Return;
}
if(loadimage(ims[k], ims[k]->r, rgbv[k]->chans[0], rgbv[k]->chanlen) < 0){
if(loadimage(img, img->r, rgbv[k]->chans[0], rgbv[k]->chanlen) < 0){
fprint(2, "gif: loadimage %s failed: %r\n", name);
err = "loadimage";
goto Return;
}
switch((images[k]->gifflags>>2)&7){
case 0:
case 1:
draw(tmp, img->r, img, msk, img->r.min);
draw(dst, tmp->r, tmp, nil, tmp->r.min);
break;
case 2:
draw(tmp, img->r, display->white, msk, img->r.min);
/* no break */
case 3:
draw(dst, tmp->r, tmp, nil, tmp->r.min);
draw(dst, img->r, img, msk, img->r.min);
break;
}
freeimage(msk);
freeimage(img);
}
}
if(tmp)
freeimage(tmp);
allims = ims;
allmasks = masks;
loopcount = images[0]->gifloopcount;
if(!dflag){
nloop = 0;
@ -362,7 +382,8 @@ show(int fd, char *name)
if(dt < 50)
dt = 50;
while(n==1 || ecankbd()){
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04) /* an odd, democratic list */
/* an odd, democratic list */
if((ch=ekbd())=='q' || ch==0x7F || ch==0x04)
exits(nil);
if(ch == '\n')
goto Out;
@ -373,7 +394,7 @@ show(int fd, char *name)
/* loop count has run out */
ekbd();
Out:
drawop(screen, screen->clipr, display->white, nil, ZP, S);
draw(screen, screen->clipr, display->white, nil, ZP);
}
if(n>1 && output)
fprint(2, "gif: warning: only writing first image in %d-image GIF %s\n", n, name);
@ -402,7 +423,6 @@ show(int fd, char *name)
Return:
allims = nil;
allmasks = nil;
for(k=0; images[k]; k++){
for(j=0; j<images[k]->nchans; j++)
free(images[k]->chans[j]);
@ -410,12 +430,10 @@ show(int fd, char *name)
if(rgbv[k])
free(rgbv[k]->chans[0]);
freeimage(ims[k]);
freeimage(masks[k]);
free(images[k]);
free(rgbv[k]);
}
free(images);
free(masks);
free(ims);
return err;
}