pike.git
/
src
/
modules
/
Image
/
togif.c
version
»
Context lines:
10
20
40
80
file
none
3
pike.git/src/modules/Image/togif.c:1:
/* togif
-
Pontus
Hagland
,
law@infovav
.
se
+
$Id:
togif.c
,
v
1
.
22 1997/11/07 06:06:17 mirar Exp $
-
$Id:
togif.c,v
1.21
1997/10/27
22:41:30 mirar Exp $
+
old
GIF
API
compat
stuff
*/ /* **! module Image **! note
-
**! $Id: togif.c,v 1.
21
1997/
10
/
27
22
:
41
:
30
mirar Exp $
+
**! $Id: togif.c,v 1.
22
1997/
11
/
07
06
:
06
:
17
mirar Exp $
**! class image */ #include "global.h" #include <math.h> #include <ctype.h> #include "stralloc.h" #include "global.h"
pike.git/src/modules/Image/togif.c:27:
#include "object.h" #include "constants.h" #include "interpret.h" #include "svalue.h" #include "array.h" #include "error.h" #include "dynamic_buffer.h" #include "operators.h" #include "image.h"
-
#include "lzw.h"
+
-
#define INITIAL_BUF_LEN 8192
-
+
#define THIS ((struct image *)(fp->current_storage)) #define THISOBJ (fp->current_object)
-
#if
0
-
#include
<sys/resource.h>
-
#define
CHRONO(X) chrono(X)
+
extern
struct
program
*image_colortable_program;
-
static void chrono(char *x)
-
{
-
struct rusage r;
-
static struct rusage rold;
-
getrusage(RUSAGE_SELF,&r);
-
fprintf(stderr,"%s: %ld.%06ld - %ld.%06ld\n",x,
-
r.ru_utime.tv_sec,r.ru_utime.tv_usec,
-
-
((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?-1:0)
-
+r.ru_utime.tv_sec-rold.ru_utime.tv_sec,
-
((r.ru_utime.tv_usec-rold.ru_utime.tv_usec<0)?1000000:0)
-
+ r.ru_utime.tv_usec-rold.ru_utime.tv_usec
-
);
-
-
rold=r;
-
}
-
#else
-
#define CHRONO(X)
-
#endif
-
-
-
#define min(a,b) ((a)<(b)?(a):(b))
-
#define max(a,b) ((a)<(b)?(b):(a))
-
#define testrange(x) max(min((x),255),0)
-
-
static void buf_word( unsigned short w, dynamic_buffer *buf )
-
{
-
low_my_putchar( w&0xff, buf );
-
low_my_putchar( (w>>8)&0xff, buf );
-
}
-
-
#define WEIGHT_NEXT(X) (((X)*8)/20)
-
#define WEIGHT_DOWNNEXT(X) (((X)*3)/20)
-
#define WEIGHT_DOWN(X) (((X)*3)/20)
-
#define WEIGHT_DOWNBACK(X) (((X)*0)/20)
-
-
static int floyd_steinberg_add(rgbl_group *errl,
-
rgbl_group *errlfwd,
-
rgbl_group *errlback,
-
rgbl_group *err,
-
rgb_group rgb,
-
struct colortable *ct,
-
int closest)
-
{
-
/* NOTE:
-
* This code MUST be MT-SAFE!
-
*/
-
rgb_group rgb2,rgb3;
-
rgbl_group cerr;
-
int c;
-
rgb2.r=testrange((long)rgb.r+err->r/FS_SCALE);
-
rgb2.g=testrange((long)rgb.g+err->g/FS_SCALE);
-
rgb2.b=testrange((long)rgb.b+err->b/FS_SCALE);
-
#ifdef FS_DEBUG
-
fprintf(stderr,"%g,%g,%g+%g,%g,%g=%g,%g,%g ",
-
1.0*rgb.r, 1.0*rgb.g, 1.0*rgb.b,
-
err->r*1.0/FS_SCALE, err->g*1.0/FS_SCALE, err->b*1.0/FS_SCALE,
-
rgb2.r*1.0, rgb2.g*1.0, rgb2.b*1.0);
-
#endif
-
if (closest)
-
c=colortable_rgb_nearest(ct,rgb2);
-
else
-
c=colortable_rgb(ct,rgb2);
-
rgb3=ct->clut[c];
-
cerr.r=(long)rgb.r*FS_SCALE-(long)rgb3.r*FS_SCALE+err->r;
-
cerr.g=(long)rgb.g*FS_SCALE-(long)rgb3.g*FS_SCALE+err->g;
-
cerr.b=(long)rgb.b*FS_SCALE-(long)rgb3.b*FS_SCALE+err->b;
-
-
#ifdef FS_DEBUG
-
fprintf(stderr,"got %g,%g,%g err %g,%g,%g ",
-
1.0*rgb3.r,
-
1.0*rgb3.g,
-
1.0*rgb3.b,
-
1.0*cerr.r,
-
1.0*cerr.g,
-
1.0*cerr.b);
-
#endif
-
-
errl->r+=WEIGHT_DOWN(cerr.r);
-
errl->g+=WEIGHT_DOWN(cerr.g);
-
errl->b+=WEIGHT_DOWN(cerr.b);
-
if (errlback)
-
{
-
errlback->r+=WEIGHT_DOWNBACK(cerr.r);
-
errlback->g+=WEIGHT_DOWNBACK(cerr.g);
-
errlback->b+=WEIGHT_DOWNBACK(cerr.b);
-
#ifdef FS_DEBUG
-
fprintf(stderr,"errlback=>%g ",errlback->g*1.0/FS_SCALE);
-
#endif
-
}
-
if (errlfwd)
-
{
-
err->r=WEIGHT_NEXT(cerr.r);
-
err->g=WEIGHT_NEXT(cerr.g);
-
err->b=WEIGHT_NEXT(cerr.b);
-
err->r+=errlfwd->r;
-
err->g+=errlfwd->g;
-
err->b+=errlfwd->b;
-
errlfwd->r=WEIGHT_DOWNNEXT(cerr.r);
-
errlfwd->g=WEIGHT_DOWNNEXT(cerr.g);
-
errlfwd->b=WEIGHT_DOWNNEXT(cerr.b);
-
#ifdef FS_DEBUG
-
fprintf(stderr,"errlfwd=>%g ",errlfwd->g*1.0/FS_SCALE);
-
#endif
-
}
-
#ifdef FS_DEBUG
-
fprintf(stderr,"errl=>%g ",errl->g*1.0/FS_SCALE);
-
fprintf(stderr,"err=>%g\n",err->g*1.0/FS_SCALE);
-
#endif
-
return c;
-
}
-
-
void image_floyd_steinberg(rgb_group *rgb,int xsize,
-
rgbl_group *errl,
-
int way,int *res,
-
struct colortable *ct,
-
int closest)
-
{
-
rgbl_group err;
-
int x;
-
HIDE_GLOBAL_VARIABLES();
-
-
if (way)
-
{
-
err.r=errl[xsize-1].r;
-
err.g=errl[xsize-1].g;
-
err.b=errl[xsize-1].b;
-
for (x=xsize-1; x>=0; x--)
-
res[x]=floyd_steinberg_add(errl+x,
-
(x==0)?NULL:errl+x-1,
-
(x==xsize-1)?NULL:errl+x+1,
-
&err,rgb[x],ct,closest);
-
}
-
else
-
{
-
err.r=errl->r;
-
err.g=errl->g;
-
err.b=errl->b;
-
for (x=0; x<xsize; x++)
-
res[x]=floyd_steinberg_add(errl+x,
-
(x==xsize-1)?NULL:errl+x+1,
-
(x==0)?NULL:errl+x-1,
-
&err,rgb[x],ct,closest);
-
}
-
REVEAL_GLOBAL_VARIABLES();
-
}
-
-
#define STD_ARENA_SIZE 16384
-
-
int image_decode_gif(struct image *dest,struct image *dest_alpha,
-
unsigned char *src,unsigned long len)
-
{
-
unsigned char *arena,*tmpstore,*q;
-
rgb_group *global_palette,*palette;
-
rgb_group *rgb;
-
int bpp;
-
unsigned long i,j;
-
INT32 mod;
-
INT32 leftofs,topofs,width,height;
-
int interlaced,transparent;
-
unsigned long arenalen,pos;
-
-
if (src[0]!='G'
-
||src[1]!='I'
-
||src[2]!='F'
-
||len<12)
-
return 0; /* not a gif, you fool */
-
-
dest->xsize=src[6]+(src[7]<<8);
-
dest->ysize=src[8]+(src[9]<<8);
-
-
if (! (arena=malloc(arenalen=STD_ARENA_SIZE)) ) return 0;
-
-
dest->img=malloc(dest->xsize*dest->ysize*sizeof(rgb_group));
-
if (!dest->img) { free(arena); return 0; }
-
/* out of memory (probably illegal size) */
-
-
bpp=(src[10]&7)+1;
-
-
THREADS_ALLOW();
-
if (src[10]&128)
-
{
-
global_palette=(rgb_group*)(src+13);
-
src+=3*(1<<bpp);
-
len-=3*(1<<bpp);
-
rgb=dest->img;
-
i=dest->xsize*dest->ysize;
-
}
-
else
-
global_palette=NULL;
-
MEMSET(dest->img,0,sizeof(rgb_group)*dest->xsize*dest->ysize);
-
src+=13; len-=13;
-
-
do
-
{
-
switch (*src)
-
{
-
case '!': /* function block */
-
if (len<7) break; /* no len left */
-
if (src[1]==0xf9)
-
transparent=src[6];
-
len-=src[3]+1;
-
src+=src[3]+1;
-
continue;
-
case ',': /* image block(s) */
-
if (len<10) len-=10; /* no len left */
-
leftofs=src[1]+(src[2]<<8);
-
topofs=src[3]+(src[4]<<8);
-
width=src[5]+(src[6]<<8);
-
height=src[7]+(src[8]<<8);
-
interlaced=src[9]&64;
-
-
if (src[9]&128)
-
{
-
palette=(rgb_group*)(src+10);
-
src+=((src[9]&7)+1)*3;
-
}
-
else
-
palette=global_palette;
-
-
src+=11;
-
len-=11;
-
pos=0;
-
if (len<3) break; /* no len left */
-
bpp=src[-1];
-
-
while (len>1)
-
{
-
if (!(i=*src)) break; /* length of block */
-
if (pos+i>arenalen)
-
{
-
arena=realloc(arena,arenalen*=2);
-
if (!arena) return 1;
-
}
-
MEMCPY(arena+pos,src+1,min(i,len-1));
-
pos+=min(i,len-1);
-
len-=i+1;
-
src+=i+1;
-
}
-
-
if (leftofs+width<=dest->xsize && topofs+height<=dest->ysize)
-
{
-
tmpstore=malloc(width*height);
-
if (!tmpstore) break;
-
i=lzw_unpack(tmpstore,width*height,arena,pos,bpp);
-
if (i!=(unsigned long)(width*height))
-
MEMSET(tmpstore+i,0,width*height-i);
-
rgb=dest->img+leftofs+topofs*dest->ysize;
-
mod=width-dest->xsize;
-
j=height;
-
q=tmpstore;
-
if (palette)
-
while (j--)
-
{
-
i=width;
-
while (i--) *(rgb++)=palette[*(q++)];
-
rgb+=mod;
-
}
-
free(tmpstore);
-
}
-
-
continue;
-
case ';':
-
-
break; /* file done */
-
default:
-
break; /* unknown, file is ok? */
-
}
-
}
-
while (0);
-
THREADS_DISALLOW();
-
-
if (arena) free(arena);
-
return 1; /* ok */
-
}
-
-
-
+
/*
-
**! method object fromgif(string gif)
-
**! Reads GIF data to the called image object.
-
**!
-
**! GIF animation delay or loops are ignored,
-
**! and the resulting image is the written result.
-
**! returns the called object
-
**! arg string pnm
-
**! pnm data, as a string
-
**! see also: togif, frompnm
-
**! bugs
-
**! yes, it does -- it may even do segment overrides...
-
*/
-
-
void image_fromgif(INT32 args)
-
{
-
if (sp[-args].type!=T_STRING)
-
error("Illegal argument to image->fromgif()\n");
-
-
if (THIS->img) free(THIS->img);
-
THIS->img=NULL;
-
-
image_decode_gif(THIS,NULL,
-
(unsigned char*)sp[-args].u.string->str,
-
sp[-args].u.string->len);
-
-
pop_n_elems(args);
-
THISOBJ->refs++;
-
push_object(THISOBJ);
-
}
-
-
static INLINE void getrgb(struct image *img,
-
INT32 args_start,INT32 args,char *name)
-
{
-
INT32 i;
-
if (args-args_start<3) return;
-
for (i=0; i<3; i++)
-
if (sp[-args+i+args_start].type!=T_INT)
-
error("Illegal r,g,b argument to %s\n",name);
-
img->rgb.r=(unsigned char)sp[-args+args_start].u.integer;
-
img->rgb.g=(unsigned char)sp[1-args+args_start].u.integer;
-
img->rgb.b=(unsigned char)sp[2-args+args_start].u.integer;
-
if (args-args_start>=4)
-
if (sp[3-args+args_start].type!=T_INT)
-
error("Illegal alpha argument to %s\n",name);
-
else
-
img->alpha=sp[3-args+args_start].u.integer;
-
else
-
img->alpha=0;
-
}
-
-
-
/*
+
**! method string gif_begin() **! method string gif_begin(int num_colors) **! method string gif_begin(array(array(int)) colors)
-
**!
Makes
GIF
header.
With
no
argument
,
there
is
no
-
**!
global
colortable
(
palette
)
.
-
**!
returns
the
GIF
data
+
**!
method
string
gif_end()
+
**!
method
string
gif_netscape_loop(int
loops)
+
**!
method
string
togif()
+
**! method string togif(int trans_r
,
int
trans_g,int
trans_b)
+
**!
method string togif(int num_colors,int trans_r,int trans_g,int trans_b)
+
**!
method
string
togif(array(array(int))
colors,int
trans_r,int
trans_g,int
trans_b)
+
**! method string togif_fs
()
+
**!
method
string
togif_fs(int trans_r,int trans_g,int trans_b)
+
**! method string togif_fs(int num_colors,int trans_r,int trans_g,int trans_b)
+
**! method string togif_fs(array(array(int)) colors,int trans_r,int trans_g,int trans_b)
+
**! old
GIF
API compatibility function. Don't use
+
**! in any new code.
**!
-
**!
arg
int
num_colors
-
**!
number
of
colors
to
quantize
to
(default
is 256)
-
**!
array
array(array(int))
colors
-
**!
colors
to
map
to,
format
is ({({r,g,b}),({r,g,b}),
..
.}).
-
**!
see
also:
gif_add,
gif_end,
togif
, gif
_
netscape_loop
+
**!
<table>
+
**!
<tr><td></td><td>is
replaced
by</td></tr>
+
**!
<tr><td>gif_begin</td><td><ref>Image.GIF.header_block</ref></td></tr>
+
**!
<tr><td>gif_end</td><td><ref>Image.GIF.end_block</ref></td></tr>
+
**!
<tr><td>gif_netscape_loop</td><td><ref>Image.GIF.netscape_loop_block</ref></td></tr>
+
**!
<tr><td>togif</td><td><ref>Image.GIF.encode</ref></td></tr>
+
**!
<tr><td>togif_fs</td><td><ref>Image
.
GIF
.
encode</ref>¹</td></tr>
+
**!
</table>
**!
-
+
**! ¹ Use <ref>Image.colortable</ref> to get whatever dithering
+
**! you want.
**!
-
**!
method string gif_end()
-
**! Ends GIF data.
-
**!
returns
the
GIF data.
-
**! see also: gif_begin
+
**! returns GIF data.
*/
-
+
extern void image_gif_header_block(INT32 args);
+
extern void image_gif_end_block(INT32 args);
+
extern void image_gif_netscape_loop_block(INT32 args);
+
void image_gif_begin(INT32 args) {
-
dynamic_buffer buf;
-
long i;
-
int colors,bpp;
-
struct colortable *ct=NULL;
-
+
if (args)
-
if (sp[-args].type==T_INT && sp[-args].u.integer!=0)
-
ct=colortable_quant(THIS,max(256,min(2,sp[-args].u.integer)));
-
else if (sp[-args].type==T_ARRAY)
-
ct=colortable_from_array(sp[-args].u.array,"image->gif_begin()\n");
-
-
pop_n_elems(args);
-
-
buf.s.str=NULL;
-
initialize_buf(&buf);
-
-
if (ct)
+
{
-
colors=4;
bpp=2
;
-
while
(
colors<ct
-
>numcol) { colors<<
=
1; bpp++; }
-
}
-
else
+
struct
object *o
;
+
if
(
sp[
-
args].type==T_INT
)
{
-
colors=256;
bpp=8;
-
}
-
-
low_my_binary_strcat("GIF89a",6,&buf);
-
buf_word((unsigned short)THIS->xsize,&buf);
-
buf_word((unsigned short)THIS->ysize,&buf);
-
low_my_putchar( (char)((0x80*!!ct) | 0x70 | (bpp-1) ), &buf);
-
/* | global colormap | 3 bits color res | sort | 3 bits bpp */
-
/* color res is'nt cared of */
-
-
low_my_putchar( 0, &buf ); /* background color */
-
low_my_putchar( 0, &buf ); /* just zero */
-
-
if (!!ct)
-
{
-
for (
i=
0; i<ct->numcol; i++)
-
{
-
low_my_putchar(ct->clut
[
i].r,&buf);
-
low_my_putchar(ct
-
>clut[i
].
g,&buf);
-
low_my_putchar(ct->clut[i]
.
b,&buf)
;
-
}
-
-
for (; i<colors; i++)
-
{
-
low_my_putchar(0,&buf);
-
low_my_putchar(0,&buf);
-
low_my_putchar(0,&buf);
-
}
-
}
-
push_string(low_free_buf(&buf));
-
}
-
-
void image_gif_end(INT32 args)
-
{
+
int
i=
sp
[-
args
].
u
.
integer
;
pop_n_elems(args);
-
push_
string
(
make
_
shared
_
binary
_
string
(
"
;
"
,
1
)
)
;
+
push_
int
(
THIS->xsize);
+
push
_
int(THIS->ysize);
+
THISOBJ->refs++;
+
push
_
object(THISOBJ);
+
push
_
int
(
i)
;
+
o=clone_object(image_colortable_program
,
2
);
}
-
-
/*
-
**! method string gif_netscape_loop()
-
**! method string gif_netscape_loop(int loops)
-
**!
-
**! returns a gif chunk that defines that the GIF animation should loop
-
**!
-
**! arg int loops
-
**! number of loops, default is 65535.
-
**! see also: gif_add, gif_begin, gif_end
-
*/
-
-
void image_gif_netscape_loop(INT32 args)
-
{
-
unsigned short loops=0;
-
char buf[30];
-
if (args)
-
if (sp[-args].type!=T_INT)
-
error("Illegal argument to image->gif_netscape_loop()\n");
+
else
-
loops=sp[-args].u.integer;
-
else
-
loops=65535;
-
pop_n_elems(args);
-
-
sprintf(buf,"%c%c%cNETSCAPE2.0%c%c%c%c%c",
-
33,255,11,3,1,loops&255,(loops>>8)&255,0);
-
-
push_string(make_shared_binary_string(buf,19));
-
}
-
-
/*
-
**! method string gif_transparency(int color)
-
**!
-
**! returns a gif chunk that transparent a color in the next image chunk
-
**!
-
**! arg int color
-
**! index of color in the palette
-
**! note
-
**! Yes - i know this function is too hard to use. :/
-
**! The palette _is_ unknown mostly...
-
**! see also: gif_add, gif_begin, gif_end
-
*/
-
-
void image_gif_transparency(INT32 args)
+
{
-
unsigned
short
i=0;
-
char
buf[30];
-
if (args)
-
if (sp[-args].type!
=
T
_
INT)
-
error
(
"Illegal argument to
image
->gif
_
transparency()\n");
-
else
-
i=sp[-args].u.integer;
-
else
-
error("Too few arguments to image->gif
_
transparency()\n");
-
pop_n_elems(
args);
-
-
sprintf(buf,"%c%c%c%c%c%c%c%c",33,0xf9,4,1,0,0,i,0);
-
-
push_string(make_shared_binary_string(buf,8));
+
o
=
clone
_
object
(image_
colortable
_
program,
args);
}
-
-
static
struct
colortable
*img_gif_add(INT32
args,int
fs,int
lm
)
-
{
-
INT32 x=0,y=0,i
;
-
struct
lzw
lzw;
-
int xs, ys;
-
rgb
_
group *rgb;
-
struct colortable *ct=NULL;
-
dynamic_buffer buf;
-
int
colors,bpp;
-
int closest=0;
-
-
CHRONO
(
"gif add init"
);
-
-
buf.s.str=NULL;
-
initialize
_
buf
(
&buf
);
-
-
if
(args==0)
x=y=0;
-
else if (args<2
-
|| sp[-args].type!=T_INT
-
|| sp[1-args].type!=T_INT)
-
error("Illegal argument(s) to
image
->
gif_
add
()
\n")
;
-
else
-
{
-
x=sp[-args].u.integer;
-
y=sp[1-args].u.integer;
+
push_
int
(THIS->xsize
);
+
push
_int(
THIS->ysize
);
+
push
_
object
(
o
);
+
image
_gif_
header_block
(
3
);
}
-
-
-
if (args>2 && sp[2-args].type==T_ARRAY)
-
{
-
ct=colortable_from_array(sp[2-args].u.array,"image->gif_add()\n");
-
if (ct->numcol<128) closest=1;
-
}
-
else if (args>3 && sp[2-args].type==T_INT)
-
ct=colortable_quant(THIS,max(256,min(2,sp[2-args].u.integer)));
-
-
if (args>2+!!ct)
-
{
-
unsigned short delay=0;
-
if (sp[2+!!ct-args].type==T_INT)
-
delay=sp[2+!!ct-args].u.integer;
-
else if (sp[2+!!ct-args].type==T_FLOAT)
-
delay=(unsigned short)(sp[2+!!ct-args].u.float_number*100);
+
else
-
error("Illegal argument %d to image->gif_add()\n",3+!!ct);
-
-
low_my_putchar( '!', &buf ); /* extension block */
-
low_my_putchar( 0xf9, &buf ); /* graphics control */
-
low_my_putchar( 4, &buf ); /* block size */
-
low_my_putchar( 0, &buf ); /* disposal, transparency, blabla */
-
buf_word( delay, &buf ); /* delay in centiseconds */
-
low_my_putchar( 0, &buf ); /* (transparency index) */
-
low_my_putchar( 0, &buf ); /* terminate block */
-
}
-
-
if(!ct)
-
ct=colortable_quant(THIS,256);
-
-
colors=4; bpp=2;
-
while (colors<ct->numcol) { colors<<=1; bpp++; }
-
-
-
low_my_putchar( ',', &buf ); /* image separator */
-
-
buf_word(x,&buf); /* leftofs */
-
buf_word(y,&buf); /* topofs */
-
buf_word(THIS->xsize,&buf); /* width */
-
buf_word(THIS->ysize,&buf); /* height */
-
-
low_my_putchar((0x80*lm)|(bpp-1), &buf);
-
/* not interlaced (interlaced == 0x40) */
-
/* local colormap ( == 0x80) */
-
/* 8 bpp in map ( == 0x07) */
-
-
if (lm)
+
{
-
for
(
i=0; i<ct
->
numcol; i++
)
-
{
-
low
_
my_putchar
(
ct
->
clut[i].r,&buf
);
-
low
_
my_putchar
(
ct->clut[i].g,&buf
);
-
low
_
my
_
putchar
(
ct->clut[i].b,&buf
);
+
push_int
(
THIS
->
xsize)
;
+
push
_
int
(
THIS
->
ysize
);
+
push
_
int
(
256
);
+
image
_
gif
_
header_block
(
3
);
}
-
for (; i<colors; i++)
-
{
-
low_my_putchar(0,&buf);
-
low_my_putchar(0,&buf);
-
low_my_putchar(0,&buf);
+
}
-
}
+
-
low
_
my
_
putchar
(
bpp, &buf
)
;
-
-
i=THIS->xsize*THIS->ysize;
-
rgb=THIS->img;
-
-
CHRONO("begin pack");
-
xs = THIS->xsize;
-
ys = THIS->ysize;
-
-
THREADS_ALLOW();
-
lzw_init(&lzw,bpp);
-
THREADS_DISALLOW();
-
-
if (!fs)
+
void
image
_
gif
_
end
(
INT32
args
)
{
-
THREADS_ALLOW();
-
if (closest)
-
while (i--) lzw_add(&lzw,colortable_rgb_nearest(ct,*(rgb++)));
-
else
-
while (i--) lzw_add(&lzw,colortable_rgb(ct,*(rgb++)));
-
THREADS_DISALLOW();
-
} else {
-
rgbl_group *errb;
-
int w,*cres,j;
-
/* NOTE: xalloc() is NOT thread-safe. */
-
errb=(rgbl_group*)xalloc(sizeof(rgbl_group)*xs);
-
cres=(int*)xalloc(sizeof(int)*xs);
-
THREADS_ALLOW();
-
for (i=0; i<xs; i++)
-
errb[i].r=(rand()%(FS_SCALE*2+1))-FS_SCALE,
-
errb[i].g=(rand()%(FS_SCALE*2+1))-FS_SCALE,
-
errb[i].b=(rand()%(FS_SCALE*2+1))-FS_SCALE;
-
-
w=0;
-
while (ys--) {
-
image_
floyd
_
steinberg(rgb,xs,errb,w=!w,cres,ct,closest);
-
for (j=0; j<xs; j++)
-
lzw
_
add
(
&lzw,cres[j]
);
-
rgb+=xs;
+
image_
gif
_
end
_
block
(
args
);
}
-
THREADS_DISALLOW();
-
free(cres);
-
free(errb);
-
}
+
-
THREADS
_
ALLOW();
-
lzw
_
write
_
last
(
&lzw);
-
THREADS_DISALLOW(
)
;
-
-
CHRONO("end pack");
-
-
/* NOTE that the low_my_* functions are NOT thread-safe.
-
*/
-
for (i=0; i<(int)lzw.outpos; i+=254)
+
void
image
_
gif
_
netscape
_
loop
(
INT32
args
)
{
-
int wr;
-
if (i+254>(int)lzw.outpos) wr=lzw.outpos-i;
-
else wr=254;
-
low
_
my
_
putchar( (unsigned char)wr, &buf ); /* bytes in chunk */
-
low
_
my
_
binary_strcat
(
(char *
)
lzw.out+i, wr, &buf )
;
+
image
_
gif
_
netscape
_
loop
_
block
(
args
);
}
-
low_my_putchar( 0, &buf ); /* terminate stream */
+
-
lzw_quit(&lzw);
-
-
CHRONO("done");
-
-
pop_n_elems(args);
-
push_string(low_free_buf(&buf));
-
-
return ct;
-
}
-
+
/* **! method string gif_add() **! method string gif_add(int x,int y) **! method string gif_add(int x,int y,int delay_cs) **! method string gif_add(int x,int y,float delay_s) **! method string gif_add(int x,int y,int num_colors,int delay_cs) **! method string gif_add(int x,int y,int num_colors,float delay_s) **! method string gif_add(int x,int y,array(array(int)) colors,int delay_cs) **! method string gif_add(int x,int y,array(array(int)) colors,float delay_s) **! method string gif_add_fs()
pike.git/src/modules/Image/togif.c:708:
**! method string gif_add_nomap(int x,int y,int num_colors,float delay_s) **! method string gif_add_nomap(int x,int y,array(array(int)) colors,int delay_cs) **! method string gif_add_nomap(int x,int y,array(array(int)) colors,float delay_s) **! method string gif_add_fs_nomap() **! method string gif_add_fs_nomap(int x,int y) **! method string gif_add_fs_nomap(int x,int y,int delay_cs) **! method string gif_add_fs_nomap(int x,int y,float delay_s) **! method string gif_add_fs_nomap(int x,int y,int num_colors,int delay_cs) **! method string gif_add_fs_nomap(int x,int y,int num_colors,float delay_s) **! method string gif_add_fs_nomap(int x,int y,array(array(int)) colors,int delay_cs)
-
**! method string gif_add_fs_nomap(int x,int y,array(array(int)) colors,float delay_s)
+
**! method string gif_add_fs_nomap(int x,int y,array(array(int)) colors,float delay_s
,rgb_group *transparent
)
**! Makes a GIF (sub)image data chunk, to be placed **! at the given position. **! **! The "fs" versions uses floyd-steinberg dithering, and the "nomap" **! versions have no local colormap. **! **! Example: **! <pre> **! object img1 = Image(200,200); **! object img2 = Image(200,200);
pike.git/src/modules/Image/togif.c:746:
**! arg int delay_cs **! frame delay in centiseconds **! arg float delay_s **! frame delay in seconds **! arg int num_colors **! number of colors to quantize to (default is 256) **! arg array array(array(int)) colors **! colors to map to, format is ({({r,g,b}),({r,g,b}),...}). **! see also: gif_add, gif_end, gif_netscape_loop, togif */
+
static void img_gif_add(INT32 args,int fs,int lm,
+
rgb_group *transparent)
+
{
+
INT32 x=0,y=0;
+
int delay=0;
+
struct object *ncto=NULL;
+
+
if (args==0) x=y=0;
+
else if (args<2
+
|| sp[-args].type!=T_INT
+
|| sp[1-args].type!=T_INT)
+
error("Illegal argument(s) to image->gif_add()\n");
+
else
+
{
+
x=sp[-args].u.integer;
+
y=sp[1-args].u.integer;
+
}
+
+
if (args>2 && sp[2-args].type==T_ARRAY)
+
{
+
struct svalue *sv=sp+2-args;
+
push_svalue(sv);
+
ncto=clone_object(image_colortable_program,2);
+
}
+
else if (args>3 && sp[2-args].type==T_INT)
+
{
+
INT32 i=sp[2-args].u.integer;
+
THISOBJ->refs++;
+
push_object(THISOBJ);
+
push_int(i);
+
ncto=clone_object(image_colortable_program,2);
+
}
+
+
if (args>2+!!ncto)
+
{
+
if (sp[2+!!ncto-args].type==T_INT)
+
delay=sp[2+!!ncto-args].u.integer;
+
else if (sp[2+!!ncto-args].type==T_FLOAT)
+
delay=(unsigned short)(sp[2+!!ncto-args].u.float_number*100);
+
else
+
error("Illegal argument %d to image->gif_add()\n",3+!!ncto);
+
}
+
+
if (!ncto)
+
{
+
THISOBJ->refs++;
+
push_object(THISOBJ);
+
push_int(256);
+
ncto=clone_object(image_colortable_program,2);
+
}
+
+
if (fs) image_colortable_internal_floyd_steinberg(
+
get_storage(ncto,image_colortable_program));
+
+
pop_n_elems(args);
+
+
THISOBJ->refs++;
+
push_object(THISOBJ);
+
push_object(ncto);
+
push_int(x);
+
push_int(y);
+
push_int(lm);
+
push_int(delay);
+
+
if (transparent)
+
{
+
unsigned char trd;
+
+
image_colortable_index_8bit_image(get_storage(ncto,
+
image_colortable_program),
+
transparent,&trd,1,1);
+
+
push_int(trd);
+
+
image_gif_render_block(7);
+
}
+
else
+
image_gif_render_block(6);
+
}
+
+
void image_gif_add(INT32 args) {
-
colortable_free(
img_gif_add(args,0,1)
)
;
+
img_gif_add(args,0,1
,NULL
);
} void image_gif_add_fs(INT32 args) {
-
colortable_free(
img_gif_add(args,1,1)
)
;
+
img_gif_add(args,1,1
,NULL
);
} void image_gif_add_nomap(INT32 args) {
-
colortable_free(
img_gif_add(args,0,0)
)
;
+
img_gif_add(args,0,0
,NULL
);
} void image_gif_add_fs_nomap(INT32 args) {
-
colortable_free(
img_gif_add(args,1,0)
)
;
+
img_gif_add(args,1,0
,NULL
);
} /* **! method string togif()
-
**! method string togif(int num_colors)
-
**! method string togif(array(array(int)) colors)
+
**! method string togif(int trans_r,int trans_g,int trans_b) **! method string togif(int num_colors,int trans_r,int trans_g,int trans_b) **! method string togif(array(array(int)) colors,int trans_r,int trans_g,int trans_b) **! method string togif_fs()
-
**! method string togif_fs(int num_colors)
-
**! method string togif_fs(array(array(int)) colors)
+
**! method string togif_fs(int trans_r,int trans_g,int trans_b) **! method string togif_fs(int num_colors,int trans_r,int trans_g,int trans_b) **! method string togif_fs(array(array(int)) colors,int trans_r,int trans_g,int trans_b) **! Makes GIF data. The togif_fs variant uses floyd-steinberg **! dithereing. **! returns the GIF data **! **! arg int num_colors **! number of colors to quantize to (default is 256) **! array array(array(int)) colors
pike.git/src/modules/Image/togif.c:797:
**! arg int trans_r **! arg int trans_g **! arg int trans_b **! one color, that is to be transparent. **! see also: gif_begin, gif_add, gif_end, toppm, fromgif */ static void img_encode_gif(rgb_group *transparent,int fs,INT32 args) {
-
struct colortable *ct;
+
struct svalue sv; /* on stack is now: - eventual colortable instruction (number or array) */ /* (swap in) arguments to gif_add, x and y position */ push_int(0); if (args) { sv=sp[-1]; sp[-1]=sp[-2]; sp[-2]=sv; } push_int(0); if (args) { sv=sp[-1]; sp[-1]=sp[-2]; sp[-2]=sv; }
-
ct=
img_gif_add(args+2,fs,1);
+
img_gif_add(args+2,fs,1
,transparent
);
image_gif_begin(0); /* on stack is now: - gif image chunk with local palette - gif beginning */ /* swap them... */ sv=sp[-1]; sp[-1]=sp[-2]; sp[-2]=sv;
-
if (transparent)
-
{
-
push_int(colortable_rgb(ct,*transparent));
-
image_gif_transparency(1);
-
sv=sp[-1]; sp[-1]=sp[-2]; sp[-2]=sv;
-
}
-
colortable_free(ct);
+
image_gif_end(0); /* on stack is now: - gif beginning
-
-
eventual transparency chunk
-
-
image with local palette
+
-
image
with
local
palette
and
eventual
gce
block
- gif end chunk */
-
f_add(
3+!!transparent
);
-
/* f_aggregate(4);*/
+
f_add(
3
);
}
-
+
static INLINE void getrgb(struct image *img,
+
INT32 args_start,INT32 args,char *name)
+
{
+
INT32 i;
+
if (args-args_start<3) return;
+
for (i=0; i<3; i++)
+
if (sp[-args+i+args_start].type!=T_INT)
+
error("Illegal r,g,b argument to %s\n",name);
+
img->rgb.r=(unsigned char)sp[-args+args_start].u.integer;
+
img->rgb.g=(unsigned char)sp[1-args+args_start].u.integer;
+
img->rgb.b=(unsigned char)sp[2-args+args_start].u.integer;
+
if (args-args_start>=4)
+
if (sp[3-args+args_start].type!=T_INT)
+
error("Illegal alpha argument to %s\n",name);
+
else
+
img->alpha=sp[3-args+args_start].u.integer;
+
else
+
img->alpha=0;
+
}
+
void image_togif(INT32 args) { rgb_group *transparent=NULL; if (args>=3) { getrgb(THIS,args>3,args,"image->togif() (transparency)"); transparent=&(THIS->rgb); } if (args==3) pop_n_elems(3);