Charles.Forsyth20060303a828770d19 years agoHistory
3607 lines · 80.3 KB · Brainfuck
RawDownload
implement Img; include "common.m"; # headers for png supportinclude "filter.m";include "crc.m"; # big tables in separate filesinclude "rgb.inc";include "ycbcr.inc"; include "xxx.inc"; # local copies from CUsys: Sys;CU: CharonUtils;	Header, ByteSource, MaskedImage, ImageCache, ResourceState: import CU;D: Draw;	Chans, Point, Rect, Image, Display: import D;E: Events;	Event: import E;G: Gui; # channel descriptionsCRGB:   con 0;  # three channels, R, G, B, no mapCY:     con 1;  # one channel, luminanceCRGB1:  con 2;  # one channel, map presentCYCbCr:  con 3;  # three channels, Y, Cb, Cr, no map dbg := 0;dbgev := 0;warn := 0;progressive := 0;display: ref D->Display; inflate: Filter;crc: Crc;CRCstate: import crc; init(cu: CharonUtils){	sys = load Sys Sys->PATH;	CU = cu;	D = load Draw Draw->PATH;	G = cu->G;	crc = load Crc Crc->PATH;	inflate = load Filter "/dis/lib/inflate.dis";	inflate->init();	init_tabs();} # Return true if mtype is an image type we can handlesupported(mtype: int) : int{	case mtype {	CU->ImageJpeg or	CU->ImageGif or	CU->ImageXXBitmap or	CU->ImageXInfernoBit or	CU->ImagePng =>		return 1;	}	return 0;} # w,h passed in are specified width and height.# Result will be resampled if they don't match the dimensions# in the decoded picture (if only one of w,h is specified, the other# dimension is scaled by the same factor).ImageSource.new(bs: ref ByteSource, w, h: int) : ref ImageSource{	dbg = int (CU->config).dbg['i'];	warn = (int (CU->config).dbg['w']) || dbg;	dbgev = int (CU->config).dbg['e'];	display = G->display;	mtype := CU->UnknownType;	if(bs.hdr != nil)		mtype = bs.hdr.mtype;	is := ref ImageSource(		w,h,		# width, height		0,0,		# origw, origh		mtype,	# mtype		0,		# i		0,		# curframe		bs,		# bs		nil,		# ghdr		nil,		# jhdr		""		# err		);	return is;} ImageSource.free(is: self ref ImageSource){	is.bs = nil;	is.gstate = nil;	is.jstate = nil;} ImageSource.getmim(is: self ref ImageSource) : (int, ref MaskedImage){	if(dbg)		sys->print("img: getmim\n");	if(dbgev)		CU->event("IMAGE_GETMIM", is.width*is.height);	ans : ref MaskedImage = nil;	ret := Mimnone;prtype := 0;	{		if(is.bs.hdr == nil)			return (Mimnone, nil);		# temporary hack: wait until whole file is here first		if(is.bs.eof) {			if(is.mtype == CU->UnknownType) {				u := is.bs.req.url;				h := is.bs.hdr;				h.setmediatype(u.path, is.bs.data);				is.mtype = h.mtype;			}			case is.mtype {			CU->ImageJpeg =>				ans = getjpegmim(is);			CU->ImageGif =>				ans = getgifmim(is);			CU->ImageXXBitmap =>				ans = getxbitmapmim(is);			CU->ImageXInfernoBit =>				ans = getbitmim(is);			CU->ImagePng =>				ans = getpngmim(is);			* =>				is.err = sys->sprint("unsupported image type %s", (CU->mnames)[is.mtype]);				ret = Mimerror;				ans = nil;			}			if(ans != nil)				ret = Mimdone;		}		else {			# slow down the spin-waiting for this image			sys->sleep(100);		}	}exception ex{	"exImageerror*" =>		ret = Mimerror;		if(dbg)			sys->print("getmim got err: %s\n", is.err);	}	if(dbg)		sys->print("img: getmim returns (%d,%x)\n", ret, ans);	if(dbgev)		CU->event("IMAGE_GETMIM_END", 0);	is.bs.lim = is.i;	return (ret, ans);} # Raise exImagerror exceptionimgerror(is: ref ImageSource, msg: string){	is.err = msg;	if(dbg)		sys->print("Image error: %s\n", msg);	CU->raisex("exImageerror:");} # Get next char or raise exception if cannotgetc(is: ref ImageSource) : int{	if(is.i >= len is.bs.data) {		imgerror(is, "premature eof");	}	return int is.bs.data[is.i++];} # Unget the last character.# When called before any other getting routines, we# know the buffer still has that character in it.ungetc(is: ref ImageSource){	if(is.i == 0)		CU->raisex("EXInternal: ungetc past beginning of buffer");	is.i--;} # Like ungetc, but ungets two bytes (gotten in order b1, another char).# Now the bytes could have spanned a boundary, if we were unlucky,# so we have to be prepared to put b1 in front of current buffer.ungetc2(is: ref ImageSource, nil: byte){	if(is.i < 2) {		if(is.i != 1)			CU->raisex("EXInternal: ungetc2 past beginning of buffer");		is.i = 0;	}	else		is.i -= 2;} # Get 2 bytes and return the 16-bit value, little-endian order.getlew(is: ref ImageSource) : int{	c0 := getc(is);	c1 := getc(is);	return c0 + (c1<<8);} # Get 2 bytes and return the 16-bit value, big-endian order.getbew(is: ref ImageSource) : int{	c0 := getc(is);	c1 := getc(is);	return (c0<<8) + c1;} # Copy next n bytes of input into buf# or raise exception if cannot.read(is: ref ImageSource, buf: array of byte, n: int){	ok := 0;	if(is.i +n < len is.bs.data) {		buf[0:] = is.bs.data[is.i:is.i+n];		is.i += n;	}	else		imgerror(is, "premature eof");} # Caller needs n bytes.# Return an (array, index into array) where at least# the next n bytes can be found.# There might be a "premature eof" exception.getn(is: ref ImageSource, n: int) : (array of byte, int){	a := is.bs.data;	i := is.i;	if(i + n <= len a)		is.i += n;	else		imgerror(is, "premature eof");	return (a, i);} # display.newimage with some defaults; throw exception if failsnewimage(is: ref ImageSource, w, h: int) : ref Image{	if(!(CU->imcache).need(w*h))		imgerror(is, "out of memory");	im := display.newimage(((0,0),(w,h)), D->CMAP8, 0, D->White);	if(im == nil)		imgerror(is, "out of memory");	return im;} newimage24(is: ref ImageSource, w, h: int) : ref Image{	if(!(CU->imcache).need(w*h*3))		imgerror(is, "out of memory");	im := display.newimage(((0,0),(w,h)), D->RGB24, 0, D->White);	if(im == nil)		imgerror(is, "out of memory");	return im;} newimagegrey(is: ref ImageSource, w, h: int) : ref Image{	if(!(CU->imcache).need(w*h))		imgerror(is, "out of memory");	im := display.newimage(((0,0),(w,h)), D->GREY8, 0, D->White);	if(im == nil)		imgerror(is, "out of memory");	return im;}  newmi(im: ref Image) : ref MaskedImage{	return ref MaskedImage(im, nil, 0, 0, -1, Point(0,0));} # Call this after origw and origh are set to set the width and height# to our desired (rescaled) answer dimensions.# If only one of the dimensions is specified, the other is scaled by# the same factor.setdims(is: ref ImageSource){	sw := is.origw;	sh := is.origh;	dw := is.width;	dh := is.height;	if(dw == 0 && dh == 0) {		dw = sw;		dh = sh;	}	else if(dw == 0 || dh == 0) {		if(dw == 0) {			dw = int ((real sw) * (real dh/real sh));			if(dw == 0)				dw = 1;		}		else {			dh = int ((real sh) * (real dw/real sw));			if(dh == 0)				dh = 1;		}	}	is.width = dw;	is.height = dh;} # for debuggingprintarray(a: array of int, name: string){	sys->print("%s:", name);	for(i := 0; i < len a; i++) {		if((i%10)==0)			sys->print("\n%5d: ", i);		sys->print("%6d", a[i]);	}	sys->print("\n");} ################# XBitmap ################### getxbitmaphdr(is: ref ImageSource){	fnd: int;	(fnd, is.origw) = getxbitmapdefine(is);	if(fnd)		(fnd, is.origh) = getxbitmapdefine(is);	if(!fnd)		imgerror(is, "xbitmap starts badly");	# now, optional x_hot, y_hot	(fnd, nil) = getxbitmapdefine(is);	if(fnd)		(fnd, nil) = getxbitmapdefine(is);	# now expect 'static char x...x_bits[] = {'	get_to_char(is, '{');} getxbitmapmim(is: ref ImageSource) : ref MaskedImage{	getxbitmaphdr(is);	setdims(is);	bytesperline := (is.origw+7) / 8;	pixels := array[is.origw*is.origh] of byte;	pixi := 0;	for(i := 0; i < is.origh; i++) {		for(j := 0; j < bytesperline; j++) {			v := get_hexbyte(is);			kend := 7;			if(j == bytesperline-1)				kend = (is.origw-1)%8;			for(k := 0; k <= kend; k++) {				if(v & (1<<k))					pixels[pixi] = byte D->Black;				else					pixels[pixi] = byte D->White;				pixi++;			}		}	}	if(is.width != is.origw || is.height != is.origh)		pixels = resample(pixels, is.origw, is.origh, is.width, is.height);	im := newimage(is, is.width, is.height);	im.writepixels(im.r, pixels);	return newmi(im);} # get a line, which should be of form#	'#define fieldname val'# and return (found, integer rep of val)getxbitmapdefine(is: ref ImageSource) : (int, int){	fnd := 0;	n := 0;	c := getc(is);	if(c == '#') {		get_to_char(is, ' ');		get_to_char(is, ' ');		c = getc(is);		while(c >= '0' && c <= '9') {			fnd = 1;			n = n*10 + c - '0';			c = getc(is);		}	}	else		ungetc(is);	get_to_char(is, '\n');	return (fnd, n);} # read fd until get char cterm# (raise exception if eof hit first)get_to_char(is: ref ImageSource, cterm: int){	for(;;) {		if(getc(is) == cterm)			return;	}} # read fd until get xDD, were DD are hex digits.# (raise exception if not hex digits or if eof hit first)get_hexbyte(is: ref ImageSource) : int{	get_to_char(is, 'x');	n1 := hexdig(getc(is));	n2 := hexdig(getc(is));	if(n1 < 0 || n2 < 0)		imgerror(is, "X Bitmap expected hex digits");	return (n1<<4) + n2;} hexdig(c: int) : int{	if('0' <= c && c <= '9')		c -= '0';	else if('a' <= c && c <= 'f')		c += 10 - 'a';	else if('A' <= c && c <= 'F')		c += 10 - 'A';	else		c = -1;	return c;} ################# GIF ################### # GIF flagsTRANSP:		con 1;INPUT:		con 2;DISPMASK:	con 7<<2;HASCMAP:	con 16r80;INTERLACED:	con 16r40; Entry: adt{	prefix: int;	exten: int;}; getgifhdr(is: ref ImageSource){	if(dbg)		sys->print("img: getgifhdr\n");	h := ref Gifstate;	(buf, i) := getn(is, 6);	vers := string buf[i:i+6];	if(vers!="GIF87a" && vers!="GIF89a")		imgerror(is, "unknown GIF version " + vers);	is.origw = getlew(is);	is.origh = getlew(is);	h.fields = getc(is);	h.bgrnd = getc(is);	h.aspect = getc(is);	setdims(is);	if(dbg)		sys->print("img: getgifhdr has vers=%s, origw=%d, origh=%d, w=%d, h=%d, fields=16r%x, bgrnd=%d, aspect=%d\n",			vers, is.origw, is.origh, is.width, is.height, h.fields, h.bgrnd, h.aspect);	h.flags = 0;	h.delay = 0;	h.trindex = byte 0;	h.tbl = array[4096] of GifEntry;	for(i = 0; i < 258; i++) {		h.tbl[i].prefix = -1;		h.tbl[i].exten = i;	}	h.globalcmap = nil;	h.cmap = nil;	if(h.fields & HASCMAP)		h.globalcmap = gifreadcmap(is, (h.fields&7)+1);	is.gstate = h;	if(warn && h.aspect != 0)		sys->print("warning: non-standard aspect ratio in GIF image ignored\n");	if(!gifgettoimage(is))		imgerror(is, "GIF file has no image");} gifgettoimage(is: ref ImageSource) : int{	if(dbg)		sys->print("img: gifgettoimage\n");	h := is.gstate;loop:	for(;;) {		# some GIFs omit Trailer		if(is.i >= len is.bs.data)			break;		case c := getc(is) {		16r2C =>	# Image Descriptor			return 1; 		16r21 =>	# Extension			hsize := 0;			hasdata := 0;					case getc(is){			16r01 =>	# Plain Text Extension

Lines 1–500 of 3607.