ref: 7e744bda2bfe0c664890b0f844591793fb08c976
parent: 2fdb279101563f0e72a11a83e29c40ccda924667
author: cinap_lenrek <[email protected]>
date: Thu Oct 6 18:49:12 EDT 2011
gif: implement dispose method for animations, do composing offscreen for speed
--- a/sys/src/cmd/jpg/gif.c
+++ b/sys/src/cmd/jpg/gif.c
@@ -13,7 +13,6 @@
int output = 0;
ulong outchan = CMAP8;
Image **allims;
-Image **allmasks;
int which;
int defaultcolor = 1;
@@ -50,9 +49,7 @@
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 @@
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 @@
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 @@
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 @@
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 @@
/* 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 @@
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 @@
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;
}