cmd/pict: import 9front's graphical tools
This commit is contained in:
		
							
								
								
									
										8
									
								
								sys/src/cmd/pict/README.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								sys/src/cmd/pict/README.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| These are the graphic tools from 9front as documented at | ||||
|  | ||||
| 	http://man.cat-v.org/9front/1/jpg | ||||
|  | ||||
| The whole pict/ folder should be an external package as it's not | ||||
| actually required for a minimal system. | ||||
| It's included in the main Jehanne's source tree because we don't have | ||||
| a package management system yet. | ||||
							
								
								
									
										219
									
								
								sys/src/cmd/pict/bmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								sys/src/cmd/pict/bmp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t		outchan = CMAP8; | ||||
| int		defaultcolor = 1; | ||||
| Image		*image; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge	= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rawimage** readbmp(int fd, int colorspace); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "bmp: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: bmp -39cdektv  [file.bmp ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "bmp: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "bmp: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "bmp: initdraw failed: %r"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	array = readbmp(fd, CRGB); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "bmp: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)) | ||||
| 			c = totruecolor(r, CY); | ||||
| 		else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "bmp: converting %s to local format failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			i = allocimage(display, c->r, GREY8, 0, 0); | ||||
| 		else | ||||
| 			i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "bmp: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "bmp: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "bmp: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "bmp: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										39
									
								
								sys/src/cmd/pict/bmp.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								sys/src/cmd/pict/bmp.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
|  | ||||
| #define BMP_RGB      	0 | ||||
| #define BMP_RLE8     	1 | ||||
| #define BMP_RLE4     	2 | ||||
| #define BMP_BITFIELDS	3 | ||||
|  | ||||
| typedef struct { | ||||
| 	unsigned char red; | ||||
| 	unsigned char green; | ||||
| 	unsigned char blue; | ||||
| 	unsigned char alpha; | ||||
| } Rgb; | ||||
|  | ||||
| #define Filehdrsz	14 | ||||
|  | ||||
| typedef struct { | ||||
|         short	type; | ||||
|         long	size;		/* file size, not structure size */ | ||||
|         short	reserved1; | ||||
|         short	reserved2; | ||||
|         long	offbits; | ||||
| } Filehdr; | ||||
|  | ||||
| typedef struct { | ||||
| 	long	size;		/* Size of the Bitmap-file */ | ||||
| 	long	lReserved;	/* Reserved */ | ||||
| 	long	dataoff;	/* Picture data location */ | ||||
| 	long	hsize;		/* Header-Size */ | ||||
| 	long	width;		/* Picture width (pixels) */ | ||||
| 	long	height;		/* Picture height (pixels) */ | ||||
| 	short	planes;		/* Planes (must be 1) */ | ||||
| 	short	bpp;		/* Bits per pixel (1, 4, 8 or 24) */ | ||||
| 	long	compression;	/* Compression mode */ | ||||
| 	long	imagesize;	/* Image size (bytes) */ | ||||
| 	long	hres;		/* Horizontal Resolution (pels/meter) */ | ||||
| 	long	vres;		/* Vertical Resolution (pels/meter) */ | ||||
| 	long	colours;	/* Used Colours (Col-Table index) */ | ||||
| 	long	impcolours;	/* Important colours (Col-Table index) */ | ||||
| } Infohdr; | ||||
							
								
								
									
										47
									
								
								sys/src/cmd/pict/build.json
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								sys/src/cmd/pict/build.json
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| { | ||||
| 	"Cmd": { | ||||
| 		"Include": [ | ||||
| 			"../cmd.json" | ||||
| 		], | ||||
| 		"Install": "/arch/$ARCH/cmd/pict/", | ||||
| 		"SourceFiles": [ | ||||
| 			"torgbv.c", | ||||
| 			"totruecolor.c", | ||||
| 			"writerawimage.c", | ||||
| 			"readjpg.c", | ||||
| 			"writejpg.c", | ||||
| 			"multichan.c", | ||||
| 			"readgif.c", | ||||
| 			"writegif.c", | ||||
| 			"onechan.c", | ||||
| 			"readpng.c", | ||||
| 			"writepng.c", | ||||
| 			"readppm.c", | ||||
| 			"writeppm.c", | ||||
| 			"readtif.c", | ||||
| 			"writetif.c", | ||||
| 			"readyuv.c", | ||||
| 			"readbmp.c", | ||||
| 			"readtga.c", | ||||
| 			"readv210.c" | ||||
| 		], | ||||
| 		"SourceFilesCmd": [ | ||||
| 			"jpg.c", | ||||
| 			"tojpg.c", | ||||
| 			"gif.c", | ||||
| 			"togif.c", | ||||
| 			"ppm.c", | ||||
| 			"toppm.c", | ||||
| 			"png.c", | ||||
| 			"topng.c", | ||||
| 			"tif.c", | ||||
| 			"totif.c", | ||||
| 			"yuv.c", | ||||
| 			"ico.c", | ||||
| 			"toico.c", | ||||
| 			"bmp.c", | ||||
| 			"tga.c", | ||||
| 			"v210.c" | ||||
| 		] | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										121
									
								
								sys/src/cmd/pict/close.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								sys/src/cmd/pict/close.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
|  | ||||
| float c1 = 1.402; | ||||
| float c2 = 0.34414; | ||||
| float c3 = 0.71414; | ||||
| float c4 = 1.772; | ||||
|  | ||||
|  | ||||
| int | ||||
| closest(int Y, int Cb, int Cr) | ||||
| { | ||||
| 	double r, g, b; | ||||
| 	double diff, min; | ||||
| 	int rgb, R, G, B, v, i; | ||||
| 	int y1, cb1, cr1; | ||||
|  | ||||
| 	Cb -= 128; | ||||
| 	Cr -= 128; | ||||
| 	r = Y+c1*Cr; | ||||
| 	g = Y-c2*Cb-c3*Cr; | ||||
| 	b = Y+c4*Cb; | ||||
|  | ||||
| //print("YCbCr: %d %d %d, RGB: %g %g %g\n", Y, Cb, Cr, r, g, b); | ||||
|  | ||||
| 	min = 1000000.; | ||||
| 	v = 1000; | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		rgb =  cmap2rgb(i); | ||||
| 		R = (rgb >> 16) & 0xFF; | ||||
| 		G = (rgb >> 8) & 0xFF; | ||||
| 		B = (rgb >> 0) & 0xFF; | ||||
| 		diff = (R-r)*(R-r) + (G-g)*(G-g) + (B-b)*(B-b); | ||||
| //		y1 = 0.5870*G + 0.114*B + 0.299*R; | ||||
| //		cb1 = (B-y1)/1.772; | ||||
| //		cr1 = (R-y1)/1.402; | ||||
| 		if(diff < min){ | ||||
| //			if(Y==0 && y1!=0) | ||||
| //				continue; | ||||
| //			if(Y==256-16 && y1<256-16) | ||||
| //				continue; | ||||
| //			if(Cb==0 && cb1!=0) | ||||
| //				continue; | ||||
| //			if(Cb==256-16 && cb1<256-16) | ||||
| //				continue; | ||||
| //			if(Cr==0 && cr1!=0) | ||||
| //				continue; | ||||
| //			if(Cr==256-16 && cr1<256-16) | ||||
| //				continue; | ||||
| //print("%d %d %d\n", R, G, B); | ||||
| 			min = diff; | ||||
| 			v = i; | ||||
| 		} | ||||
| 	} | ||||
| 	if(v > 255) | ||||
| 		abort(); | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| #define 	SHIFT	5 | ||||
| #define	INC		(1<<SHIFT) | ||||
|  | ||||
| typedef struct Color Color; | ||||
|  | ||||
| struct Color | ||||
| { | ||||
| 	int		col; | ||||
| 	Color	*next; | ||||
| }; | ||||
|  | ||||
| Color	*col[INC*INC*INC]; | ||||
|  | ||||
| void | ||||
| add(int c, int y, int cb, int cr) | ||||
| { | ||||
| 	Color *cp; | ||||
|  | ||||
| 	y >>= 8-SHIFT; | ||||
| 	cb >>= 8-SHIFT; | ||||
| 	cr >>= 8-SHIFT; | ||||
| 	cp = col[cr+INC*(cb+INC*y)]; | ||||
| 	while(cp != nil){ | ||||
| 		if(cp->col == c) | ||||
| 			return; | ||||
| 		cp = cp->next; | ||||
| 	} | ||||
| 	cp = malloc(sizeof(Color)); | ||||
| 	cp->col = c; | ||||
| 	cp->next = col[cr+INC*(cb+INC*y)]; | ||||
| 	col[cr+INC*(cb+INC*y)] = cp; | ||||
| } | ||||
|  | ||||
| void | ||||
| main(void) | ||||
| { | ||||
| 	int y, cb, cr, n; | ||||
| 	Color *cp; | ||||
|  | ||||
| 	for(y=0; y<256; y++){ | ||||
| 		for(cb=0; cb<256; cb++) | ||||
| 			for(cr=0;cr<256;cr++) | ||||
| 				add(closest(y, cb, cr), y, cb, cr); | ||||
| 		fprint(2, "%d done\n", y); | ||||
| 	} | ||||
| 	for(y=0; y<INC*INC*INC; y++){ | ||||
| 		n = 0; | ||||
| 		cp = col[y]; | ||||
| 		while(cp != nil){ | ||||
| 			n++; | ||||
| 			cp = cp->next; | ||||
| 		} | ||||
| 		cp = col[y]; | ||||
| 		while(cp != nil){ | ||||
| 			n++; | ||||
| 			print("%d ", cp->col); | ||||
| 			cp = cp->next; | ||||
| 		} | ||||
| 		print("\n"); | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										437
									
								
								sys/src/cmd/pict/gif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										437
									
								
								sys/src/cmd/pict/gif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,437 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| Image	**allims; | ||||
| int		which; | ||||
| int		defaultcolor = 1; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rectangle | ||||
| imager(void) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	if(allims==nil || allims[0]==nil) | ||||
| 		return screen->r; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(allims[0]->r.max, allims[0]->r.min), 2), allims[0]->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(allims[0]->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "gif: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(allims==nil || allims[which]==nil) | ||||
| 		return; | ||||
| 	r = imager(); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	draw(screen, r, allims[which], nil, allims[which]->r.min); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: gif -39cdektv  [file.gif ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "gif: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if(output && argc>1 && err==nil){ | ||||
| 				fprint(2, "gif: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| Image* | ||||
| transparency(Rawimage *r, char *name) | ||||
| { | ||||
| 	Image *i; | ||||
| 	int j, index; | ||||
| 	unsigned char *pic, *mpic, *mask; | ||||
|  | ||||
| 	if((r->gifflags&TRANSP) == 0) | ||||
| 		return nil; | ||||
| 	i = allocimage(display, r->r, GREY8, 0, 0); | ||||
| 	if(i == nil){ | ||||
| 		fprint(2, "gif: allocimage for mask of %s failed: %r\n", name); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	pic = r->chans[0]; | ||||
| 	mask = malloc(r->chanlen); | ||||
| 	if(mask == nil){ | ||||
| 		fprint(2, "gif: malloc for mask of %s failed: %r\n", name); | ||||
| 		freeimage(i); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	index = r->giftrindex; | ||||
| 	mpic = mask; | ||||
| 	for(j=0; j<r->chanlen; j++) | ||||
| 		if(*pic++ == index) | ||||
| 			*mpic++ = 0; | ||||
| 		else | ||||
| 			*mpic++ = 0xFF; | ||||
| 	if(loadimage(i, i->r, mask, r->chanlen) < 0){ | ||||
| 		fprint(2, "gif: loadimage for mask of %s failed: %r\n", name); | ||||
| 		free(mask); | ||||
| 		freeimage(i); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	free(mask); | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| /* interleave alpha values of 0xFF in data stream. alpha value comes first, then b g r */ | ||||
| unsigned char* | ||||
| expand(unsigned char *u, int chanlen, int nchan) | ||||
| { | ||||
| 	int j, k; | ||||
| 	unsigned char *v, *up, *vp; | ||||
|  | ||||
| 	v = malloc(chanlen*(nchan+1)); | ||||
| 	if(v == nil){ | ||||
| 		fprint(2, "gif: malloc fails: %r\n"); | ||||
| 		exits("malloc"); | ||||
| 	} | ||||
| 	up = u; | ||||
| 	vp = v; | ||||
| 	for(j=0; j<chanlen; j++){ | ||||
| 		*vp++ = 0xFF; | ||||
| 		for(k=0; k<nchan; k++) | ||||
| 			*vp++ = *up++; | ||||
| 	} | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void | ||||
| addalpha(Rawimage *i) | ||||
| { | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	switch(outchan){ | ||||
| 	case CMAP8: | ||||
| 		i->chans[0] = expand(i->chans[0], i->chanlen/1, 1); | ||||
| 		i->chanlen = 2*(i->chanlen/1); | ||||
| 		i->chandesc = CRGBVA16; | ||||
| 		outchan = CHAN2(CMap, 8, CAlpha, 8); | ||||
| 		break; | ||||
|  | ||||
| 	case GREY8: | ||||
| 		i->chans[0] = expand(i->chans[0], i->chanlen/1, 1); | ||||
| 		i->chanlen = 2*(i->chanlen/1); | ||||
| 		i->chandesc = CYA16; | ||||
| 		outchan = CHAN2(CGrey, 8, CAlpha, 8); | ||||
| 		break; | ||||
|  | ||||
| 	case RGB24: | ||||
| 		i->chans[0] = expand(i->chans[0], i->chanlen/3, 3); | ||||
| 		i->chanlen = 4*(i->chanlen/3); | ||||
| 		i->chandesc = CRGBA32; | ||||
| 		outchan = RGBA32; | ||||
| 		break; | ||||
|  | ||||
| 	default: | ||||
| 		chantostr(buf, outchan); | ||||
| 		fprint(2, "gif: can't add alpha to type %s\n", buf); | ||||
| 		exits("err"); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Called only when writing output.  If the output is RGBA32, | ||||
|  * we must write four bytes per pixel instead of two. | ||||
|  * There's always at least two: data plus alpha. | ||||
|  * r is used only for reference; the image is already in c. | ||||
|  */ | ||||
| void | ||||
| blackout(Rawimage *r, Rawimage *c) | ||||
| { | ||||
| 	int i, trindex; | ||||
| 	unsigned char *rp, *cp; | ||||
|  | ||||
| 	rp = r->chans[0]; | ||||
| 	cp = c->chans[0]; | ||||
| 	trindex = r->giftrindex; | ||||
| 	if(outchan == RGBA32) | ||||
| 		for(i=0; i<r->chanlen; i++){ | ||||
| 			if(*rp == trindex){ | ||||
| 				*cp++ = 0x00; | ||||
| 				*cp++ = 0x00; | ||||
| 				*cp++ = 0x00; | ||||
| 				*cp++ = 0x00; | ||||
| 			}else{ | ||||
| 				*cp++ = 0xFF; | ||||
| 				cp += 3; | ||||
| 			} | ||||
| 			rp++; | ||||
| 		} | ||||
| 	else | ||||
| 		for(i=0; i<r->chanlen; i++){ | ||||
| 			if(*rp == trindex){ | ||||
| 				*cp++ = 0x00; | ||||
| 				*cp++ = 0x00; | ||||
| 			}else{ | ||||
| 				*cp++ = 0xFF; | ||||
| 				cp++; | ||||
| 			} | ||||
| 			rp++; | ||||
| 		} | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "gif: initdraw failed: %r\n"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **images, **rgbv; | ||||
| 	Image *tmp, *msk, *img, *dst, **ims; | ||||
| 	Rectangle r; | ||||
| 	int j, k, n, ch, nloop, loopcount, dt; | ||||
| 	char *err; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	err = nil; | ||||
| 	images = readgif(fd, CRGB, dflag); | ||||
| 	if(images == nil){ | ||||
| 		fprint(2, "gif: decode %s failed: %r\n", 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*)); | ||||
| 	rgbv = malloc((n+1)*sizeof(Rawimage*)); | ||||
| 	if(rgbv==nil || ims==nil){ | ||||
| 		fprint(2, "gif: malloc of masks for %s failed: %r\n", name); | ||||
| 		err = "malloc"; | ||||
| 		goto Return; | ||||
| 	} | ||||
| 	memset(ims, 0, (n+1)*sizeof(Image*)); | ||||
| 	memset(rgbv, 0, (n+1)*sizeof(Rawimage*)); | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0){ | ||||
| 			err = "initdraw"; | ||||
| 			goto Return; | ||||
| 		} | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
|  | ||||
| 	for(k=0; k<n; k++){ | ||||
| 		if(outchan == CMAP8) | ||||
| 			rgbv[k] = torgbv(images[k], !eflag); | ||||
| 		else{ | ||||
| 			if(outchan==GREY8 || (images[k]->chandesc==CY && threeflag==0)) | ||||
| 				rgbv[k] = totruecolor(images[k], CY); | ||||
| 			else | ||||
| 				rgbv[k] = totruecolor(images[k], CRGB24); | ||||
| 		} | ||||
| 		if(rgbv[k] == nil){ | ||||
| 			fprint(2, "gif: converting %s to local format failed: %r\n", name); | ||||
| 			err = "torgbv"; | ||||
| 			goto Return; | ||||
| 		} | ||||
| 		if(!dflag){ | ||||
| 			msk = transparency(images[k], name); | ||||
| 			if(rgbv[k]->chandesc == CY) | ||||
| 				img = allocimage(display, rgbv[k]->r, GREY8, 0, 0); | ||||
| 			else | ||||
| 				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(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){ | ||||
| 			default: | ||||
| 				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; | ||||
| 	loopcount = images[0]->gifloopcount; | ||||
| 	if(!dflag){ | ||||
| 		nloop = 0; | ||||
| 		do{ | ||||
| 			for(k=0; k<n; k++){ | ||||
| 				which = k; | ||||
| 				eresized(0); | ||||
| 				dt = images[k]->gifdelay*10; | ||||
| 				if(dt < 50) | ||||
| 					dt = 50; | ||||
| 				while(n==1 || ecankbd()){ | ||||
| 					/* an odd, democratic list */ | ||||
| 					if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 						exits(nil); | ||||
| 					if(ch == '\n') | ||||
| 						goto Out; | ||||
| 				}sleep(dt); | ||||
| 			} | ||||
| 			/* loopcount -1 means no loop (this code's rule), loopcount 0 means loop forever (netscape's rule)*/ | ||||
| 		}while(loopcount==0 || ++nloop<loopcount); | ||||
| 		/* loop count has run out */ | ||||
| 		ekbd(); | ||||
|     Out: | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		if(images[0]->gifflags&TRANSP){ | ||||
| 			addalpha(rgbv[0]); | ||||
| 			blackout(images[0], rgbv[0]); | ||||
| 		} | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			rgbv[0]->r.min.x, rgbv[0]->r.min.y, rgbv[0]->r.max.x, rgbv[0]->r.max.y); | ||||
| 		if(write(1, rgbv[0]->chans[0], rgbv[0]->chanlen) != rgbv[0]->chanlen){ | ||||
| 			fprint(2, "gif: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(images[0]->gifflags&TRANSP){ | ||||
| 			addalpha(rgbv[0]); | ||||
| 			blackout(images[0], rgbv[0]); | ||||
| 		} | ||||
| 		if(writerawimage(1, rgbv[0]) < 0){ | ||||
| 			fprint(2, "gif: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|     Return: | ||||
| 	allims = nil; | ||||
| 	for(k=0; images[k]; k++){ | ||||
| 		for(j=0; j<images[k]->nchans; j++) | ||||
| 			free(images[k]->chans[j]); | ||||
| 		free(images[k]->cmap); | ||||
| 		if(rgbv[k]) | ||||
| 			free(rgbv[k]->chans[0]); | ||||
| 		freeimage(ims[k]); | ||||
| 		free(images[k]); | ||||
| 		free(rgbv[k]); | ||||
| 	} | ||||
| 	free(images); | ||||
| 	free(ims); | ||||
| 	return err; | ||||
| } | ||||
							
								
								
									
										627
									
								
								sys/src/cmd/pict/ico.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										627
									
								
								sys/src/cmd/pict/ico.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,627 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <event.h> | ||||
| #include <cursor.h> | ||||
|  | ||||
| #include "imagefile.h" | ||||
|  | ||||
| typedef struct Icon Icon; | ||||
| struct Icon | ||||
| { | ||||
| 	Icon	*next; | ||||
|  | ||||
| 	unsigned char	w;		/* icon width */ | ||||
| 	unsigned char	h;		/* icon height */ | ||||
| 	unsigned short	ncolor;		/* number of colors */ | ||||
| 	unsigned short	nplane;		/* number of bit planes */ | ||||
| 	unsigned short	bits;		/* bits per pixel */ | ||||
| 	uint32_t	len;		/* length of data */ | ||||
| 	uint32_t	offset;		/* file offset to data */ | ||||
|  | ||||
| 	Memimage	*img; | ||||
| 	Memimage	*mask; | ||||
|  | ||||
| 	Rectangle r;		/* relative */ | ||||
| 	Rectangle sr;		/* abs */ | ||||
| }; | ||||
|  | ||||
| typedef struct Header Header; | ||||
| struct Header | ||||
| { | ||||
| 	uint	n; | ||||
| 	Icon	*first; | ||||
| 	Icon	*last; | ||||
| }; | ||||
|  | ||||
| int debug; | ||||
| int cflag; | ||||
| Mouse mouse; | ||||
| Header h; | ||||
| Image *background; | ||||
|  | ||||
| unsigned short | ||||
| gets(unsigned char *p) | ||||
| { | ||||
| 	return p[0] | (p[1]<<8); | ||||
| } | ||||
|  | ||||
| uint32_t | ||||
| getl(unsigned char *p) | ||||
| { | ||||
| 	return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24); | ||||
| } | ||||
|  | ||||
| int | ||||
| Bgetheader(Biobuf *b, Header *h) | ||||
| { | ||||
| 	unsigned char buf[40]; | ||||
| 	Icon *icon; | ||||
| 	int i; | ||||
|  | ||||
| 	memset(h, 0, sizeof(*h)); | ||||
| 	if(Bread(b, buf, 6) != 6) | ||||
| 		goto eof; | ||||
| 	if(gets(&buf[0]) != 0) | ||||
| 		goto header; | ||||
| 	if(gets(&buf[2]) != 1) | ||||
| 		goto header; | ||||
| 	h->n = gets(&buf[4]); | ||||
| 	for(i = 0; i < h->n; i++){ | ||||
| 		icon = mallocz(sizeof(*icon), 1); | ||||
| 		if(icon == nil) | ||||
| 			sysfatal("malloc: %r"); | ||||
| 		if(Bread(b, buf, 16) != 16) | ||||
| 			goto eof; | ||||
| 		icon->w = buf[0] == 0 ? 256 : buf[0]; | ||||
| 		icon->h = buf[1] == 0 ? 256 : buf[1]; | ||||
| 		icon->ncolor = buf[2] == 0 ? 256 : buf[2]; | ||||
| 		icon->nplane = gets(&buf[4]); | ||||
| 		icon->bits = gets(&buf[6]); | ||||
| 		icon->len = getl(&buf[8]); | ||||
| 		icon->offset = getl(&buf[12]); | ||||
| 		if(i == 0) | ||||
| 			h->first = icon; | ||||
| 		else | ||||
| 			h->last->next = icon; | ||||
| 		h->last = icon; | ||||
| 	} | ||||
| 	return 0; | ||||
|  | ||||
| eof: | ||||
| 	werrstr("unexpected EOF"); | ||||
| 	return -1; | ||||
| header: | ||||
| 	werrstr("unknown header format"); | ||||
| 	return -1; | ||||
| } | ||||
|  | ||||
| unsigned char* | ||||
| transcmap(Icon *icon, int ncolor, unsigned char *map) | ||||
| { | ||||
| 	unsigned char *m, *p; | ||||
| 	int i; | ||||
|  | ||||
| 	p = m = mallocz(sizeof(int)*(1<<icon->bits), 1); | ||||
| 	if(m == nil) | ||||
| 		sysfatal("malloc: %r"); | ||||
| 	for(i = 0; i < ncolor; i++){ | ||||
| 		*p++ = rgb2cmap(map[2], map[1], map[0]); | ||||
| 		map += 4; | ||||
| 	} | ||||
| 	return m; | ||||
| } | ||||
|  | ||||
| Memimage* | ||||
| xor2img(Icon *icon, long chan, unsigned char *xor, unsigned char *map) | ||||
| { | ||||
| 	unsigned char *data; | ||||
| 	Memimage *img; | ||||
| 	int inxlen; | ||||
| 	unsigned char *from, *to; | ||||
| 	int s, byte, mask; | ||||
| 	int x, y; | ||||
|  | ||||
| 	inxlen = 4*((icon->bits*icon->w+31)/32); | ||||
| 	img = allocmemimage(Rect(0,0,icon->w,icon->h), chan); | ||||
| 	if(img == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	if(chan != CMAP8){ | ||||
| 		from = xor + icon->h*inxlen; | ||||
| 		for(y = 0; y < icon->h; y++){ | ||||
| 			from -= inxlen; | ||||
| 			loadmemimage(img, Rect(0,y,icon->w,y+1), from, inxlen); | ||||
| 		} | ||||
| 		return img; | ||||
| 	} | ||||
|  | ||||
| 	to = data = malloc(icon->w*icon->h); | ||||
| 	if(data == nil){ | ||||
| 		freememimage(img); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	/* rotate around the y axis, go to 8 bits, and convert color */ | ||||
| 	mask = (1<<icon->bits)-1; | ||||
| 	for(y = 0; y < icon->h; y++){ | ||||
| 		s = -1; | ||||
| 		byte = 0; | ||||
| 		from = xor + (icon->h - 1 - y)*inxlen; | ||||
| 		for(x = 0; x < icon->w; x++){ | ||||
| 			if(s < 0){ | ||||
| 				byte = *from++; | ||||
| 				s = 8-icon->bits; | ||||
| 			} | ||||
| 			*to++ = map[(byte>>s) & mask]; | ||||
| 			s -= icon->bits; | ||||
| 		} | ||||
| 	} | ||||
| 	/* stick in an image */ | ||||
| 	loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w); | ||||
| 	free(data); | ||||
| 	return img; | ||||
| } | ||||
|  | ||||
| Memimage* | ||||
| and2img(Icon *icon, unsigned char *and) | ||||
| { | ||||
| 	unsigned char *data; | ||||
| 	Memimage *img; | ||||
| 	int inxlen; | ||||
| 	int outxlen; | ||||
| 	unsigned char *from, *to; | ||||
| 	int x, y; | ||||
|  | ||||
| 	inxlen = 4*((icon->w+31)/32); | ||||
| 	to = data = malloc(inxlen*icon->h); | ||||
| 	if(data == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	/* rotate around the y axis and invert bits */ | ||||
| 	outxlen = (icon->w+7)/8; | ||||
| 	for(y = 0; y < icon->h; y++){ | ||||
| 		from = and + (icon->h - 1 - y)*inxlen; | ||||
| 		for(x = 0; x < outxlen; x++) | ||||
| 			*to++ = ~(*from++); | ||||
| 	} | ||||
|  | ||||
| 	/* stick in an image */ | ||||
| 	if(img = allocmemimage(Rect(0,0,icon->w,icon->h), GREY1)) | ||||
| 		loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen); | ||||
|  | ||||
| 	free(data); | ||||
| 	return img; | ||||
| } | ||||
|  | ||||
| int | ||||
| Bgeticon(Biobuf *b, Icon *icon) | ||||
| { | ||||
| 	unsigned char *end; | ||||
| 	unsigned char *xor; | ||||
| 	unsigned char *and; | ||||
| 	unsigned char *cm; | ||||
| 	unsigned char *buf; | ||||
| 	unsigned char *map2map; | ||||
| 	Memimage *img; | ||||
| 	unsigned char magic[4]; | ||||
| 	int ncolor; | ||||
| 	long chan; | ||||
|  | ||||
| 	Bseek(b, icon->offset, 0); | ||||
| 	if(Bread(b, magic, 4) != 4){ | ||||
| 		werrstr("unexpected EOF"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(magic[0] == 137 && memcmp(magic+1, "PNG", 3) == 0){ | ||||
| 		Rawimage **png; | ||||
|  | ||||
| 		Bseek(b, -4, 1); | ||||
| 		png = Breadpng(b, CRGB); | ||||
| 		if(png == nil || png[0] == nil) | ||||
| 			return -1; | ||||
| 		switch(png[0]->chandesc){ | ||||
| 		case CY: | ||||
| 			chan = GREY8; | ||||
| 			break; | ||||
| 		case CYA16: | ||||
| 			chan = CHAN2(CGrey, 8, CAlpha, 8); | ||||
| 			break; | ||||
| 		case CRGB24: | ||||
| 			chan = RGB24; | ||||
| 			break; | ||||
| 		case CRGBA32: | ||||
| 			chan = RGBA32; | ||||
| 			break; | ||||
| 		default: | ||||
| 			werrstr("bad icon png channel descriptor"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		icon->mask = nil; | ||||
| 		icon->img = allocmemimage(png[0]->r, chan); | ||||
| 		loadmemimage(icon->img, icon->img->r, png[0]->chans[0], png[0]->chanlen); | ||||
| 		return 0; | ||||
| 	} | ||||
|  | ||||
| 	if(getl(magic) != 40){ | ||||
| 		werrstr("bad icon bmp header"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(icon->len < 40){ | ||||
| 		werrstr("bad icon bmp header length"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	buf = malloc(icon->len); | ||||
| 	if(buf == nil) | ||||
| 		return -1; | ||||
| 	memmove(buf, magic, 4); | ||||
| 	if(Bread(b, buf+4, icon->len-4) != icon->len-4){ | ||||
| 		werrstr("unexpected EOF"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* this header's info takes precedence over previous one */ | ||||
| 	ncolor = 0; | ||||
| 	icon->w = getl(buf+4); | ||||
| 	icon->h = getl(buf+8)>>1; | ||||
| 	icon->nplane = gets(buf+12); | ||||
| 	icon->bits = gets(buf+14); | ||||
|  | ||||
| 	/* limit what we handle */ | ||||
| 	switch(icon->bits){ | ||||
| 	case 1: | ||||
| 	case 2: | ||||
| 	case 4: | ||||
| 	case 8: | ||||
| 		ncolor = icon->ncolor; | ||||
| 		if(ncolor > (1<<icon->bits)) | ||||
| 			ncolor = 1<<icon->bits; | ||||
| 		chan = CMAP8; | ||||
| 		break; | ||||
| 	case 15: | ||||
| 	case 16: | ||||
| 		chan = RGB16; | ||||
| 		break; | ||||
| 	case 24: | ||||
| 		chan = RGB24; | ||||
| 		break; | ||||
| 	case 32: | ||||
| 		chan = ARGB32; | ||||
| 		break; | ||||
| 	default: | ||||
| 		werrstr("don't support %d bit pixels", icon->bits); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	if(icon->nplane != 1){ | ||||
| 		werrstr("don't support %d planes", icon->nplane); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	xor = cm = buf + 40; | ||||
| 	if(chan == CMAP8) | ||||
| 		xor += 4*ncolor; | ||||
| 	end = xor + icon->h*4*((icon->bits*icon->w+31)/32); | ||||
| 	if(end < buf || end > buf+icon->len){ | ||||
| 		werrstr("bad icon length %zux != %lux", end - buf, icon->len); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	/* translate the color map to a plan 9 one */ | ||||
| 	map2map = nil; | ||||
| 	if(chan == CMAP8) | ||||
| 		map2map = transcmap(icon, ncolor, cm); | ||||
|  | ||||
| 	/* convert the images */ | ||||
| 	icon->img = xor2img(icon, chan, xor, map2map); | ||||
| 	if(icon->img == nil){ | ||||
| 		werrstr("xor2img: %r"); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	icon->mask = nil; | ||||
|  | ||||
| 	/* check for and mask */ | ||||
| 	and = end; | ||||
| 	end += icon->h*4*((icon->w+31)/32); | ||||
| 	if(end <= buf+icon->len) | ||||
| 		icon->mask = and2img(icon, and); | ||||
|  | ||||
| 	/* so that we save an image with a white background */ | ||||
| 	if(img = allocmemimage(icon->img->r, icon->img->chan)){ | ||||
| 		memfillcolor(img, DWhite); | ||||
| 		memimagedraw(img, icon->img->r, icon->img, ZP, icon->mask, ZP, SoverD); | ||||
| 		freememimage(icon->img); | ||||
| 		icon->img = img; | ||||
| 	} | ||||
|  | ||||
| 	free(buf); | ||||
| 	free(map2map); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: %s [ -c ] [ file ]\n", argv0); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	Mimage, | ||||
| 	Mmask, | ||||
| 	Mexit, | ||||
|  | ||||
| 	Up= 1, | ||||
| 	Down= 0, | ||||
| }; | ||||
|  | ||||
| char	*menu3str[] = { | ||||
| 	[Mimage]	"write image", | ||||
| 	[Mmask]		"write mask", | ||||
| 	[Mexit]		"exit", | ||||
| 	0, | ||||
| }; | ||||
|  | ||||
| Menu	menu3 = { | ||||
| 	menu3str | ||||
| }; | ||||
|  | ||||
| Cursor sight = { | ||||
| 	{-7, -7}, | ||||
| 	{0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF, | ||||
| 	 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF, | ||||
| 	 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF, | ||||
| 	 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,}, | ||||
| 	{0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84, | ||||
| 	 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE, | ||||
| 	 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, | ||||
| 	 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,} | ||||
| }; | ||||
|  | ||||
| void | ||||
| buttons(int ud) | ||||
| { | ||||
| 	while((mouse.buttons==0) != ud) | ||||
| 		mouse = emouse(); | ||||
| } | ||||
|  | ||||
| void | ||||
| mesg(char *fmt, ...) | ||||
| { | ||||
| 	va_list arg; | ||||
| 	char buf[1024]; | ||||
| 	static char obuf[1024]; | ||||
|  | ||||
| 	va_start(arg, fmt); | ||||
| 	vseprint(buf, buf+sizeof(buf), fmt, arg); | ||||
| 	va_end(arg); | ||||
| 	string(screen, screen->r.min, background, ZP, font, obuf); | ||||
| 	string(screen, screen->r.min, display->white, ZP, font, buf); | ||||
| 	strcpy(obuf, buf); | ||||
| } | ||||
|  | ||||
| void | ||||
| doimage(Icon *icon) | ||||
| { | ||||
| 	int rv; | ||||
| 	char file[256]; | ||||
| 	int fd; | ||||
|  | ||||
| 	rv = -1; | ||||
| 	snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h); | ||||
| 	fd = create(file, OWRITE, 0664); | ||||
| 	if(fd >= 0){ | ||||
| 		rv = writememimage(fd, icon->img); | ||||
| 		close(fd); | ||||
| 	} | ||||
| 	if(rv < 0) | ||||
| 		mesg("error writing %s: %r", file); | ||||
| 	else | ||||
| 		mesg("created %s", file); | ||||
| } | ||||
|  | ||||
| void | ||||
| domask(Icon *icon) | ||||
| { | ||||
| 	int rv; | ||||
| 	char file[64]; | ||||
| 	int fd; | ||||
|  | ||||
| 	if(icon->mask == nil) | ||||
| 		return; | ||||
|  | ||||
| 	rv = -1; | ||||
| 	snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h); | ||||
| 	fd = create(file, OWRITE, 0664); | ||||
| 	if(fd >= 0){ | ||||
| 		rv = writememimage(fd, icon->mask); | ||||
| 		close(fd); | ||||
| 	} | ||||
| 	if(rv < 0) | ||||
| 		mesg("error writing %s: %r", file); | ||||
| 	else | ||||
| 		mesg("created %s", file); | ||||
| } | ||||
|  | ||||
| void | ||||
| apply(void (*f)(Icon*)) | ||||
| { | ||||
| 	Icon *icon; | ||||
|  | ||||
| 	esetcursor(&sight); | ||||
| 	buttons(Down); | ||||
| 	if(mouse.buttons == 4) | ||||
| 		for(icon = h.first; icon; icon = icon->next) | ||||
| 			if(ptinrect(mouse.xy, icon->sr)){ | ||||
| 				buttons(Up); | ||||
| 				f(icon); | ||||
| 				break; | ||||
| 			} | ||||
| 	buttons(Up); | ||||
| 	esetcursor(0); | ||||
| } | ||||
|  | ||||
| void | ||||
| menu(void) | ||||
| { | ||||
| 	int sel; | ||||
|  | ||||
| 	sel = emenuhit(3, &mouse, &menu3); | ||||
| 	switch(sel){ | ||||
| 	case Mimage: | ||||
| 		apply(doimage); | ||||
| 		break; | ||||
| 	case Mmask: | ||||
| 		apply(domask); | ||||
| 		break; | ||||
| 	case Mexit: | ||||
| 		exits(0); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| void | ||||
| mousemoved(void) | ||||
| { | ||||
| 	Icon *icon; | ||||
|  | ||||
| 	for(icon = h.first; icon; icon = icon->next) | ||||
| 		if(ptinrect(mouse.xy, icon->sr)){ | ||||
| 			mesg("%dx%d", icon->w, icon->h); | ||||
| 			return; | ||||
| 		} | ||||
| 	mesg(""); | ||||
| } | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	BORDER= 1, | ||||
| }; | ||||
|  | ||||
| Image* | ||||
| screenimage(Memimage *m) | ||||
| { | ||||
| 	Rectangle r; | ||||
| 	Image *i; | ||||
|  | ||||
| 	if(i = allocimage(display, m->r, m->chan, 0, DNofill)){ | ||||
| 		r = m->r; | ||||
| 		while(r.min.y < m->r.max.y){ | ||||
| 			r.max.y = r.min.y+1; | ||||
| 			loadimage(i, r, byteaddr(m, r.min), bytesperline(r, m->depth)); | ||||
| 			r.min.y++; | ||||
| 		} | ||||
| 	} | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Icon *icon; | ||||
| 	Image *i; | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0) | ||||
| 		sysfatal("can't reattach to window"); | ||||
| 	draw(screen, screen->clipr, background, nil, ZP); | ||||
| 	r.max.x = screen->r.min.x; | ||||
| 	r.min.y = screen->r.min.y + font->height + 2*BORDER; | ||||
| 	for(icon = h.first; icon != nil; icon = icon->next){ | ||||
| 		r.min.x = r.max.x + BORDER; | ||||
| 		r.max.x = r.min.x + Dx(icon->img->r); | ||||
| 		r.max.y = r.min.y + Dy(icon->img->r); | ||||
| 		if(i = screenimage(icon->img)){ | ||||
| 			draw(screen, r, i, nil, ZP); | ||||
| 			freeimage(i); | ||||
| 		} | ||||
| 		border(screen, r, -BORDER, display->black, ZP); | ||||
| 		icon->sr = r; | ||||
| 	} | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	Biobuf in; | ||||
| 	Icon *icon; | ||||
| 	int num, fd; | ||||
| 	Rectangle r; | ||||
| 	Event e; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case 'd': | ||||
| 		debug = 1; | ||||
| 		break; | ||||
| 	case 'c': | ||||
| 		cflag = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	fd = -1; | ||||
| 	switch(argc){ | ||||
| 	case 0: | ||||
| 		fd = 0; | ||||
| 		break; | ||||
| 	case 1: | ||||
| 		fd = open(argv[0], OREAD); | ||||
| 		if(fd < 0) | ||||
| 			sysfatal("opening: %r"); | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	memimageinit(); | ||||
| 	Binit(&in, fd, OREAD); | ||||
|  | ||||
| 	if(Bgetheader(&in, &h) < 0) | ||||
| 		sysfatal("reading header: %r"); | ||||
|  | ||||
| 	num = 0; | ||||
| 	r.min = Pt(4, 4); | ||||
| 	for(icon = h.first; icon != nil; icon = icon->next){ | ||||
| 		if(Bgeticon(&in, icon) < 0){ | ||||
| 			fprint(2, "%s: read fail: %r\n", argv0); | ||||
| 			continue; | ||||
| 		} | ||||
| 		if(debug) | ||||
| 			fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n", | ||||
| 			   icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset); | ||||
| 		r.max = addpt(r.min, Pt(icon->w, icon->h)); | ||||
| 		icon->r = r; | ||||
| 		if(cflag){ | ||||
| 			writememimage(1, icon->img); | ||||
| 			exits(0); | ||||
| 		} | ||||
| 		r.min.x += r.max.x; | ||||
| 		num++; | ||||
| 	} | ||||
|  | ||||
| 	if(num == 0 || cflag) | ||||
| 		sysfatal("no images"); | ||||
|  | ||||
| 	initdraw(nil, nil, "ico"); | ||||
| 	background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x808080FF); | ||||
| 	eresized(0); | ||||
| 	einit(Emouse|Ekeyboard); | ||||
| 	for(;;) | ||||
| 		switch(event(&e)){ | ||||
| 		case Ekeyboard: | ||||
| 			break; | ||||
| 		case Emouse: | ||||
| 			mouse = e.mouse; | ||||
| 			if(mouse.buttons & 4) | ||||
| 				menu(); | ||||
| 			else | ||||
| 				mousemoved(); | ||||
| 			break; | ||||
| 		} | ||||
| 	/* not reached */ | ||||
| } | ||||
							
								
								
									
										86
									
								
								sys/src/cmd/pict/imagefile.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								sys/src/cmd/pict/imagefile.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| typedef struct Rawimage Rawimage; | ||||
|  | ||||
| struct Rawimage | ||||
| { | ||||
| 	Rectangle	r; | ||||
| 	unsigned char	*cmap; | ||||
| 	int		cmaplen; | ||||
| 	int		nchans; | ||||
| 	unsigned char	*chans[4]; | ||||
| 	int		chandesc; | ||||
| 	int		chanlen; | ||||
|  | ||||
| 	int		fields;    	/* defined by format */ | ||||
| 	int		gifflags;	/* gif only; graphics control extension flag word */ | ||||
| 	int		gifdelay;	/* gif only; graphics control extension delay in cs */ | ||||
| 	int		giftrindex;	/* gif only; graphics control extension transparency index */ | ||||
| 	int		gifloopcount;	/* number of times to loop in animation; 0 means forever */ | ||||
| }; | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	/* Channel descriptors */ | ||||
| 	CRGB	= 0,	/* three channels, no map */ | ||||
| 	CYCbCr	= 1,	/* three channels, no map, level-shifted 601 color space */ | ||||
| 	CY	= 2,	/* one channel, luminance */ | ||||
| 	CRGB1	= 3,	/* one channel, map present */ | ||||
| 	CRGBV	= 4,	/* one channel, map is RGBV, understood */ | ||||
| 	CRGB24	= 5,	/* one channel in correct data order for loadimage(RGB24) */ | ||||
| 	CRGBA32	= 6,	/* one channel in correct data order for loadimage(RGBA32) */ | ||||
| 	CYA16	= 7,	/* one channel in correct data order for loadimage(Grey8+Alpha8) */ | ||||
| 	CRGBVA16= 8,	/* one channel in correct data order for loadimage(CMAP8+Alpha8) */ | ||||
|  | ||||
| 	/* GIF flags */ | ||||
| 	TRANSP	= 1, | ||||
| 	INPUT	= 2, | ||||
| 	DISPMASK = 7<<2 | ||||
| }; | ||||
|  | ||||
|  | ||||
| enum{	/* PNG flags */ | ||||
| 	II_GAMMA =	1 << 0, | ||||
| 	II_COMMENT =	1 << 1, | ||||
| }; | ||||
|  | ||||
| typedef struct ImageInfo { | ||||
| 	uint32_t	fields_set; | ||||
| 	double	gamma; | ||||
| 	char	*comment; | ||||
| } ImageInfo; | ||||
|  | ||||
|  | ||||
| Rawimage**	readjpg(int, int); | ||||
| Rawimage**	Breadjpg(Biobuf*, int); | ||||
| Rawimage**	readpng(int, int); | ||||
| Rawimage**	Breadpng(Biobuf*, int); | ||||
| Rawimage**	readtif(int, int); | ||||
| Rawimage**	Breadtif(Biobuf*, int); | ||||
| Rawimage**	readgif(int, int, int); | ||||
| Rawimage**	readpixmap(int, int); | ||||
| Rawimage*	torgbv(Rawimage*, int); | ||||
| Rawimage*	totruecolor(Rawimage*, int); | ||||
| int		writerawimage(int, Rawimage*); | ||||
| void*		_remaperror(char*, ...); | ||||
|  | ||||
| typedef struct Memimage Memimage;	/* avoid necessity to include memdraw.h */ | ||||
|  | ||||
| char*		startgif(Biobuf*, Image*, int); | ||||
| char*		writegif(Biobuf*, Image*, char*, int, int); | ||||
| void		endgif(Biobuf*); | ||||
| char*		memstartgif(Biobuf*, Memimage*, int); | ||||
| char*		memwritegif(Biobuf*, Memimage*, char*, int, int); | ||||
| void		memendgif(Biobuf*); | ||||
| Image*		onechan(Image*); | ||||
| Memimage*	memonechan(Memimage*); | ||||
|  | ||||
| char*		writeppm(Biobuf*, Image*, char*, int); | ||||
| char*		memwriteppm(Biobuf*, Memimage*, char*, int); | ||||
| char*		writejpg(Biobuf*, Image*, char*, int, int); | ||||
| char*		memwritejpg(Biobuf*, Memimage*, char*, int, int); | ||||
| Image*		multichan(Image*); | ||||
| Memimage*	memmultichan(Memimage*); | ||||
|  | ||||
| char*		memwritepng(Biobuf*, Memimage*, ImageInfo*); | ||||
|  | ||||
| char*		writetif(Biobuf*, Image*, char*, int, int); | ||||
| char*		memwritetif(Biobuf*, Memimage*, char*, int, int); | ||||
							
								
								
									
										346
									
								
								sys/src/cmd/pict/jpegdump.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										346
									
								
								sys/src/cmd/pict/jpegdump.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,346 @@ | ||||
| /* jpeg parser by tom szymanski */ | ||||
| #include <stddef.h> | ||||
| #include <stdlib.h> | ||||
| #include <stdio.h> | ||||
| #include <string.h> | ||||
| #include <math.h> | ||||
| #include <ctype.h> | ||||
|  | ||||
| /* subroutines done by macros */ | ||||
| #define min(A,B)	((A)<(B) ? (A) : (B)) | ||||
| #define max(A,B)	((A)>(B) ? (A) : (B)) | ||||
| #define maxeql(A,B)	if (A < (B)) A = (B); | ||||
| #define mineql(A,B)	if (A > (B)) A = (B); | ||||
| #define eatarg0		(argc--, argv++) | ||||
| #define arrayLength(A) ((sizeof A)/ (sizeof A[0])) | ||||
|  | ||||
| FILE *infile; | ||||
| char *fname; | ||||
|  | ||||
| /* Routines to print error messages of varying severity */ | ||||
|  | ||||
| /* externally visible variables */ | ||||
| int   warncnt; | ||||
| char *myname; | ||||
|  | ||||
| void getname (char *arg) { | ||||
| 	/* Save name of invoking program for use by error routines */ | ||||
| 	register char *p; | ||||
| 	p = strrchr (arg, '/'); | ||||
| 	if (p == NULL) | ||||
| 		myname = arg; | ||||
| 	else | ||||
| 		myname = ++p; | ||||
| } | ||||
|  | ||||
| static void introduction (void) { | ||||
| 	warncnt++; | ||||
| 	fflush (stdout); | ||||
| 	if (myname != NULL) | ||||
| 		fprintf (stderr, "%s: ", myname); | ||||
| } | ||||
|  | ||||
| void warn (char *fmt, ...) { | ||||
| 	va_list args; | ||||
| 	introduction (); | ||||
| 	va_start (args, fmt); | ||||
| 	vfprintf (stderr, fmt, args); | ||||
| 	va_end (args); | ||||
| 	fputc ('\n', stderr); | ||||
| 	fflush (stderr); | ||||
| } | ||||
|  | ||||
| void quit (char *fmt, ...) { | ||||
| 	va_list args; | ||||
| 	introduction (); | ||||
| 	va_start (args, fmt); | ||||
| 	vfprintf (stderr, fmt, args); | ||||
| 	va_end (args); | ||||
| 	fputc ('\n', stderr); | ||||
| 	fflush (stderr); | ||||
| 	exit (1); | ||||
| } | ||||
|  | ||||
| void fatal (char *fmt, ...) { | ||||
| 	va_list args; | ||||
| 	introduction (); | ||||
| 	va_start (args, fmt); | ||||
| 	vfprintf (stderr, fmt, args); | ||||
| 	va_end (args); | ||||
| 	fprintf (stderr, "\nbetter get help!\n"); | ||||
| 	fflush (stderr); | ||||
| 	abort (); | ||||
| } | ||||
|  | ||||
| int toption = 0; | ||||
| int dqt[16][64]; | ||||
|  | ||||
| int get1 (void) { | ||||
| 	unsigned char x; | ||||
| 	if (fread(&x, 1, 1, infile) == 0) | ||||
| 		quit ("unexpected EOF"); | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| int get2 (void) { | ||||
| 	int x; | ||||
|  | ||||
| 	x = get1() << 8; | ||||
| 	return x | get1(); | ||||
| } | ||||
|  | ||||
| void eatmarker (int kind) { | ||||
| 	int l, c; | ||||
| 	l = get2(); | ||||
| 	printf ("%02x len=%d\n", kind, l); | ||||
| 	for (l -= 2; l > 0; l--) | ||||
| 		get1(); | ||||
| } | ||||
|  | ||||
| char *sofName[16] = { | ||||
| 	"Baseline sequential DCT - Huffman coding", | ||||
| 	"Extended sequential DCT - Huffman coding", | ||||
| 	"Progressive DCT - Huffman coding", | ||||
| 	"Lossless - Huffman coding", | ||||
| 	"4 is otherwise used", | ||||
| 	"Sequential DCT - differential Huffman coding", | ||||
| 	"Progressive DCT - differential Huffman coding", | ||||
| 	"Lossless - differential Huffman coding", | ||||
| 	"8 is reserved", | ||||
| 	"Extended Sequential DCT - arithmetic coding", | ||||
| 	"Progressive DCT - arithmetic coding", | ||||
| 	"Lossless - arithmetic coding", | ||||
| 	"c is otherwise used", | ||||
| 	"Sequential DCT - differential arithmetic coding", | ||||
| 	"Progressive DCT - differential arithmetic coding", | ||||
| 	"Lossless - differential arithmetic coding", | ||||
| }; | ||||
|  | ||||
| void get_sof (int kind) { | ||||
| 	int i, length, height, width, precision, ncomponents; | ||||
| 	int id, sf, tab; | ||||
| 	length = get2(); | ||||
| 	precision = get1(); | ||||
| 	height = get2(); | ||||
| 	width = get2(); | ||||
| 	ncomponents = get1(); | ||||
| 	printf ("SOF%d:\t%s\n", kind - 0xc0, sofName[kind - 0xc0]); | ||||
| 	printf ("\t%d wide, %d high, %d deep, %d components\n", | ||||
| 		width, height, precision, ncomponents); | ||||
| 	for (i = 0; i < ncomponents; i++) { | ||||
| 		id = get1(); | ||||
| 		sf = get1(); | ||||
| 		tab = get1(); | ||||
| 		printf ("\tcomponent %d: %d hsample, %d vsample, quantization table %d\n", | ||||
| 			id, sf >> 4, sf & 0xf, tab); | ||||
| 	}		 | ||||
| } | ||||
|  | ||||
| void get_com (int kind) { | ||||
| 	int l, c; | ||||
| 	l = get2(); | ||||
| 	printf ("COM len=%d '", l); | ||||
| 	for (l -= 2; l > 0; l--) | ||||
| 		putchar (c = get1()); | ||||
| 	printf ("'\n"); | ||||
| } | ||||
|  | ||||
| void get_app (int kind) { | ||||
| 	int l, c, first; | ||||
| 	char buf[6]; | ||||
| 	int nbuf, nok; | ||||
| 	l = get2(); | ||||
| 	printf ("APP%d len=%d\n", kind - 0xe0, l); | ||||
| 	nbuf = 0; | ||||
| 	nok = 0; | ||||
| 	first = 1; | ||||
| 	/* dump printable strings in comment */ | ||||
| 	for (l -= 2; l > 0; l--){ | ||||
| 		c = get1(); | ||||
| 		if(isprint(c)){ | ||||
| 			if(nbuf >= sizeof buf){ | ||||
| 				if(!first && nbuf == nok) | ||||
| 					printf(" "); | ||||
| 				printf("%.*s", nbuf, buf); | ||||
| 				nbuf = 0; | ||||
| 				first = 0; | ||||
| 			} | ||||
| 			buf[nbuf++] = c; | ||||
| 			nok++; | ||||
| 		}else{ | ||||
| 			if(nok >= sizeof buf) | ||||
| 				if(nbuf > 0) | ||||
| 					printf("%.*s", nbuf, buf); | ||||
| 			nbuf = 0; | ||||
| 			nok = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if(nok >= sizeof buf) | ||||
| 		if(nbuf > 0){ | ||||
| 			if(!first && nbuf == nok) | ||||
| 				printf(" "); | ||||
| 			printf("%.*s", nbuf, buf); | ||||
| 		} | ||||
| } | ||||
|  | ||||
| void get_dac (int kind) { | ||||
| 	eatmarker (kind); | ||||
| } | ||||
|  | ||||
| int get1dqt (void) { | ||||
| 	int t, p, i, *tab; | ||||
| 	t = get1(); | ||||
| 	p = t >> 4; | ||||
| 	t = t & 0xf; | ||||
| 	printf ("DQT:\tp = %d, table = %d\n", p, t); | ||||
| 	tab = &dqt[t][0]; | ||||
| 	for (i = 0; i < 64; i++) | ||||
| 		tab[i] = p ? get2() : get1(); | ||||
| 	if (toption) { | ||||
| 		for (i = 0; i < 64; i++) | ||||
| 			printf ("\t%q[%02d] = %d\n", i, tab[i]); | ||||
| 	} | ||||
| 	return p ? 65 : 129; | ||||
| } | ||||
|  | ||||
| void get_dqt (int kind) { | ||||
| 	int length; | ||||
| 	length = get2() - 2; | ||||
| 	while (length > 0) | ||||
| 		length -= get1dqt(); | ||||
| } | ||||
|  | ||||
| int get1dht (void) { | ||||
| 	int l, tcth, p, i, j, v[16], vv[16][256]; | ||||
| 	tcth = get1(); | ||||
| 	printf ("DHT:\tclass = %d, table = %d\n", tcth >> 4, tcth & 0xf); | ||||
| 	for (i = 0; i < 16; i++) | ||||
| 		v[i] = get1(); | ||||
| 	l = 17; | ||||
| 	for (i = 0; i < 16; i++) | ||||
| 		for (j = 0; j < v[i]; j++) { | ||||
| 			vv[i][j] = get1(); | ||||
| 			l += 1; | ||||
| 		} | ||||
| 	if (toption) { | ||||
| 		for (i = 0; i < 16; i++) | ||||
| 			printf ("\t%l[%02d] = %d\n", i+1, v[i]); | ||||
| 		for (i = 0; i < 16; i++) | ||||
| 			for (j = 0; j < v[i]; j++) | ||||
| 				printf ("\t%v[%02d,%02d] = %d\n", i+1, j+1, vv[i][j]); | ||||
| 	} | ||||
| 	return l; | ||||
| } | ||||
|  | ||||
| void get_dht (int kind) { | ||||
| 	int length; | ||||
| 	length = get2() - 2; | ||||
| 	while (length > 0) | ||||
| 		length -= get1dht(); | ||||
| } | ||||
|  | ||||
| void get_sos (int kind) { | ||||
| 	int i, length, ncomponents, id, dcac, ahal; | ||||
| 	length = get2(); | ||||
| 	ncomponents = get1(); | ||||
| 	printf ("SOS:\t%d components\n", ncomponents); | ||||
| 	for (i = 0; i < ncomponents; i++) { | ||||
| 		id = get1(); | ||||
| 		dcac = get1(); | ||||
| 		printf ("\tcomponent %d: %d DC, %d AC\n", id, dcac >> 4, dcac & 0xf); | ||||
| 	} | ||||
| 	printf ("\tstart spectral %d\n", get1()); | ||||
| 	printf ("\tend spectral %d\n", get1()); | ||||
| 	ahal = get1(); | ||||
| 	printf ("\tah = %d, al = %d\n", ahal >> 4, ahal &0xf); | ||||
| } | ||||
|  | ||||
| main (int argc, char *argv[]) { | ||||
| 	int l, stuff, i, j, c; | ||||
| 	while (argc > 1 && argv[1][0] == '-') { | ||||
| 		switch (argv[1][1]) { | ||||
| 		case 't': | ||||
| 			toption = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			warn ("bad option '%c'", argv[1][1]); | ||||
| 		} | ||||
| 		eatarg0; | ||||
| 	} | ||||
| 	fname = argv[1]; | ||||
| 	infile = fopen (fname, "r"); | ||||
| 	if (infile == NULL) | ||||
| 		quit ("can't open %s\n", fname); | ||||
|     Start: | ||||
| //	if (get1() != 0xff || get1() != 0xd8) | ||||
| //		quit ("not JFIF"); | ||||
| //	printf ("SOI\n"); | ||||
| //	get_app (0xe0); | ||||
| 	for (;;) { | ||||
| 		c = get1(); | ||||
| 		if (c != 0xff) | ||||
| 			quit ("expected marker, got %2x", c); | ||||
| 		do { | ||||
| 			c = get1(); | ||||
| 		} while (c == 0xff); | ||||
| marker: | ||||
| 		switch (c) { | ||||
| 		case 0xc0: case 0xc1: case 0xc2: case 0xc3: | ||||
| 		case 0xc5: case 0xc6: case 0xc7: | ||||
| 		case 0xc8: case 0xc9: case 0xca: case 0xcb: | ||||
| 		case 0xcd: case 0xce: case 0xcf: | ||||
| 			get_sof (c); | ||||
| 			break; | ||||
| 		case 0xc4: | ||||
| 			get_dht (c); | ||||
| 			break; | ||||
| 		case 0xcc: | ||||
| 			get_dac (c); | ||||
| 			break; | ||||
| 		case 0xd8: | ||||
| 			printf ("SOI\n"); | ||||
| 			break; | ||||
| 		case 0xe0: case 0xe1: case 0xe2: case 0xe3:  | ||||
| 		case 0xe4: case 0xe5: case 0xe6: case 0xe7:  | ||||
| 		case 0xe8: case 0xe9: case 0xea: case 0xeb:  | ||||
| 		case 0xec: case 0xed: case 0xee: case 0xef:  | ||||
| 			get_app(c); | ||||
| 			break; | ||||
| 		case 0xda: | ||||
| 			get_sos (c); | ||||
| 			goto newentropy; | ||||
| 		case 0xdb: | ||||
| 			get_dqt (c); | ||||
| 			break; | ||||
| 		case 0xfe: | ||||
| 			get_com (c); | ||||
| 			break; | ||||
| 		case 0xd9: | ||||
| 			printf ("EOI\n"); | ||||
| 			if((c=getc(infile)) == EOF) | ||||
| 				exit(0); | ||||
| 			ungetc(c, infile); | ||||
| 			goto Start; | ||||
| 		default: | ||||
| 			eatmarker (c); | ||||
| 		} | ||||
| 		continue; | ||||
| newentropy: | ||||
| 		l = stuff = 0; | ||||
| entropy: | ||||
| 		while ((c = get1()) != 0xff) | ||||
| 			l += 1; | ||||
| 		while (c == 0xff) | ||||
| 			c = get1(); | ||||
| 		if (c == 0) { | ||||
| 			stuff += 1; | ||||
| 			goto entropy; | ||||
| 		} | ||||
| 		printf ("sequence length %d with %d stuffs\n", l, stuff); | ||||
| 		if (0xd0 <= c && c <= 0xd7) { | ||||
| 			printf ("restart %d\n", c - 0xd0); | ||||
| 			goto newentropy; | ||||
| 		} | ||||
| 		goto marker; | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										357
									
								
								sys/src/cmd/pict/jpg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										357
									
								
								sys/src/cmd/pict/jpg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,357 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		jflag = 0; | ||||
| int		fflag = 0; | ||||
| int		Fflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		colorspace = CYCbCr;	/* default for 8-bit displays: combine color rotation with dither */ | ||||
| int		output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| Image	*image; | ||||
| int		defaultcolor = 1; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*, int); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "jpg: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i, yflag; | ||||
| 	char *err; | ||||
| 	char buf[12+1]; | ||||
|  | ||||
| 	yflag = 0; | ||||
| 	ARGBEGIN{ | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'F': | ||||
| 		Fflag++;	/* make a movie */ | ||||
| 		fflag++;	/* merge two fields per image */ | ||||
| 		break; | ||||
| 	case 'f': | ||||
| 		fflag++;	/* merge two fields per image */ | ||||
| 		break; | ||||
| 	case 'J':		/* decode jpeg only; no display or remap (for debugging, etc.) */ | ||||
| 		jflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'r': | ||||
| 		colorspace = CRGB; | ||||
| 		break; | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'y':	/* leave it in CYCbCr; for debugging only */ | ||||
| 		yflag = 1; | ||||
| 		colorspace = CYCbCr; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: jpg -39cdefFkJrtvy [file.jpg ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	if(yflag==0 && dflag==0 && colorspace==CYCbCr){	/* see if we should convert right to RGB */ | ||||
| 		fd = open("/dev/screen", OREAD); | ||||
| 		if(fd >= 0){ | ||||
| 			buf[12] = '\0'; | ||||
| 			if(read(fd, buf, 12)==12 && chantodepth(strtochan(buf))>8) | ||||
| 				colorspace = CRGB; | ||||
| 			close(fd); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>", outchan); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "jpg: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i], outchan); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "jpg: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| vidmerge(Rawimage **aa1, Rawimage **aa2) | ||||
| { | ||||
| 	Rawimage **aao, *ao, *a1, *a2; | ||||
| 	int i, c, row, col; | ||||
|  | ||||
| 	aao = nil; | ||||
| 	for (i = 0; aa1[i]; i++) { | ||||
|  | ||||
| 		a1 = aa1[i]; | ||||
| 		a2 = aa2[i]; | ||||
| 		if (a2 == nil){ | ||||
| 			fprint(2, "jpg: vidmerge: unequal lengths\n"); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		aao = realloc(aao, (i+2)*sizeof(Rawimage *)); | ||||
| 		if (aao == nil){ | ||||
| 			fprint(2, "jpg: vidmerge: realloc\n"); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		aao[i+1] = nil; | ||||
| 		ao = aao[i] = malloc(sizeof(Rawimage)); | ||||
| 		if (ao == nil){ | ||||
| 			fprint(2, "jpg: vidmerge: malloc\n"); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		memcpy(ao, a1, sizeof(Rawimage)); | ||||
| 		if (!eqrect(a1->r , a2->r)){ | ||||
| 			fprint(2, "jpg: vidmerge: rects different in img %d\n", i); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		if (a1->cmaplen != a2->cmaplen){ | ||||
| 			fprint(2, "jpg: vidmerge: cmaplen different in img %d\n", i); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		if (a1->nchans != a2->nchans){ | ||||
| 			fprint(2, "jpg: vidmerge: nchans different in img %d\n", i); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		if (a1->fields != a2->fields){ | ||||
| 			fprint(2, "jpg: vidmerge: fields different in img %d\n", i); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		ao->r.max.y += Dy(ao->r); | ||||
| 		ao->chanlen += ao->chanlen; | ||||
| 		if (ao->chanlen != Dx(ao->r)*Dy(ao->r)){ | ||||
| 			fprint(2, "jpg: vidmerge: chanlen wrong %d != %d*%d\n", | ||||
| 				ao->chanlen, Dx(ao->r), Dy(ao->r)); | ||||
| 			return nil; | ||||
| 		} | ||||
| 		row = Dx(a1->r); | ||||
| 		for (c = 0; c < ao->nchans; c++) { | ||||
| 			unsigned char *po, *p1, *p2; | ||||
|  | ||||
| 			ao->chans[c] = malloc(ao->chanlen); | ||||
| 			if (ao->chans[c] == nil){ | ||||
| 				fprint(2, "jpg: vidmerge: malloc chan\n"); | ||||
| 				return nil; | ||||
| 			} | ||||
| 			po = ao->chans[c]; | ||||
| 			p1 = a1->chans[c]; | ||||
| 			p2 = a2->chans[c]; | ||||
| 			for (col = 0; col < Dy(a1->r); col++) { | ||||
| 				memcpy(po, p1, row); | ||||
| 				po += row, p1 += row; | ||||
| 				memcpy(po, p2, row); | ||||
| 				po += row, p2 += row; | ||||
| 			} | ||||
| 			free(a1->chans[c]); | ||||
| 			free(a2->chans[c]); | ||||
| 		} | ||||
| 		if(a2->cmap != nil) | ||||
| 			free(a2->cmap); | ||||
| 		free(a1); | ||||
| 		free(a2); | ||||
| 	} | ||||
| 	if (aa2[i] != nil) | ||||
| 		fprint(2, "jpg: vidmerge: unequal lengths\n"); | ||||
| 	free(aa1); | ||||
| 	free(aa2); | ||||
| 	return aao; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name, int outc) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	static int inited; | ||||
| 	Image *i; | ||||
| 	int j, ch, outchan; | ||||
| 	Biobuf b; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	outchan = outc; | ||||
| rpt:	array = Breadjpg(&b, colorspace); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "jpg: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if (fflag) { | ||||
| 		Rawimage **a; | ||||
|  | ||||
| 		a = Breadjpg(&b, colorspace); | ||||
| 		if(a == nil || a[0]==nil){ | ||||
| 			fprint(2, "jpg: decode %s-2 failed: %r\n", name); | ||||
| 			return "decode"; | ||||
| 		} | ||||
| 		array = vidmerge(a, array); | ||||
| 	} else | ||||
| 		Bterm(&b); | ||||
|  | ||||
| 	r = array[0]; | ||||
| 	c = nil; | ||||
| 	if(jflag) | ||||
| 		goto Return; | ||||
| 	if(!dflag){ | ||||
| 		if (!inited) { | ||||
| 			if(initdraw(0, 0, 0) < 0){ | ||||
| 				fprint(2, "jpg: initdraw failed: %r\n"); | ||||
| 				return "initdraw"; | ||||
| 			} | ||||
| 			if(Fflag == 0) | ||||
| 				einit(Ekeyboard|Emouse); | ||||
| 			inited++; | ||||
| 		} | ||||
| 		if(defaultcolor && screen->depth>8 && outchan==CMAP8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){ | ||||
| 			c = totruecolor(r, CY); | ||||
| 			outchan = GREY8; | ||||
| 		}else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "jpg: conversion of %s failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(c->chandesc == CY) | ||||
| 			i = allocimage(display, c->r, GREY8, 0, 0); | ||||
| 		else | ||||
| 			i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "jpg: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "jpg: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if (Fflag) { | ||||
| 			freeimage(i); | ||||
| 			for(j=0; j<r->nchans; j++) | ||||
| 				free(r->chans[j]); | ||||
| 			free(r->cmap); | ||||
| 			free(r); | ||||
| 			free(array); | ||||
| 			goto rpt; | ||||
| 		} | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "jpg: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "jpg: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
|     Return: | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	if (Fflag) goto rpt; | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										54
									
								
								sys/src/cmd/pict/multichan.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										54
									
								
								sys/src/cmd/pict/multichan.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,54 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| /* Separate colors, if not a grey scale or bitmap, into one byte per color per pixel, no alpha or X */ | ||||
| /* Result is GREY[1248] or RGB24 */ | ||||
|  | ||||
| static | ||||
| int | ||||
| notrans(uint32_t chan) | ||||
| { | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case GREY8: | ||||
| 	case RGB24: | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| Image* | ||||
| multichan(Image *i) | ||||
| { | ||||
| 	Image *ni; | ||||
|  | ||||
| 	if(notrans(i->chan)) | ||||
| 		return i; | ||||
|  | ||||
| 	ni = allocimage(display, i->r, RGB24, 0, DNofill); | ||||
| 	if(ni == nil) | ||||
| 		return ni; | ||||
| 	draw(ni, ni->r, i, nil, i->r.min); | ||||
| 	return ni; | ||||
| } | ||||
|  | ||||
| Memimage* | ||||
| memmultichan(Memimage *i) | ||||
| { | ||||
| 	Memimage *ni; | ||||
|  | ||||
| 	if(notrans(i->chan)) | ||||
| 		return i; | ||||
|  | ||||
| 	ni = allocmemimage(i->r, RGB24); | ||||
| 	if(ni == nil) | ||||
| 		return ni; | ||||
| 	memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S); | ||||
| 	return ni; | ||||
| } | ||||
							
								
								
									
										229
									
								
								sys/src/cmd/pict/onechan.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										229
									
								
								sys/src/cmd/pict/onechan.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,229 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| /* Convert image to a single channel, one byte per pixel */ | ||||
|  | ||||
| static | ||||
| int | ||||
| notrans(uint32_t chan) | ||||
| { | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case	CMAP8: | ||||
| 	case GREY8: | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static | ||||
| int | ||||
| easycase(uint32_t chan) | ||||
| { | ||||
| 	switch(chan){ | ||||
| 	case RGB16: | ||||
| 	case RGB24: | ||||
| 	case RGBA32: | ||||
| 	case ARGB32: | ||||
| 		return 1; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Convert to one byte per pixel, RGBV or grey, depending | ||||
|  */ | ||||
|  | ||||
| static | ||||
| unsigned char* | ||||
| load(Image *image, Memimage *memimage) | ||||
| { | ||||
| 	unsigned char *data, *p, *q0, *q1, *q2; | ||||
| 	unsigned char *rgbv; | ||||
| 	int depth, ndata, dx, dy, i, v; | ||||
| 	uint32_t chan, pixel; | ||||
| 	Rectangle r; | ||||
| 	Rawimage ri, *nri; | ||||
|  | ||||
| 	if(memimage == nil){ | ||||
| 		r = image->r; | ||||
| 		depth = image->depth; | ||||
| 		chan = image->chan; | ||||
| 	}else{ | ||||
| 		r = memimage->r; | ||||
| 		depth = memimage->depth; | ||||
| 		chan = memimage->chan; | ||||
| 	} | ||||
| 	dx = Dx(r); | ||||
| 	dy = Dy(r); | ||||
|  | ||||
| 	/* | ||||
| 	 * Read image data into memory | ||||
| 	 * potentially one extra byte on each end of each scan line. | ||||
| 	 */ | ||||
| 	ndata = dy*(2+bytesperline(r, depth)); | ||||
| 	data = malloc(ndata); | ||||
| 	if(data == nil) | ||||
| 		return nil; | ||||
| 	if(memimage != nil) | ||||
| 		ndata = unloadmemimage(memimage, r, data, ndata); | ||||
| 	else | ||||
| 		ndata = unloadimage(image, r, data, ndata); | ||||
| 	if(ndata < 0){ | ||||
| 		werrstr("onechan: %r"); | ||||
| 		free(data); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Repack | ||||
| 	 */ | ||||
| 	memset(&ri, 0, sizeof(ri)); | ||||
| 	ri.r = r; | ||||
| 	ri.cmap = nil; | ||||
| 	ri.cmaplen = 0; | ||||
| 	ri.nchans = 3; | ||||
| 	ri.chanlen = dx*dy; | ||||
| 	ri.chans[0] = malloc(ri.chanlen); | ||||
| 	ri.chans[1] = malloc(ri.chanlen); | ||||
| 	ri.chans[2] = malloc(ri.chanlen); | ||||
| 	if(ri.chans[0]==nil || ri.chans[1]==nil || ri.chans[2]==nil){ | ||||
|     Err: | ||||
| 		free(ri.chans[0]); | ||||
| 		free(ri.chans[1]); | ||||
| 		free(ri.chans[2]); | ||||
| 		free(data); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	ri.chandesc = CRGB; | ||||
|  | ||||
| 	p = data; | ||||
| 	q0 = ri.chans[0]; | ||||
| 	q1 = ri.chans[1]; | ||||
| 	q2 = ri.chans[2]; | ||||
|  | ||||
| 	switch(chan){ | ||||
| 	default: | ||||
| 		werrstr("can't handle image type 0x%lux", chan); | ||||
| 		goto Err; | ||||
| 	case RGB16: | ||||
| 		for(i=0; i<ri.chanlen; i++, p+=2){ | ||||
| 			pixel = (p[1]<<8)|p[0];	/* rrrrrggg gggbbbbb */ | ||||
| 			v = (pixel & 0xF800) >> 8; | ||||
| 			*q0++ = v | (v>>5); | ||||
| 			v = (pixel & 0x07E0) >> 3; | ||||
| 			*q1++ = v | (v>>6); | ||||
| 			v = (pixel & 0x001F) << 3; | ||||
| 			*q2++ = v | (v>>5); | ||||
| 		} | ||||
| 		break; | ||||
| 	case RGB24: | ||||
| 		for(i=0; i<ri.chanlen; i++){ | ||||
| 			*q2++ = *p++; | ||||
| 			*q1++ = *p++; | ||||
| 			*q0++ = *p++; | ||||
| 		} | ||||
| 		break; | ||||
| 	case RGBA32: | ||||
| 		for(i=0; i<ri.chanlen; i++){ | ||||
| 			*q2++ = *p++; | ||||
| 			*q1++ = *p++; | ||||
| 			*q0++ = *p++; | ||||
| 			p++; | ||||
| 		} | ||||
| 		break; | ||||
| 	case ARGB32: | ||||
| 		for(i=0; i<ri.chanlen; i++){ | ||||
| 			p++; | ||||
| 			*q2++ = *p++; | ||||
| 			*q1++ = *p++; | ||||
| 			*q0++ = *p++; | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	rgbv = nil; | ||||
| 	nri = torgbv(&ri, 1); | ||||
| 	if(nri != nil){ | ||||
| 		rgbv = nri->chans[0]; | ||||
| 		free(nri); | ||||
| 	} | ||||
|  | ||||
| 	free(ri.chans[0]); | ||||
| 	free(ri.chans[1]); | ||||
| 	free(ri.chans[2]); | ||||
| 	free(data); | ||||
| 	return rgbv; | ||||
| } | ||||
|  | ||||
| Image* | ||||
| onechan(Image *i) | ||||
| { | ||||
| 	unsigned char *data; | ||||
| 	Image *ni; | ||||
|  | ||||
| 	if(notrans(i->chan)) | ||||
| 		return i; | ||||
|  | ||||
| 	if(easycase(i->chan)) | ||||
| 		data = load(i, nil); | ||||
| 	else{ | ||||
| 		ni = allocimage(display, i->r, RGB24, 0, DNofill); | ||||
| 		if(ni == nil) | ||||
| 			return ni; | ||||
| 		draw(ni, ni->r, i, nil, i->r.min); | ||||
| 		data = load(ni, nil); | ||||
| 		freeimage(ni); | ||||
| 	} | ||||
|  | ||||
| 	if(data == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	ni = allocimage(display, i->r, CMAP8, 0, DNofill); | ||||
| 	if(ni != nil) | ||||
| 		if(loadimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){ | ||||
| 			freeimage(ni); | ||||
| 			ni = nil; | ||||
| 		} | ||||
| 	free(data); | ||||
| 	return ni; | ||||
| } | ||||
|  | ||||
| Memimage* | ||||
| memonechan(Memimage *i) | ||||
| { | ||||
| 	unsigned char *data; | ||||
| 	Memimage *ni; | ||||
|  | ||||
| 	if(notrans(i->chan)) | ||||
| 		return i; | ||||
|  | ||||
| 	if(easycase(i->chan)) | ||||
| 		data = load(nil, i); | ||||
| 	else{ | ||||
| 		ni = allocmemimage(i->r, RGB24); | ||||
| 		if(ni == nil) | ||||
| 			return ni; | ||||
| 		memimagedraw(ni, ni->r, i, i->r.min, nil, ZP, S); | ||||
| 		data = load(nil, ni); | ||||
| 		freememimage(ni); | ||||
| 	} | ||||
|  | ||||
| 	if(data == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	ni = allocmemimage(i->r, CMAP8); | ||||
| 	if(ni != nil) | ||||
| 		if(loadmemimage(ni, ni->r, data, Dx(ni->r)*Dy(ni->r)) < 0){ | ||||
| 			freememimage(ni); | ||||
| 			ni = nil; | ||||
| 		} | ||||
| 	free(data); | ||||
| 	return ni; | ||||
| } | ||||
							
								
								
									
										250
									
								
								sys/src/cmd/pict/png.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										250
									
								
								sys/src/cmd/pict/png.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,250 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| extern int	debug; | ||||
| int	cflag = 0; | ||||
| int	dflag = 0; | ||||
| int	eflag = 0; | ||||
| int	nineflag = 0; | ||||
| int	threeflag = 0; | ||||
| int	output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| Image	*image; | ||||
| int	defaultcolor = 1; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge	= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*, int); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "png: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	draw(screen, r, image, nil, image->r.min); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'D': | ||||
| 		debug++; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: png [-39cdekrtv] [file.png ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>", outchan); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "png: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i], outchan); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "png: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name, int outc) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i, *i2; | ||||
| 	int j, ch, outchan; | ||||
| 	long len; | ||||
| 	Biobuf b; | ||||
| 	char buf[32]; | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	outchan = outc; | ||||
| 	array = Breadpng(&b, CRGB); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "png: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	Bterm(&b); | ||||
|  | ||||
| 	r = array[0]; | ||||
| 	if(!dflag){ | ||||
| 		if (!inited) { | ||||
| 			if(initdraw(0, 0, 0) < 0){ | ||||
| 				fprint(2, "png: initdraw failed: %r\n"); | ||||
| 				return "initdraw"; | ||||
| 			} | ||||
| 			einit(Ekeyboard|Emouse); | ||||
| 			inited++; | ||||
| 		} | ||||
| 		if(defaultcolor && screen->depth>8 && outchan==CMAP8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		switch(r->chandesc){ | ||||
| 		case CY: | ||||
| 			outchan = GREY8; | ||||
| 			break; | ||||
| 		case CYA16: | ||||
| 			outchan = CHAN2(CGrey, 8, CAlpha, 8); | ||||
| 			break; | ||||
| 		case CRGB24: | ||||
| 			outchan = RGB24; | ||||
| 			break; | ||||
| 		case CRGBA32: | ||||
| 			outchan = RGBA32; | ||||
| 			break; | ||||
| 		} | ||||
| 		c = r; | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "png: conversion of %s failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "png: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "png: loadimage %s of %d bytes failed: %r\n", | ||||
| 				name, c->chanlen); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		i2 = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		draw(i2, i2->r, display->black, nil, ZP); | ||||
| 		draw(i2, i2->r, i, nil, i->r.min); | ||||
| 		image = i2; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		len = (c->r.max.x - c->r.min.x) * (c->r.max.y - c->r.min.y); | ||||
| 		switch(c->chandesc){ | ||||
| 		case CY: | ||||
| 			// len *= 1; | ||||
| 			break; | ||||
| 		case CYA16: | ||||
| 			len *= 2; | ||||
| 			break; | ||||
| 		case CRGB24: | ||||
| 			len *= 3; | ||||
| 			break; | ||||
| 		case CRGBA32: | ||||
| 			len *= 4; | ||||
| 			break; | ||||
| 		} | ||||
| 		if(c->chanlen != len) | ||||
| 			fprint(2, "%s: writing %d bytes for len %ld chan %s\n", | ||||
| 				argv0, c->chanlen, len, buf); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "png: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "png: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c && c != r){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										219
									
								
								sys/src/cmd/pict/ppm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										219
									
								
								sys/src/cmd/pict/ppm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,219 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| int		defaultcolor = 1; | ||||
| Image	*image; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "ppm: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: ppm -39cdektv  [file.ppm ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "ppm: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "ppm: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "ppm: initdraw failed: %r"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	array = readpixmap(fd, CRGB); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "ppm: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)) | ||||
| 			c = totruecolor(r, CY); | ||||
| 		else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "ppm: converting %s to local format failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			outchan = GREY8; | ||||
| 		i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "ppm: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "ppm: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			outchan = GREY8; | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "ppm: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "ppm: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										626
									
								
								sys/src/cmd/pict/readbmp.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										626
									
								
								sys/src/cmd/pict/readbmp.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,626 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
| #include "bmp.h" | ||||
|  | ||||
| /* | ||||
|  MS-BMP file reader | ||||
|  (c) 2003, I.P.Keller | ||||
|  | ||||
|  aims to decode *all* valid bitmap formats, although some of the | ||||
|  flavours couldn't be verified due to lack of suitable test-files. | ||||
|  the following flavours are supported: | ||||
|  | ||||
| 	Bit/Pix	Orientation	Compression	Tested? | ||||
| 	  1	top->bottom	n/a		yes | ||||
| 	  1	bottom->top	n/a		yes | ||||
| 	  4	top->bottom	no		yes | ||||
| 	  4	bottom->top	no		yes | ||||
| 	  4	top->bottom	RLE4		yes, but not with displacement | ||||
| 	  8	top->bottom	no		yes | ||||
| 	  8	bottom->top	no		yes | ||||
| 	  8	top->bottom	RLE8		yes, but not with displacement | ||||
| 	 16	top->bottom	no		no | ||||
| 	 16	bottom->top	no		no | ||||
| 	 16	top->bottom	BITMASK		no | ||||
| 	 16	bottom->top	BITMASK		no | ||||
| 	 24	top->bottom	n/a		yes | ||||
| 	 24	bottom->top	n/a		yes | ||||
| 	 32	top->bottom	no		no | ||||
| 	 32	bottom->top	no		no | ||||
| 	 32	top->bottom	BITMASK		no | ||||
| 	 32	bottom->top	BITMASK		no | ||||
|  | ||||
|  OS/2 1.x bmp files are recognised as well, but testing was very limited. | ||||
|  | ||||
|  verifying was done with a number of test files, generated by | ||||
|  different tools. nevertheless, the tests were in no way exhaustive | ||||
|  enough to guarantee bug-free decoding. caveat emptor! | ||||
| */ | ||||
|  | ||||
| static short | ||||
| r16(Biobuf*b) | ||||
| { | ||||
| 	short s; | ||||
|  | ||||
| 	s = Bgetc(b); | ||||
| 	s |= ((short)Bgetc(b)) << 8; | ||||
| 	return s; | ||||
| } | ||||
|  | ||||
|  | ||||
| static long | ||||
| r32(Biobuf*b) | ||||
| { | ||||
| 	long l; | ||||
|  | ||||
| 	l = Bgetc(b); | ||||
| 	l |= ((long)Bgetc(b)) << 8; | ||||
| 	l |= ((long)Bgetc(b)) << 16; | ||||
| 	l |= ((long)Bgetc(b)) << 24; | ||||
| 	return l; | ||||
| } | ||||
|  | ||||
|  | ||||
| /* get highest bit set */ | ||||
| static int | ||||
| msb(uint32_t x) | ||||
| { | ||||
| 	int i; | ||||
| 	for(i = 32; i; i--, x <<= 1) | ||||
| 		if(x & 0x80000000L) | ||||
| 			return i; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 1-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_1T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	long ix, iy, i = 0, step_up = 0, padded_width = ((width + 31) / 32) * 32; | ||||
| 	int val = 0, n; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	for(iy = height; iy; iy--, i += step_up) | ||||
| 		for(ix = 0, n = 0; ix < padded_width; ix++, n--) { | ||||
| 			if(!n) { | ||||
| 				val = Bgetc(b); | ||||
| 				n = 8; | ||||
| 			} | ||||
| 			if(ix < width) { | ||||
| 				buf[i] = clut[val & 0x80 ? 1 : 0]; | ||||
| 				i++; | ||||
| 			} | ||||
| 			val <<= 1; | ||||
| 		} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 4-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_4T(Biobuf* b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	long ix, iy, i = 0, step_up = 0, skip = (4 - (((width % 8) + 1) / 2)) & 3; | ||||
| 	uint valH, valL; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	for(iy = height; iy; iy--, i += step_up) { | ||||
| 		for(ix = 0; ix < width; ) { | ||||
| 			valH = valL = Bgetc(b) & 0xff; | ||||
| 			valH >>= 4; | ||||
|  | ||||
| 			buf[i] = clut[valH]; | ||||
| 			i++; ix++; | ||||
|  | ||||
| 			if(ix < width) { | ||||
| 				valL &= 0xf; | ||||
| 				buf[i] = clut[valL]; | ||||
| 				i++; ix++; | ||||
| 			} | ||||
| 		} | ||||
| 		Bseek(b, skip, 1); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 4-Bit encoded BMP file (RLE4-compressed) */ | ||||
| static int | ||||
| load_4C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	long ix, iy = height -1; | ||||
| 	uint val, valS, skip; | ||||
| 	Rgb* p; | ||||
|  | ||||
| 	while(iy >= 0) { | ||||
| 		ix = 0; | ||||
| 		while(ix < width) { | ||||
| 			val = (uint)Bgetc(b); | ||||
|  | ||||
| 			if(0 != val) { | ||||
| 				valS = (uint)Bgetc(b); | ||||
| 				p = &buf[ix + iy * width]; | ||||
| 				while(val--) { | ||||
| 					*p = clut[0xf & (valS >> 4)]; | ||||
| 					p++; | ||||
| 					ix++; | ||||
| 					if(val != 0) { | ||||
| 						*p = clut[0xf & valS]; | ||||
| 						p++; | ||||
| 						ix++; | ||||
| 						val--; | ||||
| 					} | ||||
| 				} | ||||
| 			} else { | ||||
| 				/* Special modes... */ | ||||
| 				val = Bgetc(b); | ||||
| 				switch(val) { | ||||
| 					case 0:	/* End-Of-Line detected */ | ||||
| 						ix = width; | ||||
| 						iy--; | ||||
| 						break; | ||||
| 					case 1:	/* End-Of-Picture detected -->> abort */ | ||||
| 						ix = width; | ||||
| 						iy = -1; | ||||
| 						break; | ||||
| 					case 2:	/* Position change detected */ | ||||
| 						val = (uint)Bgetc(b); | ||||
| 						ix += val; | ||||
| 						val = (uint)Bgetc(b); | ||||
| 						iy -= val; | ||||
| 						break; | ||||
|  | ||||
| 					default:/* Transparent data sequence detected */ | ||||
| 						p = &buf[ix + iy * width]; | ||||
| 						if((1 == (val & 3)) || (2 == (val & 3))) | ||||
| 							skip = 1; | ||||
| 						else | ||||
| 							skip = 0; | ||||
|  | ||||
| 						while(val--) { | ||||
| 							valS = (uint)Bgetc(b); | ||||
| 							*p = clut[0xf & (valS >> 4)]; | ||||
| 							p++; | ||||
| 							ix++; | ||||
| 							if(val != 0) { | ||||
| 								*p = clut[0xf & valS]; | ||||
| 								p++; | ||||
| 								ix++; | ||||
| 								val--; | ||||
| 							} | ||||
| 						} | ||||
| 						if(skip) | ||||
| 							Bgetc(b); | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 8-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_8T(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	long ix, iy, i = 0, step_up = 0, skip = (4 - (width % 4)) & 3; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	for(iy = height; iy; iy--, i += step_up) { | ||||
| 		for(ix = 0; ix < width; ix++, i++) | ||||
| 			buf[i] = clut[Bgetc(b) & 0xff]; | ||||
| 		Bseek(b, skip, 1); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 8-Bit encoded BMP file (RLE8-compressed) */ | ||||
| static int | ||||
| load_8C(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	long ix, iy = height -1; | ||||
| 	int val, valS, skip; | ||||
| 	Rgb* p; | ||||
|  | ||||
| 	while(iy >= 0) { | ||||
| 		ix = 0; | ||||
| 		while(ix < width) { | ||||
| 			val = Bgetc(b); | ||||
|  | ||||
| 			if(0 != val) { | ||||
| 				valS = Bgetc(b); | ||||
| 				p = &buf[ix + iy * width]; | ||||
| 				while(val--) { | ||||
| 					*p = clut[valS]; | ||||
| 					p++; | ||||
| 					ix++; | ||||
| 				} | ||||
| 			} else { | ||||
| 				/* Special modes... */ | ||||
| 				val = Bgetc(b); | ||||
| 				switch(val) { | ||||
| 					case 0: /* End-Of-Line detected */ | ||||
| 						ix = width; | ||||
| 						iy--; | ||||
| 						break; | ||||
| 					case 1: /* End-Of-Picture detected */ | ||||
| 						ix = width; | ||||
| 						iy = -1; | ||||
| 						break; | ||||
| 					case 2: /* Position change detected */ | ||||
| 						val = Bgetc(b); | ||||
| 						ix += val; | ||||
| 						val = Bgetc(b); | ||||
| 						iy -= val; | ||||
| 						break; | ||||
| 					default: /* Transparent (not compressed) sequence detected */ | ||||
| 						p = &buf[ix + iy * width]; | ||||
| 						if(val & 1) | ||||
| 							skip = 1; | ||||
| 						else | ||||
| 							skip = 0; | ||||
|  | ||||
| 						while(val--) { | ||||
| 							valS = Bgetc(b); | ||||
| 							*p = clut[valS]; | ||||
| 							p++; | ||||
| 							ix++; | ||||
| 						} | ||||
| 						if(skip) | ||||
| 							/* Align data stream */ | ||||
| 							Bgetc(b); | ||||
| 						break; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 16-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_16(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	unsigned char c[2]; | ||||
| 	long ix, iy, i = 0, step_up = 0; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	if(clut) { | ||||
| 		unsigned mask_blue =  (unsigned)clut[0].blue + | ||||
| 		                     ((unsigned)clut[0].green << 8); | ||||
| 		unsigned mask_green =  (unsigned)clut[1].blue + | ||||
| 		                      ((unsigned)clut[1].green << 8); | ||||
| 		unsigned mask_red =  (unsigned)clut[2].blue + | ||||
| 		                    ((unsigned)clut[2].green << 8); | ||||
| 		int shft_blue = msb((uint32_t)mask_blue) - 8; | ||||
| 		int shft_green = msb((uint32_t)mask_green) - 8; | ||||
| 		int shft_red = msb((uint32_t)mask_red) - 8; | ||||
|  | ||||
| 		for(iy = height; iy; iy--, i += step_up) | ||||
| 			for(ix = 0; ix < width; ix++, i++) { | ||||
| 				unsigned val; | ||||
| 				Bread(b, c, sizeof(c)); | ||||
| 				val = (unsigned)c[0] + ((unsigned)c[1] << 8); | ||||
|  | ||||
| 				buf[i].alpha = 0; | ||||
| 				if(shft_blue >= 0) | ||||
| 					buf[i].blue = (unsigned char)((val & mask_blue) >> shft_blue); | ||||
| 				else | ||||
| 					buf[i].blue = (unsigned char)((val & mask_blue) << -shft_blue); | ||||
| 				if(shft_green >= 0) | ||||
| 					buf[i].green = (unsigned char)((val & mask_green) >> shft_green); | ||||
| 				else | ||||
| 					buf[i].green = (unsigned char)((val & mask_green) << -shft_green); | ||||
| 				if(shft_red >= 0) | ||||
| 					buf[i].red = (unsigned char)((val & mask_red) >> shft_red); | ||||
| 				else | ||||
| 					buf[i].red = (unsigned char)((val & mask_red) << -shft_red); | ||||
| 			} | ||||
| 	} else | ||||
| 		for(iy = height; iy; iy--, i += step_up) | ||||
| 			for(ix = 0; ix < width; ix++, i++) { | ||||
| 				Bread(b, c, sizeof(c)); | ||||
| 				buf[i].blue = (unsigned char)((c[0] << 3) & 0xf8); | ||||
| 				buf[i].green = (unsigned char)(((((unsigned)c[1] << 6) + | ||||
| 				                        (((unsigned)c[0]) >> 2))) & 0xf8); | ||||
| 				buf[i].red = (unsigned char)((c[1] << 1) & 0xf8); | ||||
| 			} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 24-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_24T(Biobuf* b, long width, long height, Rgb* buf) | ||||
| { | ||||
| 	long ix, iy, i = 0, step_up = 0, skip = (4 - ((width * 3) % 4)) & 3; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	for(iy = height; iy; iy--, i += step_up) { | ||||
| 		for(ix = 0; ix < width; ix++, i++) { | ||||
| 			buf[i].alpha = 0; | ||||
| 			buf[i].blue = Bgetc(b); | ||||
| 			buf[i].green = Bgetc(b); | ||||
| 			buf[i].red = Bgetc(b); | ||||
| 		} | ||||
| 		Bseek(b, skip, 1); | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| /* Load a 32-Bit encoded BMP file (uncompressed) */ | ||||
| static int | ||||
| load_32(Biobuf *b, long width, long height, Rgb* buf, Rgb* clut) | ||||
| { | ||||
| 	unsigned char c[4]; | ||||
| 	long ix, iy, i = 0, step_up = 0; | ||||
|  | ||||
| 	if(height > 0) {	/* bottom-up */ | ||||
| 		i = (height - 1) * width; | ||||
| 		step_up = -2 * width; | ||||
| 	} else | ||||
| 		height = -height; | ||||
|  | ||||
| 	if(clut) { | ||||
| 		uint32_t mask_blue =  (uint32_t)clut[0].blue + | ||||
| 		                          ((uint32_t)clut[0].green << 8) + | ||||
| 		                          ((uint32_t)clut[0].red << 16) + | ||||
| 		                          ((uint32_t)clut[0].alpha << 24); | ||||
| 		uint32_t mask_green =  (uint32_t)clut[1].blue + | ||||
| 		                           ((uint32_t)clut[1].green << 8) + | ||||
| 		                           ((uint32_t)clut[1].red << 16) + | ||||
| 		                           ((uint32_t)clut[1].alpha << 24); | ||||
| 		uint32_t mask_red =  (uint32_t)clut[2].blue + | ||||
| 		                         ((uint32_t)clut[2].green << 8) + | ||||
| 		                         ((uint32_t)clut[2].red << 16) + | ||||
| 		                         ((uint32_t)clut[2].alpha << 24); | ||||
| 		int shft_blue = msb(mask_blue) - 8; | ||||
| 		int shft_green = msb(mask_green) - 8; | ||||
| 		int shft_red = msb(mask_red) - 8; | ||||
|  | ||||
| 		for(iy = height; iy; iy--, i += step_up) | ||||
| 			for(ix = 0; ix < width; ix++, i++) { | ||||
| 				uint32_t val; | ||||
| 				Bread(b, c, sizeof(c)); | ||||
| 				val =  (uint32_t)c[0] + ((uint32_t)c[1] << 8) + | ||||
| 				      ((uint32_t)c[2] << 16) + ((uint32_t)c[1] << 24); | ||||
|  | ||||
| 				buf[i].alpha = 0; | ||||
| 				if(shft_blue >= 0) | ||||
| 					buf[i].blue = (unsigned char)((val & mask_blue) >> shft_blue); | ||||
| 				else | ||||
| 					buf[i].blue = (unsigned char)((val & mask_blue) << -shft_blue); | ||||
| 				if(shft_green >= 0) | ||||
| 					buf[i].green = (unsigned char)((val & mask_green) >> shft_green); | ||||
| 				else | ||||
| 					buf[i].green = (unsigned char)((val & mask_green) << -shft_green); | ||||
| 				if(shft_red >= 0) | ||||
| 					buf[i].red = (unsigned char)((val & mask_red) >> shft_red); | ||||
| 				else | ||||
| 					buf[i].red = (unsigned char)((val & mask_red) << -shft_red); | ||||
| 			} | ||||
| 	} else | ||||
| 		for(iy = height; iy; iy--, i += step_up) | ||||
| 			for(ix = 0; ix < width; ix++, i++) { | ||||
| 				Bread(b, c, nelem(c)); | ||||
| 				buf[i].blue = c[0]; | ||||
| 				buf[i].green = c[1]; | ||||
| 				buf[i].red = c[2]; | ||||
| 			} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static Rgb* | ||||
| ReadBMP(Biobuf *b, int *width, int *height) | ||||
| { | ||||
| 	int colours, num_coltab = 0; | ||||
| 	Filehdr bmfh; | ||||
| 	Infohdr bmih; | ||||
| 	Rgb clut[256]; | ||||
| 	Rgb* buf; | ||||
|  | ||||
| 	bmfh.type = r16(b); | ||||
| 	if(bmfh.type != 0x4d42) 	/* signature must be 'BM' */ | ||||
| 		sysfatal("bad magic number, not a BMP file"); | ||||
|  | ||||
| 	bmfh.size = r32(b); | ||||
| 	bmfh.reserved1 = r16(b); | ||||
| 	bmfh.reserved2 = r16(b); | ||||
| 	bmfh.offbits = r32(b); | ||||
|  | ||||
| 	memset(&bmih, 0, sizeof(bmih)); | ||||
| 	bmih.size = r32(b); | ||||
|  | ||||
| 	if(bmih.size == 0x0c) {			/* OS/2 1.x version */ | ||||
| 		bmih.width = r16(b); | ||||
| 		bmih.height = r16(b); | ||||
| 		bmih.planes = r16(b); | ||||
| 		bmih.bpp = r16(b); | ||||
| 		bmih.compression = BMP_RGB; | ||||
| 	} else {				/* Windows */ | ||||
| 		bmih.width = r32(b); | ||||
| 		bmih.height = r32(b); | ||||
| 		bmih.planes = r16(b); | ||||
| 		bmih.bpp = r16(b); | ||||
| 		bmih.compression = r32(b); | ||||
| 		bmih.imagesize = r32(b); | ||||
| 		bmih.hres = r32(b); | ||||
| 		bmih.vres = r32(b); | ||||
| 		bmih.colours = r32(b); | ||||
| 		bmih.impcolours = r32(b); | ||||
| 	} | ||||
|  | ||||
| 	if(bmih.bpp < 16) { | ||||
| 		/* load colour table */ | ||||
| 		if(bmih.impcolours) | ||||
| 			num_coltab = (int)bmih.impcolours; | ||||
| 		else | ||||
| 			num_coltab = 1 << bmih.bpp; | ||||
| 	} else if(bmih.compression == BMP_BITFIELDS && | ||||
| 	          (bmih.bpp == 16 || bmih.bpp == 32)) | ||||
| 		/* load bitmasks */ | ||||
| 		num_coltab = 3; | ||||
|  | ||||
| 	if(num_coltab) { | ||||
| 		int i; | ||||
| 		Bseek(b, bmih.size + Filehdrsz, 0); | ||||
|  | ||||
| 		for(i = 0; i < num_coltab; i++) { | ||||
| 			clut[i].blue  = (unsigned char)Bgetc(b); | ||||
| 			clut[i].green = (unsigned char)Bgetc(b); | ||||
| 			clut[i].red   = (unsigned char)Bgetc(b); | ||||
| 			clut[i].alpha = (unsigned char)Bgetc(b); | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	*width = bmih.width; | ||||
| 	*height = bmih.height; | ||||
| 	colours = bmih.bpp; | ||||
|  | ||||
| 	Bseek(b, bmfh.offbits, 0); | ||||
|  | ||||
| 	if ((buf = calloc(sizeof(Rgb), *width * abs(*height))) == nil) | ||||
| 		sysfatal("no memory"); | ||||
|  | ||||
| 	switch(colours) { | ||||
| 		case 1: | ||||
| 			load_1T(b, *width, *height, buf, clut); | ||||
| 			break; | ||||
| 		case 4: | ||||
| 			if(bmih.compression == BMP_RLE4) | ||||
| 				load_4C(b, *width, *height, buf, clut); | ||||
| 			else | ||||
| 				load_4T(b, *width, *height, buf, clut); | ||||
| 			break; | ||||
| 		case 8: | ||||
| 			if(bmih.compression == BMP_RLE8) | ||||
| 				load_8C(b, *width, *height, buf, clut); | ||||
| 			else | ||||
| 				load_8T(b, *width, *height, buf, clut); | ||||
| 			break; | ||||
| 		case 16: | ||||
| 			load_16(b, *width, *height, buf, | ||||
| 			        bmih.compression == BMP_BITFIELDS ? clut : nil); | ||||
| 			break; | ||||
| 		case 24: | ||||
| 			load_24T(b, *width, *height, buf); | ||||
| 			break; | ||||
| 		case 32: | ||||
| 			load_32(b, *width, *height, buf, | ||||
| 			        bmih.compression == BMP_BITFIELDS ? clut : nil); | ||||
| 			break; | ||||
| 	} | ||||
| 	return buf; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| Breadbmp(Biobuf *bp, int colourspace) | ||||
| { | ||||
| 	Rawimage *a, **array; | ||||
| 	int c, width, height; | ||||
| 	unsigned char *r, *g, *b; | ||||
| 	Rgb *s, *e; | ||||
| 	Rgb *bmp; | ||||
| 	char ebuf[128]; | ||||
|  | ||||
| 	a = nil; | ||||
| 	bmp = nil; | ||||
| 	array = nil; | ||||
| 	USED(a); | ||||
| 	USED(bmp); | ||||
| 	if (colourspace != CRGB) { | ||||
| 		errstr(ebuf, sizeof ebuf);	/* throw it away */ | ||||
| 		werrstr("ReadRGB: unknown colour space %d", colourspace); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if ((bmp = ReadBMP(bp, &width, &height)) == nil) | ||||
| 		return nil; | ||||
|  | ||||
| 	if ((a = calloc(sizeof(Rawimage), 1)) == nil) | ||||
| 		goto Error; | ||||
|  | ||||
| 	for (c = 0; c  < 3; c++) | ||||
| 		if ((a->chans[c] = calloc(width, height)) == nil) | ||||
| 			goto Error; | ||||
|  | ||||
| 	if ((array = calloc(sizeof(Rawimage *), 2)) == nil) | ||||
| 		goto Error; | ||||
| 	array[0] = a; | ||||
| 	array[1] = nil; | ||||
|  | ||||
| 	a->nchans = 3; | ||||
| 	a->chandesc = CRGB; | ||||
| 	a->chanlen = width * height; | ||||
| 	a->r = Rect(0, 0, width, height); | ||||
|  | ||||
| 	s = bmp; | ||||
| 	e = s + width * height; | ||||
| 	r = a->chans[0]; | ||||
| 	g = a->chans[1]; | ||||
| 	b = a->chans[2]; | ||||
|  | ||||
| 	do { | ||||
| 		*r++ = s->red; | ||||
| 		*g++ = s->green; | ||||
| 		*b++ = s->blue; | ||||
| 	}while(++s < e); | ||||
|  | ||||
| 	free(bmp); | ||||
| 	return array; | ||||
|  | ||||
| Error: | ||||
| 	if (a) | ||||
| 		for (c = 0; c < 3; c++) | ||||
| 			if (a->chans[c]) | ||||
| 				free(a->chans[c]); | ||||
| 	if (a) | ||||
| 		free(a); | ||||
| 	if (array) | ||||
| 		free(array); | ||||
| 	if (bmp) | ||||
| 		free(bmp); | ||||
| 	return nil; | ||||
|  | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| readbmp(int fd, int colorspace) | ||||
| { | ||||
| 	Rawimage * *a; | ||||
| 	Biobuf b; | ||||
|  | ||||
| 	if (Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	a = Breadbmp(&b, colorspace); | ||||
| 	Bterm(&b); | ||||
| 	return a; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										545
									
								
								sys/src/cmd/pict/readgif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										545
									
								
								sys/src/cmd/pict/readgif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,545 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| typedef struct Entry Entry; | ||||
| typedef struct Header Header; | ||||
|  | ||||
| struct Entry{ | ||||
| 	int		prefix; | ||||
| 	int		exten; | ||||
| }; | ||||
|  | ||||
| struct Header{ | ||||
| 	Biobuf	*fd; | ||||
| 	char		err[256]; | ||||
| 	jmp_buf	errlab; | ||||
| 	unsigned char 	buf[3*256]; | ||||
| 	char 		vers[8]; | ||||
| 	unsigned char 	*globalcmap; | ||||
| 	int		screenw; | ||||
| 	int		screenh; | ||||
| 	int		fields; | ||||
| 	int		bgrnd; | ||||
| 	int		aspect; | ||||
| 	int		flags; | ||||
| 	int		delay; | ||||
| 	int		trindex; | ||||
| 	int		loopcount; | ||||
| 	Entry	tbl[4096]; | ||||
| 	Rawimage	**array; | ||||
| 	Rawimage	*new; | ||||
|  | ||||
| 	unsigned char	*pic; | ||||
| }; | ||||
|  | ||||
| static char		readerr[] = "ReadGIF: read error: %r"; | ||||
| static char		extreaderr[] = "ReadGIF: can't read extension: %r"; | ||||
| static char		memerr[] = "ReadGIF: malloc failed: %r"; | ||||
|  | ||||
| static Rawimage**	readarray(Header*, int); | ||||
| static Rawimage*	readone(Header*); | ||||
| static void			readheader(Header*); | ||||
| static void			skipextension(Header*); | ||||
| static unsigned char*		readcmap(Header*, int); | ||||
| static unsigned char*		decode(Header*, Rawimage*, Entry*); | ||||
| static void		interlace(Header*, Rawimage*); | ||||
|  | ||||
| static | ||||
| void | ||||
| _clear(void **p) | ||||
| { | ||||
| 	if(*p){ | ||||
| 		free(*p); | ||||
| 		*p = nil; | ||||
| 	} | ||||
| } | ||||
| #define clear(p) _clear((void**)p) | ||||
|  | ||||
| static | ||||
| void | ||||
| giffreeall(Header *h, int freeimage) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	if(h->fd){ | ||||
| 		Bterm(h->fd); | ||||
| 		h->fd = nil; | ||||
| 	} | ||||
| 	clear(&h->pic); | ||||
| 	if(h->new){ | ||||
| 		clear(&h->new->cmap); | ||||
| 		clear(&h->new->chans[0]); | ||||
| 		clear(&h->new); | ||||
| 	} | ||||
| 	clear(&h->globalcmap); | ||||
| 	if(freeimage && h->array!=nil){ | ||||
| 		for(i=0; h->array[i]; i++){ | ||||
| 			clear(&h->array[i]->cmap); | ||||
| 			clear(&h->array[i]->chans[0]); | ||||
| 		} | ||||
| 		clear(&h->array); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| giferror(Header *h, char *fmt, ...) | ||||
| { | ||||
| 	va_list arg; | ||||
|  | ||||
| 	va_start(arg, fmt); | ||||
| 	vseprint(h->err, h->err+sizeof h->err, fmt, arg); | ||||
| 	va_end(arg); | ||||
|  | ||||
| 	werrstr("%s", h->err); | ||||
| 	giffreeall(h, 1); | ||||
| 	longjmp(h->errlab, 1); | ||||
| } | ||||
|  | ||||
|  | ||||
| Rawimage** | ||||
| readgif(int fd, int colorspace, int justone) | ||||
| { | ||||
| 	Rawimage **a; | ||||
| 	Biobuf b; | ||||
| 	Header *h; | ||||
| 	char buf[ERRMAX]; | ||||
|  | ||||
| 	buf[0] = '\0'; | ||||
| 	USED(colorspace); | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	h = malloc(sizeof(Header)); | ||||
| 	if(h == nil){ | ||||
| 		Bterm(&b); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	memset(h, 0, sizeof(Header)); | ||||
| 	h->fd = &b; | ||||
| 	errstr(buf, sizeof buf);	/* throw it away */ | ||||
| 	if(setjmp(h->errlab)) | ||||
| 		a = nil; | ||||
| 	else | ||||
| 		a = readarray(h, justone); | ||||
| 	giffreeall(h, 0); | ||||
| 	free(h); | ||||
| 	return a; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| inittbl(Header *h) | ||||
| { | ||||
| 	int i; | ||||
| 	Entry *tbl; | ||||
|  | ||||
| 	tbl = h->tbl; | ||||
| 	for(i=0; i<258; i++) { | ||||
| 		tbl[i].prefix = -1; | ||||
| 		tbl[i].exten = i; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static | ||||
| Rawimage** | ||||
| readarray(Header *h, int justone) | ||||
| { | ||||
| 	Entry *tbl; | ||||
| 	Rawimage *new, **array; | ||||
| 	int c, nimages; | ||||
|  | ||||
| 	tbl = h->tbl; | ||||
|  | ||||
| 	readheader(h); | ||||
|  | ||||
| 	if(h->fields & 0x80) | ||||
| 		h->globalcmap = readcmap(h, (h->fields&7)+1); | ||||
| 	array = malloc(sizeof(Rawimage*)); | ||||
| 	if(array == nil) | ||||
| 		giferror(h, memerr); | ||||
| 	nimages = 0; | ||||
| 	array[0] = nil; | ||||
| 	h->array = array; | ||||
|  | ||||
| 	for(;;){ | ||||
| 		switch(c = Bgetc(h->fd)){ | ||||
| 		case Beof: | ||||
| 			goto Return; | ||||
|  | ||||
| 		case 0x21:	/* Extension (ignored) */ | ||||
| 			skipextension(h); | ||||
| 			break; | ||||
|  | ||||
| 		case 0x2C:	/* Image Descriptor */ | ||||
| 			inittbl(h); | ||||
| 			new = readone(h); | ||||
| 			if(new->fields & 0x80){ | ||||
| 				new->cmaplen = 3*(1<<((new->fields&7)+1)); | ||||
| 				new->cmap = readcmap(h, (new->fields&7)+1); | ||||
| 			}else{ | ||||
| 				if(h->globalcmap == nil) | ||||
| 					giferror(h, "ReadGIF: globalcmap missing"); | ||||
| 				new->cmaplen = 3*(1<<((h->fields&7)+1)); | ||||
| 				new->cmap = malloc(new->cmaplen); | ||||
| 				if(new->cmap == nil) | ||||
| 					giferror(h, memerr); | ||||
| 				memmove(new->cmap, h->globalcmap, new->cmaplen); | ||||
| 			} | ||||
| 			h->new = new; | ||||
| 			new->chans[0] = decode(h, new, tbl); | ||||
| 			if(new->fields & 0x40) | ||||
| 				interlace(h, new); | ||||
| 			new->gifflags = h->flags; | ||||
| 			new->gifdelay = h->delay; | ||||
| 			new->giftrindex = h->trindex; | ||||
| 			new->gifloopcount = h->loopcount; | ||||
| 			array = realloc(h->array, (nimages+2)*sizeof(Rawimage*)); | ||||
| 			if(array == nil) | ||||
| 				giferror(h, memerr); | ||||
| 			array[nimages++] = new; | ||||
| 			array[nimages] = nil; | ||||
| 			h->array = array; | ||||
| 			h->new = nil; | ||||
| 			if(justone) | ||||
| 				goto Return; | ||||
| 			break; | ||||
|  | ||||
| 		case 0x3B:	/* Trailer */ | ||||
| 			goto Return; | ||||
|  | ||||
| 		default: | ||||
| 			fprint(2, "ReadGIF: unknown block type: 0x%.2x\n", c); | ||||
| 			goto Return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
|    Return: | ||||
| 	if(array[0]==nil || array[0]->chans[0] == nil) | ||||
| 		giferror(h, "ReadGIF: no picture in file"); | ||||
|  | ||||
| 	return array; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| readheader(Header *h) | ||||
| { | ||||
| 	if(Bread(h->fd, h->buf, 13) != 13) | ||||
| 		giferror(h, "ReadGIF: can't read header: %r"); | ||||
| 	memmove(h->vers, h->buf, 6); | ||||
| 	if(strcmp(h->vers, "GIF87a")!=0 &&  strcmp(h->vers, "GIF89a")!=0) | ||||
| 		giferror(h, "ReadGIF: can't recognize format %s", h->vers); | ||||
| 	h->screenw = h->buf[6]+(h->buf[7]<<8); | ||||
| 	h->screenh = h->buf[8]+(h->buf[9]<<8); | ||||
| 	h->fields = h->buf[10]; | ||||
| 	h->bgrnd = h->buf[11]; | ||||
| 	h->aspect = h->buf[12]; | ||||
| 	h->flags = 0; | ||||
| 	h->delay = 0; | ||||
| 	h->trindex = 0; | ||||
| 	h->loopcount = -1; | ||||
| } | ||||
|  | ||||
| static | ||||
| unsigned char* | ||||
| readcmap(Header *h, int size) | ||||
| { | ||||
| 	unsigned char *map; | ||||
|  | ||||
| 	if(size > 8) | ||||
| 		giferror(h, "ReadGIF: can't handles %d bits per pixel", size); | ||||
| 	size = 3*(1<<size); | ||||
| 	if(Bread(h->fd, h->buf, size) != size) | ||||
| 		giferror(h, "ReadGIF: short read on color map"); | ||||
| 	map = malloc(size); | ||||
| 	if(map == nil) | ||||
| 		giferror(h, memerr); | ||||
| 	memmove(map, h->buf, size); | ||||
| 	return map; | ||||
| } | ||||
|  | ||||
| static | ||||
| Rawimage* | ||||
| readone(Header *h) | ||||
| { | ||||
| 	Rawimage *i; | ||||
| 	int left, top, width, height; | ||||
|  | ||||
| 	if(Bread(h->fd, h->buf, 9) != 9) | ||||
| 		giferror(h, "ReadGIF: can't read image descriptor: %r"); | ||||
| 	i = malloc(sizeof(Rawimage)); | ||||
| 	if(i == nil) | ||||
| 		giferror(h, memerr); | ||||
| 	left = h->buf[0]+(h->buf[1]<<8); | ||||
| 	top = h->buf[2]+(h->buf[3]<<8); | ||||
| 	width = h->buf[4]+(h->buf[5]<<8); | ||||
| 	height = h->buf[6]+(h->buf[7]<<8); | ||||
| 	i->fields = h->buf[8]; | ||||
| 	i->r.min.x = left; | ||||
| 	i->r.min.y = top; | ||||
| 	i->r.max.x = left+width; | ||||
| 	i->r.max.y = top+height; | ||||
| 	i->nchans = 1; | ||||
| 	i->chandesc = CRGB1; | ||||
| 	memset(i->chans, 0, sizeof(i->chans)); | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
|  | ||||
| static | ||||
| int | ||||
| readdata(Header *h, unsigned char *data) | ||||
| { | ||||
| 	int nbytes, n; | ||||
|  | ||||
| 	nbytes = Bgetc(h->fd); | ||||
| 	if(nbytes < 0) | ||||
| 		giferror(h, "ReadGIF: can't read data: %r"); | ||||
| 	if(nbytes == 0) | ||||
| 		return 0; | ||||
| 	n = Bread(h->fd, data, nbytes); | ||||
| 	if(n < 0) | ||||
| 		giferror(h, "ReadGIF: can't read data: %r"); | ||||
| 	if(n != nbytes) | ||||
| 		fprint(2, "ReadGIF: short data subblock\n"); | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| graphiccontrol(Header *h) | ||||
| { | ||||
| 	if(Bread(h->fd, h->buf, 5+1) != 5+1) | ||||
| 		giferror(h, readerr); | ||||
| 	h->flags = h->buf[1]; | ||||
| 	h->delay = h->buf[2]+(h->buf[3]<<8); | ||||
| 	h->trindex = h->buf[4]; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| skipextension(Header *h) | ||||
| { | ||||
| 	int type, hsize, hasdata, n; | ||||
| 	unsigned char data[256]; | ||||
|  | ||||
| 	hsize = 0; | ||||
| 	hasdata = 0; | ||||
|  | ||||
| 	type = Bgetc(h->fd); | ||||
| 	switch(type){ | ||||
| 	case Beof: | ||||
| 		giferror(h, extreaderr); | ||||
| 		break; | ||||
| 	case 0x01:	/* Plain Text Extension */ | ||||
| 		hsize = 13; | ||||
| 		hasdata = 1; | ||||
| 		break; | ||||
| 	case 0xF9:	/* Graphic Control Extension */ | ||||
| 		graphiccontrol(h); | ||||
| 		return; | ||||
| 	case 0xFE:	/* Comment Extension */ | ||||
| 		hasdata = 1; | ||||
| 		break; | ||||
| 	case 0xFF:	/* Application Extension */ | ||||
| 		hsize = Bgetc(h->fd); | ||||
| 		/* standard says this must be 11, but Adobe likes to put out 10-byte ones, | ||||
| 		 * so we pay attention to the field. */ | ||||
| 		hasdata = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		giferror(h, "ReadGIF: unknown extension"); | ||||
| 	} | ||||
| 	if(hsize>0 && Bread(h->fd, h->buf, hsize) != hsize) | ||||
| 		giferror(h, extreaderr); | ||||
| 	if(!hasdata){ | ||||
| 		/* | ||||
| 		 * This code used to check h->buf[hsize-1] != 0 | ||||
| 		 * and giferror if so, but if !hasdata, hsize == 0. | ||||
| 		 */ | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	/* loop counter: Application Extension with NETSCAPE2.0 as string and 1 <loop.count> in data */ | ||||
| 	if(type == 0xFF && hsize==11 && memcmp(h->buf, "NETSCAPE2.0", 11)==0){ | ||||
| 		n = readdata(h, data); | ||||
| 		if(n == 0) | ||||
| 			return; | ||||
| 		if(n==3 && data[0]==1) | ||||
| 			h->loopcount = data[1] | (data[2]<<8); | ||||
| 	} | ||||
| 	while(readdata(h, data) != 0) | ||||
| 		; | ||||
| } | ||||
|  | ||||
| static | ||||
| unsigned char* | ||||
| decode(Header *h, Rawimage *i, Entry *tbl) | ||||
| { | ||||
| 	int c, incode, codesize, CTM, EOD, pici, datai, stacki, nbits, sreg, fc, code, piclen; | ||||
| 	int csize, nentry, maxentry, first, ocode, ndata, nb; | ||||
| 	unsigned char clip, *p, *pic; | ||||
| 	unsigned char stack[4096], data[256]; | ||||
|  | ||||
| 	if(Bread(h->fd, h->buf, 1) != 1) | ||||
| 		giferror(h, "ReadGIF: can't read data: %r"); | ||||
| 	codesize = h->buf[0]; | ||||
| 	if(codesize>8 || 0>codesize) | ||||
| 		giferror(h, "ReadGIF: can't handle codesize %d", codesize); | ||||
|  | ||||
| 	CTM =1<<codesize; | ||||
| 	EOD = CTM+1; | ||||
|  | ||||
| 	piclen = (i->r.max.x-i->r.min.x)*(i->r.max.y-i->r.min.y); | ||||
| 	i->chanlen = piclen; | ||||
| 	pic = malloc(piclen); | ||||
| 	if(pic == nil) | ||||
| 		giferror(h, memerr); | ||||
| 	h->pic = pic; | ||||
| 	pici = 0; | ||||
| 	ndata = 0; | ||||
| 	datai = 0; | ||||
| 	nbits = 0; | ||||
| 	sreg = 0; | ||||
| 	fc = 0; | ||||
|  | ||||
|     Loop: | ||||
| 	for(;;){ | ||||
| 		csize = codesize+1; | ||||
| 		nentry = EOD+1; | ||||
| 		maxentry = (1<<csize)-1; | ||||
| 		first = 1; | ||||
| 		ocode = -1; | ||||
|  | ||||
| 		for(;; ocode = incode) { | ||||
| 			while(nbits < csize) { | ||||
| 				if(datai == ndata){ | ||||
| 					ndata = readdata(h, data); | ||||
| 					if(ndata == 0) | ||||
| 						goto Return; | ||||
| 					datai = 0; | ||||
| 				} | ||||
| 				c = data[datai++]; | ||||
| 				sreg |= c<<nbits; | ||||
| 				nbits += 8; | ||||
| 			} | ||||
| 			code = sreg & ((1<<csize) - 1); | ||||
| 			sreg >>= csize; | ||||
| 			nbits -= csize; | ||||
|  | ||||
| 			if(code == EOD){ | ||||
| 				ndata = readdata(h, data); | ||||
| 				if(ndata != 0) | ||||
| 					fprint(2, "ReadGIF: unexpected data past EOD\n"); | ||||
| 				goto Return; | ||||
| 			} | ||||
|  | ||||
| 			if(code == CTM) | ||||
| 				goto Loop; | ||||
|  | ||||
| 			stacki = (sizeof stack)-1; | ||||
|  | ||||
| 			incode = code; | ||||
|  | ||||
| 			/* special case for KwKwK */ | ||||
| 			if(code == nentry) { | ||||
| 				stack[stacki--] = fc; | ||||
| 				code = ocode; | ||||
| 			} | ||||
|  | ||||
| 			if(code > nentry){ | ||||
| 				fprint(2, "ReadGIF: GIF invalid, code out of range, %x > %x\n", code, nentry); | ||||
| 				code = nentry; | ||||
| 			} | ||||
| 			for(c=code; stacki>0 && c>=0; c=tbl[c].prefix) | ||||
| 				stack[stacki--] = tbl[c].exten; | ||||
|  | ||||
| 			nb = (sizeof stack)-(stacki+1); | ||||
| 			if(pici+nb > piclen){ | ||||
| 				/* this common error is harmless | ||||
| 				 * we have to keep reading to keep the blocks in sync */ | ||||
| 				; | ||||
| 			}else{ | ||||
| 				memmove(pic+pici, stack+stacki+1, sizeof stack - (stacki+1)); | ||||
| 				pici += nb; | ||||
| 			} | ||||
|  | ||||
| 			fc = stack[stacki+1]; | ||||
|  | ||||
| 			if(first){ | ||||
| 				first = 0; | ||||
| 				continue; | ||||
| 			} | ||||
| 			#define early 0 /* peculiar tiff feature here for reference */ | ||||
| 			if(nentry == maxentry-early) { | ||||
| 				if(csize >= 12) | ||||
| 					continue; | ||||
| 				csize++; | ||||
| 				maxentry = (1<<csize); | ||||
| 				if(csize < 12) | ||||
| 					maxentry--; | ||||
| 			} | ||||
| 			tbl[nentry].prefix = ocode; | ||||
| 			tbl[nentry].exten = fc; | ||||
| 			nentry++; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| Return: | ||||
| 	if(i->cmap!=nil && i->cmaplen!=3*256){ | ||||
| 		clip = (i->cmaplen/3)-1; | ||||
| 		for(p = pic; p < pic+piclen; p++) | ||||
| 			if(*p > clip) | ||||
| 				*p = clip; | ||||
| 	} | ||||
| 	h->pic = nil; | ||||
| 	return pic; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| interlace(Header *h, Rawimage *image) | ||||
| { | ||||
| 	unsigned char *pic; | ||||
| 	Rectangle r; | ||||
| 	int dx, yy, y; | ||||
| 	unsigned char *ipic; | ||||
|  | ||||
| 	pic = image->chans[0]; | ||||
| 	r = image->r; | ||||
| 	dx = r.max.x-r.min.x; | ||||
| 	ipic = malloc(dx*(r.max.y-r.min.y)); | ||||
| 	if(ipic == nil) | ||||
| 		giferror(h, nil); | ||||
|  | ||||
| 	/* Group 1: every 8th row, starting with row 0 */ | ||||
| 	yy = 0; | ||||
| 	for(y=r.min.y; y<r.max.y; y+=8){ | ||||
| 		memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); | ||||
| 		yy++; | ||||
| 	} | ||||
|  | ||||
| 	/* Group 2: every 8th row, starting with row 4 */ | ||||
| 	for(y=r.min.y+4; y<r.max.y; y+=8){ | ||||
| 		memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); | ||||
| 		yy++; | ||||
| 	} | ||||
|  | ||||
| 	/* Group 3: every 4th row, starting with row 2 */ | ||||
| 	for(y=r.min.y+2; y<r.max.y; y+=4){ | ||||
| 		memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); | ||||
| 		yy++; | ||||
| 	} | ||||
|  | ||||
| 	/* Group 4: every 2nd row, starting with row 1 */ | ||||
| 	for(y=r.min.y+1; y<r.max.y; y+=2){ | ||||
| 		memmove(&ipic[(y-r.min.y)*dx], &pic[yy*dx], dx); | ||||
| 		yy++; | ||||
| 	} | ||||
|  | ||||
| 	free(image->chans[0]); | ||||
| 	image->chans[0] = ipic; | ||||
| } | ||||
							
								
								
									
										1659
									
								
								sys/src/cmd/pict/readjpg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1659
									
								
								sys/src/cmd/pict/readjpg.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										531
									
								
								sys/src/cmd/pict/readpng.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										531
									
								
								sys/src/cmd/pict/readpng.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,531 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include <flate.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int debug; | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	IDATSIZE = 8*1024*1024, | ||||
|  | ||||
| 	/* filtering algorithms */ | ||||
| 	FilterNone =	0,	/* new[x][y] = buf[x][y] */ | ||||
| 	FilterSub =	1,	/* new[x][y] = buf[x][y] + new[x-1][y] */ | ||||
| 	FilterUp =		2,	/* new[x][y] = buf[x][y] + new[x][y-1] */ | ||||
| 	FilterAvg =	3,	/* new[x][y] = buf[x][y] + (new[x-1][y]+new[x][y-1])/2 */ | ||||
| 	FilterPaeth =	4,	/* new[x][y] = buf[x][y] + paeth(new[x-1][y],new[x][y-1],new[x-1][y-1]) */ | ||||
| 	FilterLast =	5, | ||||
|  | ||||
| 	PropertyBit = 1<<5, | ||||
| }; | ||||
|  | ||||
| typedef struct ZlibR ZlibR; | ||||
| typedef struct ZlibW ZlibW; | ||||
|  | ||||
| struct ZlibW | ||||
| { | ||||
| 	unsigned char *data;		/* Rawimage data */ | ||||
| 	int ndata; | ||||
| 	int noutchan; | ||||
| 	int chandesc; | ||||
| 	int nchan; | ||||
|  | ||||
| 	unsigned char *scan;		/* new scanline */ | ||||
| 	unsigned char *lastscan;	/* previous scan line */ | ||||
| 	int scanlen;		/* scan line length */ | ||||
| 	int scanpos;		/* scan position */ | ||||
|  | ||||
| 	int dx;			/* width of image */ | ||||
| 	int dy;			/* height of image */ | ||||
| 	int bpc;			/* bits per channel (per pixel) */ | ||||
| 	int y;				/* current scan line */ | ||||
| 	int pass;			/* adam7 pass#; 0 means no adam7 */ | ||||
| 	unsigned char palette[3*256];	/* color palette */ | ||||
| 	int palsize;		/* number of palette entries */ | ||||
| }; | ||||
|  | ||||
| struct ZlibR | ||||
| { | ||||
| 	Biobuf *io;		/* input buffer */ | ||||
| 	unsigned char *buf;		/* malloc'ed staging buffer */ | ||||
| 	unsigned char *p;			/* next byte to decompress */ | ||||
| 	unsigned char *e;			/* end of buffer */ | ||||
| 	ZlibW *w; | ||||
| }; | ||||
|  | ||||
| static uint32_t *crctab; | ||||
| static unsigned char PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'}; | ||||
|  | ||||
| static uint32_t | ||||
| get4(unsigned char *a) | ||||
| { | ||||
| 	return (a[0]<<24) | (a[1]<<16) | (a[2]<<8) | a[3]; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| pnginit(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited) | ||||
| 		return; | ||||
| 	inited = 1; | ||||
| 	crctab = mkcrctab(0xedb88320); | ||||
| 	if(crctab == nil) | ||||
| 		sysfatal("mkcrctab error"); | ||||
| 	inflateinit(); | ||||
| } | ||||
|  | ||||
| static | ||||
| void* | ||||
| pngmalloc(uint32_t n, int clear) | ||||
| { | ||||
| 	void *p; | ||||
|  | ||||
| 	p = mallocz(n, clear); | ||||
| 	if(p == nil) | ||||
| 		sysfatal("malloc: %r"); | ||||
| 	return p; | ||||
| } | ||||
|  | ||||
| static int | ||||
| getchunk(Biobuf *b, char *type, unsigned char *d, int m) | ||||
| { | ||||
| 	unsigned char buf[8]; | ||||
| 	uint32_t crc = 0, crc2; | ||||
| 	int n, nr; | ||||
|  | ||||
| 	if(Bread(b, buf, 8) != 8) | ||||
| 		return -1; | ||||
| 	n = get4(buf); | ||||
| 	memmove(type, buf+4, 4); | ||||
| 	type[4] = 0; | ||||
| 	if(n > m) | ||||
| 		sysfatal("getchunk needed %d, had %d", n, m); | ||||
| 	nr = Bread(b, d, n); | ||||
| 	if(nr != n) | ||||
| 		sysfatal("getchunk read %d, expected %d", nr, n); | ||||
| 	crc = blockcrc(crctab, crc, type, 4); | ||||
| 	crc = blockcrc(crctab, crc, d, n); | ||||
| 	if(Bread(b, buf, 4) != 4) | ||||
| 		sysfatal("getchunk tlr failed"); | ||||
| 	crc2 = get4(buf); | ||||
| 	if(crc != crc2) | ||||
| 		sysfatal("getchunk crc failed"); | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static int | ||||
| zread(void *va) | ||||
| { | ||||
| 	ZlibR *z = va; | ||||
| 	char type[5]; | ||||
| 	int n; | ||||
|  | ||||
| 	if(z->p >= z->e){ | ||||
| 	Again: | ||||
| 		z->p = z->buf; | ||||
| 		z->e = z->p; | ||||
| 		n = getchunk(z->io, type, z->p, IDATSIZE); | ||||
| 		if(n < 0 || strcmp(type, "IEND") == 0) | ||||
| 			return -1; | ||||
| 		z->e = z->p + n; | ||||
| 		if(!strcmp(type,"PLTE")){ | ||||
| 			if(n < 3 || n > 3*256 || n%3) | ||||
| 				sysfatal("invalid PLTE chunk len %d", n); | ||||
| 			memcpy(z->w->palette, z->p, n); | ||||
| 			z->w->palsize = 256; | ||||
| 			goto Again; | ||||
| 		} | ||||
| 		if(type[0] & PropertyBit) | ||||
| 			goto Again;  /* skip auxiliary chunks fornow */ | ||||
| 		if(strcmp(type,"IDAT")){ | ||||
| 			sysfatal("unrecognized mandatory chunk %s", type); | ||||
| 			goto Again; | ||||
| 		} | ||||
| 	} | ||||
| 	return *z->p++; | ||||
| } | ||||
|  | ||||
| static unsigned char | ||||
| paeth(unsigned char a, unsigned char b, unsigned char c) | ||||
| { | ||||
| 	int p, pa, pb, pc; | ||||
|  | ||||
| 	p = a + b - c; | ||||
| 	pa = abs(p - a); | ||||
| 	pb = abs(p - b); | ||||
| 	pc = abs(p - c); | ||||
|  | ||||
| 	if(pa <= pb && pa <= pc) | ||||
| 		return a; | ||||
| 	else if(pb <= pc) | ||||
| 		return b; | ||||
| 	return c; | ||||
| } | ||||
|  | ||||
| static void | ||||
| unfilter(int alg, unsigned char *buf, unsigned char *up, int len, int bypp) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	switch(alg){ | ||||
| 	default: | ||||
| 		fprint(2, "unknown filtering scheme %d\n", alg); | ||||
| 	case FilterNone: | ||||
| 		break; | ||||
|  | ||||
| 	case FilterSub: | ||||
| 		for(i = bypp; i < len; ++i) | ||||
| 			buf[i] += buf[i-bypp]; | ||||
| 		break; | ||||
|  | ||||
| 	case FilterUp: | ||||
| 		for(i = 0; i < len; ++i) | ||||
| 			buf[i] += up[i]; | ||||
| 		break; | ||||
|  | ||||
| 	case FilterAvg: | ||||
| 		for(i = 0; i < bypp; ++i) | ||||
| 			buf[i] += (0+up[i])/2; | ||||
| 		for(; i < len; ++i) | ||||
| 			buf[i] += (buf[i-bypp]+up[i])/2; | ||||
| 		break; | ||||
|  | ||||
| 	case FilterPaeth: | ||||
| 		for(i = 0; i < bypp; ++i) | ||||
| 			buf[i] += paeth(0, up[i], 0); | ||||
| 		for(; i < len; ++i) | ||||
| 			buf[i] += paeth(buf[i-bypp], up[i], up[i-bypp]); | ||||
| 		break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| struct { | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	int dx; | ||||
| 	int dy; | ||||
| } adam7[] = { | ||||
| 	{0,0,1,1},	/* eve alone */ | ||||
| 	{0,0,8,8},	/* pass 1 */ | ||||
| 	{4,0,8,8},	/* pass 2 */ | ||||
| 	{0,4,4,8},	/* pass 3 */ | ||||
| 	{2,0,4,4},	/* pass 4 */ | ||||
| 	{0,2,2,4},	/* pass 5 */ | ||||
| 	{1,0,2,2},	/* pass 6 */ | ||||
| 	{0,1,1,2},	/* pass 7 */ | ||||
| }; | ||||
|  | ||||
| static void | ||||
| scan(int len, ZlibW *z) | ||||
| { | ||||
| 	int chan, i, j, nbit, off, val; | ||||
| 	unsigned char pixel[4], *p, *w; | ||||
|  | ||||
| 	unfilter(z->scan[0], z->scan+1, z->lastscan+1, len-1, (z->nchan*z->bpc+7)/8); | ||||
|  | ||||
| 	/* | ||||
| 	 * loop over raw bits extracting pixel values and converting to 8-bit | ||||
| 	 */ | ||||
| 	nbit = 0; | ||||
| 	chan = 0; | ||||
| 	val = 0; | ||||
| 	off = z->y*z->dx + adam7[z->pass].x; | ||||
| 	w = z->data + z->noutchan*off; | ||||
| 	p = z->scan+1;	/* skip alg byte */ | ||||
| 	len--; | ||||
| 	for(i=0; i<len*8; i++){ | ||||
| 		val <<= 1; | ||||
| 		if(p[i>>3] & (1<<(7-(i&7)))) | ||||
| 			val++; | ||||
| 		if(++nbit == z->bpc){ | ||||
| 			/* finished the value */ | ||||
| 			pixel[chan++] = (val*255)/((1<<z->bpc)-1); | ||||
| 			val = 0; | ||||
| 			nbit = 0; | ||||
| 			if(chan == z->nchan){ | ||||
| 				/* finished the pixel */ | ||||
| 				if(off < z->dx*z->dy){ | ||||
| 					if(z->nchan < 3 && z->palsize){ | ||||
| 						j = pixel[0]; | ||||
| 						if(z->bpc < 8) | ||||
| 							j >>= 8-z->bpc; | ||||
| 						if(j >= z->palsize) | ||||
| 							sysfatal("index %d >= palette size %d", j, z->palsize); | ||||
| 						pixel[3] = pixel[1];	/* alpha */ | ||||
| 						pixel[0] = z->palette[3*j]; | ||||
| 						pixel[1] = z->palette[3*j+1]; | ||||
| 						pixel[2] = z->palette[3*j+2]; | ||||
| 					} | ||||
| 					switch(z->chandesc){ | ||||
| 					case CYA16: | ||||
| 					//	print("%.2x%.2x ", pixel[0], pixel[1]); | ||||
| 						*w++ = pixel[1]; | ||||
| 						*w++ += (pixel[0]*pixel[1])/255; | ||||
| 						break; | ||||
| 					case CRGBA32: | ||||
| 					//	print("%.2x%.2x%.2x%.2x ", pixel[0], pixel[1], pixel[2], pixel[3]); | ||||
| 						*w++ += pixel[3]; | ||||
| 						*w++ += (pixel[2]*pixel[3])/255; | ||||
| 						*w++ += (pixel[1]*pixel[3])/255; | ||||
| 						*w++ += (pixel[0]*pixel[3])/255; | ||||
| 						break; | ||||
| 					case CRGB24: | ||||
| 						*w++ = pixel[2]; | ||||
| 						*w++ = pixel[1]; | ||||
| 					case CY: | ||||
| 						*w++ = pixel[0]; | ||||
| 						break; | ||||
| 					} | ||||
| 					w += (adam7[z->pass].dx-1)*z->noutchan; | ||||
| 				} | ||||
| 				off += adam7[z->pass].dx; | ||||
| 				if(off >= (z->y+1)*z->dx){ | ||||
| 					/* finished the line */ | ||||
| 					return; | ||||
| 				} | ||||
| 				chan = 0; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	sysfatal("scan line too short"); | ||||
| } | ||||
|  | ||||
| static int | ||||
| scanbytes(ZlibW *z) | ||||
| { | ||||
| 	int bits, n, adx, dx; | ||||
|  | ||||
| 	if(adam7[z->pass].y >= z->dy || adam7[z->pass].x >= z->dx) | ||||
| 		return 0; | ||||
| 	adx = adam7[z->pass].dx; | ||||
| 	dx = z->dx - adam7[z->pass].x; | ||||
| 	if(dx <= 0) | ||||
| 		n = 1; | ||||
| 	else | ||||
| 		n = (dx+adx-1)/adx; | ||||
| 	if(n != 1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx){ | ||||
| 		fprint(2, "%d/%d != 1+(%d-1)/%d = %d\n", | ||||
| 			z->dx - adam7[z->pass].x - 1 + adx, adx, | ||||
| 			z->dx - (adam7[z->pass].x+1), adam7[z->pass].dx, | ||||
| 			1 + (z->dx - (adam7[z->pass].x+1)) / adam7[z->pass].dx); | ||||
| 	} | ||||
| 	bits = n*z->bpc*z->nchan; | ||||
| 	return 1 + (bits+7)/8; | ||||
| } | ||||
|  | ||||
| static int | ||||
| nextpass(ZlibW *z) | ||||
| { | ||||
| 	int len; | ||||
|  | ||||
| 	memset(z->lastscan, 0, z->scanlen); | ||||
| 	do{ | ||||
| 		z->pass = (z->pass+1)%8; | ||||
| 		z->y = adam7[z->pass].y; | ||||
| 		len = scanbytes(z); | ||||
| 	}while(len < 2); | ||||
| 	return len; | ||||
| } | ||||
|  | ||||
| static int | ||||
| zwrite(void *vz, void *vbuf, int n) | ||||
| { | ||||
| 	int oldn, m, len; | ||||
| 	unsigned char *buf, *t; | ||||
| 	ZlibW *z; | ||||
|  | ||||
| 	z = vz; | ||||
| 	buf = vbuf; | ||||
| 	oldn = n; | ||||
|  | ||||
| 	len = scanbytes(z); | ||||
| 	if(len < 2) | ||||
| 		len = nextpass(z); | ||||
|  | ||||
| 	while(n > 0){ | ||||
| 		m = len - z->scanpos; | ||||
| 		if(m > n){ | ||||
| 			/* save final partial line */ | ||||
| 			memmove(z->scan+z->scanpos, buf, n); | ||||
| 			z->scanpos += n; | ||||
| 			break; | ||||
| 		} | ||||
|  | ||||
| 		/* fill line */ | ||||
| 		memmove(z->scan+z->scanpos, buf, m); | ||||
| 		buf += m; | ||||
| 		n -= m; | ||||
|  | ||||
| 		/* process line */ | ||||
| 		scan(len, z); | ||||
| 		t = z->scan; | ||||
| 		z->scan = z->lastscan; | ||||
| 		z->lastscan = t; | ||||
|  | ||||
| 		z->scanpos = 0; | ||||
| 		z->y += adam7[z->pass].dy; | ||||
| 		if(z->y >= z->dy) | ||||
| 			len = nextpass(z); | ||||
| 	} | ||||
| 	return oldn; | ||||
| } | ||||
|  | ||||
| static Rawimage* | ||||
| readslave(Biobuf *b) | ||||
| { | ||||
| 	char type[5]; | ||||
| 	int bpc, colorfmt, dx, dy, err, n, nchan, nout, useadam7; | ||||
| 	unsigned char *buf, *h; | ||||
| 	Rawimage *image; | ||||
| 	ZlibR zr; | ||||
| 	ZlibW zw; | ||||
|  | ||||
| 	buf = pngmalloc(IDATSIZE, 0); | ||||
| 	if(Bread(b, buf, sizeof PNGmagic) != sizeof PNGmagic | ||||
| 	|| memcmp(PNGmagic, buf, sizeof PNGmagic) != 0) | ||||
| 		sysfatal("bad PNGmagic"); | ||||
|  | ||||
| 	n = getchunk(b, type, buf, IDATSIZE); | ||||
| 	if(n < 13 || strcmp(type,"IHDR") != 0) | ||||
| 		sysfatal("missing IHDR chunk"); | ||||
| 	h = buf; | ||||
| 	dx = get4(h); | ||||
| 	h += 4; | ||||
| 	dy = get4(h); | ||||
| 	h += 4; | ||||
| 	if(dx <= 0 || dy <= 0) | ||||
| 		sysfatal("impossible image size %dx%d", dx, dy); | ||||
| 	if(debug) | ||||
| 		fprint(2, "readpng %dx%d\n", dx, dy); | ||||
|  | ||||
| 	bpc = *h++; | ||||
| 	colorfmt = *h++; | ||||
| 	nchan = 0; | ||||
| 	if(*h++ != 0) | ||||
| 		sysfatal("only deflate supported for now [%d]", h[-1]); | ||||
| 	if(*h++ != FilterNone) | ||||
| 		sysfatal("only FilterNone supported for now [%d]", h[-1]); | ||||
| 	useadam7 = *h++; | ||||
| 	USED(h); | ||||
|  | ||||
| 	image = pngmalloc(sizeof(Rawimage), 1); | ||||
| 	image->r = Rect(0, 0, dx, dy); | ||||
| 	nout = 0; | ||||
| 	switch(colorfmt){ | ||||
| 	case 0:	/* grey */ | ||||
| 		if(bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8 && bpc != 16) | ||||
| 			sysfatal("invalid greyscale bpc %d", bpc); | ||||
| 		image->nchans = 1; | ||||
| 		image->chandesc = CY; | ||||
| 		nout = 1; | ||||
| 		nchan = 1; | ||||
| 		break; | ||||
| 	case 2:	/* rgb */ | ||||
| 		if(bpc != 8 && bpc != 16) | ||||
| 			sysfatal("invalid rgb bpc %d", bpc); | ||||
| 		image->nchans = 1; | ||||
| 		image->chandesc = CRGB24; | ||||
| 		nout = 3; | ||||
| 		nchan = 3; | ||||
| 		break; | ||||
| 	case 3: /* indexed rgb with PLTE */ | ||||
| 		if(bpc != 1 && bpc != 2 && bpc != 4 && bpc != 8) | ||||
| 			sysfatal("invalid indexed rgb bpc %d", bpc); | ||||
| 		image->nchans = 1; | ||||
| 		image->chandesc = CRGB24; | ||||
| 		nout = 3; | ||||
| 		nchan = 1; | ||||
| 		break; | ||||
| 	case 4:	/* grey+alpha */ | ||||
| 		if(bpc != 8 && bpc != 16) | ||||
| 			sysfatal("invalid grey+alpha bpc %d", bpc); | ||||
| 		image->nchans = 1; | ||||
| 		image->chandesc = CYA16; | ||||
| 		nout = 2; | ||||
| 		nchan = 2; | ||||
| 		break; | ||||
| 	case 6:	/* rgb+alpha */ | ||||
| 		if(bpc != 8 && bpc != 16) | ||||
| 			sysfatal("invalid rgb+alpha bpc %d", bpc); | ||||
| 		image->nchans = 1; | ||||
| 		image->chandesc = CRGBA32; | ||||
| 		nout = 4; | ||||
| 		nchan = 4; | ||||
| 		break; | ||||
| 	default: | ||||
| 		sysfatal("unsupported color scheme %d", h[-1]); | ||||
| 	} | ||||
| 	image->chanlen = dx*dy*nout; | ||||
| 	image->chans[0] = pngmalloc(image->chanlen, 0); | ||||
| 	memset(image->chans[0], 0, image->chanlen); | ||||
|  | ||||
| 	memset(&zr, 0, sizeof zr); | ||||
| 	zr.w = &zw; | ||||
| 	zr.io = b; | ||||
| 	zr.buf = buf; | ||||
|  | ||||
| 	memset(&zw, 0, sizeof zw); | ||||
| 	if(useadam7) | ||||
| 		zw.pass = 1; | ||||
| 	zw.data = image->chans[0]; | ||||
| 	zw.ndata = image->chanlen; | ||||
| 	zw.chandesc = image->chandesc; | ||||
| 	zw.noutchan = nout; | ||||
|  | ||||
| 	zw.dx = dx; | ||||
| 	zw.dy = dy; | ||||
| 	zw.scanlen = (nchan*dx*bpc+7)/8+1; | ||||
| 	zw.scan = pngmalloc(zw.scanlen, 1); | ||||
| 	zw.lastscan = pngmalloc(zw.scanlen, 1); | ||||
| 	zw.nchan = nchan; | ||||
| 	zw.bpc = bpc; | ||||
|  | ||||
| 	err = inflatezlib(&zw, zwrite, &zr, zread); | ||||
|  | ||||
| 	if(err) | ||||
| 		sysfatal("inflatezlib %s\n", flateerr(err)); | ||||
|  | ||||
| 	free(buf); | ||||
| 	free(zw.scan); | ||||
| 	free(zw.lastscan); | ||||
| 	return image; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| Breadpng(Biobuf *b, int colorspace) | ||||
| { | ||||
| 	Rawimage **array, *r; | ||||
|  | ||||
| 	if(colorspace != CRGB){ | ||||
| 		werrstr("ReadPNG: unknown color space %d", colorspace); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	pnginit(); | ||||
| 	array = malloc(2*sizeof(*array)); | ||||
| 	if(array==nil) | ||||
| 		return nil; | ||||
| 	r = readslave(b); | ||||
| 	array[0] = r; | ||||
| 	array[1] = nil; | ||||
| 	return array; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| readpng(int fd, int colorspace) | ||||
| { | ||||
| 	Biobuf b; | ||||
| 	Rawimage **a; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	a = Breadpng(&b, colorspace); | ||||
| 	Bterm(&b); | ||||
| 	return a; | ||||
| } | ||||
							
								
								
									
										237
									
								
								sys/src/cmd/pict/readppm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										237
									
								
								sys/src/cmd/pict/readppm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,237 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <ctype.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| Rawimage *readppm(Biobuf*, Rawimage*); | ||||
|  | ||||
| /* | ||||
|  * fetch a non-comment character. | ||||
|  */ | ||||
| static | ||||
| int | ||||
| Bgetch(Biobufhdr *b) | ||||
| { | ||||
| 	int c; | ||||
|  | ||||
| 	for(;;) { | ||||
| 		c = Bgetc(b); | ||||
| 		if(c == '#') { | ||||
| 			while((c = Bgetc(b)) != Beof && c != '\n') | ||||
| 				; | ||||
| 		} | ||||
| 		return c; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * fetch a nonnegative decimal integer. | ||||
|  */ | ||||
| static | ||||
| int | ||||
| Bgetint(Biobufhdr *b) | ||||
| { | ||||
| 	int c; | ||||
| 	int i; | ||||
|  | ||||
| 	while((c = Bgetch(b)) != Beof && !isdigit(c)) | ||||
| 		; | ||||
| 	if(c == Beof) | ||||
| 		return -1; | ||||
|  | ||||
| 	i = 0; | ||||
| 	do { | ||||
| 		i = i*10 + (c-'0'); | ||||
| 	} while((c = Bgetch(b)) != Beof && isdigit(c)); | ||||
|  | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| static | ||||
| int | ||||
| Bgetdecimalbit(Biobufhdr *b) | ||||
| { | ||||
| 	int c; | ||||
| 	while((c = Bgetch(b)) != Beof && c != '0' && c != '1') | ||||
| 		; | ||||
| 	if(c == Beof) | ||||
| 		return -1; | ||||
| 	return c == '1'; | ||||
| } | ||||
|  | ||||
| static int bitc, nbit; | ||||
|  | ||||
| static | ||||
| int | ||||
| Bgetbit(Biobufhdr *b) | ||||
| { | ||||
| 	if(nbit == 0) { | ||||
| 		nbit = 8; | ||||
| 		bitc = Bgetc(b); | ||||
| 		if(bitc == -1) | ||||
| 			return -1; | ||||
| 	} | ||||
| 	nbit--; | ||||
| 	return (bitc >> nbit) & 0x1; | ||||
| } | ||||
|  | ||||
| static | ||||
| void | ||||
| Bflushbit(Biobufhdr* _) | ||||
| { | ||||
| 	nbit = 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| Rawimage** | ||||
| readpixmap(int fd, int colorspace) | ||||
| { | ||||
| 	Rawimage **array, *a; | ||||
| 	Biobuf b; | ||||
| 	char buf[ERRMAX]; | ||||
| 	int i; | ||||
| 	char *e; | ||||
|  | ||||
| 	USED(colorspace); | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
|  | ||||
| 	werrstr(""); | ||||
| 	e = "out of memory"; | ||||
| 	if((array = malloc(sizeof *array)) == nil) | ||||
| 		goto Error; | ||||
| 	if((array[0] = malloc(sizeof *array[0])) == nil) | ||||
| 		goto Error; | ||||
| 	memset(array[0], 0, sizeof *array[0]); | ||||
|  | ||||
| 	for(i=0; i<3; i++) | ||||
| 		array[0]->chans[i] = nil; | ||||
|  | ||||
| 	e = "bad file format"; | ||||
| 	switch(Bgetc(&b)) { | ||||
| 	case 'P': | ||||
| 		Bungetc(&b); | ||||
| 		a = readppm(&b, array[0]); | ||||
| 		break; | ||||
| 	default: | ||||
| 		a = nil; | ||||
| 		break; | ||||
| 	} | ||||
| 	if(a == nil) | ||||
| 		goto Error; | ||||
| 	array[0] = a; | ||||
|  | ||||
| 	return array; | ||||
|  | ||||
| Error: | ||||
| 	if(array) | ||||
| 		free(array[0]); | ||||
| 	free(array); | ||||
|  | ||||
| 	errstr(buf, sizeof buf); | ||||
| 	if(buf[0] == 0) | ||||
| 		strcpy(buf, e); | ||||
| 	errstr(buf, sizeof buf); | ||||
|  | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| typedef struct Pix	Pix; | ||||
| struct Pix { | ||||
| 	char magic; | ||||
| 	int	maxcol; | ||||
| 	int	(*fetch)(Biobufhdr*); | ||||
| 	int	nchan; | ||||
| 	int	chandesc; | ||||
| 	int	invert; | ||||
| 	void	(*flush)(Biobufhdr*); | ||||
| }; | ||||
|  | ||||
| static Pix pix[] = { | ||||
| 	{ '1', 1, Bgetdecimalbit, 1, CY, 1, nil },	/* portable bitmap */ | ||||
| 	{ '4', 1, Bgetbit, 1, CY, 1, Bflushbit },	/* raw portable bitmap */ | ||||
| 	{ '2', 0, Bgetint, 1, CY, 0, nil },	/* portable greymap */ | ||||
| 	{ '5', 0, Bgetc, 1, CY, 0, nil },	/* raw portable greymap */ | ||||
| 	{ '3', 0, Bgetint, 3, CRGB, 0, nil },	/* portable pixmap */ | ||||
| 	{ '6', 0, Bgetc, 3, CRGB, 0, nil },	/* raw portable pixmap */ | ||||
| 	{ 0 }, | ||||
| }; | ||||
|  | ||||
| Rawimage* | ||||
| readppm(Biobuf *b, Rawimage *a) | ||||
| { | ||||
| 	int i, ch, wid, ht, r, c; | ||||
| 	int maxcol, nchan, invert; | ||||
| 	int (*fetch)(Biobufhdr*); | ||||
| 	unsigned char *rgb[3]; | ||||
| 	char buf[ERRMAX]; | ||||
| 	char *e; | ||||
| 	Pix *p; | ||||
|  | ||||
| 	e = "bad file format"; | ||||
| 	if(Bgetc(b) != 'P') | ||||
| 		goto Error; | ||||
|  | ||||
| 	c = Bgetc(b); | ||||
| 	for(p=pix; p->magic; p++) | ||||
| 		if(p->magic == c) | ||||
| 			break; | ||||
| 	if(p->magic == 0) | ||||
| 		goto Error; | ||||
|  | ||||
|  | ||||
| 	wid = Bgetint(b); | ||||
| 	ht = Bgetint(b); | ||||
| 	if(wid <= 0 || ht <= 0) | ||||
| 		goto Error; | ||||
| 	a->r = Rect(0,0,wid,ht); | ||||
|  | ||||
| 	maxcol = p->maxcol; | ||||
| 	if(maxcol == 0) { | ||||
| 		maxcol = Bgetint(b); | ||||
| 		if(maxcol <= 0) | ||||
| 			goto Error; | ||||
| 	} | ||||
|  | ||||
| 	e = "out of memory"; | ||||
| 	for(i=0; i<p->nchan; i++) | ||||
| 		if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil) | ||||
| 			goto Error; | ||||
| 	a->nchans = p->nchan; | ||||
| 	a->chanlen = wid*ht; | ||||
| 	a->chandesc = p->chandesc; | ||||
|  | ||||
| 	e = "error reading file"; | ||||
|  | ||||
| 	fetch = p->fetch; | ||||
| 	nchan = p->nchan; | ||||
| 	invert = p->invert; | ||||
| 	for(r=0; r<ht; r++) { | ||||
| 		for(c=0; c<wid; c++) { | ||||
| 			for(i=0; i<nchan; i++) { | ||||
| 				if((ch = (*fetch)(b)) < 0) | ||||
| 					goto Error; | ||||
| 				if(invert) | ||||
| 					ch = maxcol - ch; | ||||
| 				*rgb[i]++ = (ch * 255)/maxcol; | ||||
| 			} | ||||
| 		} | ||||
| 		if(p->flush) | ||||
| 			(*p->flush)(b); | ||||
| 	} | ||||
|  | ||||
| 	return a; | ||||
|  | ||||
| Error: | ||||
| 	errstr(buf, sizeof buf); | ||||
| 	if(buf[0] == 0) | ||||
| 		strcpy(buf, e); | ||||
| 	errstr(buf, sizeof buf); | ||||
|  | ||||
| 	for(i=0; i<3; i++) | ||||
| 		free(a->chans[i]); | ||||
| 	free(a->cmap); | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										510
									
								
								sys/src/cmd/pict/readtga.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										510
									
								
								sys/src/cmd/pict/readtga.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,510 @@ | ||||
| /* | ||||
|  * TGA is a fairly dead standard, however in the video industry | ||||
|  * it is still used a little for test patterns and the like. | ||||
|  * | ||||
|  * Thus we ignore any alpha channels. | ||||
|  */ | ||||
|  | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <ctype.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| enum { | ||||
| 	HdrLen = 18, | ||||
| }; | ||||
|  | ||||
| typedef struct { | ||||
| 	int idlen;			/* length of string after header */ | ||||
| 	int cmaptype;		/* 1 => datatype = 1 => colourmapped */ | ||||
| 	int datatype;		/* see below */ | ||||
| 	int cmaporigin;		/* index of first entry in colour map */ | ||||
| 	int cmaplen;		/* length of colour map */ | ||||
| 	int cmapbpp;		/* bits per pixel of colour map: 16, 24, or 32 */ | ||||
| 	int xorigin;		/* source image origin */ | ||||
| 	int yorigin; | ||||
| 	int width; | ||||
| 	int height; | ||||
| 	int bpp;			/* bits per pixel of image: 16, 24, or 32 */ | ||||
| 	int descriptor; | ||||
| 	unsigned char *cmap;		/* colour map (optional) */ | ||||
| } Tga; | ||||
|  | ||||
| /* | ||||
|  * descriptor: | ||||
|  * d0-3 = number of attribute bits per pixel | ||||
|  * d4 	= reserved, always zero | ||||
|  * d6-7	= origin: 0=lower left, 1=upper left, 2=lower right, 3=upper right | ||||
|  * d8-9 = interleave: 0=progressive, 1=2 way, 3=4 way, 4=reserved. | ||||
|  */ | ||||
|  | ||||
| char *datatype[] = { | ||||
| 	[0]		"No image data", | ||||
| 	[1]		"Color-mapped", | ||||
| 	[2]		"RGB", | ||||
| 	[3]		"B&W", | ||||
| 	[9]		"RLE color-mapped", | ||||
| 	[10]	"RLE RGB", | ||||
| 	[11]	"RLE B&W", | ||||
| 	[32]	"Compressed color", | ||||
| 	[33]	"Quadtree compressed color", | ||||
| }; | ||||
|  | ||||
| static int | ||||
| Bgeti(Biobuf *bp) | ||||
| { | ||||
| 	int x, y; | ||||
|  | ||||
| 	if((x = Bgetc(bp)) < 0) | ||||
| 		return -1; | ||||
| 	if((y = Bgetc(bp)) < 0) | ||||
| 		return -1; | ||||
| 	return (y<<8)|x; | ||||
| } | ||||
|  | ||||
| static int | ||||
| fixcmap(unsigned char *cmap, int *cmapbpp, int cmaplen) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned short x; | ||||
| 	unsigned char tmp; | ||||
|  | ||||
| 	switch(*cmapbpp){ | ||||
| 	case 32: | ||||
| 		/* swap B with R */ | ||||
| 		for(i = 0; i < cmaplen; i++){ | ||||
| 			tmp = cmap[4*i+0]; | ||||
| 			cmap[4*i+0] = cmap[4*i+2]; | ||||
| 			cmap[4*i+2] = tmp; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 24: | ||||
| 		/* swap B with R */ | ||||
| 		for(i = 0; i < cmaplen; i++){ | ||||
| 			tmp = cmap[3*i+0]; | ||||
| 			cmap[3*i+0] = cmap[3*i+2]; | ||||
| 			cmap[3*i+2] = tmp; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 16: | ||||
| 	case 15: | ||||
| 		/* convert to 24-bit colormap */ | ||||
| 		if((cmap = realloc(cmap, 3*cmaplen)) == nil) | ||||
| 			return -1; | ||||
| 		for(i = cmaplen-1; i >= 0; i--){ | ||||
| 			x = (cmap[2*i+1]<<8) | cmap[2*i+0]; | ||||
| 			tmp = (x>>0)&0x1f; | ||||
| 			cmap[3*i+2] = (tmp<<3) | (tmp>>2); | ||||
| 			tmp = (x>>5)&0x1f; | ||||
| 			cmap[3*i+1] = (tmp<<3) | (tmp>>2); | ||||
| 			tmp = (x>>10)&0x1f; | ||||
| 			cmap[3*i+0] = (tmp<<3) | (tmp>>2); | ||||
| 		} | ||||
| 		*cmapbpp = 24; | ||||
| 		break; | ||||
| 	default: | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static Tga * | ||||
| rdhdr(Biobuf *bp) | ||||
| { | ||||
| 	int n; | ||||
| 	Tga *h; | ||||
|  | ||||
| 	if((h = malloc(sizeof(Tga))) == nil) | ||||
| 		return nil; | ||||
| 	if((h->idlen = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->cmaptype = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->datatype = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->cmaporigin = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->cmaplen = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->cmapbpp = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->xorigin = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->yorigin = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->width = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->height = Bgeti(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->bpp = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
| 	if((h->descriptor = Bgetc(bp)) == -1) | ||||
| 		return nil; | ||||
|  | ||||
| 	/* skip over ID, usually empty anyway */ | ||||
| 	if(Bseek(bp, h->idlen, 1) < 0){ | ||||
| 		free(h); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if(h->cmaptype == 0){ | ||||
| 		h->cmap = 0; | ||||
| 		return h; | ||||
| 	} | ||||
|  | ||||
| 	/* skip over unused color map data */ | ||||
| 	n = (h->cmapbpp/8)*h->cmaporigin; | ||||
| 	if(Bseek(bp, n, 1) < 0){ | ||||
| 		free(h); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	h->cmaplen -= h->cmaporigin; | ||||
|  | ||||
| 	n = (h->cmapbpp/8)*h->cmaplen; | ||||
| 	if((h->cmap = malloc(n)) == nil){ | ||||
| 		free(h); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	if(Bread(bp, h->cmap, n) != n){ | ||||
| 		free(h); | ||||
| 		free(h->cmap); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	if(fixcmap(h->cmap, &h->cmapbpp, h->cmaplen) != 0){ | ||||
| 		free(h); | ||||
| 		free(h->cmap); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	return h; | ||||
| } | ||||
|  | ||||
| static int | ||||
| cmap(Biobuf *bp, unsigned char *l, int num) | ||||
| { | ||||
| 	return Bread(bp, l, num); | ||||
| } | ||||
|  | ||||
| static int | ||||
| luma(Biobuf *bp, int bpp, unsigned char *l, int num) | ||||
| { | ||||
| 	char tmp[2]; | ||||
| 	int got; | ||||
|  | ||||
| 	if(bpp == 8){ | ||||
| 		got = Bread(bp, l, num); | ||||
| 	} | ||||
| 	else{ | ||||
| 		for(got = 0; got < num; got++){ | ||||
| 			if(Bread(bp, tmp, 2) != 2) | ||||
| 				break; | ||||
| 			*l++ = tmp[0]; | ||||
| 		} | ||||
| 	} | ||||
| 	return got; | ||||
| } | ||||
|  | ||||
| static int | ||||
| luma_rle(Biobuf *bp, int bpp, unsigned char *l, int num) | ||||
| { | ||||
| 	unsigned char len, p; | ||||
| 	int got; | ||||
|  | ||||
| 	for(got = 0; got < num;){ | ||||
| 		if(Bread(bp, &len, 1) != 1) | ||||
| 			break; | ||||
| 		if(len & 0x80){ | ||||
| 			len &= 0x7f; | ||||
| 			if(luma(bp, bpp, &p, 1) != 1) | ||||
| 				break; | ||||
| 			for(len++; len > 0 && got < num; len--, got++) | ||||
| 				*l++ = p; | ||||
| 		} | ||||
| 		else{ | ||||
| 			for(len++; len > 0 && got < num; len--, got++) | ||||
| 				if(luma(bp, bpp, l++, 1) != 1) | ||||
| 					return got; | ||||
| 		} | ||||
| 	} | ||||
| 	return got; | ||||
| } | ||||
|  | ||||
| static int | ||||
| cmap_rle(Biobuf *bp, unsigned char *l, int num) | ||||
| { | ||||
| 	return luma_rle(bp, 8, l, num); | ||||
| } | ||||
|  | ||||
| static int | ||||
| rgba(Biobuf *bp, int bpp, unsigned char *r, unsigned char *g, unsigned char *b, int num) | ||||
| { | ||||
| 	int i; | ||||
| 	unsigned char buf[4], tmp; | ||||
| 	unsigned short x; | ||||
|  | ||||
| 	switch(bpp){ | ||||
| 	case 16: | ||||
| 	case 15: | ||||
| 		for(i = 0; i < num; i++){ | ||||
| 			if(Bread(bp, buf, 2) != 2) | ||||
| 				break; | ||||
| 			x = (buf[1]<<8) | buf[0]; | ||||
| 			tmp = (x>>0)&0x1f; | ||||
| 			*b++ = (tmp<<3) | (tmp>>2); | ||||
| 			tmp = (x>>5)&0x1f; | ||||
| 			*g++ = (tmp<<3) | (tmp>>2); | ||||
| 			tmp = (x>>10)&0x1f; | ||||
| 			*r++ = (tmp<<3) | (tmp>>2); | ||||
| 		} | ||||
| 		break; | ||||
| 	case 24: | ||||
| 		for(i = 0; i < num; i++){ | ||||
| 			if(Bread(bp, buf, 3) != 3) | ||||
| 				break; | ||||
| 			*b++ = buf[0]; | ||||
| 			*g++ = buf[1]; | ||||
| 			*r++ = buf[2]; | ||||
| 		} | ||||
| 		break; | ||||
| 	case 32: | ||||
| 		for(i = 0; i < num; i++){ | ||||
| 			if(Bread(bp, buf, 4) != 4) | ||||
| 				break; | ||||
| 			*b++ = buf[0]; | ||||
| 			*g++ = buf[1]; | ||||
| 			*r++ = buf[2]; | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		i = 0; | ||||
| 		break; | ||||
| 	} | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| static int | ||||
| rgba_rle(Biobuf *bp, int bpp, unsigned char *r, unsigned char *g, unsigned char *b, int num) | ||||
| { | ||||
| 	unsigned char len; | ||||
| 	int i, got; | ||||
|  | ||||
| 	for(got = 0; got < num; got += len){ | ||||
| 		if(Bread(bp, &len, 1) != 1) | ||||
| 			break; | ||||
| 		if(len & 0x80){ | ||||
| 			len &= 0x7f; | ||||
| 			len += 1;	/* run of zero is meaningless */ | ||||
| 			if(rgba(bp, bpp, r, g, b, 1) != 1) | ||||
| 				break; | ||||
| 			for(i = 1; i < len && got+i < num; i++){ | ||||
| 				r[i] = *r; | ||||
| 				g[i] = *g; | ||||
| 				b[i] = *b; | ||||
| 			} | ||||
| 			len = i; | ||||
| 		} | ||||
| 		else{ | ||||
| 			len += 1;	/* raw block of zero is meaningless */ | ||||
| 			if(rgba(bp, bpp, r, g, b, len) != len) | ||||
| 				break; | ||||
| 		} | ||||
| 		r += len; | ||||
| 		g += len; | ||||
| 		b += len; | ||||
| 	} | ||||
| 	return got; | ||||
| } | ||||
|  | ||||
| int | ||||
| flip(Rawimage *ar) | ||||
| { | ||||
| 	int w, h, c, l; | ||||
| 	unsigned char *t, *s, *d; | ||||
|  | ||||
| 	w = Dx(ar->r); | ||||
| 	h = Dy(ar->r); | ||||
| 	if((t = malloc(w)) == nil){ | ||||
| 		werrstr("ReadTGA: no memory - %r\n"); | ||||
| 		return -1; | ||||
| 	} | ||||
|  | ||||
| 	for(c = 0; c < ar->nchans; c++){ | ||||
| 		s = ar->chans[c]; | ||||
| 		d = ar->chans[c] + ar->chanlen - w; | ||||
| 		for(l = 0; l < (h/2); l++){ | ||||
| 			memcpy(t, s, w); | ||||
| 			memcpy(s, d, w); | ||||
| 			memcpy(d, t, w); | ||||
| 			s += w; | ||||
| 			d -= w; | ||||
| 		} | ||||
| 	} | ||||
| 	free(t); | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| int | ||||
| reflect(Rawimage *ar) | ||||
| { | ||||
| 	int w, h, c, l, p; | ||||
| 	unsigned char t, *sol, *eol, *s, *d; | ||||
|  | ||||
| 	w = Dx(ar->r); | ||||
| 	h = Dy(ar->r); | ||||
|  | ||||
| 	for(c = 0; c < ar->nchans; c++){ | ||||
| 		sol = ar->chans[c]; | ||||
| 		eol = ar->chans[c] +w -1; | ||||
| 		for(l = 0; l < h; l++){ | ||||
| 			s = sol; | ||||
| 			d = eol; | ||||
| 			for(p = 0; p < w/2; p++){ | ||||
| 				t = *s; | ||||
| 				*s = *d; | ||||
| 				*d = t; | ||||
| 				s++; | ||||
| 				d--; | ||||
| 			} | ||||
| 			sol += w; | ||||
| 			eol += w; | ||||
| 		} | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| Rawimage** | ||||
| Breadtga(Biobuf *bp) | ||||
| { | ||||
| 	Tga *h; | ||||
| 	int n, c, num; | ||||
| 	unsigned char *r, *g, *b; | ||||
| 	Rawimage *ar, **array; | ||||
|  | ||||
| 	if((h = rdhdr(bp)) == nil){ | ||||
| 		werrstr("ReadTGA: bad header %r"); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if(0){ | ||||
| 		fprint(2, "idlen=%d\n", h->idlen); | ||||
| 		fprint(2, "cmaptype=%d\n", h->cmaptype); | ||||
| 		fprint(2, "datatype=%s\n", datatype[h->datatype]); | ||||
| 		fprint(2, "cmaporigin=%d\n", h->cmaporigin); | ||||
| 		fprint(2, "cmaplen=%d\n", h->cmaplen); | ||||
| 		fprint(2, "cmapbpp=%d\n", h->cmapbpp); | ||||
| 		fprint(2, "xorigin=%d\n", h->xorigin); | ||||
| 		fprint(2, "yorigin=%d\n", h->yorigin); | ||||
| 		fprint(2, "width=%d\n", h->width); | ||||
| 		fprint(2, "height=%d\n", h->height); | ||||
| 		fprint(2, "bpp=%d\n", h->bpp); | ||||
| 		fprint(2, "descriptor=%d\n", h->descriptor); | ||||
| 	} | ||||
|  | ||||
| 	array = nil; | ||||
| 	if((ar = calloc(1, sizeof(Rawimage))) == nil){ | ||||
| 		werrstr("ReadTGA: no memory - %r\n"); | ||||
| 		goto Error; | ||||
| 	} | ||||
|  | ||||
| 	if((array = calloc(2, sizeof(Rawimage *))) == nil){ | ||||
| 		werrstr("ReadTGA: no memory - %r\n"); | ||||
| 		goto Error; | ||||
| 	} | ||||
| 	array[0] = ar; | ||||
| 	array[1] = nil; | ||||
|  | ||||
| 	if(h->datatype == 3 || h->datatype == 11){ | ||||
| 		ar->nchans = 1; | ||||
| 		ar->chandesc = CY; | ||||
| 	} | ||||
| 	else if(h->datatype == 1){ | ||||
| 		ar->nchans = 1; | ||||
| 		ar->chandesc = CRGB1; | ||||
| 	} | ||||
| 	else if(h->datatype == 9){ | ||||
| 		ar->nchans = 1; | ||||
| 		ar->chandesc = (h->cmapbpp == 32) ? CRGBV : CRGB1; | ||||
| 	} | ||||
| 	else{ | ||||
| 		ar->nchans = 3; | ||||
| 		ar->chandesc = CRGB; | ||||
| 	} | ||||
|  | ||||
| 	ar->cmap = h->cmap; | ||||
| 	ar->cmaplen = (h->cmapbpp/8)*h->cmaplen; | ||||
| 	ar->chanlen = h->width*h->height; | ||||
| 	ar->r = Rect(0, 0, h->width, h->height); | ||||
| 	for(c = 0; c < ar->nchans; c++) | ||||
| 		if((ar->chans[c] = malloc(h->width*h->height)) == nil){ | ||||
| 			werrstr("ReadTGA: no memory - %r\n"); | ||||
| 			goto Error; | ||||
| 		} | ||||
| 	r = ar->chans[0]; | ||||
| 	g = ar->chans[1]; | ||||
| 	b = ar->chans[2]; | ||||
|  | ||||
| 	num = h->width*h->height; | ||||
| 	switch(h->datatype){ | ||||
| 	case 1: | ||||
| 		n = cmap(bp, r, num); | ||||
| 		break; | ||||
| 	case 2: | ||||
| 		n = rgba(bp, h->bpp, r, g, b, num); | ||||
| 		break; | ||||
| 	case 3: | ||||
| 		n = luma(bp, h->bpp, r, num); | ||||
| 		break; | ||||
| 	case 9: | ||||
| 		n = cmap_rle(bp, r, num); | ||||
| 		break; | ||||
| 	case 10: | ||||
| 		n = rgba_rle(bp, h->bpp, r, g, b, num); | ||||
| 		break; | ||||
| 	case 11: | ||||
| 		n = luma_rle(bp, h->bpp, r, num); | ||||
| 		break; | ||||
| 	default: | ||||
| 		werrstr("ReadTGA: type=%d (%s) unsupported\n", h->datatype, datatype[h->datatype]); | ||||
| 		goto Error; | ||||
|  	} | ||||
|  | ||||
| 	if(n != num){ | ||||
| 		werrstr("ReadTGA: decode fail (%d!=%d) - %r\n", n, num); | ||||
| 		goto Error; | ||||
| 	} | ||||
| 	if((h->descriptor&(1<<4)) != 0) | ||||
| 		reflect(ar); | ||||
| 	if((h->descriptor&(1<<5)) == 0) | ||||
| 		flip(ar); | ||||
|  | ||||
| 	free(h); | ||||
| 	return array; | ||||
| Error: | ||||
|  | ||||
| 	if(ar) | ||||
| 		for (c = 0; c < ar->nchans; c++) | ||||
| 			free(ar->chans[c]); | ||||
| 	free(ar); | ||||
| 	free(array); | ||||
| 	free(h->cmap); | ||||
| 	free(h); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| readtga(int fd) | ||||
| { | ||||
| 	Rawimage * *a; | ||||
| 	Biobuf b; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	a = Breadtga(&b); | ||||
| 	Bterm(&b); | ||||
| 	return a; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										1862
									
								
								sys/src/cmd/pict/readtif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1862
									
								
								sys/src/cmd/pict/readtif.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										203
									
								
								sys/src/cmd/pict/readv210.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										203
									
								
								sys/src/cmd/pict/readv210.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,203 @@ | ||||
| /* | ||||
|  * readV210.c - read single uncompressed Quicktime YUV image. | ||||
|  * http://developer.apple.com/quicktime/icefloe/dispatch019.html#v210 | ||||
|  * Steve Simon, 2009 | ||||
|  */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <ctype.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| enum { | ||||
| 	Pixels = 720, | ||||
| 	R601pal = 576, | ||||
| 	R601ntsc = 486, | ||||
| 	Shift = 13 | ||||
| }; | ||||
|  | ||||
| static int | ||||
| looksize(char *file, long size, int *pixels, int *lines, int *chunk) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
| 	unsigned long l, p, c; | ||||
| 	char *s, *a[12]; | ||||
|  | ||||
| 	/* | ||||
| 	 * This may not always work, there could be an alias between file | ||||
| 	 * sizes of different standards stored in 8bits and 10 bits. | ||||
| 	 */ | ||||
| 	if((bp = Bopen(file, OREAD)) == nil) | ||||
| 		return -1; | ||||
| 	while((s = Brdstr(bp, '\n', 1)) != nil){ | ||||
| 		if(tokenize(s, a, nelem(a)) < 3) | ||||
| 			continue; | ||||
| 		if(a[0][0] == '#') | ||||
| 			continue; | ||||
| 		p = atoll(a[3]); | ||||
| 		l = atoll(a[5]); | ||||
| 		l += atoll(a[7]); | ||||
| 		c = 128 * ceil(p/48); | ||||
| 		if(l*c == size){ | ||||
| 			*pixels = p; | ||||
| 			*lines = l; | ||||
| 			*chunk = c; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	Bterm(bp); | ||||
| 	if(s == nil) | ||||
| 		return -1; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| static int | ||||
| clip(int x) | ||||
| { | ||||
| 	x >>= Shift + 2;	/* +2 as we assume all input images are 10 bit */ | ||||
| 	if(x > 255) | ||||
| 		return 0xff; | ||||
| 	if(x <= 0) | ||||
| 		return 0; | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| BreadV210(Biobuf *bp, int colourspace) | ||||
| { | ||||
| 	Dir *d; | ||||
| 	unsigned long sz; | ||||
| 	Rawimage *a, **array; | ||||
| 	unsigned short *mux, *end, *frm, *wr; | ||||
| 	unsigned char *buf, *r, *g, *b; | ||||
| 	uint i, t; | ||||
| 	int y1, y2, cb, cr, c, l, rd; | ||||
| 	int chunk, lines, pixels; | ||||
| 	int F1, F2, F3, F4; | ||||
|  | ||||
| 	buf = nil; | ||||
| 	if(colourspace != CYCbCr){ | ||||
| 		werrstr("BreadV210: unknown colour space %d", colourspace); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if((d = dirfstat(Bfildes(bp))) != nil){ | ||||
| 		sz = d->length; | ||||
| 		free(d); | ||||
| 	} | ||||
| 	else { | ||||
| 		fprint(2, "cannot stat input, assuming pixelsx576x10bit\n"); | ||||
| 		sz = Pixels * R601pal * 2L + (pixels * R601pal / 2L); | ||||
| 	} | ||||
|  | ||||
| 	if(looksize("/lib/video.specs", sz, &pixels, &lines, &chunk) == -1){ | ||||
| 		werrstr("file spec not in /lib/video.specs\n"); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if((a = calloc(sizeof(Rawimage), 1)) == nil) | ||||
| 		sysfatal("no memory"); | ||||
|  | ||||
| 	if((array = calloc(sizeof(Rawimage * ), 2)) == nil) | ||||
| 		sysfatal("no memory"); | ||||
| 	array[0] = a; | ||||
| 	array[1] = nil; | ||||
|  | ||||
| 	a->nchans = 3; | ||||
| 	a->chandesc = CRGB; | ||||
| 	a->chanlen = pixels * lines; | ||||
| 	a->r = Rect(0, 0, pixels, lines); | ||||
|  | ||||
| 	if((frm = malloc(pixels*2*lines*sizeof(unsigned short))) == nil) | ||||
| 		goto Error; | ||||
|  | ||||
| 	for(c = 0; c  < 3; c++) | ||||
| 		if((a->chans[c] = malloc(pixels*lines)) == nil) | ||||
| 			goto Error; | ||||
|  | ||||
| 	if((buf = malloc(chunk)) == nil) | ||||
| 		goto Error; | ||||
|  | ||||
| 	for(l = 0; l < lines; l++){ | ||||
| 		if(Bread(bp, buf, chunk) == -1) | ||||
| 			goto Error; | ||||
|  | ||||
| 		rd = 0; | ||||
| 		wr = &frm[l*pixels*2]; | ||||
| 		end = &frm[(l+1)*pixels*2]; | ||||
| 		while(wr < end){ | ||||
| 			t = 0; | ||||
| 			for(i = 0; i < 4; i++) | ||||
| 				t += buf[rd+i] << 8*i; | ||||
| 			*wr++ = t & 0x3ff; | ||||
| 			*wr++ = t>>10 & 0x3ff; | ||||
| 			*wr++ = t>>20 & 0x3ff; | ||||
| 			rd += 4; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	mux = frm; | ||||
| 	end = frm + pixels * lines * 2; | ||||
| 	r = a->chans[0]; | ||||
| 	g = a->chans[1]; | ||||
| 	b = a->chans[2]; | ||||
|  | ||||
| 	if(pixels == Pixels && lines != R601pal){	// 625 | ||||
| 		F1 = floor(1.402 * (1 << Shift)); | ||||
| 		F2 = floor(0.34414 * (1 << Shift)); | ||||
| 		F3 = floor(0.71414 * (1 << Shift)); | ||||
| 		F4 = floor(1.772 * (1 << Shift)); | ||||
| 	} | ||||
| 	else{						// 525 and HD | ||||
| 		F1 = floor(1.5748 * (1 << Shift)); | ||||
| 		F2 = floor(0.1874 * (1 << Shift)); | ||||
| 		F3 = floor(0.4681 * (1 << Shift)); | ||||
| 		F4 = floor(1.8560 * (1 << Shift)); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Fixme: fixed colourspace conversion at present | ||||
| 	 */ | ||||
| 	while(mux < end){ | ||||
|  | ||||
| 		cb = *mux++ - 512; | ||||
| 		y1 = (int)*mux++ << Shift; | ||||
| 		cr = *mux++ - 512; | ||||
| 		y2 = (int)*mux++ << Shift; | ||||
|  | ||||
| 		*r++ = clip(y1 + F1*cr); | ||||
| 		*g++ = clip(y1 - F2*cb - F3*cr); | ||||
| 		*b++ = clip((y1 + F4*cb)); | ||||
|  | ||||
| 		*r++ = clip(y2 + F1*cr); | ||||
| 		*g++ = clip(y2 - F2*cb - F3*cr); | ||||
| 		*b++ = clip((y2 + F4*cb)); | ||||
| 	} | ||||
| 	free(frm); | ||||
| 	free(buf); | ||||
| 	return array; | ||||
|  | ||||
| Error: | ||||
| 	for(c = 0; c < 3; c++) | ||||
| 		free(a->chans[c]); | ||||
| 	free(a->cmap); | ||||
| 	free(array[0]); | ||||
| 	free(array); | ||||
| 	free(frm); | ||||
| 	free(buf); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| readV210(int fd, int colorspace) | ||||
| { | ||||
| 	Rawimage * *a; | ||||
| 	Biobuf b; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	a = BreadV210(&b, colorspace); | ||||
| 	Bterm(&b); | ||||
| 	return a; | ||||
| } | ||||
							
								
								
									
										215
									
								
								sys/src/cmd/pict/readyuv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										215
									
								
								sys/src/cmd/pict/readyuv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,215 @@ | ||||
| /* readyuv.c - read an Abekas A66 style image file.   Steve Simon, 2003 */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <ctype.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
|  | ||||
| enum { | ||||
| 	Pixels = 720, | ||||
| 	R601pal = 576, | ||||
| 	R601ntsc = 486, | ||||
| 	Shift = 13 | ||||
| }; | ||||
|  | ||||
|  | ||||
| static int lsbtab[] = { 6, 4, 2, 0}; | ||||
|  | ||||
| static int | ||||
| looksize(char *file, long size, int *pixels, int *lines, int *bits) | ||||
| { | ||||
| 	Biobuf *bp; | ||||
| 	unsigned long l, p; | ||||
| 	char *s, *a[12]; | ||||
|  | ||||
| 	/* | ||||
| 	 * This may not always work, there could be an alias between file | ||||
| 	 * sizes of different standards stored in 8bits and 10 bits. | ||||
| 	 */ | ||||
| 	if ((bp = Bopen(file, OREAD)) == nil) | ||||
| 		return -1; | ||||
| 	while((s = Brdstr(bp, '\n', 1)) != nil){ | ||||
| 		if (tokenize(s, a, nelem(a)) < 3) | ||||
| 			continue; | ||||
| 		if (a[0][0] == '#') | ||||
| 			continue; | ||||
| 		p = atoll(a[3]); | ||||
| 		l = atoll(a[5]); | ||||
| 		l += atoll(a[7]); | ||||
| 		if (l*p*2 == size){ | ||||
| 			*pixels = p; | ||||
| 			*lines = l; | ||||
| 			*bits = 8; | ||||
| 			break; | ||||
| 		} | ||||
| 		if ((l*p*20)/8 == size){ | ||||
| 			*pixels = p; | ||||
| 			*lines = l; | ||||
| 			*bits = 10; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	Bterm(bp); | ||||
| 	if (s == nil) | ||||
| 		return -1; | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
|  | ||||
| static int | ||||
| clip(int x) | ||||
| { | ||||
| 	x >>= (Shift+2); // +2 as we assume all input images are 10 bit | ||||
|  | ||||
| 	if (x > 255) | ||||
| 		return 0xff; | ||||
| 	if (x <= 0) | ||||
| 		return 0; | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| Rawimage** | ||||
| Breadyuv(Biobuf *bp, int colourspace) | ||||
| { | ||||
| 	Dir *d; | ||||
| 	unsigned long sz; | ||||
| 	Rawimage *a, **array; | ||||
| 	unsigned short * mux, *end, *frm; | ||||
| 	unsigned char *buf, *r, *g, *b; | ||||
| 	int y1, y2, cb, cr, c, l, w, base; | ||||
| 	int bits, lines, pixels; | ||||
| 	int F1, F2, F3, F4; | ||||
|  | ||||
| 	if ((d = dirfstat(Bfildes(bp))) != nil){ | ||||
| 		sz = d->length; | ||||
| 		free(d); | ||||
| 	} | ||||
| 	else{ | ||||
| 		fprint(2, "cannot stat input, assuming pixelsx576x10bit\n"); | ||||
| 		sz = Pixels * R601pal * 2L + (Pixels * R601pal / 2L); | ||||
| 	} | ||||
|  | ||||
| 	if (looksize("/lib/video.specs", sz, &pixels, &lines, &bits) == -1){ | ||||
| 		werrstr("file size not listed in /lib/video.specs"); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	buf = nil; | ||||
| 	if (colourspace != CYCbCr) { | ||||
| 		werrstr("ReadYUV: unknown colour space %d", colourspace); | ||||
| 		return nil; | ||||
| 	} | ||||
|  | ||||
| 	if ((a = calloc(sizeof(Rawimage), 1)) == nil) | ||||
| 		sysfatal("no memory"); | ||||
|  | ||||
| 	if ((array = calloc(sizeof(Rawimage * ), 2)) == nil) | ||||
| 		sysfatal("no memory"); | ||||
| 	array[0] = a; | ||||
| 	array[1] = nil; | ||||
|  | ||||
| 	a->nchans = 3; | ||||
| 	a->chandesc = CRGB; | ||||
| 	a->chanlen = pixels * lines; | ||||
| 	a->r = Rect(0, 0, pixels, lines); | ||||
|  | ||||
| 	if ((frm = malloc(pixels*2*lines*sizeof(unsigned short))) == nil) | ||||
| 		goto Error; | ||||
|  | ||||
| 	for (c = 0; c  < 3; c++) | ||||
| 		if ((a->chans[c] = malloc(pixels*lines)) == nil) | ||||
| 			goto Error; | ||||
|  | ||||
| 	if ((buf = malloc(pixels*2)) == nil) | ||||
| 		goto Error; | ||||
|  | ||||
| 	for (l = 0; l < lines; l++) { | ||||
| 		if (Bread(bp, buf, pixels *2) == -1) | ||||
| 			goto Error; | ||||
|  | ||||
| 		base = l*pixels*2; | ||||
| 		for (w = 0; w < pixels *2; w++) | ||||
| 			frm[base + w] = ((unsigned short)buf[w]) << 2; | ||||
| 	} | ||||
|  | ||||
|  | ||||
| 	if (bits == 10) | ||||
| 		for (l = 0; l < lines; l++) { | ||||
| 			if (Bread(bp, buf, pixels / 2) == -1) | ||||
| 				goto Error; | ||||
|  | ||||
|  | ||||
| 			base = l * pixels * 2; | ||||
| 			for (w = 0; w < pixels * 2; w++) | ||||
| 				frm[base + w] |= (buf[w / 4] >> lsbtab[w % 4]) & 3; | ||||
| 		} | ||||
|  | ||||
| 	mux = frm; | ||||
| 	end = frm + pixels * lines * 2; | ||||
| 	r = a->chans[0]; | ||||
| 	g = a->chans[1]; | ||||
| 	b = a->chans[2]; | ||||
|  | ||||
| 	if(pixels == Pixels && lines != R601pal){	// 625 | ||||
| 		F1 = floor(1.402 * (1 << Shift)); | ||||
| 		F2 = floor(0.34414 * (1 << Shift)); | ||||
| 		F3 = floor(0.71414 * (1 << Shift)); | ||||
| 		F4 = floor(1.772 * (1 << Shift)); | ||||
| 	} | ||||
| 	else{				// 525 | ||||
| 		F1 = floor(1.5748 * (1 << Shift)); | ||||
| 		F2 = floor(0.1874 * (1 << Shift)); | ||||
| 		F3 = floor(0.4681 * (1 << Shift)); | ||||
| 		F4 = floor(1.8560 * (1 << Shift)); | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Fixme: fixed colourspace conversion at present | ||||
| 	 */ | ||||
| 	while (mux < end) { | ||||
|  | ||||
| 		cb = *mux++ - 512; | ||||
| 		y1 = (int)*mux++ << Shift; | ||||
| 		cr = *mux++ - 512; | ||||
| 		y2 = (int)*mux++ << Shift; | ||||
|  | ||||
| 		*r++ = clip(y1 + F1*cr); | ||||
| 		*g++ = clip(y1 - F2*cb - F3*cr); | ||||
| 		*b++ = clip((y1 + F4*cb)); | ||||
|  | ||||
| 		*r++ = clip(y2 + F1*cr); | ||||
| 		*g++ = clip(y2 - F2*cb - F3*cr); | ||||
| 		*b++ = clip((y2 + F4*cb)); | ||||
| 	} | ||||
| 	free(frm); | ||||
| 	free(buf); | ||||
| 	return array; | ||||
|  | ||||
| Error: | ||||
| 	for (c = 0; c < 3; c++) | ||||
| 		free(a->chans[c]); | ||||
| 	free(a->cmap); | ||||
| 	free(array[0]); | ||||
| 	free(array); | ||||
| 	free(frm); | ||||
| 	free(buf); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
|  | ||||
| Rawimage** | ||||
| readyuv(int fd, int colorspace) | ||||
| { | ||||
| 	Rawimage * *a; | ||||
| 	Biobuf b; | ||||
|  | ||||
| 	if (Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	a = Breadyuv(&b, colorspace); | ||||
| 	Bterm(&b); | ||||
| 	return a; | ||||
| } | ||||
|  | ||||
|  | ||||
							
								
								
									
										70
									
								
								sys/src/cmd/pict/rgbrgbv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sys/src/cmd/pict/rgbrgbv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
|  | ||||
| /* | ||||
|  * This version of closest() is now (feb 20, 2001) installed as rgb2cmap in libdraw | ||||
|  */ | ||||
|  | ||||
| int | ||||
| closest(int cr, int cg, int cb) | ||||
| { | ||||
| 	int i, r, g, b, sq; | ||||
| 	uint32_t rgb; | ||||
| 	int best, bestsq; | ||||
|  | ||||
| 	best = 0; | ||||
| 	bestsq = 0x7FFFFFFF; | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		rgb = cmap2rgb(i); | ||||
| 		r = (rgb>>16) & 0xFF; | ||||
| 		g = (rgb>>8) & 0xFF; | ||||
| 		b = (rgb>>0) & 0xFF; | ||||
| 		sq = (r-cr)*(r-cr)+(g-cg)*(g-cg)+(b-cb)*(b-cb); | ||||
| 		if(sq < bestsq){ | ||||
| 			bestsq = sq; | ||||
| 			best = i; | ||||
| 		} | ||||
| 	} | ||||
| 	return best; | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int i, rgb; | ||||
| 	int r, g, b; | ||||
| 	unsigned char close[16*16*16]; | ||||
|  | ||||
| 	print("/* This file has been generated by rgbrgbv */\n"); | ||||
| 	/* rgbmap */ | ||||
| 	print("unsigned int rgbmap[256] = {\n"); | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		if(i%8 == 0) | ||||
| 			print("\t"); | ||||
| 		rgb = cmap2rgb(i); | ||||
| 		r = (rgb>>16) & 0xFF; | ||||
| 		g = (rgb>>8) & 0xFF; | ||||
| 		b = (rgb>>0) & 0xFF; | ||||
| 		print("0x%.6ulX, ", (r<<16) | (g<<8) | b); | ||||
| 		if(i%8 == 7) | ||||
| 			print("\n"); | ||||
| 	} | ||||
| 	print("};\n\n"); | ||||
|  | ||||
| 	/* closestrgb */ | ||||
| 	print("unsigned char closestrgb[16*16*16] = {\n"); | ||||
| 	for(r=0; r<256; r+=16) | ||||
| 	for(g=0; g<256; g+=16) | ||||
| 	for(b=0; b<256; b+=16) | ||||
| 		close[(b/16)+16*((g/16)+16*(r/16))] = closest(r+8, g+8, b+8); | ||||
| 	for(i=0; i<16*16*16; i++){ | ||||
| 		if(i%16 == 0) | ||||
| 			print("\t"); | ||||
| 		print("%d,", close[i]); | ||||
| 		if(i%16 == 15) | ||||
| 			print("\n"); | ||||
| 	} | ||||
| 	print("};\n\n"); | ||||
| 	exits(nil); | ||||
| } | ||||
							
								
								
									
										295
									
								
								sys/src/cmd/pict/rgbv.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										295
									
								
								sys/src/cmd/pict/rgbv.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,295 @@ | ||||
| /* This file has been generated by rgbrgbv */ | ||||
| unsigned int rgbmap[256] = { | ||||
| 	0x000000, 0x000044, 0x000088, 0x0000CC, 0x004400, 0x004444, 0x004488, 0x0044CC, | ||||
| 	0x008800, 0x008844, 0x008888, 0x0088CC, 0x00CC00, 0x00CC44, 0x00CC88, 0x00CCCC, | ||||
| 	0x00DDDD, 0x111111, 0x000055, 0x000099, 0x0000DD, 0x005500, 0x005555, 0x004C99, | ||||
| 	0x0049DD, 0x009900, 0x00994C, 0x009999, 0x0093DD, 0x00DD00, 0x00DD49, 0x00DD93, | ||||
| 	0x00EE9E, 0x00EEEE, 0x222222, 0x000066, 0x0000AA, 0x0000EE, 0x006600, 0x006666, | ||||
| 	0x0055AA, 0x004FEE, 0x00AA00, 0x00AA55, 0x00AAAA, 0x009EEE, 0x00EE00, 0x00EE4F, | ||||
| 	0x00FF55, 0x00FFAA, 0x00FFFF, 0x333333, 0x000077, 0x0000BB, 0x0000FF, 0x007700, | ||||
| 	0x007777, 0x005DBB, 0x0055FF, 0x00BB00, 0x00BB5D, 0x00BBBB, 0x00AAFF, 0x00FF00, | ||||
| 	0x440044, 0x440088, 0x4400CC, 0x444400, 0x444444, 0x444488, 0x4444CC, 0x448800, | ||||
| 	0x448844, 0x448888, 0x4488CC, 0x44CC00, 0x44CC44, 0x44CC88, 0x44CCCC, 0x440000, | ||||
| 	0x550000, 0x550055, 0x4C0099, 0x4900DD, 0x555500, 0x555555, 0x4C4C99, 0x4949DD, | ||||
| 	0x4C9900, 0x4C994C, 0x4C9999, 0x4993DD, 0x49DD00, 0x49DD49, 0x49DD93, 0x49DDDD, | ||||
| 	0x4FEEEE, 0x660000, 0x660066, 0x5500AA, 0x4F00EE, 0x666600, 0x666666, 0x5555AA, | ||||
| 	0x4F4FEE, 0x55AA00, 0x55AA55, 0x55AAAA, 0x4F9EEE, 0x4FEE00, 0x4FEE4F, 0x4FEE9E, | ||||
| 	0x55FFAA, 0x55FFFF, 0x770000, 0x770077, 0x5D00BB, 0x5500FF, 0x777700, 0x777777, | ||||
| 	0x5D5DBB, 0x5555FF, 0x5DBB00, 0x5DBB5D, 0x5DBBBB, 0x55AAFF, 0x55FF00, 0x55FF55, | ||||
| 	0x880088, 0x8800CC, 0x884400, 0x884444, 0x884488, 0x8844CC, 0x888800, 0x888844, | ||||
| 	0x888888, 0x8888CC, 0x88CC00, 0x88CC44, 0x88CC88, 0x88CCCC, 0x880000, 0x880044, | ||||
| 	0x99004C, 0x990099, 0x9300DD, 0x994C00, 0x994C4C, 0x994C99, 0x9349DD, 0x999900, | ||||
| 	0x99994C, 0x999999, 0x9393DD, 0x93DD00, 0x93DD49, 0x93DD93, 0x93DDDD, 0x990000, | ||||
| 	0xAA0000, 0xAA0055, 0xAA00AA, 0x9E00EE, 0xAA5500, 0xAA5555, 0xAA55AA, 0x9E4FEE, | ||||
| 	0xAAAA00, 0xAAAA55, 0xAAAAAA, 0x9E9EEE, 0x9EEE00, 0x9EEE4F, 0x9EEE9E, 0x9EEEEE, | ||||
| 	0xAAFFFF, 0xBB0000, 0xBB005D, 0xBB00BB, 0xAA00FF, 0xBB5D00, 0xBB5D5D, 0xBB5DBB, | ||||
| 	0xAA55FF, 0xBBBB00, 0xBBBB5D, 0xBBBBBB, 0xAAAAFF, 0xAAFF00, 0xAAFF55, 0xAAFFAA, | ||||
| 	0xCC00CC, 0xCC4400, 0xCC4444, 0xCC4488, 0xCC44CC, 0xCC8800, 0xCC8844, 0xCC8888, | ||||
| 	0xCC88CC, 0xCCCC00, 0xCCCC44, 0xCCCC88, 0xCCCCCC, 0xCC0000, 0xCC0044, 0xCC0088, | ||||
| 	0xDD0093, 0xDD00DD, 0xDD4900, 0xDD4949, 0xDD4993, 0xDD49DD, 0xDD9300, 0xDD9349, | ||||
| 	0xDD9393, 0xDD93DD, 0xDDDD00, 0xDDDD49, 0xDDDD93, 0xDDDDDD, 0xDD0000, 0xDD0049, | ||||
| 	0xEE004F, 0xEE009E, 0xEE00EE, 0xEE4F00, 0xEE4F4F, 0xEE4F9E, 0xEE4FEE, 0xEE9E00, | ||||
| 	0xEE9E4F, 0xEE9E9E, 0xEE9EEE, 0xEEEE00, 0xEEEE4F, 0xEEEE9E, 0xEEEEEE, 0xEE0000, | ||||
| 	0xFF0000, 0xFF0055, 0xFF00AA, 0xFF00FF, 0xFF5500, 0xFF5555, 0xFF55AA, 0xFF55FF, | ||||
| 	0xFFAA00, 0xFFAA55, 0xFFAAAA, 0xFFAAFF, 0xFFFF00, 0xFFFF55, 0xFFFFAA, 0xFFFFFF, | ||||
| }; | ||||
|  | ||||
| unsigned char closestrgb[16*16*16] = { | ||||
| 	0,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54, | ||||
| 	17,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54, | ||||
| 	17,17,34,5,5,5,35,6,6,6,23,7,7,7,24,41, | ||||
| 	4,4,5,5,5,5,6,6,6,6,23,7,7,7,24,41, | ||||
| 	4,4,5,5,5,22,22,6,6,23,40,40,7,24,41,41, | ||||
| 	21,21,5,5,22,22,39,39,6,23,40,57,57,24,41,58, | ||||
| 	38,38,38,9,22,39,39,56,56,40,40,57,57,57,41,58, | ||||
| 	55,55,9,9,9,39,56,56,10,10,57,11,11,11,28,58, | ||||
| 	8,8,9,9,9,9,56,10,10,10,27,11,11,11,28,45, | ||||
| 	25,25,9,9,26,26,43,10,10,27,27,44,11,28,45,45, | ||||
| 	42,42,26,26,43,43,43,60,27,27,44,44,61,28,45,62, | ||||
| 	59,59,13,13,43,60,60,14,14,44,44,61,61,15,45,62, | ||||
| 	12,12,13,13,13,60,60,14,14,14,61,61,15,15,16,62, | ||||
| 	29,29,13,13,30,30,60,14,14,31,31,15,15,16,16,33, | ||||
| 	46,46,30,30,47,47,47,31,31,32,32,32,16,16,33,33, | ||||
| 	63,63,47,47,47,48,48,48,32,32,49,49,49,33,33,50, | ||||
| 	17,17,17,1,1,18,35,52,2,19,36,53,3,20,37,54, | ||||
| 	17,17,34,34,1,18,35,52,2,19,36,53,3,20,37,54, | ||||
| 	17,34,34,34,51,5,35,6,6,6,23,7,7,7,24,41, | ||||
| 	4,34,34,51,5,5,6,6,6,6,23,7,7,7,24,41, | ||||
| 	4,4,51,5,5,22,22,6,6,23,40,40,7,24,41,41, | ||||
| 	21,21,5,5,22,22,39,39,6,23,40,57,57,24,41,58, | ||||
| 	38,38,38,9,22,39,39,56,56,40,40,57,57,57,41,58, | ||||
| 	55,55,9,9,9,39,56,56,10,10,57,11,11,11,28,58, | ||||
| 	8,8,9,9,9,9,56,10,10,10,27,11,11,11,28,45, | ||||
| 	25,25,9,9,26,26,43,10,10,27,27,44,11,28,45,45, | ||||
| 	42,42,26,26,43,43,43,60,27,27,44,44,61,28,45,62, | ||||
| 	59,59,13,13,43,60,60,14,14,44,44,61,61,15,45,62, | ||||
| 	12,12,13,13,13,60,60,14,14,14,61,61,15,15,16,62, | ||||
| 	29,29,13,13,30,30,60,14,14,31,31,15,15,16,16,33, | ||||
| 	46,46,30,30,47,47,47,31,31,32,32,32,16,16,33,33, | ||||
| 	63,63,47,47,47,48,48,48,32,32,49,49,49,33,33,50, | ||||
| 	17,17,34,64,64,64,35,65,65,65,82,66,66,66,83,100, | ||||
| 	17,34,34,34,51,64,35,65,65,65,82,66,66,66,83,100, | ||||
| 	34,34,34,51,51,51,69,69,69,69,69,70,70,70,87,87, | ||||
| 	67,34,51,51,51,68,69,69,69,69,86,70,70,70,87,87, | ||||
| 	67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104, | ||||
| 	67,67,51,68,68,68,39,69,69,69,40,70,70,70,87,58, | ||||
| 	38,38,72,72,72,39,39,56,73,73,40,57,74,74,87,58, | ||||
| 	71,71,72,72,72,72,56,73,73,73,73,74,74,74,74,91, | ||||
| 	71,71,72,72,72,72,73,73,73,73,73,74,74,74,91,91, | ||||
| 	71,71,72,72,72,72,73,73,73,73,90,74,74,91,91,108, | ||||
| 	88,88,72,89,89,43,43,73,73,90,44,44,74,91,91,62, | ||||
| 	75,75,76,76,76,76,60,77,77,77,44,78,78,78,78,62, | ||||
| 	75,75,76,76,76,76,77,77,77,77,77,78,78,78,78,95, | ||||
| 	75,75,76,76,76,76,77,77,77,94,94,78,78,78,95,95, | ||||
| 	92,92,93,93,93,93,93,77,94,94,94,78,78,95,95,96, | ||||
| 	109,109,93,93,110,48,48,94,94,111,49,49,95,95,96,50, | ||||
| 	79,79,64,64,64,64,65,65,65,65,82,66,66,66,83,100, | ||||
| 	79,34,34,51,64,64,65,65,65,65,82,66,66,66,83,100, | ||||
| 	67,34,51,51,51,68,69,69,69,69,86,70,70,70,87,87, | ||||
| 	67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104, | ||||
| 	67,67,51,68,68,68,69,69,69,69,86,70,70,70,87,104, | ||||
| 	67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104, | ||||
| 	71,71,72,72,72,85,85,73,73,86,103,103,74,87,104,121, | ||||
| 	71,71,72,72,72,72,73,73,73,73,73,74,74,74,91,91, | ||||
| 	71,71,72,72,72,72,73,73,73,73,90,74,74,74,91,108, | ||||
| 	71,71,72,72,72,89,89,73,73,90,90,74,74,91,91,108, | ||||
| 	88,88,89,89,89,89,106,73,90,90,107,107,91,91,108,108, | ||||
| 	75,75,76,76,76,76,106,77,77,77,107,78,78,78,108,125, | ||||
| 	75,75,76,76,76,76,77,77,77,77,94,78,78,78,95,95, | ||||
| 	75,75,76,76,76,93,93,77,77,94,94,78,78,95,95,95, | ||||
| 	92,92,93,93,93,93,110,94,94,94,111,111,95,95,95,96, | ||||
| 	109,109,93,110,110,110,127,94,111,111,111,112,95,95,96,96, | ||||
| 	79,79,64,64,64,81,81,65,65,82,99,99,66,83,100,100, | ||||
| 	79,79,51,64,64,81,81,65,65,82,99,99,66,83,100,100, | ||||
| 	67,51,51,51,68,68,69,69,69,69,86,70,70,70,87,104, | ||||
| 	67,67,51,68,68,68,69,69,69,69,86,70,70,70,87,104, | ||||
| 	67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104, | ||||
| 	84,84,68,68,85,85,85,69,69,86,103,103,70,87,104,121, | ||||
| 	84,84,72,72,85,85,85,102,73,86,103,120,120,87,104,121, | ||||
| 	71,71,72,72,72,72,102,73,73,73,73,74,74,74,91,121, | ||||
| 	71,71,72,72,72,72,73,73,73,73,90,74,74,91,91,108, | ||||
| 	88,88,72,72,89,89,89,73,73,90,90,74,74,91,108,108, | ||||
| 	105,105,89,89,89,106,106,73,90,90,107,107,91,91,108,125, | ||||
| 	105,105,76,76,76,106,123,77,77,77,107,124,78,78,108,125, | ||||
| 	75,75,76,76,76,76,123,77,77,77,94,78,78,78,95,125, | ||||
| 	92,92,76,76,93,93,93,77,94,94,94,78,78,95,95,96, | ||||
| 	109,109,93,93,93,110,110,94,94,111,111,111,95,95,96,96, | ||||
| 	109,109,110,110,110,127,127,127,111,111,112,112,112,96,96,96, | ||||
| 	80,80,64,64,81,81,98,98,65,82,99,116,116,83,100,117, | ||||
| 	80,80,64,64,81,81,98,98,65,82,99,116,116,83,100,117, | ||||
| 	67,67,51,68,68,68,98,69,69,69,99,70,70,70,87,117, | ||||
| 	67,67,68,68,68,85,85,69,69,86,86,70,70,87,87,104, | ||||
| 	84,84,68,68,85,85,85,69,69,86,103,103,70,87,104,121, | ||||
| 	84,84,68,85,85,85,85,102,86,86,103,120,120,87,104,121, | ||||
| 	101,101,101,85,85,85,102,102,86,103,103,120,120,120,104,121, | ||||
| 	101,101,72,72,72,102,102,102,73,73,120,120,74,74,91,121, | ||||
| 	71,71,72,72,72,89,89,73,73,90,90,74,74,91,91,108, | ||||
| 	88,88,72,89,89,89,106,73,90,90,107,107,74,91,108,108, | ||||
| 	105,105,105,89,106,106,106,123,90,107,107,107,124,108,108,125, | ||||
| 	122,122,76,76,106,123,123,123,77,107,107,124,124,124,125,125, | ||||
| 	122,122,76,76,76,123,123,77,77,77,124,124,124,78,95,125, | ||||
| 	92,92,76,93,93,93,123,77,94,94,111,124,78,95,95,96, | ||||
| 	109,109,93,93,110,110,110,94,94,111,111,112,95,95,96,96, | ||||
| 	126,126,126,110,127,127,127,127,111,111,112,112,112,96,96,113, | ||||
| 	97,97,97,143,81,98,98,115,115,99,99,116,116,116,100,117, | ||||
| 	97,97,97,143,81,98,98,115,115,99,99,116,116,116,100,117, | ||||
| 	97,97,131,131,131,98,98,115,132,132,99,116,133,133,87,117, | ||||
| 	130,130,131,131,131,85,85,132,132,86,103,103,133,87,104,121, | ||||
| 	84,84,131,131,85,85,85,102,132,86,103,120,120,87,104,121, | ||||
| 	101,101,101,85,85,85,102,102,86,103,103,120,120,120,104,121, | ||||
| 	101,101,101,85,85,102,102,102,119,103,120,120,120,120,121,121, | ||||
| 	118,118,118,135,102,102,102,119,119,119,120,120,120,137,91,121, | ||||
| 	118,118,135,135,135,89,119,119,119,90,90,137,137,91,108,108, | ||||
| 	105,105,135,89,89,106,106,119,90,90,107,107,137,91,108,125, | ||||
| 	105,105,105,106,106,106,123,123,90,107,107,124,124,108,108,125, | ||||
| 	122,122,122,106,123,123,123,123,140,107,124,124,124,124,125,125, | ||||
| 	122,122,139,139,123,123,123,123,140,140,124,124,124,124,95,125, | ||||
| 	122,122,139,93,93,123,123,140,94,94,111,124,124,95,95,96, | ||||
| 	109,109,93,110,110,110,127,94,111,111,111,112,95,95,96,96, | ||||
| 	126,126,126,127,127,127,127,127,111,112,112,112,112,96,96,113, | ||||
| 	114,114,143,143,143,98,115,115,128,128,116,129,129,129,146,117, | ||||
| 	114,114,143,143,143,98,115,115,128,128,116,129,129,129,146,117, | ||||
| 	130,130,131,131,131,131,115,132,132,132,132,133,133,133,133,150, | ||||
| 	130,130,131,131,131,131,132,132,132,132,132,133,133,133,150,150, | ||||
| 	130,130,131,131,131,131,102,132,132,132,132,133,133,133,150,121, | ||||
| 	101,101,131,131,131,102,102,102,132,132,120,120,133,133,150,121, | ||||
| 	118,118,118,135,102,102,102,119,119,119,120,120,120,137,150,121, | ||||
| 	118,118,135,135,135,102,119,119,119,136,136,137,137,137,137,154, | ||||
| 	134,134,135,135,135,135,119,119,136,136,136,137,137,137,154,154, | ||||
| 	134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154, | ||||
| 	122,122,135,135,135,123,123,136,136,153,107,124,124,154,154,125, | ||||
| 	138,138,139,139,139,123,123,140,140,140,124,124,141,141,141,125, | ||||
| 	138,138,139,139,139,139,123,140,140,140,124,141,141,141,141,158, | ||||
| 	138,138,139,139,139,139,140,140,140,140,157,141,141,141,158,158, | ||||
| 	155,155,139,156,156,156,156,140,157,157,157,141,141,158,158,158, | ||||
| 	126,126,156,156,127,127,127,157,157,157,112,112,158,158,158,113, | ||||
| 	142,142,143,143,143,143,115,128,128,128,145,129,129,129,146,163, | ||||
| 	142,142,143,143,143,143,115,128,128,128,145,129,129,129,146,163, | ||||
| 	130,130,131,131,131,131,132,132,132,132,132,133,133,133,150,150, | ||||
| 	130,130,131,131,131,131,132,132,132,132,149,133,133,133,150,167, | ||||
| 	130,130,131,131,131,131,132,132,132,132,149,133,133,150,150,167, | ||||
| 	130,130,131,131,131,148,148,132,132,149,149,133,133,150,150,167, | ||||
| 	118,118,135,135,135,148,119,119,119,149,149,137,137,150,167,167, | ||||
| 	134,134,135,135,135,135,119,119,136,136,136,137,137,137,154,154, | ||||
| 	134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154, | ||||
| 	134,134,135,135,135,152,152,136,136,153,153,137,137,154,154,171, | ||||
| 	151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171, | ||||
| 	138,138,139,139,139,139,140,140,140,140,170,141,141,141,141,171, | ||||
| 	138,138,139,139,139,139,140,140,140,140,157,141,141,141,158,158, | ||||
| 	138,138,139,139,156,156,156,140,140,157,157,141,141,158,158,158, | ||||
| 	155,155,156,156,156,156,173,157,157,157,174,141,158,158,158,175, | ||||
| 	172,172,156,173,173,173,173,157,157,174,174,174,158,158,175,175, | ||||
| 	159,159,143,143,144,144,161,128,128,145,145,162,129,146,163,163, | ||||
| 	159,159,143,143,144,144,161,128,128,145,145,162,129,146,163,163, | ||||
| 	130,130,131,131,131,131,132,132,132,132,149,133,133,150,150,167, | ||||
| 	130,130,131,131,131,148,148,132,132,149,149,133,133,150,150,167, | ||||
| 	147,147,131,131,148,148,148,132,132,149,149,133,133,150,167,167, | ||||
| 	147,147,131,148,148,148,165,132,149,149,166,166,133,150,167,167, | ||||
| 	164,164,135,148,148,165,165,119,149,149,166,166,137,150,167,184, | ||||
| 	134,134,135,135,135,135,119,136,136,136,153,137,137,137,154,154, | ||||
| 	134,134,135,135,135,152,152,136,136,153,153,137,137,154,154,171, | ||||
| 	151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171, | ||||
| 	151,151,152,152,152,169,169,153,153,153,170,170,154,154,171,171, | ||||
| 	168,168,139,139,139,169,169,140,140,170,170,170,141,141,171,188, | ||||
| 	138,138,139,139,139,139,140,140,140,157,157,141,141,141,158,158, | ||||
| 	155,155,156,156,156,156,156,140,157,157,157,141,141,158,158,175, | ||||
| 	172,172,156,156,173,173,173,157,157,174,174,174,158,158,175,175, | ||||
| 	172,172,173,173,173,173,190,157,174,174,174,191,158,175,175,175, | ||||
| 	160,160,144,144,161,161,161,178,145,145,162,162,179,146,163,180, | ||||
| 	160,160,144,144,161,161,161,178,145,145,162,162,179,146,163,180, | ||||
| 	147,147,131,148,148,161,161,132,132,149,162,162,133,150,150,180, | ||||
| 	147,147,148,148,148,148,165,132,149,149,166,166,150,150,167,167, | ||||
| 	164,164,148,148,148,165,165,132,149,149,166,166,150,150,167,184, | ||||
| 	164,164,164,148,165,165,165,182,149,166,166,166,183,167,167,184, | ||||
| 	164,164,164,165,165,165,182,182,149,166,166,183,183,167,167,184, | ||||
| 	181,181,135,135,135,182,182,136,136,153,166,183,183,154,154,184, | ||||
| 	151,151,135,152,152,152,152,136,153,153,153,170,154,154,171,171, | ||||
| 	151,151,152,152,152,169,169,153,153,153,170,170,154,154,171,171, | ||||
| 	168,168,168,169,169,169,169,169,153,170,170,170,187,171,171,188, | ||||
| 	168,168,168,169,169,169,186,186,170,170,170,187,187,187,188,188, | ||||
| 	185,185,139,156,156,186,186,186,157,157,187,187,187,158,158,188, | ||||
| 	155,155,156,156,156,173,173,157,157,157,174,187,158,158,158,175, | ||||
| 	172,172,156,173,173,173,173,157,174,174,174,191,158,158,175,175, | ||||
| 	189,189,189,173,190,190,190,190,174,174,191,191,191,175,175,176, | ||||
| 	177,177,206,206,161,178,178,207,207,162,162,179,179,192,163,180, | ||||
| 	177,177,206,206,161,178,178,207,207,162,162,179,179,192,163,180, | ||||
| 	193,193,194,194,194,194,178,195,195,195,162,196,196,196,196,180, | ||||
| 	193,193,194,194,194,194,165,195,195,195,166,196,196,196,167,184, | ||||
| 	164,164,194,194,194,165,182,195,195,195,166,183,196,196,167,184, | ||||
| 	181,181,194,194,165,182,182,182,195,166,166,183,183,183,184,184, | ||||
| 	181,181,181,165,182,182,182,182,199,166,183,183,183,183,184,184, | ||||
| 	197,197,198,198,198,182,182,199,199,199,183,183,200,200,200,184, | ||||
| 	197,197,198,198,198,198,199,199,199,199,170,200,200,200,200,171, | ||||
| 	168,168,198,198,198,169,169,199,199,170,170,170,200,200,171,188, | ||||
| 	168,168,168,169,169,169,186,186,170,170,170,187,187,187,188,188, | ||||
| 	185,185,202,202,186,186,186,186,203,170,187,187,187,187,188,188, | ||||
| 	185,185,202,202,202,186,186,203,203,203,187,187,187,204,204,188, | ||||
| 	201,201,202,202,202,186,186,203,203,203,187,187,204,204,175,175, | ||||
| 	172,172,202,173,173,190,190,203,203,174,191,191,204,175,175,176, | ||||
| 	189,189,189,190,190,190,190,190,174,191,191,191,191,175,176,176, | ||||
| 	205,205,206,206,206,178,178,207,207,207,179,179,192,192,209,180, | ||||
| 	205,205,206,206,206,178,178,207,207,207,179,179,192,192,209,180, | ||||
| 	193,193,194,194,194,194,195,195,195,195,195,196,196,196,196,213, | ||||
| 	193,193,194,194,194,194,195,195,195,195,212,196,196,196,213,213, | ||||
| 	193,193,194,194,194,194,182,195,195,195,212,196,196,196,213,184, | ||||
| 	181,181,194,194,194,182,182,195,195,195,183,183,183,196,213,184, | ||||
| 	181,181,198,198,182,182,182,182,199,199,183,183,183,183,213,184, | ||||
| 	197,197,198,198,198,198,182,199,199,199,183,200,200,200,200,217, | ||||
| 	197,197,198,198,198,198,199,199,199,199,216,200,200,200,217,217, | ||||
| 	197,197,198,198,198,198,199,199,199,216,216,200,200,200,217,217, | ||||
| 	185,185,198,215,215,186,186,186,216,216,187,187,187,217,217,188, | ||||
| 	185,185,202,202,202,186,186,203,203,203,187,187,187,204,204,188, | ||||
| 	201,201,202,202,202,186,186,203,203,203,187,187,204,204,204,221, | ||||
| 	201,201,202,202,202,202,186,203,203,203,220,204,204,204,221,221, | ||||
| 	218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221, | ||||
| 	189,189,219,219,190,190,190,220,220,220,191,191,221,221,221,176, | ||||
| 	222,222,206,206,223,223,178,207,207,208,208,192,192,209,209,226, | ||||
| 	222,222,206,206,223,223,178,207,207,208,208,192,192,209,209,226, | ||||
| 	193,193,194,194,194,194,195,195,195,212,212,196,196,196,213,213, | ||||
| 	193,193,194,194,194,211,211,195,195,212,212,196,196,213,213,213, | ||||
| 	210,210,194,194,211,211,211,195,212,212,212,196,196,213,213,230, | ||||
| 	210,210,194,211,211,211,182,195,212,212,229,183,196,213,213,230, | ||||
| 	181,181,198,211,211,182,182,199,212,212,229,183,183,213,213,230, | ||||
| 	197,197,198,198,198,198,199,199,199,199,216,200,200,200,217,217, | ||||
| 	197,197,198,198,215,215,215,199,199,216,216,200,200,217,217,217, | ||||
| 	214,214,215,215,215,215,215,199,216,216,216,200,200,217,217,234, | ||||
| 	214,214,215,215,215,232,232,216,216,216,233,187,217,217,217,234, | ||||
| 	201,201,202,202,202,186,186,203,203,203,187,187,204,204,234,234, | ||||
| 	201,201,202,202,202,202,186,203,203,203,220,204,204,204,221,221, | ||||
| 	218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221, | ||||
| 	218,218,219,219,219,219,219,220,220,220,220,237,221,221,221,238, | ||||
| 	235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238, | ||||
| 	239,239,223,223,224,224,224,208,208,225,225,225,209,209,226,226, | ||||
| 	239,239,223,223,224,224,224,208,208,225,225,225,209,209,226,226, | ||||
| 	210,210,211,211,211,211,211,195,212,212,212,196,196,213,213,230, | ||||
| 	210,210,211,211,211,211,228,212,212,212,229,229,213,213,213,230, | ||||
| 	227,227,211,211,211,228,228,212,212,229,229,229,213,213,230,230, | ||||
| 	227,227,211,211,228,228,228,212,212,229,229,246,213,213,230,230, | ||||
| 	227,227,211,228,228,228,245,212,229,229,229,246,213,213,230,230, | ||||
| 	214,214,198,215,215,215,215,199,216,216,216,200,200,217,217,217, | ||||
| 	214,214,215,215,215,215,232,216,216,216,233,200,217,217,217,234, | ||||
| 	231,231,215,215,232,232,232,216,216,233,233,233,217,217,234,234, | ||||
| 	231,231,215,232,232,232,232,216,233,233,233,250,217,217,234,234, | ||||
| 	231,231,202,232,232,249,249,203,203,233,250,250,204,234,234,251, | ||||
| 	218,218,202,219,219,219,219,203,220,220,220,204,204,221,221,221, | ||||
| 	218,218,219,219,219,219,219,220,220,220,220,237,221,221,221,238, | ||||
| 	235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238, | ||||
| 	235,235,236,236,236,236,236,220,237,237,237,254,221,238,238,238, | ||||
| 	240,240,224,224,224,241,241,241,225,225,242,242,242,226,226,243, | ||||
| 	240,240,224,224,224,241,241,241,225,225,242,242,242,226,226,243, | ||||
| 	227,227,211,211,228,241,241,212,212,229,242,242,213,213,230,243, | ||||
| 	227,227,211,228,228,228,245,212,229,229,229,246,213,213,230,230, | ||||
| 	227,227,228,228,228,245,245,245,229,229,246,246,246,230,230,230, | ||||
| 	244,244,244,228,245,245,245,245,229,229,246,246,246,230,230,247, | ||||
| 	244,244,244,245,245,245,245,245,229,246,246,246,246,230,230,247, | ||||
| 	244,244,215,215,245,245,245,216,216,216,246,246,217,217,217,247, | ||||
| 	231,231,215,232,232,232,232,216,216,233,233,233,217,217,234,234, | ||||
| 	231,231,232,232,232,232,249,216,233,233,233,250,217,234,234,234, | ||||
| 	248,248,248,232,249,249,249,249,233,233,250,250,250,234,234,251, | ||||
| 	248,248,248,249,249,249,249,249,233,250,250,250,250,234,251,251, | ||||
| 	248,248,219,219,249,249,249,220,220,220,250,250,221,221,221,251, | ||||
| 	235,235,219,219,236,236,236,220,220,237,237,237,221,221,238,238, | ||||
| 	235,235,236,236,236,236,236,220,237,237,237,254,221,238,238,238, | ||||
| 	252,252,252,236,236,253,253,253,237,237,254,254,254,238,238,255, | ||||
| }; | ||||
|  | ||||
							
								
								
									
										121
									
								
								sys/src/cmd/pict/rgbycc.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										121
									
								
								sys/src/cmd/pict/rgbycc.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,121 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
|  | ||||
| float c1 = 1.402; | ||||
| float c2 = 0.34414; | ||||
| float c3 = 0.71414; | ||||
| float c4 = 1.772; | ||||
|  | ||||
| int | ||||
| closest(int Y, int Cb, int Cr) | ||||
| { | ||||
| 	double r, g, b; | ||||
| 	double diff, min; | ||||
| 	int rgb, R, G, B, v, i; | ||||
| 	int y1, cb1, cr1; | ||||
|  | ||||
| 	Cb -= 128; | ||||
| 	Cr -= 128; | ||||
| 	r = Y+c1*Cr; | ||||
| 	g = Y-c2*Cb-c3*Cr; | ||||
| 	b = Y+c4*Cb; | ||||
|  | ||||
| //print("YCbCr: %d %d %d, RGB: %g %g %g\n", Y, Cb, Cr, r, g, b); | ||||
|  | ||||
| 	min = 1000000.; | ||||
| 	v = 1000; | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		rgb =  cmap2rgb(i); | ||||
| 		R = (rgb >> 16) & 0xFF; | ||||
| 		G = (rgb >> 8) & 0xFF; | ||||
| 		B = (rgb >> 0) & 0xFF; | ||||
| 		diff = (R-r)*(R-r) + (G-g)*(G-g) + (B-b)*(B-b); | ||||
| 		y1 = 0.5870*G + 0.114*B + 0.299*R; | ||||
| 		cb1 = (B-y1)/1.772; | ||||
| 		cr1 = (R-y1)/1.402; | ||||
| 		if(diff < min){ | ||||
| //			if(Y==0 && y1!=0) | ||||
| //				continue; | ||||
| 			if(Y==256-16 && y1<256-16) | ||||
| 				continue; | ||||
| //			if(Cb==0 && cb1!=0) | ||||
| //				continue; | ||||
| 			if(Cb==256-16 && cb1<256-16) | ||||
| 				continue; | ||||
| //			if(Cr==0 && cr1!=0) | ||||
| //				continue; | ||||
| 			if(Cr==256-16 && cr1<256-16) | ||||
| 				continue; | ||||
| //print("%d %d %d\n", R, G, B); | ||||
| 			min = diff; | ||||
| 			v = i; | ||||
| 		} | ||||
| 	} | ||||
| 	if(v > 255) | ||||
| 		abort(); | ||||
| 	return v; | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int i, rgb; | ||||
| 	int r, g, b; | ||||
| 	double Y, Cr, Cb; | ||||
| 	int y, cb, cr; | ||||
| 	unsigned char close[16*16*16]; | ||||
|  | ||||
| //print("%d\n", closest(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]))); | ||||
| //exits("X"); | ||||
|  | ||||
| 	print("/* This file has been generated by rgbycc */\n"); | ||||
| 	/* ycbcrmap */ | ||||
| 	print("uint ycbcrmap[256] = {\n"); | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		if(i%8 == 0) | ||||
| 			print("\t"); | ||||
| 		rgb = cmap2rgb(i); | ||||
| 		r = (rgb>>16) & 0xFF; | ||||
| 		g = (rgb>>8) & 0xFF; | ||||
| 		b = (rgb>>0) & 0xFF; | ||||
| 		Y = 0.5870*g + 0.114*b + 0.299*r; | ||||
| 		Cr = (r-Y)/1.402 + 128.; | ||||
| 		Cb = (b-Y)/1.772 + 128.; | ||||
| 		if(Y<0. || Y>=256. || Cr<0. || Cr>=256. || Cb<0. || Cb>=256.) | ||||
| 			print("bad at %d: %d %d %d; %g %g %g\n", i, r, g, b, Y, Cb, Cr); | ||||
| 		r = Y; | ||||
| 		g = Cb; | ||||
| 		b = Cr; | ||||
| 		print("0x%.6ulX, ", (r<<16) | (g<<8) | b); | ||||
| 		if(i%8 == 7) | ||||
| 			print("\n"); | ||||
| 	} | ||||
| 	print("};\n\n"); | ||||
|  | ||||
| 	/* closestycbcr */ | ||||
| 	print("unsigned char closestycbcr[16*16*16] = {\n"); | ||||
| 	for(y=0; y<256; y+=16) | ||||
| 	for(cb=0; cb<256; cb+=16) | ||||
| 	for(cr=0; cr<256; cr+=16) | ||||
| 		close[(cr/16)+16*((cb/16)+16*(y/16))] = closest(y, cb, cr); | ||||
| if(0){ | ||||
| 	/*weird: set white for nearly white */ | ||||
| 	for(cb=128-32; cb<=128+32; cb+=16) | ||||
| 	for(cr=128-32; cr<=128+32; cr+=16) | ||||
| 		close[(cr/16)+16*((cb/16)+16*(255/16))] = 0; | ||||
| 	/*weird: set black for nearly black */ | ||||
| 	for(cb=128-32; cb<=128+32; cb+=16) | ||||
| 	for(cr=128-32; cr<=128+32; cr+=16) | ||||
| 		close[(cr/16)+16*((cb/16)+16*(0/16))] = 255; | ||||
| } | ||||
| 	for(i=0; i<16*16*16; i++){ | ||||
| 		if(i%16 == 0) | ||||
| 			print("\t"); | ||||
| 		print("%d,", close[i]); | ||||
| 		if(i%16 == 15) | ||||
| 			print("\n"); | ||||
| 	} | ||||
| 	print("};\n\n"); | ||||
| 	exits(nil); | ||||
| } | ||||
							
								
								
									
										223
									
								
								sys/src/cmd/pict/tga.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										223
									
								
								sys/src/cmd/pict/tga.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,223 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t		outchan = CMAP8; | ||||
| int		defaultcolor = 1; | ||||
| Image	*image; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rawimage** readtga(int fd); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "tga: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: tga -39cdektv  [file ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "tga: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "tga: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "tga: initdraw failed: %r"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	array = readtga(fd); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "tga: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)){ | ||||
| 			c = totruecolor(r, CY); | ||||
| 			outchan = GREY8; | ||||
| 		}else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "tga: converting %s to local format failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			i = allocimage(display, c->r, GREY8, 0, 0); | ||||
| 		else | ||||
| 			i = allocimage(display, c->r, outchan, 0, 0); | ||||
|  | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "tga: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
|  | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "tga: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "tga: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "tga: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										256
									
								
								sys/src/cmd/pict/tif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										256
									
								
								sys/src/cmd/pict/tif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,256 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int cflag = 0; | ||||
| int dflag = 0; | ||||
| int eflag = 0; | ||||
| int nineflag = 0; | ||||
| int threeflag = 0; | ||||
| int output = 0; | ||||
| Image *image; | ||||
| int defaultcolor = 1; | ||||
|  | ||||
| enum { | ||||
| 	Border = 2, | ||||
| 	Edge = 5 | ||||
| }; | ||||
|  | ||||
| int init(void); | ||||
| char *show(int, char *, int); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0) | ||||
| 		sysfatal("getwindow: %r"); | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: %s [-39cdektv] [file.tif ...]\n", argv0); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
| 	uint32_t outchan; | ||||
|  | ||||
| 	outchan = CMAP8; | ||||
| 	ARGBEGIN { | ||||
| 	/* | ||||
| 	* produce encoded, compressed, bitmap file; | ||||
| 	* no display by default | ||||
| 	*/ | ||||
| 	case 'c': | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	/* suppress display of image */ | ||||
| 	case 'd': | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	/* disable floyd-steinberg error diffusion */ | ||||
| 	case 'e': | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	/* force black and white */ | ||||
| 	case 'k': | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	/* | ||||
| 	* produce encoded, compressed, three-color | ||||
| 	* bitmap file; no display by default | ||||
| 	*/ | ||||
| 	case '3': | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	/* | ||||
| 	* produce encoded, compressed, true-color | ||||
| 	* bitmap file; no display by default | ||||
| 	*/ | ||||
| 	case 't': | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	/* force RGBV */ | ||||
| 	case 'v': | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	/* | ||||
| 	* produce plan 9, uncompressed, bitmap file; | ||||
| 	* no display by default | ||||
| 	*/ | ||||
| 	case '9': | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	} ARGEND | ||||
|  | ||||
| 	if(argc <= 0) | ||||
| 		exits(show(0, "<stdin>", outchan)); | ||||
| 	err = nil; | ||||
| 	for(i = 0; i < argc; i++) { | ||||
| 		if((fd = open(argv[i], OREAD)) < 0) { | ||||
| 			fprint(2, "%s: open %s: %r\n", | ||||
| 				argv0, argv[i]); | ||||
| 			err = "open"; | ||||
| 		} else { | ||||
| 			err = show(fd, argv[i], outchan); | ||||
| 			close(fd); | ||||
| 		} | ||||
| 		if((nineflag || cflag) && argc > 1 && err == nil) { | ||||
| 			fprint(2, "%s: exiting after one file\n", | ||||
| 				argv0); | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited = 0; | ||||
|  | ||||
| 	if(!inited) { | ||||
| 		if(initdraw(0, 0, 0) < 0) { | ||||
| 			fprint(2, "%s: initdraw: %r", argv0); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| char * | ||||
| show(int fd, char *name, int outchan) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	Biobuf b; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	if(Binit(&b, fd, OREAD) < 0) | ||||
| 		return nil; | ||||
| 	array = Breadtif(&b, CRGB24); | ||||
| 	if(array == nil || array[0] == nil) { | ||||
| 		if(array != nil) | ||||
| 			free(array); | ||||
| 		fprint(2, "%s: decode %s failed: %r\n", | ||||
| 			argv0, name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	Bterm(&b); | ||||
| 	if(!dflag) { | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth > 8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan != CMAP8) { | ||||
| 		switch(r->chandesc) { | ||||
| 		case CY: | ||||
| 			outchan = GREY8; | ||||
| 			break; | ||||
| 		case CRGB24: | ||||
| 			outchan = RGB24; | ||||
| 			break; | ||||
| 		} | ||||
| 		c = r; | ||||
| 	} else if((c = torgbv(r, !eflag)) == nil) { | ||||
| 		fprint(2, "%s: conversion of %s failed: %r\n", | ||||
| 			argv0, name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag) { | ||||
| 		i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil) { | ||||
| 			fprint(2, "%s: allocimage %s: %r\n", | ||||
| 				argv0, name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], | ||||
| 			c->chanlen) < 0) { | ||||
| 			fprint(2, "%s: loadimage %s: %r\n", | ||||
| 				argv0, name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		ch = ekbd(); | ||||
| 		if(ch == 'q' || ch == Kdel || ch == Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, | ||||
| 			nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag) { | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, | ||||
| 			c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != | ||||
| 			c->chanlen) { | ||||
| 			fprint(2, "%s: %s: write error: %r\n", | ||||
| 				argv0, name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} else if(cflag && writerawimage(1, c) < 0) { | ||||
| 		fprint(2, "%s: %s: write error: %r\n", | ||||
| 			argv0, name); | ||||
| 		return "write"; | ||||
| 	} | ||||
| 	if(c != nil && c != r) { | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	for(j = 0; j < r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										178
									
								
								sys/src/cmd/pict/togif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										178
									
								
								sys/src/cmd/pict/togif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,178 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: togif [-l loopcount] [-c 'comment'] [-d Δt (ms)] [-t transparency-index] [file ... [-d Δt] file ... | -E]\n"); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| #define	UNSET (-12345678) | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	Biobuf bout; | ||||
| 	Memimage *i, *ni; | ||||
| 	int fd, j, dt, trans, loop, eof; | ||||
| 	char buf[256]; | ||||
| 	char *err, *comment, *s; | ||||
|  | ||||
| 	comment = nil; | ||||
| 	dt = -1; | ||||
| 	trans = -1; | ||||
| 	loop = UNSET; | ||||
| 	eof = 0; | ||||
| 	ARGBEGIN{ | ||||
| 	case 'l': | ||||
| 		s = ARGF(); | ||||
| 		if(s==nil || (!isdigit(s[0]) && s[0]!='-')) | ||||
| 			usage(); | ||||
| 		loop = atoi(s); | ||||
| 		break; | ||||
| 	case 'c': | ||||
| 		comment = ARGF(); | ||||
| 		if(comment == nil) | ||||
| 			usage(); | ||||
| 		break; | ||||
| 	case 'd': | ||||
| 		s = ARGF(); | ||||
| 		if(s==nil || !isdigit(s[0])) | ||||
| 			usage(); | ||||
| 		dt = atoi(s); | ||||
| 		break; | ||||
| 	case 't': | ||||
| 		s = ARGF(); | ||||
| 		if(s==nil || !isdigit(s[0])) | ||||
| 			usage(); | ||||
| 		trans = atoi(s); | ||||
| 		if(trans > 255) | ||||
| 			usage(); | ||||
| 		break; | ||||
| 	case 'E': | ||||
| 		eof++; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	}ARGEND | ||||
|  | ||||
| 	if(Binit(&bout, 1, OWRITE) < 0) | ||||
| 		sysfatal("Binit failed: %r"); | ||||
|  | ||||
| 	memimageinit(); | ||||
|  | ||||
| 	err = nil; | ||||
|  | ||||
| 	if(eof){ | ||||
| 		if(argc != 0) usage(); | ||||
| 		for(j = 0;;j++){ | ||||
| 			i = readmemimage(0); | ||||
| 			if(i == nil) break; | ||||
| 			ni = memonechan(i); | ||||
| 			if(ni == nil) | ||||
| 				sysfatal("converting image to RGBV: %r"); | ||||
| 			if(i != nil){ | ||||
| 				freememimage(i); | ||||
| 				i = ni; | ||||
| 			} | ||||
| 			if(j == 0){ | ||||
| 				err = memstartgif(&bout, i, loop); | ||||
| 				if(err != nil) | ||||
| 					break; | ||||
| 			} | ||||
| 			if(comment) | ||||
| 				err = memwritegif(&bout, i, comment, dt, trans); | ||||
| 			else{ | ||||
| 				snprint(buf, sizeof buf, "Converted by Plan 9 from <stdin>"); | ||||
| 				err = memwritegif(&bout, i, buf, dt, trans); | ||||
| 			} | ||||
| 			if(err != nil) break; | ||||
| 			freememimage(i); | ||||
| 			comment = nil; | ||||
| 		} | ||||
| 	}else if(argc == 0){ | ||||
| 		i = readmemimage(0); | ||||
| 		if(i == nil) | ||||
| 			sysfatal("reading input: %r"); | ||||
| 		ni = memonechan(i); | ||||
| 		if(ni == nil) | ||||
| 			sysfatal("converting image to RGBV: %r"); | ||||
| 		if(i != ni){ | ||||
| 			freememimage(i); | ||||
| 			i = ni; | ||||
| 		} | ||||
| 		err = memstartgif(&bout, i, -1); | ||||
| 		if(err == nil){ | ||||
| 			if(comment) | ||||
| 				err = memwritegif(&bout, i, comment, dt, trans); | ||||
| 			else{ | ||||
| 				snprint(buf, sizeof buf, "Converted by Plan 9 from <stdin>"); | ||||
| 				err = memwritegif(&bout, i, buf, dt, trans); | ||||
| 			} | ||||
| 		} | ||||
| 	}else{ | ||||
| 		if(loop == UNSET){ | ||||
| 			if(argc == 1) | ||||
| 				loop = -1;	/* no loop for single image */ | ||||
| 			else | ||||
| 				loop = 0;	/* the default case: 0 means infinite loop */ | ||||
| 		} | ||||
| 		for(j=0; j<argc; j++){ | ||||
| 			if(argv[j][0] == '-' && argv[j][1]=='d'){ | ||||
| 				/* time change */ | ||||
| 				if(argv[j][2] == '\0'){ | ||||
| 					s = argv[++j]; | ||||
| 					if(j == argc) | ||||
| 						usage(); | ||||
| 				}else | ||||
| 					s = &argv[j][2]; | ||||
| 				if(!isdigit(s[0])) | ||||
| 					usage(); | ||||
| 				dt = atoi(s); | ||||
| 				if(j == argc-1)	/* last argument must be file */ | ||||
| 					usage(); | ||||
| 				continue; | ||||
| 			} | ||||
| 			fd = open(argv[j], OREAD); | ||||
| 			if(fd < 0) | ||||
| 				sysfatal("can't open %s: %r", argv[j]); | ||||
| 			i = readmemimage(fd); | ||||
| 			if(i == nil) | ||||
| 				sysfatal("can't readimage %s: %r", argv[j]); | ||||
| 			close(fd); | ||||
| 			ni = memonechan(i); | ||||
| 			if(ni == nil) | ||||
| 				sysfatal("converting image to RGBV: %r"); | ||||
| 			if(i != ni){ | ||||
| 				freememimage(i); | ||||
| 				i = ni; | ||||
| 			} | ||||
| 			if(j == 0){ | ||||
| 				err = memstartgif(&bout, i, loop); | ||||
| 				if(err != nil) | ||||
| 					break; | ||||
| 			} | ||||
| 			if(comment) | ||||
| 				err = memwritegif(&bout, i, comment, dt, trans); | ||||
| 			else{ | ||||
| 				snprint(buf, sizeof buf, "Converted by Plan 9 from %s", argv[j]); | ||||
| 				err = memwritegif(&bout, i, buf, dt, trans); | ||||
| 			} | ||||
| 			if(err != nil) | ||||
| 				break; | ||||
| 			freememimage(i); | ||||
| 			comment = nil; | ||||
| 		} | ||||
| 	} | ||||
| 	memendgif(&bout); | ||||
|  | ||||
| 	if(err != nil) | ||||
| 		fprint(2, "togif: %s\n", err); | ||||
| 	exits(err); | ||||
| } | ||||
							
								
								
									
										322
									
								
								sys/src/cmd/pict/toico.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										322
									
								
								sys/src/cmd/pict/toico.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,322 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	FileHdrLen=	6, | ||||
| 	IconDescrLen=	16, | ||||
| 	IconHdrLen=	40, | ||||
| }; | ||||
|  | ||||
| typedef struct Icon Icon; | ||||
| struct Icon | ||||
| { | ||||
| 	Icon	*next; | ||||
| 	char	*file; | ||||
|  | ||||
| 	unsigned char	w;		/* icon width */ | ||||
| 	unsigned char	h;		/* icon height */ | ||||
| 	unsigned short	ncolor;		/* number of colors */ | ||||
| 	unsigned short	nplane;		/* number of bit planes */ | ||||
| 	unsigned short	bits;		/* bits per pixel */ | ||||
| 	uint32_t	len;		/* length of data */ | ||||
| 	uint32_t	offset;		/* file offset to data */ | ||||
| 	unsigned char	map[4*256];	/* color map */ | ||||
|  | ||||
| 	Image	*img; | ||||
|  | ||||
| 	unsigned char	*xor; | ||||
| 	int	xorlen; | ||||
| 	unsigned char	*and; | ||||
| 	int	andlen; | ||||
| }; | ||||
|  | ||||
| typedef struct Header Header; | ||||
| struct Header | ||||
| { | ||||
| 	uint	n; | ||||
| 	Icon	*first; | ||||
| 	Icon	*last; | ||||
| }; | ||||
|  | ||||
| void | ||||
| Bputs(Biobuf *b, unsigned short x) | ||||
| { | ||||
| 	Bputc(b, x&0xff); | ||||
| 	Bputc(b, x>>8); | ||||
| } | ||||
|  | ||||
| void | ||||
| Bputl(Biobuf *b, uint32_t x) | ||||
| { | ||||
| 	Bputs(b, x&0xffff); | ||||
| 	Bputs(b, x>>16); | ||||
| } | ||||
|  | ||||
| Header h; | ||||
|  | ||||
| void*	emalloc(int); | ||||
| void	mk8bit(Icon*, int); | ||||
| void	mkxorand(Icon*, int); | ||||
| void	readicon(char*); | ||||
|  | ||||
| void | ||||
| main(int argc, char **argv) | ||||
| { | ||||
| 	int i; | ||||
| 	Biobuf *b, out; | ||||
| 	Icon *icon; | ||||
| 	uint32_t offset; | ||||
| 	uint32_t len; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	/* read in all the images */ | ||||
| 	display = initdisplay(nil, nil, nil); | ||||
| 	if(argc < 1){ | ||||
| 		readicon("/fd/0"); | ||||
| 	} else { | ||||
| 		for(i = 0; i < argc; i++) | ||||
| 			readicon(argv[i]); | ||||
| 	} | ||||
|  | ||||
| 	/* create the .ico file */ | ||||
| 	b = &out; | ||||
| 	Binit(b, 1, OWRITE); | ||||
|  | ||||
| 	/* offset to first icon */ | ||||
| 	offset = FileHdrLen + h.n*IconDescrLen; | ||||
|  | ||||
| 	/* file header is */ | ||||
| 	Bputs(b, 0); | ||||
| 	Bputs(b, 1); | ||||
| 	Bputs(b, h.n); | ||||
|  | ||||
| 	/* icon description */ | ||||
| 	for(icon = h.first; icon != nil; icon = icon->next){ | ||||
| 		Bputc(b, icon->w); | ||||
| 		Bputc(b, icon->h); | ||||
| 		Bputc(b, icon->ncolor); | ||||
| 		Bputc(b, 0); | ||||
| 		Bputs(b, icon->nplane); | ||||
| 		Bputs(b, icon->bits); | ||||
| 		len = IconHdrLen + icon->ncolor*4 + icon->xorlen + icon->andlen; | ||||
| 		Bputl(b, len); | ||||
| 		Bputl(b, offset); | ||||
| 		offset += len; | ||||
| 	} | ||||
|  | ||||
| 	/* icons */ | ||||
| 	for(icon = h.first; icon != nil; icon = icon->next){ | ||||
| 		/* icon header (BMP like) */ | ||||
| 		Bputl(b, IconHdrLen); | ||||
| 		Bputl(b, icon->w); | ||||
| 		Bputl(b, 2*icon->h); | ||||
| 		Bputs(b, icon->nplane); | ||||
| 		Bputs(b, icon->bits); | ||||
| 		Bputl(b, 0);	/* compression info */ | ||||
| 		Bputl(b, 0); | ||||
| 		Bputl(b, 0); | ||||
| 		Bputl(b, 0); | ||||
| 		Bputl(b, 0); | ||||
| 		Bputl(b, 0); | ||||
|  | ||||
| 		/* color map */ | ||||
| 		if(Bwrite(b, icon->map, 4*icon->ncolor) < 0) | ||||
| 			sysfatal("writing color map: %r"); | ||||
|  | ||||
| 		/* xor bits */ | ||||
| 		if(Bwrite(b, icon->xor, icon->xorlen) < 0) | ||||
| 			sysfatal("writing xor bits: %r"); | ||||
|  | ||||
| 		/* and bits */ | ||||
| 		if(Bwrite(b, icon->and, icon->andlen) < 0) | ||||
| 			sysfatal("writing and bits: %r"); | ||||
| 	} | ||||
|  | ||||
| 	Bterm(b); | ||||
| 	exits(0); | ||||
| } | ||||
|  | ||||
| void | ||||
| readicon(char *file) | ||||
| { | ||||
| 	int fd; | ||||
| 	Icon *icon; | ||||
|  | ||||
| 	fd = open(file, OREAD); | ||||
| 	if(fd < 0) | ||||
| 		sysfatal("opening %s: %r", file); | ||||
| 	icon = emalloc(sizeof(Icon)); | ||||
| 	icon->img = readimage(display, fd, 0); | ||||
| 	if(icon->img == nil) | ||||
| 		sysfatal("reading image %s: %r", file); | ||||
| 	close(fd); | ||||
|  | ||||
| 	if(h.first) | ||||
| 		h.last->next = icon; | ||||
| 	else | ||||
| 		h.first = icon; | ||||
| 	h.last = icon; | ||||
| 	h.n++; | ||||
|  | ||||
| 	icon->h = Dy(icon->img->r); | ||||
| 	icon->w = Dx(icon->img->r); | ||||
| 	icon->bits = 1<<icon->img->depth; | ||||
| 	icon->nplane = 1; | ||||
|  | ||||
| 	/* convert to 8 bits per pixel */ | ||||
| 	switch(icon->img->chan){ | ||||
| 	case GREY8: | ||||
| 	case CMAP8: | ||||
| 		break; | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 		mk8bit(icon, 1); | ||||
| 		break; | ||||
| 	default: | ||||
| 		mk8bit(icon, 0); | ||||
| 		break; | ||||
| 	} | ||||
| 	icon->bits = 8; | ||||
| 	icon->file = file; | ||||
|  | ||||
| 	/* create xor/and masks, minimizing bits per pixel */ | ||||
| 	mkxorand(icon, icon->img->chan == GREY8); | ||||
| } | ||||
|  | ||||
| void* | ||||
| emalloc(int len) | ||||
| { | ||||
| 	void *x; | ||||
|  | ||||
| 	x = mallocz(len, 1); | ||||
| 	if(x == nil) | ||||
| 		sysfatal("memory: %r"); | ||||
| 	return x; | ||||
| } | ||||
|  | ||||
| /* convert to 8 bit */ | ||||
| void | ||||
| mk8bit(Icon *icon, int grey) | ||||
| { | ||||
| 	Image *img; | ||||
|  | ||||
| 	img = allocimage(display, icon->img->r, grey ? GREY8 : CMAP8, 0, DNofill); | ||||
| 	if(img == nil) | ||||
| 		sysfatal("can't allocimage: %r"); | ||||
| 	draw(img, img->r, icon->img, nil, ZP); | ||||
| 	freeimage(icon->img); | ||||
| 	icon->img = img; | ||||
| } | ||||
|  | ||||
| /* make xor and and mask */ | ||||
| void | ||||
| mkxorand(Icon *icon, int grey) | ||||
| { | ||||
| 	int i, x, y, s, sa; | ||||
| 	unsigned char xx[256]; | ||||
| 	unsigned char *data, *p, *e; | ||||
| 	int ndata; | ||||
| 	unsigned char *mp; | ||||
| 	int ncolor; | ||||
| 	uint32_t color; | ||||
| 	int bits; | ||||
| 	unsigned char andbyte, xorbyte; | ||||
| 	unsigned char *ato, *xto; | ||||
| 	int xorrl, andrl; | ||||
|  | ||||
| 	ndata = icon->h * icon->w; | ||||
| 	data = emalloc(ndata); | ||||
| 	if(unloadimage(icon->img, icon->img->r, data, ndata) < 0) | ||||
| 		sysfatal("can't unload %s: %r", icon->file); | ||||
| 	e = data + ndata; | ||||
|  | ||||
| 	/* find colors used */ | ||||
| 	memset(xx, 0, sizeof xx); | ||||
| 	for(p = data; p < e; p++) | ||||
| 		xx[*p]++; | ||||
|  | ||||
| 	/* count the colors and create a mapping from plan 9 */ | ||||
| 	mp = icon->map; | ||||
| 	ncolor = 0; | ||||
| 	for(i = 0; i < 256; i++){ | ||||
| 		if(xx[i] == 0) | ||||
| 			continue; | ||||
| 		if(grey){ | ||||
| 			*mp++ = i; | ||||
| 			*mp++ = i; | ||||
| 			*mp++ = i; | ||||
| 			*mp++ = 0; | ||||
| 		} else { | ||||
| 			color = cmap2rgb(i); | ||||
| 			*mp++ = color; | ||||
| 			*mp++ = color>>8; | ||||
| 			*mp++ = color>>16; | ||||
| 			*mp++ = 0; | ||||
| 		} | ||||
| 		xx[i] = ncolor; | ||||
| 		ncolor++; | ||||
| 	} | ||||
|  | ||||
| 	/* get minimum number of pixels per bit (with a color map) */ | ||||
| 	if(ncolor <= 2){ | ||||
| 		ncolor = 2; | ||||
| 		bits = 1; | ||||
| 	} else if(ncolor <= 4){ | ||||
| 		ncolor = 4; | ||||
| 		bits = 2; | ||||
| 	} else if(ncolor <= 16){ | ||||
| 		ncolor = 16; | ||||
| 		bits = 4; | ||||
| 	} else { | ||||
| 		ncolor = 256; | ||||
| 		bits = 8; | ||||
| 	} | ||||
| 	icon->bits = bits; | ||||
| 	icon->ncolor = ncolor; | ||||
|  | ||||
| 	/* the xor mask rows are justified to a 32 bit boundary */ | ||||
| 	/* the and mask is 1 bit grey */ | ||||
| 	xorrl = 4*((bits*icon->w + 31)/32); | ||||
| 	andrl = 4*((icon->w + 31)/32); | ||||
| 	icon->xor = emalloc(xorrl * icon->h); | ||||
| 	icon->and = emalloc(andrl * icon->h); | ||||
| 	icon->xorlen = xorrl*icon->h; | ||||
| 	icon->andlen = andrl*icon->h; | ||||
|  | ||||
| 	/* make both masks.  they're upside down relative to plan9 ones */ | ||||
| 	p = data; | ||||
| 	for(y = 0; y < icon->h; y++){ | ||||
| 		andbyte = 0; | ||||
| 		xorbyte = 0; | ||||
| 		sa = s = 0; | ||||
| 		xto = icon->xor + (icon->h-1-y)*xorrl; | ||||
| 		ato = icon->and + (icon->h-1-y)*andrl; | ||||
| 		for(x = 0; x < icon->w; x++){ | ||||
| 			xorbyte <<= bits; | ||||
| 			xorbyte |= xx[*p]; | ||||
| 			s += bits; | ||||
| 			if(s == 8){ | ||||
| 				*xto++ = xorbyte; | ||||
| 				xorbyte = 0; | ||||
| 				s = 0; | ||||
| 			} | ||||
| 			andbyte <<= 1; | ||||
| 			if(*p == 0xff) | ||||
| 				andbyte |= 1; | ||||
| 			sa++; | ||||
| 			if(sa == 0){ | ||||
| 				*ato++ = andbyte; | ||||
| 				sa = 0; | ||||
| 				andbyte = 0; | ||||
| 			} | ||||
| 			p++; | ||||
| 		} | ||||
| 	} | ||||
| 	free(data); | ||||
| } | ||||
							
								
								
									
										70
									
								
								sys/src/cmd/pict/tojpg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sys/src/cmd/pict/tojpg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: %s [-c 'comment'] [-ks] [file]\n", argv0); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	Biobuf bout; | ||||
| 	Memimage *i, *ni; | ||||
| 	int fd, kflag, sflag; | ||||
| 	char *err, *file, *com; | ||||
|  | ||||
| 	kflag = sflag = 0; | ||||
| 	com = nil; | ||||
| 	ARGBEGIN { | ||||
| 	case 'c': | ||||
| 		com = EARGF(usage()); | ||||
| 		break; | ||||
| 	case 'k': | ||||
| 		kflag = 1; | ||||
| 		break; | ||||
| 	case 's': | ||||
| 		sflag = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	} ARGEND | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 		usage(); | ||||
| 	if(argc == 0) { | ||||
| 		file = "<stdin>"; | ||||
| 		fd = 0; | ||||
| 	} else { | ||||
| 		file = argv[0]; | ||||
| 		if((fd = open(file, OREAD)) < 0) | ||||
| 			sysfatal("open %s: %r", file); | ||||
| 	} | ||||
|  | ||||
| 	if(Binit(&bout, 1, OWRITE) < 0) | ||||
| 		sysfatal("Binit: %r"); | ||||
| 	memimageinit(); | ||||
|  | ||||
| 	if((i = readmemimage(fd)) == nil) | ||||
| 		sysfatal("readimage %s: %r", file); | ||||
| 	close(fd); | ||||
| 	if((ni = memmultichan(i)) == nil) | ||||
| 		sysfatal("converting image to RGB24: %r"); | ||||
| 	if(i != ni) { | ||||
| 		freememimage(i); | ||||
| 		i = ni; | ||||
| 	} | ||||
| 	err = memwritejpg(&bout, i, com, kflag, sflag); | ||||
| 	freememimage(i); | ||||
|  | ||||
| 	if(err != nil) | ||||
| 		fprint(2, "%s: %s\n", argv0, err); | ||||
| 	exits(err); | ||||
| } | ||||
							
								
								
									
										70
									
								
								sys/src/cmd/pict/topng.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								sys/src/cmd/pict/topng.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,70 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include <flate.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: topng [-c 'comment'] [-g 'gamma'] [file]\n"); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	Biobuf bout; | ||||
| 	Memimage *i; | ||||
| 	int fd; | ||||
| 	char *err, *filename; | ||||
| 	ImageInfo II; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case 'c': | ||||
| 		II.comment = ARGF(); | ||||
| 		if(II.comment == nil) | ||||
| 			usage(); | ||||
| 		II.fields_set |= II_COMMENT; | ||||
| 		break; | ||||
| 	case 'g': | ||||
| 		II.gamma = atof(ARGF()); | ||||
| 		if(II.gamma == 0.) | ||||
| 			usage(); | ||||
| 		II.fields_set |= II_GAMMA; | ||||
| 		break; | ||||
| 	case 't': | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	}ARGEND | ||||
|  | ||||
| 	if(Binit(&bout, 1, OWRITE) < 0) | ||||
| 		sysfatal("Binit failed: %r"); | ||||
| 	memimageinit(); | ||||
|  | ||||
| 	if(argc == 0){ | ||||
| 		fd = 0; | ||||
| 		filename = "<stdin>"; | ||||
| 	}else{ | ||||
| 		fd = open(argv[0], OREAD); | ||||
| 		if(fd < 0) | ||||
| 			sysfatal("can't open %s: %r", argv[0]); | ||||
| 		filename = argv[0]; | ||||
| 	} | ||||
|  | ||||
| 	i = readmemimage(fd); | ||||
| 	if(i == nil) | ||||
| 		sysfatal("can't readimage %s: %r", filename); | ||||
| 	close(fd); | ||||
|  | ||||
| 	err = memwritepng(&bout, i, &II); | ||||
| 	freememimage(i); | ||||
|  | ||||
| 	if(err != nil) | ||||
| 		fprint(2, "topng: %s\n", err); | ||||
| 	exits(err); | ||||
| } | ||||
							
								
								
									
										91
									
								
								sys/src/cmd/pict/toppm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										91
									
								
								sys/src/cmd/pict/toppm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,91 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: toppm [-c 'comment'] [-r] [file]\n"); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	Biobuf bout; | ||||
| 	Memimage *i, *ni; | ||||
| 	int fd, rflag; | ||||
| 	char buf[256]; | ||||
| 	char *err, *comment; | ||||
|  | ||||
| 	rflag = 0; | ||||
| 	comment = nil; | ||||
| 	ARGBEGIN{ | ||||
| 	case 'c': | ||||
| 		comment = ARGF(); | ||||
| 		if(comment == nil) | ||||
| 			usage(); | ||||
| 		if(strchr(comment, '\n') != nil){ | ||||
| 			fprint(2, "ppm: comment cannot contain newlines\n"); | ||||
| 			usage(); | ||||
| 		} | ||||
| 		break; | ||||
| 	case 'r': | ||||
| 		rflag = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	}ARGEND | ||||
|  | ||||
| 	if(argc > 1) | ||||
| 		usage(); | ||||
|  | ||||
| 	if(Binit(&bout, 1, OWRITE) < 0) | ||||
| 		sysfatal("Binit failed: %r"); | ||||
|  | ||||
| 	memimageinit(); | ||||
|  | ||||
| 	if(argc == 0){ | ||||
| 		i = readmemimage(0); | ||||
| 		if(i == nil) | ||||
| 			sysfatal("reading input: %r"); | ||||
| 		ni = memmultichan(i); | ||||
| 		if(ni == nil) | ||||
| 			sysfatal("converting image to RGBV: %r"); | ||||
| 		if(i != ni){ | ||||
| 			freememimage(i); | ||||
| 			i = ni; | ||||
| 		} | ||||
| 		err = memwriteppm(&bout, i, comment, rflag); | ||||
| 	}else{ | ||||
| 		fd = open(argv[0], OREAD); | ||||
| 		if(fd < 0) | ||||
| 			sysfatal("can't open %s: %r", argv[0]); | ||||
| 		i = readmemimage(fd); | ||||
| 		if(i == nil) | ||||
| 			sysfatal("can't readimage %s: %r", argv[0]); | ||||
| 		close(fd); | ||||
| 		ni = memmultichan(i); | ||||
| 		if(ni == nil) | ||||
| 			sysfatal("converting image to RGB24: %r"); | ||||
| 		if(i != ni){ | ||||
| 			freememimage(i); | ||||
| 			i = ni; | ||||
| 		} | ||||
| 		if(comment) | ||||
| 			err = memwriteppm(&bout, i, comment, rflag); | ||||
| 		else{ | ||||
| 			snprint(buf, sizeof buf, "Converted by Plan 9 from %s", argv[0]); | ||||
| 			err = memwriteppm(&bout, i, buf, rflag); | ||||
| 		} | ||||
| 		freememimage(i); | ||||
| 	} | ||||
|  | ||||
| 	if(err != nil) | ||||
| 		fprint(2, "toppm: %s\n", err); | ||||
| 	exits(err); | ||||
| } | ||||
							
								
								
									
										339
									
								
								sys/src/cmd/pict/torgbv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										339
									
								
								sys/src/cmd/pict/torgbv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,339 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| #include "rgbv.h" | ||||
| #include "ycbcr.h" | ||||
|  | ||||
| #define	CLAMPOFF 128 | ||||
|  | ||||
| static	int	clamp[CLAMPOFF+256+CLAMPOFF]; | ||||
| static	int	inited; | ||||
|  | ||||
| void* | ||||
| _remaperror(char *fmt, ...) | ||||
| { | ||||
| 	va_list arg; | ||||
| 	char buf[ERRMAX]; | ||||
|  | ||||
| 	va_start(arg, fmt); | ||||
| 	vseprint(buf, buf+sizeof buf, fmt, arg); | ||||
| 	va_end(arg); | ||||
|  | ||||
| 	errstr(buf, sizeof buf); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| Rawimage* | ||||
| torgbv(Rawimage *i, int errdiff) | ||||
| { | ||||
| 	int j, k, rgb, x, y, er, eg, eb, col, t; | ||||
| 	int r, g, b, r1, g1, b1; | ||||
| 	int *ered, *egrn, *eblu, *rp, *gp, *bp; | ||||
| 	int bpc; | ||||
| 	uint *map3; | ||||
| 	unsigned char *closest; | ||||
| 	Rawimage *im; | ||||
| 	int dx, dy; | ||||
| 	char err[ERRMAX]; | ||||
| 	unsigned char *cmap, *cm, *in, *out, *inp, *outp, cmap1[3*256], map[256], *rpic, *bpic, *gpic; | ||||
|  | ||||
| 	err[0] = '\0'; | ||||
| 	errstr(err, sizeof err);	/* throw it away */ | ||||
| 	im = malloc(sizeof(Rawimage)); | ||||
| 	if(im == nil) | ||||
| 		return nil; | ||||
| 	memset(im, 0, sizeof(Rawimage)); | ||||
| 	im->chans[0] = malloc(i->chanlen); | ||||
| 	if(im->chans[0] == nil){ | ||||
| 		free(im); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	im->r = i->r; | ||||
| 	im->nchans = 1; | ||||
| 	im->chandesc = CRGBV; | ||||
| 	im->chanlen = i->chanlen; | ||||
|  | ||||
| 	dx = i->r.max.x-i->r.min.x; | ||||
| 	dy = i->r.max.y-i->r.min.y; | ||||
| 	cmap = i->cmap; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		inited = 1; | ||||
| 		for(j=0; j<CLAMPOFF; j++) | ||||
| 			clamp[j] = 0; | ||||
| 		for(j=0; j<256; j++) | ||||
| 			clamp[CLAMPOFF+j] = (j>>4); | ||||
| 		for(j=0; j<CLAMPOFF; j++) | ||||
| 			clamp[CLAMPOFF+256+j] = (255>>4); | ||||
| 	} | ||||
|  | ||||
| 	in = i->chans[0]; | ||||
| 	inp = in; | ||||
| 	out = im->chans[0]; | ||||
| 	outp = out; | ||||
|  | ||||
| 	ered = malloc((dx+1)*sizeof(int)); | ||||
| 	egrn = malloc((dx+1)*sizeof(int)); | ||||
| 	eblu = malloc((dx+1)*sizeof(int)); | ||||
| 	if(ered==nil || egrn==nil || eblu==nil){ | ||||
| 		free(im->chans[0]); | ||||
| 		free(im); | ||||
| 		free(ered); | ||||
| 		free(egrn); | ||||
| 		free(eblu); | ||||
| 		return _remaperror("remap: malloc failed: %r"); | ||||
| 	} | ||||
| 	memset(ered, 0, (dx+1)*sizeof(int)); | ||||
| 	memset(egrn, 0, (dx+1)*sizeof(int)); | ||||
| 	memset(eblu, 0, (dx+1)*sizeof(int)); | ||||
|  | ||||
| 	switch(i->chandesc){ | ||||
| 	default: | ||||
| 		return _remaperror("remap: can't recognize channel type %d", i->chandesc); | ||||
| 	case CRGB1: | ||||
| 		if(cmap == nil) | ||||
| 			return _remaperror("remap: image has no color map"); | ||||
| 		if(i->nchans != 1) | ||||
| 			return _remaperror("remap: can't handle nchans %d", i->nchans); | ||||
| 		for(j=1; j<=8; j++) | ||||
| 			if(i->cmaplen == 3*(1<<j)) | ||||
| 				break; | ||||
| 		if(j > 8) | ||||
| 			return _remaperror("remap: can't do colormap size 3*%d", i->cmaplen/3); | ||||
| 		if(i->cmaplen != 3*256){ | ||||
| 			/* to avoid a range check in inner loop below, make a full-size cmap */ | ||||
| 			memmove(cmap1, cmap, i->cmaplen); | ||||
| 			cmap = cmap1; | ||||
| 		} | ||||
| 		if(errdiff == 0){ | ||||
| 			k = 0; | ||||
| 			for(j=0; j<256; j++){ | ||||
| 				r = cmap[k]>>4; | ||||
| 				g = cmap[k+1]>>4; | ||||
| 				b = cmap[k+2]>>4; | ||||
| 				k += 3; | ||||
| 				map[j] = closestrgb[b+16*(g+16*r)]; | ||||
| 			} | ||||
| 			for(j=0; j<i->chanlen; j++) | ||||
| 				out[j] = map[in[j]]; | ||||
| 		}else{ | ||||
| 			/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ | ||||
| 			for(y=0; y<dy; y++){ | ||||
| 				er = 0; | ||||
| 				eg = 0; | ||||
| 				eb = 0; | ||||
| 				rp = ered; | ||||
| 				gp = egrn; | ||||
| 				bp = eblu; | ||||
| 				for(x=0; x<dx; x++){ | ||||
| 					cm = &cmap[3 * *inp++]; | ||||
| 					r = cm[0] +*rp; | ||||
| 					g = cm[1] +*gp; | ||||
| 					b = cm[2] +*bp; | ||||
|  | ||||
| 					/* sanity checks are new */ | ||||
| 					if(r >= 256+CLAMPOFF) | ||||
| 						r = 0; | ||||
| 					if(g >= 256+CLAMPOFF) | ||||
| 						g = 0; | ||||
| 					if(b >= 256+CLAMPOFF) | ||||
| 						b = 0; | ||||
| 					r1 = clamp[r+CLAMPOFF]; | ||||
| 					g1 = clamp[g+CLAMPOFF]; | ||||
| 					b1 = clamp[b+CLAMPOFF]; | ||||
| 					if(r1 >= 16 || g1 >= 16 || b1 >= 16) | ||||
| 						col = 0; | ||||
| 					else | ||||
| 						col = closestrgb[b1+16*(g1+16*r1)]; | ||||
| 					*outp++ = col; | ||||
|  | ||||
| 					rgb = rgbmap[col]; | ||||
| 					r -= (rgb>>16) & 0xFF; | ||||
| 					t = (3*r)>>4; | ||||
| 					*rp++ = t+er; | ||||
| 					*rp += t; | ||||
| 					er = r-3*t; | ||||
|  | ||||
| 					g -= (rgb>>8) & 0xFF; | ||||
| 					t = (3*g)>>4; | ||||
| 					*gp++ = t+eg; | ||||
| 					*gp += t; | ||||
| 					eg = g-3*t; | ||||
|  | ||||
| 					b -= rgb & 0xFF; | ||||
| 					t = (3*b)>>4; | ||||
| 					*bp++ = t+eb; | ||||
| 					*bp += t; | ||||
| 					eb = b-3*t; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CYCbCr: | ||||
| 		bpc = 1; | ||||
| 		rpic = i->chans[0]; | ||||
| 		gpic = i->chans[1]; | ||||
| 		bpic = i->chans[2]; | ||||
| 		closest = closestycbcr; | ||||
| 		map3 = ycbcrmap; | ||||
| 		if(i->nchans != 3) | ||||
| 			return _remaperror("remap: RGB image has %d channels", i->nchans); | ||||
| 		goto Threecolor; | ||||
|  | ||||
| 	case CRGB: | ||||
| 		bpc = 1; | ||||
| 		rpic = i->chans[0]; | ||||
| 		gpic = i->chans[1]; | ||||
| 		bpic = i->chans[2]; | ||||
| 		if(i->nchans != 3) | ||||
| 			return _remaperror("remap: RGB image has %d channels", i->nchans); | ||||
| 		goto rgbgen; | ||||
|  | ||||
| 	case CRGB24: | ||||
| 		bpc = 3; | ||||
| 		bpic = i->chans[0]; | ||||
| 		gpic = i->chans[0] + 1; | ||||
| 		rpic = i->chans[0] + 2; | ||||
| 		goto rgbgen; | ||||
|  | ||||
| 	case CRGBA32: | ||||
| 		bpc = 4; | ||||
| 		/* i->chans[0]+0 is alpha */ | ||||
| 		bpic = i->chans[0] + 1; | ||||
| 		gpic = i->chans[0] + 2; | ||||
| 		rpic = i->chans[0] + 3; | ||||
|  | ||||
| 	rgbgen: | ||||
| 		closest = closestrgb; | ||||
| 		map3 = rgbmap; | ||||
|  | ||||
| 	Threecolor: | ||||
|  | ||||
| 		if(errdiff == 0){ | ||||
| 			outp = out; | ||||
| 			for(j=0; j<i->chanlen; j+=bpc){ | ||||
| 				r = rpic[j]>>4; | ||||
| 				g = gpic[j]>>4; | ||||
| 				b = bpic[j]>>4; | ||||
| 				*outp++ = closest[b+16*(g+16*r)]; | ||||
| 			} | ||||
| 		}else{ | ||||
| 			/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ | ||||
| 			for(y=0; y<dy; y++){ | ||||
| 				er = 0; | ||||
| 				eg = 0; | ||||
| 				eb = 0; | ||||
| 				rp = ered; | ||||
| 				gp = egrn; | ||||
| 				bp = eblu; | ||||
| 				for(x=0; x<dx; x++){ | ||||
| 					r = *rpic + *rp; | ||||
| 					g = *gpic + *gp; | ||||
| 					b = *bpic + *bp; | ||||
| 					rpic += bpc; | ||||
| 					gpic += bpc; | ||||
| 					bpic += bpc; | ||||
| 					/* | ||||
| 					 * Errors can be uncorrectable if converting from YCbCr, | ||||
| 					 * since we can't guarantee that an extremal value of one of | ||||
| 					 * the components selects a color with an extremal value. | ||||
| 					 * If we don't, the errors accumulate without bound.  This | ||||
| 					 * doesn't happen in RGB because the closest table can guarantee | ||||
| 					 * a color on the edge of the gamut, producing a zero error in | ||||
| 					 * that component.  For the rotation YCbCr space, there may be | ||||
| 					 * no color that can guarantee zero error at the edge. | ||||
| 					 * Therefore we must clamp explicitly rather than by assuming | ||||
| 					 * an upper error bound of CLAMPOFF.  The performance difference | ||||
| 					 * is miniscule anyway. | ||||
| 					 */ | ||||
| 					if(r < 0) | ||||
| 						r = 0; | ||||
| 					else if(r > 255) | ||||
| 						r = 255; | ||||
| 					if(g < 0) | ||||
| 						g = 0; | ||||
| 					else if(g > 255) | ||||
| 						g = 255; | ||||
| 					if(b < 0) | ||||
| 						b = 0; | ||||
| 					else if(b > 255) | ||||
| 						b = 255; | ||||
| 					r1 = r>>4; | ||||
| 					g1 = g>>4; | ||||
| 					b1 = b>>4; | ||||
| 					col = closest[b1+16*(g1+16*r1)]; | ||||
| 					*outp++ = col; | ||||
|  | ||||
| 					rgb = map3[col]; | ||||
| 					r -= (rgb>>16) & 0xFF; | ||||
| 					t = (3*r)>>4; | ||||
| 					*rp++ = t+er; | ||||
| 					*rp += t; | ||||
| 					er = r-3*t; | ||||
|  | ||||
| 					g -= (rgb>>8) & 0xFF; | ||||
| 					t = (3*g)>>4; | ||||
| 					*gp++ = t+eg; | ||||
| 					*gp += t; | ||||
| 					eg = g-3*t; | ||||
|  | ||||
| 					b -= rgb & 0xFF; | ||||
| 					t = (3*b)>>4; | ||||
| 					*bp++ = t+eb; | ||||
| 					*bp += t; | ||||
| 					eb = b-3*t; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CYA16: | ||||
| 		bpc = 2; | ||||
| 		/* i->chans[0] + 0 is alpha */ | ||||
| 		rpic = i->chans[0] + 1; | ||||
| 		goto greygen; | ||||
|  | ||||
| 	case CY: | ||||
| 		bpc = 1; | ||||
| 		rpic = i->chans[0]; | ||||
| 		if(i->nchans != 1) | ||||
| 			return _remaperror("remap: Y image has %d chans", i->nchans); | ||||
|  | ||||
| 	greygen: | ||||
| 		if(errdiff == 0){ | ||||
| 			for(j=0; j<i->chanlen; j+=bpc){ | ||||
| 				r = rpic[j]>>4; | ||||
| 				*outp++ = closestrgb[r+16*(r+16*r)]; | ||||
| 			} | ||||
| 		}else{ | ||||
| 			/* modified floyd steinberg, coefficients (1 0) 3/16, (0, 1) 3/16, (1, 1) 7/16 */ | ||||
| 			for(y=0; y<dy; y++){ | ||||
| 				er = 0; | ||||
| 				rp = ered; | ||||
| 				for(x=0; x<dx; x++){ | ||||
| 					r = *rpic + *rp; | ||||
| 					rpic += bpc; | ||||
| 					r1 = clamp[r+CLAMPOFF]; | ||||
| 					col = closestrgb[r1+16*(r1+16*r1)]; | ||||
| 					*outp++ = col; | ||||
|  | ||||
| 					rgb = rgbmap[col]; | ||||
| 					r -= (rgb>>16) & 0xFF; | ||||
| 					t = (3*r)>>4; | ||||
| 					*rp++ = t+er; | ||||
| 					*rp += t; | ||||
| 					er = r-3*t; | ||||
| 				} | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	free(ered); | ||||
| 	free(egrn); | ||||
| 	free(eblu); | ||||
| 	return im; | ||||
| } | ||||
							
								
								
									
										157
									
								
								sys/src/cmd/pict/totif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										157
									
								
								sys/src/cmd/pict/totif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,157 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| static Memimage *memtochan(Memimage *, uint32_t); | ||||
|  | ||||
| void | ||||
| usage(void) | ||||
| { | ||||
| 	fprint(2, "usage: %s [-c 'comment'] " | ||||
| 		"[-3bgGhklLptvyY] [file]\n", argv0); | ||||
| 	exits("usage"); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	Biobuf bout; | ||||
| 	Memimage *i, *ni; | ||||
| 	int fd, chanflag, comp, opt; | ||||
| 	char *err, *file, *c; | ||||
| 	uint32_t chan; | ||||
|  | ||||
| 	chan = BGR24; | ||||
| 	chanflag = opt = 0; | ||||
| 	comp = 1; | ||||
| 	c = nil; | ||||
| 	ARGBEGIN { | ||||
| 	case '3': /* force RGB */ | ||||
| 		chan = BGR24; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	case 'b': | ||||
| 		chan = GREY1; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	case 'c': | ||||
| 		c = EARGF(usage()); | ||||
| 		break; | ||||
| 	case 'g': /* t4 */ | ||||
| 		comp = 3; | ||||
| 		opt = 0; | ||||
| 		break; | ||||
| 	case 'G': /* t4 two-dimensional */ | ||||
| 		comp = 3; | ||||
| 		opt = 1; | ||||
| 		break; | ||||
| 	case 'h': /* huffman */ | ||||
| 		comp = 2; | ||||
| 		break; | ||||
| 	case 'k': | ||||
| 		chan = GREY8; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	case 'l': /* lzw */ | ||||
| 		comp = 5; | ||||
| 		opt = 0; | ||||
| 		break; | ||||
| 	case 'L': /* lzw, horizontal differencing */ | ||||
| 		comp = 5; | ||||
| 		opt = 1; | ||||
| 		break; | ||||
| 	case 'p': /* packbits */ | ||||
| 		comp = 0x8005; | ||||
| 		break; | ||||
| 	case 't': /* t6 */ | ||||
| 		comp = 4; | ||||
| 		break; | ||||
| 	case 'v': /* RGBV */ | ||||
| 		chan = CMAP8; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	case 'y': | ||||
| 		chan = GREY2; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	case 'Y': | ||||
| 		chan = GREY4; | ||||
| 		chanflag = 1; | ||||
| 		break; | ||||
| 	default: | ||||
| 		usage(); | ||||
| 	} ARGEND | ||||
| 	if(argc > 1) | ||||
| 		usage(); | ||||
| 	if(argc == 0) { | ||||
| 		file = "<stdin>"; | ||||
| 		fd = 0; | ||||
| 	} else { | ||||
| 		file = argv[0]; | ||||
| 		if((fd = open(file, OREAD)) < 0) | ||||
| 			sysfatal("open %s: %r", file); | ||||
| 	} | ||||
| 	if(Binit(&bout, 1, OWRITE) < 0) | ||||
| 		sysfatal("Binit: %r"); | ||||
| 	memimageinit(); | ||||
| 	if((i = readmemimage(fd)) == nil) | ||||
| 		sysfatal("readmemimage %s: %r", file); | ||||
| 	close(fd); | ||||
| 	if(comp >= 2 && comp <= 4) { | ||||
| 		chan = GREY1; | ||||
| 		chanflag = 1; | ||||
| 	} else if(chan == GREY2) { | ||||
| 		if((ni = memtochan(i, chan)) == nil) | ||||
| 			sysfatal("memtochan: %r"); | ||||
| 		if(i != ni) { | ||||
| 			freememimage(i); | ||||
| 			i = ni; | ||||
| 		} | ||||
| 		chan = GREY4; | ||||
| 	} | ||||
| 	if(!chanflag) { | ||||
| 		switch(i->chan) { | ||||
| 		case GREY1: | ||||
| 		case GREY4: | ||||
| 		case GREY8: | ||||
| 		case CMAP8: | ||||
| 		case BGR24: | ||||
| 			break; | ||||
| 		case GREY2: | ||||
| 			chan = GREY4; | ||||
| 			chanflag = 1; | ||||
| 			break; | ||||
| 		default: | ||||
| 			chanflag = 1; | ||||
| 			break; | ||||
| 		} | ||||
| 	} | ||||
| 	if(chanflag) { | ||||
| 		if((ni = memtochan(i, chan)) == nil) | ||||
| 			sysfatal("memtochan: %r"); | ||||
| 		if(i != ni) { | ||||
| 			freememimage(i); | ||||
| 			i = ni; | ||||
| 		} | ||||
| 	} | ||||
| 	if((err = memwritetif(&bout, i, c, comp, opt)) != nil) | ||||
| 		fprint(2, "%s: %s\n", argv0, err); | ||||
| 	freememimage(i); | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| static Memimage * | ||||
| memtochan(Memimage *i, uint32_t chan) | ||||
| { | ||||
| 	Memimage *ni; | ||||
|  | ||||
| 	if(i->chan == chan) | ||||
| 		return i; | ||||
| 	if((ni = allocmemimage(i->r, chan)) == nil) | ||||
| 		return nil; | ||||
| 	memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S); | ||||
| 	return ni; | ||||
| } | ||||
							
								
								
									
										162
									
								
								sys/src/cmd/pict/totruecolor.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								sys/src/cmd/pict/totruecolor.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,162 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| enum { | ||||
| 	c1 = 2871,	/* 1.402 * 2048 */ | ||||
| 	c2 = 705,		/* 0.34414 * 2048 */ | ||||
| 	c3 = 1463,	/* 0.71414 * 2048 */ | ||||
| 	c4 = 3629,	/* 1.772 * 2048 */ | ||||
| }; | ||||
|  | ||||
| Rawimage* | ||||
| totruecolor(Rawimage *i, int chandesc) | ||||
| { | ||||
| 	int j, k; | ||||
| 	Rawimage *im; | ||||
| 	char err[ERRMAX]; | ||||
| 	unsigned char *rp, *gp, *bp, *cmap, *inp, *outp, cmap1[4*256]; | ||||
| 	int r, g, b, Y, Cr, Cb, psize; | ||||
|  | ||||
| 	if(chandesc!=CY && chandesc!=CRGB24) | ||||
| 		return _remaperror("remap: can't convert to chandesc %d", chandesc); | ||||
|  | ||||
| 	err[0] = '\0'; | ||||
| 	errstr(err, sizeof err);	/* throw it away */ | ||||
| 	im = malloc(sizeof(Rawimage)); | ||||
| 	if(im == nil) | ||||
| 		return nil; | ||||
| 	memset(im, 0, sizeof(Rawimage)); | ||||
| 	if(chandesc == CY) | ||||
| 		im->chanlen = i->chanlen; | ||||
| 	else | ||||
| 		im->chanlen = 3*i->chanlen; | ||||
| 	im->chandesc = chandesc; | ||||
| 	im->chans[0] = malloc(im->chanlen); | ||||
| 	if(im->chans[0] == nil){ | ||||
| 		free(im); | ||||
| 		return nil; | ||||
| 	} | ||||
| 	im->r = i->r; | ||||
| 	im->nchans = 1; | ||||
|  | ||||
| 	cmap = i->cmap; | ||||
|  | ||||
| 	outp = im->chans[0]; | ||||
|  | ||||
| 	switch(i->chandesc){ | ||||
| 	default: | ||||
| 		return _remaperror("remap: can't recognize channel type %d", i->chandesc); | ||||
| 	case CY: | ||||
| 		if(i->nchans != 1) | ||||
| 			return _remaperror("remap: Y image has %d chans", i->nchans); | ||||
| 		if(chandesc == CY){ | ||||
| 			memmove(im->chans[0], i->chans[0], i->chanlen); | ||||
| 			break; | ||||
| 		} | ||||
| 		/* convert to three color */ | ||||
| 		inp = i->chans[0]; | ||||
| 		for(j=0; j<i->chanlen; j++){ | ||||
| 			k = *inp++; | ||||
| 			*outp++ = k; | ||||
| 			*outp++ = k; | ||||
| 			*outp++ = k; | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CRGB1: | ||||
| 	case CRGBV: | ||||
| 		psize = (i->chandesc == CRGB1) ? 3 : 4; | ||||
| 		if(cmap == nil) | ||||
| 			return _remaperror("remap: image has no color map"); | ||||
| 		if(i->nchans != 1) | ||||
| 			return _remaperror("remap: can't handle nchans %d", i->nchans); | ||||
| 		if(i->cmaplen > psize*256) | ||||
| 			return _remaperror("remap: can't do colormap size %d*%d", psize, i->cmaplen/psize); | ||||
| 		if(i->cmaplen != psize*256){ | ||||
| 			/* to avoid a range check in loop below, make a full-size cmap */ | ||||
| 			memmove(cmap1, cmap, i->cmaplen); | ||||
| 			cmap = cmap1; | ||||
| 		} | ||||
| 		inp = i->chans[0]; | ||||
| 		if(chandesc == CY){ | ||||
| 			for(j=0; j<i->chanlen; j++){ | ||||
| 				k = psize*(*inp++); | ||||
| 				r = cmap[k+2]; | ||||
| 				g = cmap[k+1]; | ||||
| 				b = cmap[k+0]; | ||||
| 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */ | ||||
| 				*outp++ = r; | ||||
| 			} | ||||
| 		}else{ | ||||
| 			for(j=0; j<i->chanlen; j++){ | ||||
| 				k = psize*(*inp++); | ||||
| 				*outp++ = cmap[k+2]; | ||||
| 				*outp++ = cmap[k+1]; | ||||
| 				*outp++ = cmap[k+0]; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
|  | ||||
| 	case CRGB: | ||||
| 		if(i->nchans != 3) | ||||
| 			return _remaperror("remap: can't handle nchans %d", i->nchans); | ||||
| 		rp = i->chans[0]; | ||||
| 		gp = i->chans[1]; | ||||
| 		bp = i->chans[2]; | ||||
| 		if(chandesc == CY){ | ||||
| 			for(j=0; j<i->chanlen; j++){ | ||||
| 				r = *bp++; | ||||
| 				g = *gp++; | ||||
| 				b = *rp++; | ||||
| 				r = (2125*r + 7154*g + 721*b)/10000;	/* Poynton page 84 */ | ||||
| 				*outp++ = r; | ||||
| 			} | ||||
| 		}else | ||||
| 			for(j=0; j<i->chanlen; j++){ | ||||
| 				*outp++ = *bp++; | ||||
| 				*outp++ = *gp++; | ||||
| 				*outp++ = *rp++; | ||||
| 			} | ||||
| 		break; | ||||
|  | ||||
| 	case CYCbCr: | ||||
| 		if(i->nchans != 3) | ||||
| 			return _remaperror("remap: can't handle nchans %d", i->nchans); | ||||
| 		rp = i->chans[0]; | ||||
| 		gp = i->chans[1]; | ||||
| 		bp = i->chans[2]; | ||||
| 		for(j=0; j<i->chanlen; j++){ | ||||
| 			Y = *rp++ << 11; | ||||
| 			Cb = *gp++ - 128; | ||||
| 			Cr = *bp++ - 128; | ||||
| 			r = (Y+c1*Cr) >> 11; | ||||
| 			g = (Y-c2*Cb-c3*Cr) >> 11; | ||||
| 			b = (Y+c4*Cb) >> 11; | ||||
| 			if(r < 0) | ||||
| 				r = 0; | ||||
| 			if(r > 255) | ||||
| 				r = 255; | ||||
| 			if(g < 0) | ||||
| 				g = 0; | ||||
| 			if(g > 255) | ||||
| 				g = 255; | ||||
| 			if(b < 0) | ||||
| 				b = 0; | ||||
| 			if(b > 255) | ||||
| 				b = 255; | ||||
| 			if(chandesc == CY){ | ||||
| 				r = (2125*r + 7154*g + 721*b)/10000; | ||||
| 				*outp++ = r; | ||||
| 			}else{ | ||||
| 				*outp++ = b; | ||||
| 				*outp++ = g; | ||||
| 				*outp++ = r; | ||||
| 			} | ||||
| 		} | ||||
| 		break; | ||||
| 	} | ||||
| 	return im; | ||||
| } | ||||
							
								
								
									
										220
									
								
								sys/src/cmd/pict/v210.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								sys/src/cmd/pict/v210.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| int		defaultcolor = 1; | ||||
| Image	*image; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rawimage** readV210(int fd, int colorspace); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "readV210: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: %s -39cdektv  [file.yuv ...]\n", argv0); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "readV210: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "readV210: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "readV210: initdraw failed: %r"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	array = readV210(fd, CYCbCr); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "readV210: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)) | ||||
| 			c = totruecolor(r, CY); | ||||
| 		else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "readV210: converting %s to local format failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			i = allocimage(display, c->r, GREY8, 0, 0); | ||||
| 		else | ||||
| 			i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "readV210: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "readV210: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "readV210: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "readV210: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										574
									
								
								sys/src/cmd/pict/writegif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										574
									
								
								sys/src/cmd/pict/writegif.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,574 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	Nhash	= 4001, | ||||
| 	Nbuf	= 300, | ||||
| }; | ||||
|  | ||||
| typedef struct Entry Entry; | ||||
| typedef struct IO IO; | ||||
|  | ||||
|  | ||||
| struct Entry | ||||
| { | ||||
| 	int	index; | ||||
| 	int	prefix; | ||||
| 	int	exten; | ||||
| 	Entry	*next; | ||||
| }; | ||||
|  | ||||
| struct IO | ||||
| { | ||||
| 	Biobuf	*fd; | ||||
| 	unsigned char	buf[Nbuf]; | ||||
| 	int		i; | ||||
| 	int		nbits;	/* bits in right side of shift register */ | ||||
| 	int		sreg;		/* shift register */ | ||||
| }; | ||||
|  | ||||
| static Rectangle	mainrect; | ||||
| static Entry	tbl[4096]; | ||||
| static unsigned char	*colormap[5];	/* one for each ldepth: GREY1 GREY2 GREY4 CMAP8=rgbv plus GREY8 */ | ||||
| #define	GREYMAP	4 | ||||
| static int		colormapsize[] = { 2, 4, 16, 256, 256 };	/* 2 for zero is an odd property of GIF */ | ||||
|  | ||||
| static void		writeheader(Biobuf*, Rectangle, int, uint32_t, int); | ||||
| static void		writedescriptor(Biobuf*, Rectangle); | ||||
| static char*		writedata(Biobuf*, Image*, Memimage*); | ||||
| static void		writecomment(Biobuf *fd, char*); | ||||
| static void		writegraphiccontrol(Biobuf *fd, int, int); | ||||
| static void*		gifmalloc(uint32_t); | ||||
| static void		encode(Biobuf*, Rectangle, int, unsigned char*, uint); | ||||
|  | ||||
| static | ||||
| char* | ||||
| startgif0(Biobuf *fd, uint32_t chan, Rectangle r, int depth, int loopcount) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	for(i=0; i<nelem(tbl); i++) | ||||
| 		tbl[i] = (Entry){i, -1, i, nil}; | ||||
|  | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case CMAP8: | ||||
| 	case GREY8: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WriteGIF: can't handle channel type"; | ||||
| 	} | ||||
|  | ||||
| 	mainrect = r; | ||||
| 	writeheader(fd, r, depth, chan, loopcount); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| char* | ||||
| startgif(Biobuf *fd, Image *image, int loopcount) | ||||
| { | ||||
| 	return startgif0(fd, image->chan, image->r, image->depth, loopcount); | ||||
| } | ||||
|  | ||||
| char* | ||||
| memstartgif(Biobuf *fd, Memimage *memimage, int loopcount) | ||||
| { | ||||
| 	return startgif0(fd, memimage->chan, memimage->r, memimage->depth, loopcount); | ||||
| } | ||||
|  | ||||
| static | ||||
| char* | ||||
| writegif0(Biobuf *fd, Image *image, Memimage *memimage, uint32_t chan, Rectangle r, char *comment, int dt, int trans) | ||||
| { | ||||
| 	char *err; | ||||
|  | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case CMAP8: | ||||
| 	case GREY8: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WriteGIF: can't handle channel type"; | ||||
| 	} | ||||
|  | ||||
| 	writecomment(fd, comment); | ||||
| 	writegraphiccontrol(fd, dt, trans); | ||||
| 	writedescriptor(fd, r); | ||||
|  | ||||
| 	err = writedata(fd, image, memimage); | ||||
| 	if(err != nil) | ||||
| 		return err; | ||||
|  | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| char* | ||||
| writegif(Biobuf *fd, Image *image, char *comment, int dt, int trans) | ||||
| { | ||||
| 	return writegif0(fd, image, nil, image->chan, image->r, comment, dt, trans); | ||||
| } | ||||
|  | ||||
| char* | ||||
| memwritegif(Biobuf *fd, Memimage *memimage, char *comment, int dt, int trans) | ||||
| { | ||||
| 	return writegif0(fd, nil, memimage, memimage->chan, memimage->r, comment, dt, trans); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write little-endian 16-bit integer | ||||
|  */ | ||||
| static | ||||
| void | ||||
| put2(Biobuf *fd, int i) | ||||
| { | ||||
| 	Bputc(fd, i); | ||||
| 	Bputc(fd, i>>8); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Get color map for all ldepths, in format suitable for writing out | ||||
|  */ | ||||
| static | ||||
| void | ||||
| getcolormap(void) | ||||
| { | ||||
| 	int i, col; | ||||
| 	uint32_t rgb; | ||||
| 	unsigned char *c; | ||||
|  | ||||
| 	if(colormap[0] != nil) | ||||
| 		return; | ||||
| 	for(i=0; i<nelem(colormap); i++) | ||||
| 		colormap[i] = gifmalloc(3* colormapsize[i]); | ||||
| 	c = colormap[GREYMAP];	/* GREY8 */ | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		c[3*i+0] = i;	/* red */ | ||||
| 		c[3*i+1] = i;	/* green */ | ||||
| 		c[3*i+2] = i;	/* blue */ | ||||
| 	} | ||||
| 	c = colormap[3];	/* RGBV */ | ||||
| 	for(i=0; i<256; i++){ | ||||
| 		rgb = cmap2rgb(i); | ||||
| 		c[3*i+0] = (rgb>>16) & 0xFF;	/* red */ | ||||
| 		c[3*i+1] = (rgb>> 8) & 0xFF;	/* green */ | ||||
| 		c[3*i+2] = (rgb>> 0) & 0xFF;	/* blue */ | ||||
| 	} | ||||
| 	c = colormap[2];	/* GREY4 */ | ||||
| 	for(i=0; i<16; i++){ | ||||
| 		col = (i<<4)|i; | ||||
| 		rgb = cmap2rgb(col); | ||||
| 		c[3*i+0] = (rgb>>16) & 0xFF;	/* red */ | ||||
| 		c[3*i+1] = (rgb>> 8) & 0xFF;	/* green */ | ||||
| 		c[3*i+2] = (rgb>> 0) & 0xFF;	/* blue */ | ||||
| 	} | ||||
| 	c = colormap[1];	/* GREY2 */ | ||||
| 	for(i=0; i<4; i++){ | ||||
| 		col = (i<<6)|(i<<4)|(i<<2)|i; | ||||
| 		rgb = cmap2rgb(col); | ||||
| 		c[3*i+0] = (rgb>>16) & 0xFF;	/* red */ | ||||
| 		c[3*i+1] = (rgb>> 8) & 0xFF;	/* green */ | ||||
| 		c[3*i+2] = (rgb>> 0) & 0xFF;	/* blue */ | ||||
| 	} | ||||
| 	c = colormap[0];	/* GREY1 */ | ||||
| 	for(i=0; i<2; i++){ | ||||
| 		if(i == 0) | ||||
| 			col = 0; | ||||
| 		else | ||||
| 			col = 0xFF; | ||||
| 		rgb = cmap2rgb(col); | ||||
| 		c[3*i+0] = (rgb>>16) & 0xFF;	/* red */ | ||||
| 		c[3*i+1] = (rgb>> 8) & 0xFF;	/* green */ | ||||
| 		c[3*i+2] = (rgb>> 0) & 0xFF;	/* blue */ | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* imported from libdraw/arith.c to permit an extern log2 function */ | ||||
| static int log2[] = { | ||||
| 	-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, | ||||
| 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 | ||||
| }; | ||||
|  | ||||
| /* | ||||
|  * Write header, logical screen descriptor, and color map | ||||
|  */ | ||||
| static | ||||
| void | ||||
| writeheader(Biobuf *fd, Rectangle r, int depth, uint32_t chan, int loopcount) | ||||
| { | ||||
| 	/* Header */ | ||||
| 	Bprint(fd, "%s", "GIF89a"); | ||||
|  | ||||
| 	/*  Logical Screen Descriptor */ | ||||
| 	put2(fd, Dx(r)); | ||||
| 	put2(fd, Dy(r)); | ||||
|  | ||||
| 	/* Color table present, 4 bits per color (for RGBV best case), size of color map */ | ||||
| 	Bputc(fd, (1<<7)|(3<<4)|(depth-1));	/* not right for GREY8, but GIF doesn't let us specify enough bits */ | ||||
| 	Bputc(fd, 0xFF);	/* white background (doesn't matter anyway) */ | ||||
| 	Bputc(fd, 0);	/* pixel aspect ratio - unused */ | ||||
|  | ||||
| 	/* Global Color Table */ | ||||
| 	getcolormap(); | ||||
| 	if(chan == GREY8) | ||||
| 		depth = GREYMAP; | ||||
| 	else | ||||
| 		depth = log2[depth]; | ||||
| 	Bwrite(fd, colormap[depth], 3*colormapsize[depth]); | ||||
|  | ||||
| 	if(loopcount >= 0){	/* hard-to-discover way to force cycled animation */ | ||||
| 		/* Application Extension with (1 loopcountlo loopcounthi) as data */ | ||||
| 		Bputc(fd, 0x21); | ||||
| 		Bputc(fd, 0xFF); | ||||
| 		Bputc(fd, 11); | ||||
| 		Bwrite(fd, "NETSCAPE2.0", 11); | ||||
| 		Bputc(fd, 3); | ||||
| 		Bputc(fd, 1); | ||||
| 		put2(fd, loopcount); | ||||
| 		Bputc(fd, 0); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write optional comment block | ||||
|  */ | ||||
| static | ||||
| void | ||||
| writecomment(Biobuf *fd, char *comment) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| 	if(comment==nil || comment[0]=='\0') | ||||
| 		return; | ||||
|  | ||||
| 	/* Comment extension and label */ | ||||
| 	Bputc(fd, 0x21); | ||||
| 	Bputc(fd, 0xFE); | ||||
|  | ||||
| 	/* Comment data */ | ||||
| 	n = strlen(comment); | ||||
| 	if(n > 255) | ||||
| 		n = 255; | ||||
| 	Bputc(fd, n); | ||||
| 	Bwrite(fd, comment, n); | ||||
|  | ||||
| 	/* Block terminator */ | ||||
| 	Bputc(fd, 0x00); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write optional control block (sets Delay Time) | ||||
|  */ | ||||
| static | ||||
| void | ||||
| writegraphiccontrol(Biobuf *fd, int dt, int trans) | ||||
| { | ||||
| 	if(dt < 0 && trans < 0) | ||||
| 		return; | ||||
|  | ||||
| 	/* Comment extension and label and block size*/ | ||||
| 	Bputc(fd, 0x21); | ||||
| 	Bputc(fd, 0xF9); | ||||
| 	Bputc(fd, 0x04); | ||||
|  | ||||
| 	/* Disposal method and other flags (none) */ | ||||
| 	if(trans >= 0) | ||||
| 		Bputc(fd, 0x01); | ||||
| 	else | ||||
| 		Bputc(fd, 0x00); | ||||
|  | ||||
| 	/* Delay time, in centisec (argument is millisec for sanity) */ | ||||
| 	if(dt < 0) | ||||
| 		dt = 0; | ||||
| 	else if(dt < 10) | ||||
| 		dt = 1; | ||||
| 	else | ||||
| 		dt = (dt+5)/10; | ||||
| 	put2(fd, dt); | ||||
|  | ||||
| 	/* Transparency index */ | ||||
| 	if(trans < 0) | ||||
| 		trans = 0; | ||||
| 	Bputc(fd, trans); | ||||
|  | ||||
| 	/* Block terminator */ | ||||
| 	Bputc(fd, 0x00); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write image descriptor | ||||
|  */ | ||||
| static | ||||
| void | ||||
| writedescriptor(Biobuf *fd, Rectangle r) | ||||
| { | ||||
| 	/* Image Separator */ | ||||
| 	Bputc(fd, 0x2C); | ||||
|  | ||||
| 	/* Left, top, width, height */ | ||||
| 	put2(fd, r.min.x-mainrect.min.x); | ||||
| 	put2(fd, r.min.y-mainrect.min.y); | ||||
| 	put2(fd, Dx(r)); | ||||
| 	put2(fd, Dy(r)); | ||||
| 	/* no special processing */ | ||||
| 	Bputc(fd, 0); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write data | ||||
|  */ | ||||
| static | ||||
| char* | ||||
| writedata(Biobuf *fd, Image *image, Memimage *memimage) | ||||
| { | ||||
| 	char *err; | ||||
| 	unsigned char *data; | ||||
| 	int ndata, depth; | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(memimage != nil){ | ||||
| 		r = memimage->r; | ||||
| 		depth = memimage->depth; | ||||
| 	}else{ | ||||
| 		r = image->r; | ||||
| 		depth = image->depth; | ||||
| 	} | ||||
|  | ||||
| 	/* LZW Minimum code size */ | ||||
| 	if(depth == 1) | ||||
| 		Bputc(fd, 2); | ||||
| 	else | ||||
| 		Bputc(fd, depth); | ||||
|  | ||||
| 	/* | ||||
| 	 * Read image data into memory | ||||
| 	 * potentially one extra byte on each end of each scan line | ||||
| 	 */ | ||||
| 	ndata = Dy(r)*(2+(Dx(r)>>(3-log2[depth]))); | ||||
| 	data = gifmalloc(ndata); | ||||
| 	if(memimage != nil) | ||||
| 		ndata = unloadmemimage(memimage, r, data, ndata); | ||||
| 	else | ||||
| 		ndata = unloadimage(image, r, data, ndata); | ||||
| 	if(ndata < 0){ | ||||
| 		err = gifmalloc(ERRMAX); | ||||
| 		snprint(err, ERRMAX, "WriteGIF: %r"); | ||||
| 		free(data); | ||||
| 		return err; | ||||
| 	} | ||||
|  | ||||
| 	/* Encode and emit the data */ | ||||
| 	encode(fd, r, depth, data, ndata); | ||||
| 	free(data); | ||||
|  | ||||
| 	/*  Block Terminator */ | ||||
| 	Bputc(fd, 0); | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write trailer | ||||
|  */ | ||||
| void | ||||
| endgif(Biobuf *fd) | ||||
| { | ||||
| 	Bputc(fd, 0x3B); | ||||
| 	Bflush(fd); | ||||
| } | ||||
|  | ||||
| void | ||||
| memendgif(Biobuf *fd) | ||||
| { | ||||
| 	endgif(fd); | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Put n bits of c into output at io.buf[i]; | ||||
|  */ | ||||
| static | ||||
| void | ||||
| output(IO *io, int c, int n) | ||||
| { | ||||
| 	if(c < 0){ | ||||
| 		if(io->nbits != 0) | ||||
| 			io->buf[io->i++] = io->sreg; | ||||
| 		Bputc(io->fd, io->i); | ||||
| 		Bwrite(io->fd, io->buf, io->i); | ||||
| 		io->nbits = 0; | ||||
| 		return; | ||||
| 	} | ||||
|  | ||||
| 	if(io->nbits+n >= 31){ | ||||
| 		fprint(2, "panic: WriteGIF sr overflow\n"); | ||||
| 		exits("WriteGIF panic"); | ||||
| 	} | ||||
| 	io->sreg |= c<<io->nbits; | ||||
| 	io->nbits += n; | ||||
|  | ||||
| 	while(io->nbits >= 8){ | ||||
| 		io->buf[io->i++] = io->sreg; | ||||
| 		io->sreg >>= 8; | ||||
| 		io->nbits -= 8; | ||||
| 	} | ||||
|  | ||||
| 	if(io->i >= 255){ | ||||
| 		Bputc(io->fd, 255); | ||||
| 		Bwrite(io->fd, io->buf, 255); | ||||
| 		memmove(io->buf, io->buf+255, io->i-255); | ||||
| 		io->i -= 255; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * LZW encoder | ||||
|  */ | ||||
| static | ||||
| void | ||||
| encode(Biobuf *fd, Rectangle r, int depth, unsigned char *data, uint ndata) | ||||
| { | ||||
| 	int i, c, h, csize, prefix, first, sreg, nbits, bitsperpixel; | ||||
| 	int CTM, EOD, codesize, ld0, datai, x, ld, pm; | ||||
| 	int nentry, maxentry, early; | ||||
| 	Entry *e, *oe; | ||||
| 	IO *io; | ||||
| 	Entry **hash; | ||||
|  | ||||
| 	first = 1; | ||||
| 	ld = log2[depth]; | ||||
| 	/* ldepth 0 must generate codesize 2 with values 0 and 1 (see the spec.) */ | ||||
| 	ld0 = ld; | ||||
| 	if(ld0 == 0) | ||||
| 		ld0 = 1; | ||||
| 	codesize = (1<<ld0); | ||||
| 	CTM = 1<<codesize; | ||||
| 	EOD = CTM+1; | ||||
|  | ||||
| 	io = gifmalloc(sizeof(IO)); | ||||
| 	io->fd = fd; | ||||
| 	sreg = 0; | ||||
| 	nbits = 0; | ||||
| 	bitsperpixel = 1<<ld; | ||||
| 	pm = (1<<bitsperpixel)-1; | ||||
|  | ||||
| 	datai = 0; | ||||
| 	x = r.min.x; | ||||
| 	hash = gifmalloc(Nhash*sizeof(Entry*)); | ||||
|  | ||||
| Init: | ||||
| 	memset(hash, 0, Nhash*sizeof(Entry*)); | ||||
| 	csize = codesize+1; | ||||
| 	nentry = EOD+1; | ||||
| 	maxentry = (1<<csize); | ||||
| 	for(i = 0; i<nentry; i++){ | ||||
| 		e = &tbl[i]; | ||||
| 		h = (e->prefix<<24) | (e->exten<<8); | ||||
| 		h %= Nhash; | ||||
| 		if(h < 0) | ||||
| 			h += Nhash; | ||||
| 		e->next = hash[h]; | ||||
| 		hash[h] = e; | ||||
| 	} | ||||
| 	prefix = -1; | ||||
| 	if(first) | ||||
| 		output(io, CTM, csize); | ||||
| 	first = 0; | ||||
|  | ||||
| 	/* | ||||
| 	 * Scan over pixels.  Because of partially filled bytes on ends of scan lines, | ||||
| 	 * which must be ignored in the data stream passed to GIF, this is more | ||||
| 	 * complex than we'd like. | ||||
| 	 */ | ||||
| Next: | ||||
| 	for(;;){ | ||||
| 		if(ld != 3){ | ||||
| 			/* beginning of scan line is difficult; prime the shift register */ | ||||
| 			if(x == r.min.x){ | ||||
| 				if(datai == ndata) | ||||
| 					break; | ||||
| 				sreg = data[datai++]; | ||||
| 				nbits = 8-((x&(7>>ld))<<ld); | ||||
| 			} | ||||
| 			x++; | ||||
| 			if(x == r.max.x) | ||||
| 				x = r.min.x; | ||||
| 		} | ||||
| 		if(nbits == 0){ | ||||
| 			if(datai == ndata) | ||||
| 				break; | ||||
| 			sreg = data[datai++]; | ||||
| 			nbits = 8; | ||||
| 		} | ||||
| 		nbits -= bitsperpixel; | ||||
| 		c = sreg>>nbits & pm; | ||||
| 		h = prefix<<24 | c<<8; | ||||
| 		h %= Nhash; | ||||
| 		if(h < 0) | ||||
| 			h += Nhash; | ||||
| 		oe = nil; | ||||
| 		for(e = hash[h]; e!=nil; e=e->next){ | ||||
| 			if(e->prefix == prefix && e->exten == c){ | ||||
| 				if(oe != nil){ | ||||
| 					oe->next = e->next; | ||||
| 					e->next = hash[h]; | ||||
| 					hash[h] = e; | ||||
| 				} | ||||
| 				prefix = e->index; | ||||
| 				goto Next; | ||||
| 			} | ||||
| 			oe = e; | ||||
| 		} | ||||
|  | ||||
| 		output(io, prefix, csize); | ||||
| 		early = 0; /* peculiar tiff feature here for reference */ | ||||
| 		if(nentry == maxentry-early){ | ||||
| 			if(csize == 12){ | ||||
| 				nbits += bitsperpixel;	/* unget pixel */ | ||||
| 				x--; | ||||
| 				if(ld != 3 && x == r.min.x) | ||||
| 					datai--; | ||||
| 				output(io, CTM, csize); | ||||
| 				goto Init; | ||||
| 			} | ||||
| 			csize++; | ||||
| 			maxentry = (1<<csize); | ||||
| 		} | ||||
|  | ||||
| 		e = &tbl[nentry]; | ||||
| 		e->prefix = prefix; | ||||
| 		e->exten = c; | ||||
| 		e->next = hash[h]; | ||||
| 		hash[h] = e; | ||||
|  | ||||
| 		prefix = c; | ||||
| 		nentry++; | ||||
| 	} | ||||
|  | ||||
| 	output(io, prefix, csize); | ||||
| 	output(io, EOD, csize); | ||||
| 	output(io, -1, csize); | ||||
| 	free(io); | ||||
| 	free(hash); | ||||
| } | ||||
|  | ||||
| static | ||||
| void* | ||||
| gifmalloc(uint32_t sz) | ||||
| { | ||||
| 	void *v; | ||||
| 	v = malloc(sz); | ||||
| 	if(v == nil) { | ||||
| 		fprint(2, "WriteGIF: out of memory allocating %ld\n", sz); | ||||
| abort(); | ||||
| 		exits("mem"); | ||||
| 	} | ||||
| 	memset(v, 0, sz); | ||||
| 	return v; | ||||
| } | ||||
							
								
								
									
										915
									
								
								sys/src/cmd/pict/writejpg.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										915
									
								
								sys/src/cmd/pict/writejpg.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,915 @@ | ||||
| /* | ||||
| * code/documentation from: | ||||
| * http://www.w3.org/Graphics/JPEG/jfif3.pdf | ||||
| * http://www.w3.org/Graphics/JPEG/itu-t81.pdf | ||||
| * http://en.wikipedia.org/wiki/JPEG | ||||
| * http://en.wikibooks.org/wiki/JPEG_-_Idea_and_Practice | ||||
| * http://code.google.com/p/go/source/browse/src/pkg/image/jpeg/writer.go | ||||
| * /sys/src/cmd/jpg | ||||
| * | ||||
| * fdct code from: | ||||
| * http://www.ijg.org/files/jpegsrc.v8c.tar.gz | ||||
| * http://code.google.com/p/go/source/browse/src/pkg/image/jpeg/fdct.go | ||||
| */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <bio.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| /* | ||||
| * imported from libdraw/arith.c to permit | ||||
| * extern log2 function | ||||
| */ | ||||
| static int log2[] = { | ||||
| 	-1, 0, 1, -1, 2, -1, -1, -1, 3, | ||||
| 	-1, -1, -1, -1, -1, -1, -1, 4, | ||||
| 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, | ||||
| 	-1, -1, -1, -1, -1, -1, -1, 5 | ||||
| }; | ||||
|  | ||||
| /* fdct constants */ | ||||
| enum { | ||||
| 	Fix02 = 2446, /* 0.298631336 */ | ||||
| 	Fix03 = 3196, /* 0.390180644 */ | ||||
| 	Fix05 = 4433, /* 0.541196100 */ | ||||
| 	Fix07 = 6270, /* 0.765366865 */ | ||||
| 	Fix08 = 7373, /* 0.899976223 */ | ||||
| 	Fix11 = 9633, /* 1.175875602 */ | ||||
| 	Fix15 = 12299, /* 1.501321110 */ | ||||
| 	Fix18 = 15137, /* 1.847759065 */ | ||||
| 	Fix19 = 16069, /* 1.961570560 */ | ||||
| 	Fix20 = 16819, /* 2.053119869 */ | ||||
| 	Fix25 = 20995, /* 2.562915447 */ | ||||
| 	Fix30 = 25172 /* 3.072711026 */ | ||||
| }; | ||||
|  | ||||
| static int zigzag[64] = { | ||||
| 	0, 1, 5, 6, 14, 15, 27, 28, | ||||
| 	2, 4, 7, 13, 16, 26, 29, 42, | ||||
| 	3, 8, 12, 17, 25, 30, 41, 43, | ||||
| 	9, 11, 18, 24, 31, 40, 44, 53, | ||||
| 	10, 19, 23, 32, 39, 45, 52, 54, | ||||
| 	20, 22, 33, 38, 46, 51, 55, 60, | ||||
| 	21, 34, 37, 47, 50, 56, 59, 61, | ||||
| 	35, 36, 48, 49, 57, 58, 62, 63 | ||||
| }; | ||||
|  | ||||
| static int invzigzag[64] = { | ||||
| 	0, 1, 8, 16, 9, 2, 3, 10, | ||||
| 	17, 24, 32, 25, 18, 11, 4, 5, | ||||
| 	12, 19, 26, 33, 40, 48, 41, 34, | ||||
| 	27, 20, 13, 6, 7, 14, 21, 28, | ||||
| 	35, 42, 49, 56, 57, 50, 43, 36, | ||||
| 	29, 22, 15, 23, 30, 37, 44, 51, | ||||
| 	58, 59, 52, 45, 38, 31, 39, 46, | ||||
| 	53, 60, 61, 54, 47, 55, 62, 63 | ||||
| }; | ||||
|  | ||||
| /* section K.1 for quantization tables */ | ||||
| static int qt[2][64] = { | ||||
| 	/* luminance */ | ||||
| 	{16, 11, 10, 16, 24, 40, 51, 61, | ||||
| 	12, 12, 14, 19, 26, 58, 60, 55, | ||||
| 	14, 13, 16, 24, 40, 57, 69, 56, | ||||
| 	14, 17, 22, 29, 51, 87, 80, 62, | ||||
| 	18, 22, 37, 56, 68, 109, 103, 77, | ||||
| 	24, 35, 55, 64, 81, 104, 113, 92, | ||||
| 	49, 64, 78, 87, 103, 121, 120, 101, | ||||
| 	72, 92, 95, 98, 112, 100, 103, 99}, | ||||
|  | ||||
| 	/* chrominance */ | ||||
| 	{17, 18, 24, 47, 99, 99, 99, 99, | ||||
| 	18, 21, 26, 66, 99, 99, 99, 99, | ||||
| 	24, 26, 56, 99, 99, 99, 99, 99, | ||||
| 	47, 66, 99, 99, 99, 99, 99, 99, | ||||
| 	99, 99, 99, 99, 99, 99, 99, 99, | ||||
| 	99, 99, 99, 99, 99, 99, 99, 99, | ||||
| 	99, 99, 99, 99, 99, 99, 99, 99, | ||||
| 	99, 99, 99, 99, 99, 99, 99, 99} | ||||
| }; | ||||
|  | ||||
| /* section K.3.3 for huffman tables */ | ||||
| static int dcbits[2][16] = { | ||||
| 	/* luminance */ | ||||
| 	{0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 	0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, | ||||
|  | ||||
| 	/* chrominance */ | ||||
| 	{0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, | ||||
| 	0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00} | ||||
| }; | ||||
|  | ||||
| static int dchuffval[2][12] = { | ||||
| 	/* luminance */ | ||||
| 	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, | ||||
| 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b}, | ||||
|  | ||||
| 	/* chrominance */ | ||||
| 	{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, | ||||
| 	0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b} | ||||
| }; | ||||
|  | ||||
| static int acbits[2][16] = { | ||||
| 	/* luminance */ | ||||
| 	{0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03, | ||||
| 	0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d}, | ||||
|  | ||||
| 	/* chrominance */ | ||||
| 	{0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04, | ||||
| 	0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77} | ||||
| }; | ||||
|  | ||||
| static int achuffval[2][162] = { | ||||
| 	/* luminance */ | ||||
| 	{0x01, 0x02, 0x03, 0x00, 0x04, 0x11, | ||||
| 	0x05, 0x12, 0x21, 0x31, 0x41, 0x06, | ||||
| 	0x13, 0x51, 0x61, 0x07, 0x22, 0x71, | ||||
| 	0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, | ||||
| 	0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, | ||||
| 	0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, | ||||
| 	0x82, 0x09, 0x0a, 0x16, 0x17, 0x18, | ||||
| 	0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, | ||||
| 	0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, | ||||
| 	0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, | ||||
| 	0x46, 0x47, 0x48, 0x49, 0x4a, 0x53, | ||||
| 	0x54, 0x55, 0x56, 0x57, 0x58, 0x59, | ||||
| 	0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, | ||||
| 	0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, | ||||
| 	0x76, 0x77, 0x78, 0x79, 0x7a, 0x83, | ||||
| 	0x84, 0x85, 0x86, 0x87, 0x88, 0x89, | ||||
| 	0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, | ||||
| 	0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, | ||||
| 	0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, | ||||
| 	0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, | ||||
| 	0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, | ||||
| 	0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, | ||||
| 	0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, | ||||
| 	0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, | ||||
| 	0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, | ||||
| 	0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, | ||||
| 	0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa}, | ||||
|  | ||||
| 	/* chrominance */ | ||||
| 	{0x00, 0x01, 0x02, 0x03, 0x11, 0x04, | ||||
| 	0x05, 0x21, 0x31, 0x06, 0x12, 0x41, | ||||
| 	0x51, 0x07, 0x61, 0x71, 0x13, 0x22, | ||||
| 	0x32, 0x81, 0x08, 0x14, 0x42, 0x91, | ||||
| 	0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, | ||||
| 	0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, | ||||
| 	0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25, | ||||
| 	0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, | ||||
| 	0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, | ||||
| 	0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, | ||||
| 	0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, | ||||
| 	0x53, 0x54, 0x55, 0x56, 0x57, 0x58, | ||||
| 	0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, | ||||
| 	0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, | ||||
| 	0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, | ||||
| 	0x82, 0x83, 0x84, 0x85, 0x86, 0x87, | ||||
| 	0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, | ||||
| 	0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, | ||||
| 	0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, | ||||
| 	0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, | ||||
| 	0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, | ||||
| 	0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, | ||||
| 	0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, | ||||
| 	0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, | ||||
| 	0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, | ||||
| 	0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, | ||||
| 	0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa} | ||||
| }; | ||||
|  | ||||
| static int ehufcod[2][12]; /* dc codes */ | ||||
| static int ehufsid[2][12]; /* dc sizes */ | ||||
| static int ehufcoa[2][251]; /* ac codes */ | ||||
| static int ehufsia[2][251]; /* ac sizes */ | ||||
|  | ||||
| static int byte; | ||||
| static int nbyte; | ||||
|  | ||||
| /* utilities */ | ||||
| static int Bputs(Biobuf *, int); | ||||
| static int min(int, int); | ||||
|  | ||||
| /* encoding */ | ||||
| static void grey2rgb(int *, int *, int *, int, int); | ||||
| static void rgb2ycc(int *, int *, int *, int, int, int); | ||||
| static void fdct(int *, int); | ||||
| static int csize(int, int); | ||||
| static void writebyte(Biobuf *); | ||||
| static void writebits(Biobuf *, int, int); | ||||
| static void writecode(Biobuf *, int, int); | ||||
| static int huf(Biobuf *, int *, int, int, int); | ||||
| static char *toycc1(int *, int *, int *, int, int, int, int, int, | ||||
| 	unsigned char *, int, int); | ||||
| static char *toycc2(int *, int *, int *, int, int, int, int, int, | ||||
| 	unsigned char *, int, int); | ||||
| static char *encode(Biobuf *, Rectangle, unsigned char *, uint32_t, int, | ||||
| 	int, int); | ||||
|  | ||||
| /* huffman tables */ | ||||
| static void makehuf(int *, int *, int *, int *, int); | ||||
|  | ||||
| /* tables, markers, headers, trailers */ | ||||
| static void writejfif(Biobuf *, int, int); | ||||
| static void writecomment(Biobuf *, char *); | ||||
| static void writequant(Biobuf *, int, int); | ||||
| static void writehuffman(Biobuf *, int, int); | ||||
| static void writeframe(Biobuf *, int, int, int); | ||||
| static void writescan(Biobuf *, int); | ||||
| static void writeheader(Biobuf *, int, int, char *, int, int); | ||||
| static void writetrailer(Biobuf *); | ||||
| static char *writedata(Biobuf *, Image *, Memimage *, int, int); | ||||
| static char *writejpg0(Biobuf *, Image *, Memimage *, | ||||
| 	Rectangle, uint32_t, char *, int, int); | ||||
|  | ||||
| static int | ||||
| Bputs(Biobuf *b, int s) | ||||
| { | ||||
| 	if(Bputc(b, s>>8) < 0) | ||||
| 		return -1; | ||||
| 	return Bputc(b, s); | ||||
| } | ||||
|  | ||||
| static int | ||||
| min(int a, int b) | ||||
| { | ||||
| 	return a < b? a: b; | ||||
| } | ||||
|  | ||||
| static void | ||||
| grey2rgb(int *r, int *g, int *b, int c, int depth) | ||||
| { | ||||
| 	if(depth == 1) { | ||||
| 		if(c != 0) | ||||
| 			c = 0xff; | ||||
| 	} else if(depth == 2) | ||||
| 		c = (c << 6) | (c << 4) | (c << 2) | c; | ||||
| 	else | ||||
| 		c = (c << 4) | c; | ||||
| 	c = cmap2rgb(c); | ||||
| 	*r = (c >> 16) & 0xff; | ||||
| 	*g = (c >> 8) & 0xff; | ||||
| 	*b = c & 0xff; | ||||
| } | ||||
|  | ||||
| static void | ||||
| rgb2ycc(int *y, int *cb, int *cr, int r, int g, int b) | ||||
| { | ||||
| 	*y = (int)(0.299*r + 0.587*g + 0.114*b); | ||||
| 	*cb = (int)(128.0 - 0.1687*r - 0.3313*g + 0.5*b); | ||||
| 	*cr = (int)(128.0 + 0.5*r - 0.4187*g - 0.0813*b); | ||||
| } | ||||
|  | ||||
| /* coefficients remain scaled up by 8 at the end */ | ||||
| static void | ||||
| fdct(int *b, int sflag) | ||||
| { | ||||
| 	int x, y, z, tmp0, tmp1, tmp2, tmp3; | ||||
| 	int tmp10, tmp12, tmp11, tmp13; | ||||
|  | ||||
| 	/* rows */ | ||||
| 	for(y = 0; y < 8; y++) { | ||||
| 		tmp0 = b[y*8+0] + b[y*8+7]; | ||||
| 		tmp1 = b[y*8+1] + b[y*8+6]; | ||||
| 		tmp2 = b[y*8+2] + b[y*8+5]; | ||||
| 		tmp3 = b[y*8+3] + b[y*8+4]; | ||||
|  | ||||
| 		tmp10 = tmp0 + tmp3; | ||||
| 		tmp12 = tmp0 - tmp3; | ||||
| 		tmp11 = tmp1 + tmp2; | ||||
| 		tmp13 = tmp1 - tmp2; | ||||
|  | ||||
| 		tmp0 = b[y*8+0] - b[y*8+7]; | ||||
| 		tmp1 = b[y*8+1] - b[y*8+6]; | ||||
| 		tmp2 = b[y*8+2] - b[y*8+5]; | ||||
| 		tmp3 = b[y*8+3] - b[y*8+4]; | ||||
|  | ||||
| 		b[y*8+0] = (tmp10 + tmp11 - 8*128) << 2; | ||||
| 		b[y*8+4] = (tmp10 - tmp11) << 2; | ||||
|  | ||||
| 		z = (tmp12 + tmp13) * Fix05; | ||||
| 		z += 1 << 10; | ||||
| 		b[y*8+2] = (z + tmp12*Fix07) >> 11; | ||||
| 		b[y*8+6] = (z - tmp13*Fix18) >> 11; | ||||
|  | ||||
| 		tmp10 = tmp0 + tmp3; | ||||
| 		tmp11 = tmp1 + tmp2; | ||||
| 		tmp12 = tmp0 + tmp2; | ||||
| 		tmp13 = tmp1 + tmp3; | ||||
| 		z = (tmp12 + tmp13) * Fix11; | ||||
| 		z += 1 << 10; | ||||
|  | ||||
| 		tmp0 *= Fix15; | ||||
| 		tmp1 *= Fix30; | ||||
| 		tmp2 *= Fix20; | ||||
| 		tmp3 *= Fix02; | ||||
| 		tmp10 *= -Fix08; | ||||
| 		tmp11 *= -Fix25; | ||||
| 		tmp12 *= -Fix03; | ||||
| 		tmp13 *= -Fix19; | ||||
|  | ||||
| 		tmp12 += z; | ||||
| 		tmp13 += z; | ||||
|  | ||||
| 		b[y*8+1] = (tmp0 + tmp10 + tmp12) >> 11; | ||||
| 		b[y*8+3] = (tmp1 + tmp11 + tmp13) >> 11; | ||||
| 		b[y*8+5] = (tmp2 + tmp11 + tmp12) >> 11; | ||||
| 		b[y*8+7] = (tmp3 + tmp10 + tmp13) >> 11; | ||||
| 	} | ||||
| 	/* columns */ | ||||
| 	for(x = 0; x < 8; x++) { | ||||
| 		tmp0 = b[0*8+x] + b[7*8+x]; | ||||
| 		tmp1 = b[1*8+x] + b[6*8+x]; | ||||
| 		tmp2 = b[2*8+x] + b[5*8+x]; | ||||
| 		tmp3 = b[3*8+x] + b[4*8+x]; | ||||
|  | ||||
| 		if(sflag) | ||||
| 			tmp10 = (tmp0 + tmp3 + 1) << 1; | ||||
| 		else | ||||
| 			tmp10 = tmp0 + tmp3 + (1 << 1); | ||||
| 		tmp12 = tmp0 - tmp3; | ||||
| 		tmp11 = tmp1 + tmp2; | ||||
| 		tmp13 = tmp1 - tmp2; | ||||
|  | ||||
| 		tmp0 = b[0*8+x] - b[7*8+x]; | ||||
| 		tmp1 = b[1*8+x] - b[6*8+x]; | ||||
| 		tmp2 = b[2*8+x] - b[5*8+x]; | ||||
| 		tmp3 = b[3*8+x] - b[4*8+x]; | ||||
|  | ||||
| 		b[0*8+x] = (tmp10 + tmp11) >> 2; | ||||
| 		b[4*8+x] = (tmp10 - tmp11) >> 2; | ||||
|  | ||||
| 		z = (tmp12 + tmp13) * Fix05; | ||||
| 		z += 1 << 14; | ||||
| 		b[2*8+x] = (z + tmp12*Fix07) >> 15; | ||||
| 		b[6*8+x] = (z - tmp13*Fix18) >> 15; | ||||
|  | ||||
| 		tmp10 = tmp0 + tmp3; | ||||
| 		tmp11 = tmp1 + tmp2; | ||||
| 		tmp12 = tmp0 + tmp2; | ||||
| 		tmp13 = tmp1 + tmp3; | ||||
| 		z = (tmp12 + tmp13) * Fix11; | ||||
| 		z += 1 << 14; | ||||
|  | ||||
| 		tmp0 *= Fix15; | ||||
| 		tmp1 *= Fix30; | ||||
| 		tmp2 *= Fix20; | ||||
| 		tmp3 *= Fix02; | ||||
| 		tmp10 *= -Fix08; | ||||
| 		tmp11 *= -Fix25; | ||||
| 		tmp12 *= -Fix03; | ||||
| 		tmp13 *= -Fix19; | ||||
|  | ||||
| 		tmp12 += z; | ||||
| 		tmp13 += z; | ||||
|  | ||||
| 		b[1*8+x] = (tmp0 + tmp10 + tmp12) >> 15; | ||||
| 		b[3*8+x] = (tmp1 + tmp11 + tmp13) >> 15; | ||||
| 		b[5*8+x] = (tmp2 + tmp11 + tmp12) >> 15; | ||||
| 		b[7*8+x] = (tmp3 + tmp10 + tmp13) >> 15; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static int | ||||
| csize(int coeff, int ac) | ||||
| { | ||||
| 	int i, max; | ||||
|  | ||||
| 	max = 1 << 10; | ||||
| 	if(!ac) | ||||
| 		max <<= 1; | ||||
| 	if(coeff < 0) | ||||
| 		coeff *= -1; | ||||
| 	if(coeff > max) | ||||
| 		sysfatal("csize: coeff too big: %d", coeff); | ||||
| 	i = ac? 1: 0; | ||||
| 	while(coeff >= (1<<i)) | ||||
| 		i++; | ||||
| 	if(ac && (i < 1 || i > 10)) | ||||
| 		sysfatal("csize: invalid ac ssss: %d", i); | ||||
| 	if(!ac && (i < 0 || i > 11)) | ||||
| 		sysfatal("csize: invalid dc ssss: %d", i); | ||||
| 	return i; | ||||
| } | ||||
|  | ||||
| static void | ||||
| writebyte(Biobuf *fd) | ||||
| { | ||||
| 	Bputc(fd, byte); | ||||
| 	if(byte == 0xff) /* byte stuffing */ | ||||
| 		Bputc(fd, 0x00); | ||||
| 	byte = 0; | ||||
| 	nbyte = 7; | ||||
| } | ||||
|  | ||||
| static void | ||||
| writebits(Biobuf *fd, int co, int si) | ||||
| { | ||||
| 	int i, bit; | ||||
|  | ||||
| 	for(i = si-1; i >= 0; i--) { | ||||
| 		bit = (co >> i) & 0x1; | ||||
| 		byte |= bit << nbyte; | ||||
| 		nbyte--; | ||||
| 		if(nbyte < 0) | ||||
| 			writebyte(fd); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| writecode(Biobuf *fd, int co, int si) | ||||
| { | ||||
| 	if(si > 8) { | ||||
| 		writebits(fd, co>>8, si-8); | ||||
| 		si = 8; | ||||
| 	} | ||||
| 	writebits(fd, co, si); | ||||
| } | ||||
|  | ||||
| static int | ||||
| huf(Biobuf *fd, int *b, int pred, int chr, int sflag) | ||||
| { | ||||
| 	int k, r, s, rs, si, co, dc, diff, zz[64], p, q, z; | ||||
|  | ||||
| 	if(sflag) { | ||||
| 		for(k = 0; k < 64; k++) { | ||||
| 			p = b[zigzag[k]]; | ||||
| 			q = qt[chr][zigzag[k]]; | ||||
| 			zz[k] = p / q; | ||||
| 		} | ||||
| 	} else { | ||||
| 		for(k = 0; k < 64; k++) { | ||||
| 			p = b[k]; | ||||
| 			q = (qt[chr][k] << 3); | ||||
| 			/* rounding */ | ||||
| 			if(p >= 0) | ||||
| 				z = (p + (q >> 1)) / q; | ||||
| 			else | ||||
| 				z = -(-p + (q >> 1)) / q; | ||||
| 			zz[zigzag[k]] = z; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	/* dc coefficient */ | ||||
| 	dc = zz[0]; | ||||
| 	zz[0] = diff = dc - pred; | ||||
|  | ||||
| 	s = csize(diff, 0); | ||||
| 	si = ehufsid[chr][s]; | ||||
| 	co = ehufcod[chr][s]; | ||||
| 	writecode(fd, co, si); | ||||
| 	if(diff < 0) | ||||
| 		diff -= 1; | ||||
| 	writecode(fd, diff, s); | ||||
|  | ||||
| 	/* figure F.2 */ | ||||
| 	for(k = 1, r = 0; k < 64; k++) { | ||||
| 		if(zz[k] == 0) { | ||||
| 			if(k < 63) | ||||
| 				r++; | ||||
| 			else { | ||||
| 				si = ehufsia[chr][0x00]; | ||||
| 				co = ehufcoa[chr][0x00]; | ||||
| 				writecode(fd, co, si); | ||||
| 			} | ||||
| 		} else { | ||||
| 			while(r > 15) { | ||||
| 				si = ehufsia[chr][0xf0]; | ||||
| 				co = ehufcoa[chr][0xf0]; | ||||
| 				writecode(fd, co, si); | ||||
| 				r -= 16; | ||||
| 			} | ||||
| 			/* figure F.3 */ | ||||
| 			s = csize(zz[k], 1); | ||||
| 			rs = (r << 4) | s; | ||||
| 			si = ehufsia[chr][rs]; | ||||
| 			co = ehufcoa[chr][rs]; | ||||
| 			writecode(fd, co, si); | ||||
| 			if(zz[k] < 0) | ||||
| 				zz[k] -= 1; | ||||
| 			writecode(fd, zz[k], s); | ||||
| 			r = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	return dc; | ||||
| } | ||||
|  | ||||
| static char * | ||||
| toycc1(int *y, int *cb, int *cr, int jx, int jy, int dx, int dy, | ||||
| 	int bpl, unsigned char *data, int ndata, int depth) | ||||
| { | ||||
| 	int i, j, k, l, m, n, u, v, pos, pmask, nmask, pix; | ||||
| 	int r, g, b; | ||||
|  | ||||
| 	m = 8 / depth; | ||||
| 	pmask = (1 << depth) - 1; | ||||
| 	nmask = 7 >> log2[depth]; | ||||
| 	for(i = jy, k = 0; i < jy+8; i++) { | ||||
| 		v = min(i, dy-1); | ||||
| 		for(l = 0, j = jx/m; l < 8; l++, k++) { | ||||
| 			u = min(j, (dx-1)/m); | ||||
| 			n = l+jx >= dx? dx-jx-1: l; | ||||
| 			pos = v*bpl + u; | ||||
| 			if(pos >= ndata) | ||||
| 				return "WriteJPG: overflow"; | ||||
| 			/* thanks writeppm */ | ||||
| 			pix = (data[pos] >> depth*((nmask - n) & | ||||
| 				nmask)) & pmask; | ||||
| 			if(((n + 1) & nmask) == 0) | ||||
| 				j++; | ||||
| 			grey2rgb(&r, &g, &b, pix, depth); | ||||
| 			rgb2ycc(&y[k], &cb[k], &cr[k], r, g, b); | ||||
| 		} | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| static char * | ||||
| toycc2(int *y, int *cb, int *cr, int jx, int jy, int dx, int dy, | ||||
| 	int bpl, unsigned char *data, int ndata, int depth) | ||||
| { | ||||
| 	int i, j, k, m, u, v, pos; | ||||
|  | ||||
| 	m = depth / 8; | ||||
| 	for(i = jy, k = 0; i < jy+8; i++) { | ||||
| 		v = min(i, dy-1); | ||||
| 		for(j = jx*m; j < (jx+8)*m; j+=m, k++) { | ||||
| 			u = min(j, (dx-1)*m); | ||||
| 			pos = v*bpl + u; | ||||
| 			if(pos+m-1 >= ndata) | ||||
| 				return "WriteJPG: overflow"; | ||||
| 			rgb2ycc(&y[k], &cb[k], &cr[k], | ||||
| 				data[pos+2*m/3], | ||||
| 				data[pos+m/3], | ||||
| 				data[pos]); | ||||
| 		} | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| static char * | ||||
| encode(Biobuf *fd, Rectangle r, unsigned char *data, uint32_t chan, | ||||
| 	int ndata, int kflag, int sflag) | ||||
| { | ||||
| 	int k, x, y, dx, dy, depth, bpl, ncomp; | ||||
| 	int b[3][64], pred[3]; | ||||
| 	char *err; | ||||
| 	char *(*toycc)(int *, int *, int *, int, int, int, int, | ||||
| 		int, unsigned char *, int, int); | ||||
|  | ||||
| 	byte = 0; | ||||
| 	nbyte = 7; | ||||
|  | ||||
| 	switch(chan) { | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 		toycc = toycc1; | ||||
| 		break; | ||||
| 	case GREY8: | ||||
| 	case RGB24: | ||||
| 		toycc = toycc2; | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WriteJPG: can't handle channel type"; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	* if dx or dy is not a multiple of 8, | ||||
| 	* the decoder should continue until reaching | ||||
| 	* the last mcu, even if the extra pixels go beyond | ||||
| 	* 0xffff. they are not shown anyway. | ||||
| 	*/ | ||||
| 	dx = min(Dx(r), 0xffff); | ||||
| 	dy = min(Dy(r), 0xffff); | ||||
| 	depth = chantodepth(chan); | ||||
| 	bpl = bytesperline(r, depth); | ||||
| 	ncomp = kflag? 1: 3; | ||||
| 	memset(pred, 0, sizeof pred); | ||||
| 	for(x = 0, y = 0;;) { | ||||
| 		err = (*toycc)(b[0], b[1], b[2], x, y, dx, dy, | ||||
| 			bpl, data, ndata, depth); | ||||
| 		if(err != nil) | ||||
| 			return err; | ||||
| 		for(k = 0; k < ncomp; k++) { | ||||
| 			fdct(b[k], sflag); | ||||
| 			pred[k] = huf(fd, b[k], pred[k], | ||||
| 				k>0, sflag); | ||||
| 		} | ||||
| 		if((x += 8) >= dx) { | ||||
| 			if((y += 8) >= dy) | ||||
| 				break; | ||||
| 			x = 0; | ||||
| 		} | ||||
| 	} | ||||
| 	if(nbyte < 7) { /* bit padding */ | ||||
| 		for(; nbyte >= 0; nbyte--) | ||||
| 			byte |= 0x1 << nbyte; | ||||
| 		writebyte(fd); | ||||
| 	} | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| static void | ||||
| makehuf(int *ehufco, int *ehufsi, int *bits, int *huffval, int n) | ||||
| { | ||||
| 	int i, j, k, code, si, lastk, *huffcode, *huffsize; | ||||
|  | ||||
| 	/* n+1 for lastk */ | ||||
| 	if((huffcode = malloc((n+1)*sizeof *huffcode)) == nil) | ||||
| 		sysfatal("malloc: %r"); | ||||
| 	if((huffsize = malloc((n+1)*sizeof *huffsize)) == nil) | ||||
| 		sysfatal("malloc: %r"); | ||||
| 	/* figure C.1 */ | ||||
| 	for(k = 0, i = 1, j = 1; i <= 16;) { | ||||
| 		if(j > bits[i-1]) { /* bits[i] in T.81: bug? */ | ||||
| 			i++; | ||||
| 			j = 1; | ||||
| 		} else { | ||||
| 			huffsize[k++] = i; | ||||
| 			j++; | ||||
| 		} | ||||
| 	} | ||||
| 	huffsize[k] = 0; | ||||
| 	lastk = k; | ||||
| 	/* figure C.2 */ | ||||
| 	for(k = 0, code = 0, si = huffsize[0];;) { | ||||
| 		do { | ||||
| 			huffcode[k++] = code++; | ||||
| 		} while(huffsize[k] == si); | ||||
| 		if(huffsize[k] == 0) | ||||
| 			break; | ||||
| 		while(huffsize[k] != si) { | ||||
| 			code <<= 1; | ||||
| 			si++; | ||||
| 		} | ||||
| 	} | ||||
| 	/* figure C.3 */ | ||||
| 	for(k = 0; k < lastk; k++) { | ||||
| 		i = huffval[k]; | ||||
| 		ehufco[i] = huffcode[k]; | ||||
| 		ehufsi[i] = huffsize[k]; | ||||
| 	} | ||||
| 	free(huffcode); | ||||
| 	free(huffsize); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writejfif(Biobuf *fd, int dx, int dy) | ||||
| { | ||||
| 	if(dx > 0xffff || dy > 0xffff) | ||||
| 		sysfatal("writejfif: dx or dy too big"); | ||||
| 	Bputs(fd, 0xffe0); | ||||
| 	Bputs(fd, 0x0010); | ||||
| 	Bputc(fd, 0x4a); | ||||
| 	Bputc(fd, 0x46); | ||||
| 	Bputc(fd, 0x49); | ||||
| 	Bputc(fd, 0x46); | ||||
| 	Bputc(fd, 0x00); | ||||
| 	Bputs(fd, 0x0102); | ||||
| 	Bputc(fd, 0x01); | ||||
| 	Bputs(fd, dx); | ||||
| 	Bputs(fd, dy); | ||||
| 	Bputc(fd, 0x00); | ||||
| 	Bputc(fd, 0x00); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writecomment(Biobuf *fd, char *com) | ||||
| { | ||||
| 	int n; | ||||
|  | ||||
| 	if(com != nil && com[0] != '\0') { | ||||
| 		n = min(strlen(com)+2, 0xffff); | ||||
| 		Bputs(fd, 0xfffe); | ||||
| 		Bputs(fd, n); | ||||
| 		Bwrite(fd, com, n-2); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| writequant(Biobuf *fd, int tq, int sflag) | ||||
| { | ||||
| 	int i, *p, *q; | ||||
|  | ||||
| 	if(tq != 0x0 && tq != 0x1) | ||||
| 		sysfatal("writequant: invalid Tq"); | ||||
| 	q = qt[tq]; | ||||
| 	Bputs(fd, 0xffdb); | ||||
| 	Bputs(fd, 0x0043); | ||||
| 	Bputc(fd, (0x0<<4)|tq); | ||||
| 	p = sflag? zigzag: invzigzag; | ||||
| 	for(i = 0; i < 64; i++) | ||||
| 		Bputc(fd, q[p[i]]); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writehuffman(Biobuf *fd, int tc, int th) | ||||
| { | ||||
| 	int i, n, m, *b, *hv; | ||||
|  | ||||
| 	if((tc != 0x0 && tc != 0x1) || (th != 0x0 && th != 0x1)) | ||||
| 		sysfatal("writehuffman: invalid Tc or Th"); | ||||
| 	n = 0x0013; | ||||
| 	if(tc == 0x0) { | ||||
| 		b = dcbits[th]; | ||||
| 		hv = dchuffval[th]; | ||||
| 		m = nelem(dchuffval[th]); | ||||
| 	} else { | ||||
| 		b = acbits[th]; | ||||
| 		hv = achuffval[th]; | ||||
| 		m = nelem(achuffval[th]); | ||||
| 	} | ||||
| 	Bputs(fd, 0xffc4); | ||||
| 	Bputs(fd, n+m); | ||||
| 	Bputc(fd, (tc<<4)|th); | ||||
| 	for(i = 0; i < 16; i++) | ||||
| 		Bputc(fd, b[i]); | ||||
| 	for(i = 0; i < m; i++) | ||||
| 		Bputc(fd, hv[i]); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writeframe(Biobuf *fd, int y, int x, int kflag) | ||||
| { | ||||
| 	int n, nf; | ||||
|  | ||||
| 	nf = kflag? 0x01: 0x03; | ||||
| 	n = 0x0008 + 0x0003*nf; | ||||
|  | ||||
| 	Bputs(fd, 0xffc0); | ||||
| 	Bputs(fd, n); | ||||
| 	Bputc(fd, 0x08); | ||||
| 	Bputs(fd, y); | ||||
| 	Bputs(fd, x); | ||||
| 	Bputc(fd, nf); | ||||
|  | ||||
| 	/* Y component */ | ||||
| 	Bputc(fd, 0x00); | ||||
| 	Bputc(fd, (0x1<<4)|0x1); | ||||
| 	Bputc(fd, 0x00); | ||||
|  | ||||
| 	if(!kflag) { | ||||
| 		/* Cb component */ | ||||
| 		Bputc(fd, 0x01); | ||||
| 		Bputc(fd, (0x1<<4)|0x1); | ||||
| 		Bputc(fd, 0x01); | ||||
|  | ||||
| 		/* Cr component */ | ||||
| 		Bputc(fd, 0x02); | ||||
| 		Bputc(fd, (0x1<<4)|0x1); | ||||
| 		Bputc(fd, 0x01); | ||||
| 	} | ||||
| } | ||||
|  | ||||
| static void | ||||
| writescan(Biobuf *fd, int kflag) | ||||
| { | ||||
| 	int n, ns; | ||||
|  | ||||
| 	ns = kflag? 0x01: 0x03; | ||||
| 	n = 0x0006 + 0x0002*ns; | ||||
|  | ||||
| 	Bputs(fd, 0xffda); | ||||
| 	Bputs(fd, n); | ||||
| 	Bputc(fd, ns); | ||||
|  | ||||
| 	/* Y component */ | ||||
| 	Bputc(fd, 0x00); | ||||
| 	Bputc(fd, (0x0<<4)|0x0); | ||||
|  | ||||
| 	if(!kflag) { | ||||
| 		/* Cb component */ | ||||
| 		Bputc(fd, 0x01); | ||||
| 		Bputc(fd, (0x1<<4)|0x1); | ||||
|  | ||||
| 		/* Cr component */ | ||||
| 		Bputc(fd, 0x02); | ||||
| 		Bputc(fd, (0x1<<4)|0x1); | ||||
| 	} | ||||
|  | ||||
| 	Bputc(fd, 0x00); | ||||
| 	Bputc(fd, 0x3f); | ||||
| 	Bputc(fd, (0x0<<4)|0x0); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writeheader(Biobuf *fd, int dx, int dy, char *s, int kflag, int sflag) | ||||
| { | ||||
| 	int i; | ||||
|  | ||||
| 	dx = min(dx, 0xffff); | ||||
| 	dy = min(dy, 0xffff); | ||||
|  | ||||
| 	Bputs(fd, 0xffd8); | ||||
| 	writejfif(fd, dx, dy); | ||||
| 	writecomment(fd, s); | ||||
| 	writequant(fd, 0, sflag); | ||||
| 	if(!kflag) | ||||
| 		writequant(fd, 1, sflag); | ||||
| 	writeframe(fd, dy, dx, kflag); | ||||
| 	for(i = 0; i < 2; i++) { | ||||
| 		writehuffman(fd, i, 0); | ||||
| 		if(!kflag) | ||||
| 			writehuffman(fd, i, 1); | ||||
| 	} | ||||
| 	writescan(fd, kflag); | ||||
| } | ||||
|  | ||||
| static void | ||||
| writetrailer(Biobuf *fd) | ||||
| { | ||||
| 	Bputs(fd, 0xffd9); | ||||
| } | ||||
|  | ||||
| static char * | ||||
| writedata(Biobuf *fd, Image *i, Memimage *m, int kflag, int sflag) | ||||
| { | ||||
| 	char *err; | ||||
| 	unsigned char *data; | ||||
| 	int ndata, depth; | ||||
| 	uint32_t chan; | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(m != nil) { | ||||
| 		r = m->r; | ||||
| 		depth = m->depth; | ||||
| 		chan = m->chan; | ||||
| 	} else { | ||||
| 		r = i->r; | ||||
| 		depth = i->depth; | ||||
| 		chan = i->chan; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	* potentially one extra byte on each | ||||
| 	* end of each scan line | ||||
| 	*/ | ||||
| 	ndata = Dy(r) * (2 + Dx(r)*depth/8); | ||||
| 	if((data = malloc(ndata)) == nil) | ||||
| 		return "WriteJPG: malloc failed"; | ||||
| 	if(m != nil) | ||||
| 		ndata = unloadmemimage(m, r, data, ndata); | ||||
| 	else | ||||
| 		ndata = unloadimage(i, r, data, ndata); | ||||
| 	if(ndata < 0) { | ||||
| 		if((err = malloc(ERRMAX)) == nil) { | ||||
| 			free(data); | ||||
| 			return "WriteJPG: malloc failed"; | ||||
| 		} | ||||
| 		snprint(err, ERRMAX, "WriteJPG: %r"); | ||||
| 	} else | ||||
| 		err = encode(fd, r, data, chan, ndata, kflag, sflag); | ||||
| 	free(data); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| static char * | ||||
| writejpg0(Biobuf *fd, Image *image, Memimage *memimage, | ||||
| 	Rectangle r, uint32_t chan, char *s, int kflag, int sflag) | ||||
| { | ||||
| 	int i; | ||||
| 	char *err; | ||||
|  | ||||
| 	switch(chan) { | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case GREY8: | ||||
| 		kflag = 1; | ||||
| 		break; | ||||
| 	case RGB24: | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WriteJPG: can't handle channel type"; | ||||
| 	} | ||||
| 	for(i = 0; i < 2; i++) { | ||||
| 		memset(ehufcod[i], 0, sizeof ehufcod[i]); | ||||
| 		memset(ehufsid[i], 0, sizeof ehufsid[i]); | ||||
| 		memset(ehufcoa[i], 0, sizeof ehufcoa[i]); | ||||
| 		memset(ehufsia[i], 0, sizeof ehufsia[i]); | ||||
| 		makehuf(ehufcod[i], ehufsid[i], dcbits[i], | ||||
| 			dchuffval[i], nelem(dchuffval[i])); | ||||
| 		makehuf(ehufcoa[i], ehufsia[i], acbits[i], | ||||
| 			achuffval[i], nelem(achuffval[i])); | ||||
| 	} | ||||
| 	writeheader(fd, Dx(r), Dy(r), s, kflag, sflag); | ||||
| 	err = writedata(fd, image, memimage, kflag, sflag); | ||||
| 	writetrailer(fd); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| char * | ||||
| writejpg(Biobuf *fd, Image *i, char *s, int kflag, int sflag) | ||||
| { | ||||
| 	return writejpg0(fd, i, nil, i->r, i->chan, s, kflag, sflag); | ||||
| } | ||||
|  | ||||
| char * | ||||
| memwritejpg(Biobuf *fd, Memimage *m, char *s, int kflag, int sflag) | ||||
| { | ||||
| 	return writejpg0(fd, nil, m, m->r, m->chan, s, kflag, sflag); | ||||
| } | ||||
							
								
								
									
										267
									
								
								sys/src/cmd/pict/writepng.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										267
									
								
								sys/src/cmd/pict/writepng.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,267 @@ | ||||
| /* | ||||
|  * See PNG 1.2 spec, also RFC 2083. | ||||
|  */ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <ctype.h> | ||||
| #include <bio.h> | ||||
| #include <flate.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| enum | ||||
| { | ||||
| 	IDATSIZE = 	20000, | ||||
| 	FilterNone =	0, | ||||
| }; | ||||
|  | ||||
| typedef struct ZlibR ZlibR; | ||||
| typedef struct ZlibW ZlibW; | ||||
|  | ||||
| struct ZlibR | ||||
| { | ||||
| 	unsigned char *data; | ||||
| 	int width; | ||||
| 	int dx; | ||||
| 	int dy; | ||||
| 	int x; | ||||
| 	int y; | ||||
| 	int pixwid; | ||||
| }; | ||||
|  | ||||
| struct ZlibW | ||||
| { | ||||
| 	Biobuf *io; | ||||
| 	unsigned char *buf; | ||||
| 	unsigned char *b; | ||||
| 	unsigned char *e; | ||||
| }; | ||||
|  | ||||
| static uint32_t *crctab; | ||||
| static unsigned char PNGmagic[] = { 137, 'P', 'N', 'G', '\r', '\n', 26, '\n'}; | ||||
|  | ||||
| static void | ||||
| put4(unsigned char *a, uint32_t v) | ||||
| { | ||||
| 	a[0] = v>>24; | ||||
| 	a[1] = v>>16; | ||||
| 	a[2] = v>>8; | ||||
| 	a[3] = v; | ||||
| } | ||||
|  | ||||
| static void | ||||
| chunk(Biobuf *bo, char *type, unsigned char *d, int n) | ||||
| { | ||||
| 	unsigned char buf[4]; | ||||
| 	uint32_t crc = 0; | ||||
|  | ||||
| 	if(strlen(type) != 4) | ||||
| 		return; | ||||
| 	put4(buf, n); | ||||
| 	Bwrite(bo, buf, 4); | ||||
| 	Bwrite(bo, type, 4); | ||||
| 	Bwrite(bo, d, n); | ||||
| 	crc = blockcrc(crctab, crc, type, 4); | ||||
| 	crc = blockcrc(crctab, crc, d, n); | ||||
| 	put4(buf, crc); | ||||
| 	Bwrite(bo, buf, 4); | ||||
| } | ||||
|  | ||||
| static int | ||||
| zread(void *va, void *buf, int n) | ||||
| { | ||||
| 	int a, i, pixels, pixwid; | ||||
| 	unsigned char *b, *e, *img; | ||||
| 	ZlibR *z; | ||||
|  | ||||
| 	z = va; | ||||
| 	pixwid = z->pixwid; | ||||
| 	b = buf; | ||||
| 	e = b+n; | ||||
| 	while(b+pixwid < e){	/* one less for filter alg byte */ | ||||
| 		if(z->y >= z->dy) | ||||
| 			break; | ||||
| 		if(z->x == 0) | ||||
| 			*b++ = FilterNone; | ||||
| 		pixels = (e-b)/pixwid; | ||||
| 		if(pixels > z->dx - z->x) | ||||
| 			pixels = z->dx - z->x; | ||||
| 		img = z->data + z->width*z->y + pixwid*z->x; | ||||
| 		memmove(b, img, pixwid*pixels); | ||||
| 		if(pixwid == 4){ | ||||
| 			/* | ||||
| 			 * Convert to non-premultiplied alpha. | ||||
| 			 */ | ||||
| 			for(i=0; i<pixels; i++, b+=4){ | ||||
| 				a = b[3]; | ||||
| 				if(a == 0) | ||||
| 					b[0] = b[1] = b[2] = 0; | ||||
| 				else if(a != 255){ | ||||
| 					if(b[0] >= a) | ||||
| 						b[0] = a; | ||||
| 					b[0] = (b[0]*255)/a; | ||||
| 					if(b[1] >= a) | ||||
| 						b[1] = a; | ||||
| 					b[1] = (b[1]*255)/a; | ||||
| 					if(b[2] >= a) | ||||
| 						b[2] = a; | ||||
| 					b[2] = (b[2]*255)/a; | ||||
| 				} | ||||
| 			} | ||||
| 		}else | ||||
| 			b += pixwid*pixels; | ||||
|  | ||||
| 		z->x += pixels; | ||||
| 		if(z->x >= z->dx){ | ||||
| 			z->x = 0; | ||||
| 			z->y++; | ||||
| 		} | ||||
| 	} | ||||
| 	return b - (unsigned char*)buf; | ||||
| } | ||||
|  | ||||
| static void | ||||
| IDAT(ZlibW *z) | ||||
| { | ||||
| 	chunk(z->io, "IDAT", z->buf, z->b - z->buf); | ||||
| 	z->b = z->buf; | ||||
| } | ||||
|  | ||||
| static int | ||||
| zwrite(void *va, void *buf, int n) | ||||
| { | ||||
| 	int m; | ||||
| 	unsigned char *b, *e; | ||||
| 	ZlibW *z; | ||||
|  | ||||
| 	z = va; | ||||
| 	b = buf; | ||||
| 	e = b+n; | ||||
|  | ||||
| 	while(b < e){ | ||||
| 		m = z->e - z->b; | ||||
| 		if(m > e - b) | ||||
| 			m = e - b; | ||||
| 		memmove(z->b, b, m); | ||||
| 		z->b += m; | ||||
| 		b += m; | ||||
| 		if(z->b >= z->e) | ||||
| 			IDAT(z); | ||||
| 	} | ||||
| 	return n; | ||||
| } | ||||
|  | ||||
| static Memimage* | ||||
| memRGBA(Memimage *i) | ||||
| { | ||||
| 	Memimage *ni; | ||||
| 	char buf[32]; | ||||
| 	uint32_t dst; | ||||
|  | ||||
| 	/* | ||||
| 	 * [A]BGR because we want R,G,B,[A] in big-endian order.  Sigh. | ||||
| 	 */ | ||||
| 	chantostr(buf, i->chan); | ||||
| 	if(strchr(buf, 'a')) | ||||
| 		dst = ABGR32; | ||||
| 	else | ||||
| 		dst = BGR24; | ||||
|  | ||||
| 	if(i->chan == dst) | ||||
| 		return i; | ||||
|  | ||||
| 	ni = allocmemimage(i->r, dst); | ||||
| 	if(ni == nil) | ||||
| 		return ni; | ||||
| 	memimagedraw(ni, ni->r, i, i->r.min, nil, i->r.min, S); | ||||
| 	return ni; | ||||
| } | ||||
|  | ||||
| char* | ||||
| memwritepng(Biobuf *io, Memimage *m, ImageInfo *II) | ||||
| { | ||||
| 	int err, n; | ||||
| 	unsigned char buf[200], *h; | ||||
| 	uint32_t vgamma; | ||||
| 	Tm *tm; | ||||
| 	Memimage *rgb; | ||||
| 	ZlibR zr; | ||||
| 	ZlibW zw; | ||||
|  | ||||
| 	crctab = mkcrctab(0xedb88320); | ||||
| 	if(crctab == nil) | ||||
| 		sysfatal("mkcrctab error"); | ||||
| 	deflateinit(); | ||||
|  | ||||
| 	rgb = memRGBA(m); | ||||
| 	if(rgb == nil) | ||||
| 		return "allocmemimage nil"; | ||||
|  | ||||
| 	Bwrite(io, PNGmagic, sizeof PNGmagic); | ||||
|  | ||||
| 	/* IHDR chunk */ | ||||
| 	h = buf; | ||||
| 	put4(h, Dx(m->r)); h += 4; | ||||
| 	put4(h, Dy(m->r)); h += 4; | ||||
| 	*h++ = 8;	/* 8 bits per channel */ | ||||
| 	if(rgb->chan == BGR24) | ||||
| 		*h++ = 2;		/* RGB */ | ||||
| 	else | ||||
| 		*h++ = 6;		/* RGBA */ | ||||
| 	*h++ = 0;	/* compression - deflate */ | ||||
| 	*h++ = 0;	/* filter - none */ | ||||
| 	*h++ = 0;	/* interlace - none */ | ||||
| 	chunk(io, "IHDR", buf, h-buf); | ||||
|  | ||||
| 	/* time - using now is suspect */ | ||||
| 	tm = gmtime(time(0)); | ||||
| 	h = buf; | ||||
| 	*h++ = (tm->year + 1900)>>8; | ||||
| 	*h++ = (tm->year + 1900)&0xff; | ||||
| 	*h++ = tm->mon + 1; | ||||
| 	*h++ = tm->mday; | ||||
| 	*h++ = tm->hour; | ||||
| 	*h++ = tm->min; | ||||
| 	*h++ = tm->sec; | ||||
| 	chunk(io, "tIME", buf, h-buf); | ||||
|  | ||||
| 	/* gamma */ | ||||
| 	if(II->fields_set & II_GAMMA){ | ||||
| 		vgamma = II->gamma*100000; | ||||
| 		put4(buf, vgamma); | ||||
| 		chunk(io, "gAMA", buf, 4); | ||||
| 	} | ||||
|  | ||||
| 	/* comment */ | ||||
| 	if(II->fields_set & II_COMMENT){ | ||||
| 		strncpy((char*)buf, "Comment", sizeof buf); | ||||
| 		n = strlen((char*)buf)+1; // leave null between Comment and text | ||||
| 		strncpy((char*)(buf+n), II->comment, sizeof buf - n); | ||||
| 		chunk(io, "tEXt", buf, n+strlen((char*)buf+n)); | ||||
| 	} | ||||
|  | ||||
| 	/* image data */ | ||||
| 	zr.dx = Dx(m->r); | ||||
| 	zr.dy = Dy(m->r); | ||||
| 	zr.width = rgb->width * sizeof(uint32_t); | ||||
| 	zr.data = rgb->data->bdata; | ||||
| 	zr.x = 0; | ||||
| 	zr.y = 0; | ||||
| 	zr.pixwid = chantodepth(rgb->chan)/8; | ||||
| 	zw.io = io; | ||||
| 	zw.buf = malloc(IDATSIZE); | ||||
| 	if(zw.buf == nil) | ||||
| 		sysfatal("malloc: %r"); | ||||
| 	zw.b = zw.buf; | ||||
| 	zw.e = zw.b + IDATSIZE; | ||||
| 	if((err=deflatezlib(&zw, zwrite, &zr, zread, 6, 0)) < 0) | ||||
| 		sysfatal("deflatezlib %s", flateerr(err)); | ||||
| 	if(zw.b > zw.buf) | ||||
| 		IDAT(&zw); | ||||
| 	free(zw.buf); | ||||
| 	chunk(io, "IEND", nil, 0); | ||||
| 	if(m != rgb) | ||||
| 		freememimage(rgb); | ||||
| 	return nil; | ||||
| } | ||||
							
								
								
									
										214
									
								
								sys/src/cmd/pict/writeppm.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										214
									
								
								sys/src/cmd/pict/writeppm.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,214 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <draw.h> | ||||
| #include <memdraw.h> | ||||
| #include <bio.h> | ||||
|  | ||||
| #define	MAXLINE	70 | ||||
|  | ||||
| /* imported from libdraw/arith.c to permit an extern log2 function */ | ||||
| static int log2[] = { | ||||
| 	-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4, | ||||
| 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5 | ||||
| }; | ||||
|  | ||||
| static int bitc = 0; | ||||
| static int nbit = 0; | ||||
|  | ||||
| static | ||||
| void | ||||
| Bputbit(Biobufhdr *b, int c) | ||||
| { | ||||
| 	if(c >= 0x0){ | ||||
| 		bitc = (bitc << 1) | (c & 0x1); | ||||
| 		nbit++; | ||||
| 	}else if(nbit > 0){ | ||||
| 		for(; nbit < 8; nbit++) | ||||
| 			bitc <<= 1; | ||||
| 	} | ||||
| 	if(nbit == 8){ | ||||
| 		Bputc(b, bitc); | ||||
| 		bitc = nbit = 0; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| /* | ||||
|  * Write data | ||||
|  */ | ||||
| static | ||||
| char* | ||||
| writedata(Biobuf *fd, Image *image, Memimage *memimage, int rflag) | ||||
| { | ||||
| 	char *err; | ||||
| 	unsigned char *data; | ||||
| 	int i, x, y, ndata, depth, col, pix, xmask, pmask; | ||||
| 	uint32_t chan; | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(memimage != nil){ | ||||
| 		r = memimage->r; | ||||
| 		depth = memimage->depth; | ||||
| 		chan = memimage->chan; | ||||
| 	}else{ | ||||
| 		r = image->r; | ||||
| 		depth = image->depth; | ||||
| 		chan = image->chan; | ||||
| 	} | ||||
|  | ||||
| 	/* | ||||
| 	 * Read image data into memory | ||||
| 	 * potentially one extra byte on each end of each scan line | ||||
| 	 */ | ||||
| 	ndata = Dy(r)*(2+Dx(r)*depth/8); | ||||
| 	data = malloc(ndata); | ||||
| 	if(data == nil) | ||||
| 		return "WritePPM: malloc failed"; | ||||
| 	if(memimage != nil) | ||||
| 		ndata = unloadmemimage(memimage, r, data, ndata); | ||||
| 	else | ||||
| 		ndata = unloadimage(image, r, data, ndata); | ||||
| 	if(ndata < 0){ | ||||
| 		err = malloc(ERRMAX); | ||||
| 		if(err == nil) | ||||
| 			return "WritePPM: malloc failed"; | ||||
| 		snprint(err, ERRMAX, "WritePPM: %r"); | ||||
| 		free(data); | ||||
| 		return err; | ||||
| 	} | ||||
|  | ||||
| 	/* Encode and emit the data */ | ||||
| 	col = 0; | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 		pmask = (1<<depth)-1; | ||||
| 		xmask = 7>>log2[depth]; | ||||
| 		for(y=r.min.y; y<r.max.y; y++){ | ||||
| 			i = (y-r.min.y)*bytesperline(r, depth); | ||||
| 			for(x=r.min.x; x<r.max.x; x++){ | ||||
| 				pix = (data[i]>>depth*((xmask-x)&xmask))&pmask; | ||||
| 				if(((x+1)&xmask) == 0) | ||||
| 					i++; | ||||
| 				if(chan == GREY1){ | ||||
| 					pix ^= 1; | ||||
| 					if(rflag){ | ||||
| 						Bputbit(fd, pix); | ||||
| 						continue; | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(rflag){ | ||||
| 						Bputc(fd, pix); | ||||
| 						continue; | ||||
| 					} | ||||
| 				} | ||||
| 				col += Bprint(fd, "%d", pix); | ||||
| 				if(col >= MAXLINE-(2+1)){ | ||||
| 					Bprint(fd, "\n"); | ||||
| 					col = 0; | ||||
| 				}else if(y < r.max.y-1 || x < r.max.x-1) | ||||
| 					col += Bprint(fd, " "); | ||||
| 			} | ||||
| 			if(rflag) | ||||
| 				Bputbit(fd, -1); | ||||
| 		} | ||||
| 		break; | ||||
| 	case GREY8: | ||||
| 		for(i=0; i<ndata; i++){ | ||||
| 			if(rflag){ | ||||
| 				Bputc(fd, data[i]); | ||||
| 				continue; | ||||
| 			} | ||||
| 			col += Bprint(fd, "%d", data[i]); | ||||
| 			if(col >= MAXLINE-(4+1)){ | ||||
| 				Bprint(fd, "\n"); | ||||
| 				col = 0; | ||||
| 			}else if(i < ndata-1) | ||||
| 				col += Bprint(fd, " "); | ||||
| 		} | ||||
| 		break; | ||||
| 	case RGB24: | ||||
| 		for(i=0; i<ndata; i+=3){ | ||||
| 			if(rflag){ | ||||
| 				Bputc(fd, data[i+2]); | ||||
| 				Bputc(fd, data[i+1]); | ||||
| 				Bputc(fd, data[i]); | ||||
| 				continue; | ||||
| 			} | ||||
| 			col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]); | ||||
| 			if(col >= MAXLINE-(4+4+4+1)){ | ||||
| 				Bprint(fd, "\n"); | ||||
| 				col = 0; | ||||
| 			}else if(i < ndata-3) | ||||
| 				col += Bprint(fd, " "); | ||||
| 		} | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WritePPM: can't handle channel type"; | ||||
| 	} | ||||
|  | ||||
| 	return nil; | ||||
| } | ||||
|  | ||||
| static | ||||
| char* | ||||
| writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment, int rflag) | ||||
| { | ||||
| 	char *err; | ||||
|  | ||||
| 	switch(chan){ | ||||
| 	case GREY1: | ||||
| 		Bprint(fd, "%s\n", rflag? "P4": "P1"); | ||||
| 		break; | ||||
| 	case GREY2: | ||||
| 	case GREY4: | ||||
| 	case GREY8: | ||||
| 		Bprint(fd, "%s\n", rflag? "P5": "P2"); | ||||
| 		break; | ||||
| 	case RGB24: | ||||
| 		Bprint(fd, "%s\n", rflag? "P6": "P3"); | ||||
| 		break; | ||||
| 	default: | ||||
| 		return "WritePPM: can't handle channel type"; | ||||
| 	} | ||||
|  | ||||
| 	if(comment!=nil && comment[0]!='\0'){ | ||||
| 		Bprint(fd, "# %s", comment); | ||||
| 		if(comment[strlen(comment)-1] != '\n') | ||||
| 			Bprint(fd, "\n"); | ||||
| 	} | ||||
| 	Bprint(fd, "%d %d\n", Dx(r), Dy(r)); | ||||
|  | ||||
| 	/* maximum pixel value */ | ||||
| 	switch(chan){ | ||||
| 	case GREY2: | ||||
| 		Bprint(fd, "%d\n", 3); | ||||
| 		break; | ||||
| 	case GREY4: | ||||
| 		Bprint(fd, "%d\n", 15); | ||||
| 		break; | ||||
| 	case GREY8: | ||||
| 	case RGB24: | ||||
| 		Bprint(fd, "%d\n", 255); | ||||
| 		break; | ||||
| 	} | ||||
|  | ||||
| 	err = writedata(fd, image, memimage, rflag); | ||||
|  | ||||
| 	if(!rflag) | ||||
| 		Bprint(fd, "\n"); | ||||
| 	Bflush(fd); | ||||
| 	return err; | ||||
| } | ||||
|  | ||||
| char* | ||||
| writeppm(Biobuf *fd, Image *image, char *comment, int rflag) | ||||
| { | ||||
| 	return writeppm0(fd, image, nil, image->r, image->chan, comment, rflag); | ||||
| } | ||||
|  | ||||
| char* | ||||
| memwriteppm(Biobuf *fd, Memimage *memimage, char *comment, int rflag) | ||||
| { | ||||
| 	return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment, rflag); | ||||
| } | ||||
							
								
								
									
										206
									
								
								sys/src/cmd/pict/writerawimage.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								sys/src/cmd/pict/writerawimage.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,206 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| /* | ||||
|  * Hacked version for writing from Rawimage to file. | ||||
|  * Assumes 8 bits per component. | ||||
|  */ | ||||
|  | ||||
| #define	HSHIFT	3	/* HSHIFT==5 runs slightly faster, but hash table is 64x bigger */ | ||||
| #define	NHASH	(1<<(HSHIFT*NMATCH)) | ||||
| #define	HMASK	(NHASH-1) | ||||
| #define	hupdate(h, c)	((((h)<<HSHIFT)^(c))&HMASK) | ||||
| typedef struct Hlist Hlist; | ||||
| struct Hlist{ | ||||
| 	unsigned char *s; | ||||
| 	Hlist *next, *prev; | ||||
| }; | ||||
|  | ||||
| int | ||||
| writerawimage(int fd, Rawimage *i) | ||||
| { | ||||
| 	unsigned char *outbuf, *outp, *eout;		/* encoded data, pointer, end */ | ||||
| 	unsigned char *loutp;				/* start of encoded line */ | ||||
| 	Hlist *hash;				/* heads of hash chains of past strings */ | ||||
| 	Hlist *chain, *hp;			/* hash chain members, pointer */ | ||||
| 	Hlist *cp;				/* next Hlist to fall out of window */ | ||||
| 	int h;					/* hash value */ | ||||
| 	unsigned char *line, *eline;			/* input line, end pointer */ | ||||
| 	unsigned char *data, *edata;			/* input buffer, end pointer */ | ||||
| 	uint32_t n;				/* length of input buffer */ | ||||
| 	int bpl;				/* input line length */ | ||||
| 	int offs, runlen;			/* offset, length of consumed data */ | ||||
| 	unsigned char dumpbuf[NDUMP];			/* dump accumulator */ | ||||
| 	int ndump;				/* length of dump accumulator */ | ||||
| 	int ncblock;				/* size of buffer */ | ||||
| 	Rectangle r; | ||||
| 	unsigned char *p, *q, *s, *es, *t; | ||||
| 	char hdr[11+5*12+1], buf[16]; | ||||
| 	uint32_t desc; | ||||
|  | ||||
| 	r = i->r; | ||||
| 	switch(i->chandesc){ | ||||
| 	default: | ||||
| 		werrstr("can't handle chandesc %d", i->chandesc); | ||||
| 		return -1; | ||||
| 	case CY: | ||||
| 		bpl = Dx(r); | ||||
| 		desc = GREY8; | ||||
| 		break; | ||||
| 	case CYA16: | ||||
| 		bpl = 2*Dx(r); | ||||
| 		desc = CHAN2(CGrey, 8, CAlpha, 8); | ||||
| 		break; | ||||
| 	case CRGBV: | ||||
| 		bpl = Dx(r); | ||||
| 		desc = CMAP8; | ||||
| 		break; | ||||
| 	case CRGBVA16: | ||||
| 		bpl = 2*Dx(r); | ||||
| 		desc = CHAN2(CMap, 8, CAlpha, 8); | ||||
| 		break; | ||||
| 	case CRGB24: | ||||
| 		bpl = 3*Dx(r); | ||||
| 		desc = RGB24; | ||||
| 		break; | ||||
| 	case CRGBA32: | ||||
| 		bpl = 4*Dx(r); | ||||
| 		desc = RGBA32; | ||||
| 		break; | ||||
| 	} | ||||
| 	ncblock = _compblocksize(r, bpl/Dx(r)); | ||||
| 	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); | ||||
| 		return -1; | ||||
| 	} | ||||
| 	n = Dy(r)*bpl; | ||||
| 	data = i->chans[0]; | ||||
| 	sprint(hdr, "compressed\n%11s %11d %11d %11d %11d ", | ||||
| 		chantostr(buf, desc), r.min.x, r.min.y, r.max.x, r.max.y); | ||||
| 	if(write(fd, hdr, 11+5*12) != 11+5*12){ | ||||
| 		werrstr("i/o error writing header"); | ||||
| 		goto ErrOut; | ||||
| 	} | ||||
| 	edata = data+n; | ||||
| 	eout = outbuf+ncblock; | ||||
| 	line = data; | ||||
| 	r.max.y = r.min.y; | ||||
| 	while(line != edata){ | ||||
| 		memset(hash, 0, NHASH*sizeof(Hlist)); | ||||
| 		memset(chain, 0, NMEM*sizeof(Hlist)); | ||||
| 		cp = chain; | ||||
| 		h = 0; | ||||
| 		outp = outbuf; | ||||
| 		for(n = 0; n != NMATCH; n++) | ||||
| 			h = hupdate(h, line[n]); | ||||
| 		loutp = outbuf; | ||||
| 		while(line != edata){ | ||||
| 			ndump = 0; | ||||
| 			eline = line+bpl; | ||||
| 			for(p = line; p != eline; ){ | ||||
| 				if(eline-p < NRUN) | ||||
| 					es = eline; | ||||
| 				else | ||||
| 					es = p+NRUN; | ||||
| 				q = 0; | ||||
| 				runlen = 0; | ||||
| 				for(hp = hash[h].next; hp; hp = hp->next){ | ||||
| 					s = p + runlen; | ||||
| 					if(s >= es) | ||||
| 						continue; | ||||
| 					t = hp->s + runlen; | ||||
| 					for(; s >= p; s--) | ||||
| 						if(*s != *t--) | ||||
| 							goto matchloop; | ||||
| 					t += runlen+2; | ||||
| 					s += runlen+2; | ||||
| 					for(; s < es; s++) | ||||
| 						if(*s != *t++) | ||||
| 							break; | ||||
| 					n = s-p; | ||||
| 					if(n > runlen){ | ||||
| 						runlen = n; | ||||
| 						q = hp->s; | ||||
| 						if(n == NRUN) | ||||
| 							break; | ||||
| 					} | ||||
| 			matchloop: ; | ||||
| 				} | ||||
| 				if(runlen < NMATCH){ | ||||
| 					if(ndump == NDUMP){ | ||||
| 						if(eout-outp < ndump+1) | ||||
| 							goto Bfull; | ||||
| 						*outp++ = ndump-1+128; | ||||
| 						memmove(outp, dumpbuf, ndump); | ||||
| 						outp += ndump; | ||||
| 						ndump = 0; | ||||
| 					} | ||||
| 					dumpbuf[ndump++] = *p; | ||||
| 					runlen = 1; | ||||
| 				} | ||||
| 				else{ | ||||
| 					if(ndump != 0){ | ||||
| 						if(eout-outp < ndump+1) | ||||
| 							goto Bfull; | ||||
| 						*outp++ = ndump-1+128; | ||||
| 						memmove(outp, dumpbuf, ndump); | ||||
| 						outp += ndump; | ||||
| 						ndump = 0; | ||||
| 					} | ||||
| 					offs = p-q-1; | ||||
| 					if(eout-outp < 2) | ||||
| 						goto Bfull; | ||||
| 					*outp++ = ((runlen-NMATCH)<<2) + (offs>>8); | ||||
| 					*outp++ = offs&255; | ||||
| 				} | ||||
| 				for(q = p+runlen; p != q; p++){ | ||||
| 					if(cp->prev) | ||||
| 						cp->prev->next = 0; | ||||
| 					cp->next = hash[h].next; | ||||
| 					cp->prev = &hash[h]; | ||||
| 					if(cp->next) | ||||
| 						cp->next->prev = cp; | ||||
| 					cp->prev->next = cp; | ||||
| 					cp->s = p; | ||||
| 					if(++cp == &chain[NMEM]) | ||||
| 						cp = chain; | ||||
| 					if(edata-p > NMATCH) | ||||
| 						h = hupdate(h, p[NMATCH]); | ||||
| 				} | ||||
| 			} | ||||
| 			if(ndump != 0){ | ||||
| 				if(eout-outp < ndump+1) | ||||
| 					goto Bfull; | ||||
| 				*outp++ = ndump-1+128; | ||||
| 				memmove(outp, dumpbuf, ndump); | ||||
| 				outp += ndump; | ||||
| 			} | ||||
| 			line = eline; | ||||
| 			loutp = outp; | ||||
| 			r.max.y++; | ||||
| 		} | ||||
| 	Bfull: | ||||
| 		if(loutp == outbuf){ | ||||
| 			werrstr("compressor out of sync"); | ||||
| 			goto ErrOut; | ||||
| 		} | ||||
| 		n = loutp-outbuf; | ||||
| 		sprint(hdr, "%11d %11ld ", r.max.y, n); | ||||
| 		write(fd, hdr, 2*12); | ||||
| 		write(fd, outbuf, n); | ||||
| 		r.min.y = r.max.y; | ||||
| 	} | ||||
| 	free(outbuf); | ||||
| 	free(hash); | ||||
| 	free(chain); | ||||
| 	return 0; | ||||
| } | ||||
							
								
								
									
										1333
									
								
								sys/src/cmd/pict/writetif.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1333
									
								
								sys/src/cmd/pict/writetif.c
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										294
									
								
								sys/src/cmd/pict/ycbcr.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										294
									
								
								sys/src/cmd/pict/ycbcr.h
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,294 @@ | ||||
| unsigned int ycbcrmap[256] = { | ||||
| 	0x008080, 0x07A27A, 0x0FC474, 0x17E66F, 0x276963, 0x2F8B5E, 0x37AD58, 0x3FCF52, | ||||
| 	0x4F5247, 0x577441, 0x5F963C, 0x67B836, 0x773C2A, 0x7F5E25, 0x87801F, 0x8FA21A, | ||||
| 	0x9AA511, 0x118080, 0x09AA79, 0x11CC73, 0x19EE6E, 0x31635C, 0x3B8E55, 0x3EB353, | ||||
| 	0x44D64F, 0x594D3F, 0x627339, 0x6B9933, 0x6FBD30, 0x813623, 0x8A5B1D, 0x928017, | ||||
| 	0x9D800F, 0xA6A809, 0x228080, 0x0BB377, 0x13D572, 0x1BF76C, 0x3B5E55, 0x47914D, | ||||
| 	0x45B84E, 0x49DC4B, 0x634738, 0x6D7231, 0x779C2B, 0x77C22A, 0x8B311C, 0x945815, | ||||
| 	0x9F560E, 0xA98007, 0xB2AB00, 0x338080, 0x0DBB76, 0x15DD70, 0x1DFF6B, 0x45584E, | ||||
| 	0x539444, 0x4BBE49, 0x4EE347, 0x6D4231, 0x78702A, 0x839F22, 0x80C724, 0x952B15, | ||||
| 	0x1C969C, 0x23B896, 0x2BDA91, 0x3C5E85, 0x448080, 0x4BA27A, 0x53C474, 0x644769, | ||||
| 	0x6B6963, 0x738B5E, 0x7BAD58, 0x8C304C, 0x935247, 0x9B7441, 0xA3963C, 0x1474A2, | ||||
| 	0x1971AA, 0x239CA3, 0x28BF99, 0x2FE292, 0x4B5586, 0x558080, 0x54A679, 0x59CA73, | ||||
| 	0x704065, 0x79665F, 0x818C59, 0x85B154, 0x972A47, 0x9F4E42, 0xA8733C, 0xB09836, | ||||
| 	0xBE9A30, 0x1E6EB3, 0x2AA1AA, 0x2CC69C, 0x32E994, 0x5A4D88, 0x668080, 0x5EAA79, | ||||
| 	0x61CF73, 0x7D3963, 0x86635C, 0x908E55, 0x8FB551, 0xA32343, 0xAC4B3D, 0xB57237, | ||||
| 	0xC27231, 0xCC9C2B, 0x236BBB, 0x31A7B1, 0x31CD9F, 0x36F195, 0x694489, 0x778080, | ||||
| 	0x67AF78, 0x68D572, 0x893260, 0x946058, 0x9E8F51, 0x9AB84E, 0xAF1D3F, 0xB84738, | ||||
| 	0x38ADB8, 0x3FCFB3, 0x5052A7, 0x5874A2, 0x60969C, 0x67B896, 0x783C8B, 0x805E85, | ||||
| 	0x888080, 0x8FA27A, 0xA0256E, 0xA84769, 0xAF6963, 0xB78B5E, 0x2869C4, 0x308BBE, | ||||
| 	0x368CC6, 0x3FB2C0, 0x45D5B7, 0x5A4DAC, 0x6373A6, 0x6B99A0, 0x6FBD98, 0x87338C, | ||||
| 	0x905986, 0x998080, 0x9BA579, 0xAD1D6C, 0xB64267, 0xBE6761, 0xC68C5B, 0x2D66CC, | ||||
| 	0x3263D5, 0x3C8DCE, 0x46B8C7, 0x4ADCBB, 0x6447B1, 0x6E71AA, 0x789CA3, 0x78C29A, | ||||
| 	0x962B8D, 0xA05586, 0xAA8080, 0xA7A879, 0xBA166B, 0xC33D64, 0xCC655E, 0xD68D58, | ||||
| 	0xE58E55, 0x3760DD, 0x428ED5, 0x4DBDCE, 0x4FE2C0, 0x6E41B6, 0x7970AF, 0x839FA7, | ||||
| 	0x81C69C, 0xA5228F, 0xB05187, 0xBB8080, 0xB3AA79, 0xC80E6A, 0xD23963, 0xDB635C, | ||||
| 	0x54C3D5, 0x6447C9, 0x6C69C4, 0x748BBE, 0x7CADB8, 0x8C30AD, 0x9452A7, 0x9C74A2, | ||||
| 	0xA4969C, 0xB41A90, 0xBC3C8B, 0xC45E85, 0xCC8080, 0x3C5DE6, 0x447FE0, 0x4CA1DA, | ||||
| 	0x52A4E2, 0x5BC9DC, 0x6C42CF, 0x7567CA, 0x7D8CC3, 0x86B1BD, 0x982AB0, 0xA04EAB, | ||||
| 	0xA973A5, 0xB1989E, 0xC31191, 0xCC368C, 0xD45A86, 0xDD8080, 0x425AEE, 0x4A7FE8, | ||||
| 	0x507FF0, 0x59A6EA, 0x62CEE3, 0x753DD5, 0x7E65CF, 0x878CC9, 0x90B4C2, 0xA323B4, | ||||
| 	0xAC4BAE, 0xB572A8, 0xBF9AA1, 0xD20993, 0xDB308C, 0xE45886, 0xEE8080, 0x4757F7, | ||||
| 	0x4C54FF, 0x557FF8, 0x5FA9F1, 0x69D4EA, 0x7E38DB, 0x8763D5, 0x918DCE, 0x9BB8C7, | ||||
| 	0xB01CB8, 0xB947B1, 0xC371AA, 0xCD9CA3, 0xE10094, 0xEB2B8D, 0xF55586, 0xFF8080, | ||||
| }; | ||||
|  | ||||
| unsigned char closestycbcr[16*16*16] = { | ||||
| 	8,55,55,38,21,21,4,4,4,0,79,79,80,114,142,159, | ||||
| 	8,55,38,38,21,4,4,4,4,0,79,79,80,114,142,159, | ||||
| 	55,55,38,21,21,4,4,4,0,0,79,79,80,114,142,159, | ||||
| 	55,38,38,21,4,4,4,4,0,0,79,79,80,114,142,159, | ||||
| 	55,38,21,21,4,4,4,0,0,0,79,79,80,114,142,159, | ||||
| 	38,38,21,4,4,4,4,0,0,0,79,79,80,114,142,159, | ||||
| 	38,21,21,4,4,4,0,0,0,0,79,79,80,114,142,159, | ||||
| 	38,21,4,4,4,4,0,0,0,0,79,79,80,114,142,159, | ||||
| 	21,21,4,4,4,4,0,0,0,0,79,79,80,114,142,159, | ||||
| 	21,4,4,4,4,0,0,0,0,17,79,79,80,114,142,159, | ||||
| 	5,5,5,5,5,1,1,1,1,1,64,64,64,143,143,144, | ||||
| 	22,5,5,5,18,18,18,18,18,18,64,64,81,98,143,144, | ||||
| 	6,6,6,52,52,52,52,52,52,52,65,65,98,115,115,128, | ||||
| 	6,6,6,2,2,2,2,2,2,2,65,65,82,115,128,145, | ||||
| 	23,23,36,36,36,36,36,36,36,36,82,99,99,116,145,162, | ||||
| 	7,7,3,3,3,3,3,3,3,3,66,66,116,116,129,129, | ||||
| 	25,8,8,55,38,38,21,4,4,67,67,80,97,142,159,160, | ||||
| 	25,8,55,55,38,21,21,4,4,67,79,80,97,142,159,160, | ||||
| 	8,8,55,38,38,21,4,4,4,67,79,80,97,142,159,160, | ||||
| 	8,55,55,38,21,21,4,4,4,79,79,80,97,142,159,160, | ||||
| 	8,55,38,38,21,4,4,4,4,79,79,80,97,142,159,160, | ||||
| 	55,55,38,21,21,4,4,4,0,79,79,80,97,142,159,160, | ||||
| 	55,38,38,21,4,4,4,4,0,79,79,80,97,142,159,160, | ||||
| 	55,38,21,21,4,4,4,0,0,79,79,80,97,142,159,160, | ||||
| 	38,38,21,4,4,4,4,17,17,17,79,80,97,142,159,160, | ||||
| 	5,5,5,5,5,5,1,1,17,34,64,64,143,143,143,144, | ||||
| 	22,22,5,5,5,5,1,1,1,64,64,81,81,143,144,161, | ||||
| 	39,22,22,22,5,35,35,35,35,35,81,81,98,115,144,178, | ||||
| 	6,6,6,6,6,2,2,2,2,65,65,65,115,128,128,145, | ||||
| 	23,23,23,23,19,19,19,19,19,65,82,82,99,128,145,162, | ||||
| 	57,7,7,7,53,53,53,53,53,66,66,116,116,129,129,179, | ||||
| 	24,7,7,7,20,20,20,20,20,66,66,83,116,129,146,146, | ||||
| 	42,25,25,8,55,38,38,21,4,67,67,67,114,142,160,177, | ||||
| 	42,25,8,8,55,38,21,21,4,67,67,97,114,142,160,177, | ||||
| 	25,25,8,55,55,38,21,4,4,67,67,97,114,142,160,177, | ||||
| 	25,8,8,55,38,38,21,4,4,67,67,97,114,142,160,177, | ||||
| 	25,8,55,55,38,21,21,4,4,67,80,97,114,142,160,177, | ||||
| 	8,8,55,38,38,21,4,4,4,67,80,97,114,142,160,177, | ||||
| 	8,55,55,38,21,21,4,4,4,79,80,97,114,142,160,177, | ||||
| 	8,55,38,38,21,4,4,4,17,79,80,97,114,142,160,177, | ||||
| 	55,55,38,21,21,4,4,34,34,34,80,97,114,142,160,177, | ||||
| 	9,9,22,5,5,5,5,5,34,64,64,81,143,143,144,206, | ||||
| 	39,39,22,22,22,5,5,18,18,64,81,98,98,144,161,178, | ||||
| 	56,39,39,6,6,6,6,52,52,65,65,98,115,128,178,178, | ||||
| 	23,23,23,6,6,6,19,19,19,65,82,82,128,145,145,207, | ||||
| 	40,40,40,40,23,36,36,36,36,82,99,116,116,145,162,179, | ||||
| 	57,7,7,7,7,3,3,3,3,66,66,116,129,129,179,192, | ||||
| 	41,41,24,24,24,37,37,37,37,83,100,100,146,146,163,192, | ||||
| 	59,42,25,25,8,55,55,38,67,67,84,130,130,159,177,205, | ||||
| 	42,42,25,8,8,55,38,38,67,67,84,130,130,159,177,205, | ||||
| 	42,25,25,8,55,55,38,21,67,67,67,130,130,159,177,205, | ||||
| 	42,25,8,8,55,38,38,21,67,67,67,130,142,159,177,205, | ||||
| 	25,25,8,55,55,38,21,21,67,67,67,114,142,159,177,205, | ||||
| 	25,25,8,55,38,38,21,4,67,67,67,114,142,159,177,205, | ||||
| 	25,8,8,55,38,21,21,4,67,67,80,114,142,159,177,205, | ||||
| 	25,8,55,55,38,21,4,4,34,67,80,114,142,159,177,205, | ||||
| 	9,9,9,9,5,5,5,51,51,51,64,143,143,144,206,206, | ||||
| 	9,9,9,22,22,22,5,5,51,64,81,143,143,144,161,206, | ||||
| 	56,56,39,39,39,22,22,6,69,81,98,98,115,161,178,178, | ||||
| 	10,56,56,6,6,6,6,6,65,65,65,115,128,145,207,207, | ||||
| 	10,40,40,40,23,23,23,19,82,82,99,99,145,145,162,208, | ||||
| 	57,57,57,57,7,7,7,53,66,66,116,116,129,162,179,192, | ||||
| 	11,24,24,24,24,7,7,20,66,83,83,129,146,146,192,192, | ||||
| 	58,58,41,41,41,41,37,37,100,100,117,117,163,163,180,209, | ||||
| 	12,59,42,42,25,8,8,71,71,84,101,130,147,193,193,222, | ||||
| 	59,59,42,25,25,8,55,71,84,84,101,130,147,193,205,222, | ||||
| 	59,42,42,25,8,8,55,71,84,84,84,130,130,193,205,222, | ||||
| 	59,42,25,25,8,55,55,38,84,84,130,130,130,160,205,222, | ||||
| 	42,42,25,8,8,55,38,67,67,84,130,130,130,160,205,222, | ||||
| 	42,25,25,8,55,55,38,67,67,84,130,130,159,160,205,222, | ||||
| 	42,25,8,8,55,38,38,67,67,67,130,130,159,160,205,222, | ||||
| 	25,9,9,9,55,38,21,51,51,68,131,131,159,160,206,222, | ||||
| 	26,9,9,9,9,22,5,68,68,68,131,143,144,161,206,223, | ||||
| 	26,26,9,39,39,22,22,68,68,68,98,143,144,161,178,223, | ||||
| 	10,56,56,56,39,39,6,69,69,69,115,115,128,178,207,207, | ||||
| 	10,10,10,40,23,23,23,69,69,82,128,128,145,162,207,208, | ||||
| 	11,11,57,57,40,40,40,70,70,99,116,129,162,162,179,225, | ||||
| 	11,11,57,57,7,7,7,70,70,66,116,129,146,179,192,209, | ||||
| 	28,41,41,41,41,41,24,87,100,100,100,146,163,163,209,209, | ||||
| 	58,58,58,58,58,58,58,54,117,117,117,163,180,180,180,226, | ||||
| 	29,12,59,59,42,25,71,71,71,101,118,147,164,193,193,210, | ||||
| 	12,12,59,42,42,25,71,71,71,101,101,147,164,193,193,210, | ||||
| 	12,59,59,42,25,25,71,71,101,101,130,147,164,193,193,239, | ||||
| 	12,59,42,42,25,8,71,71,101,101,130,147,147,193,193,239, | ||||
| 	59,59,42,25,25,8,71,71,84,101,130,147,147,193,222,239, | ||||
| 	59,42,42,25,8,8,55,71,84,101,130,130,147,193,222,239, | ||||
| 	59,42,25,25,8,55,55,84,84,84,130,130,147,177,222,239, | ||||
| 	13,26,9,9,9,9,72,68,68,131,131,131,148,206,206,223, | ||||
| 	43,26,26,9,9,9,22,68,85,85,131,131,161,178,223,224, | ||||
| 	43,43,56,56,56,39,39,69,85,85,132,132,178,178,207,224, | ||||
| 	27,10,10,10,56,56,69,69,69,132,132,132,145,207,207,208, | ||||
| 	27,27,27,10,40,40,40,86,86,103,132,145,162,179,208,225, | ||||
| 	11,11,11,57,57,57,70,70,70,133,133,129,179,179,192,242, | ||||
| 	28,28,11,11,41,24,24,87,87,87,129,146,163,192,209,209, | ||||
| 	45,45,58,58,58,58,41,104,104,117,163,163,180,180,226,226, | ||||
| 	62,58,58,58,58,58,58,121,117,117,117,180,180,180,243,243, | ||||
| 	46,29,12,12,59,42,88,88,88,118,134,164,181,193,210,227, | ||||
| 	29,29,12,59,59,42,88,88,88,118,118,164,181,193,210,227, | ||||
| 	29,12,12,59,42,42,71,71,118,118,118,164,181,193,210,227, | ||||
| 	29,12,59,59,42,25,71,71,101,118,147,164,181,193,210,227, | ||||
| 	12,12,59,42,42,25,71,71,101,118,147,164,193,193,210,240, | ||||
| 	12,59,59,42,25,25,71,71,101,101,147,164,193,193,210,240, | ||||
| 	13,13,42,26,9,9,72,72,101,101,131,148,194,194,194,240, | ||||
| 	13,43,43,26,26,9,72,72,85,131,131,148,194,194,223,241, | ||||
| 	60,60,43,26,26,56,72,85,102,102,148,165,194,194,224,241, | ||||
| 	14,27,10,10,10,56,73,102,102,132,132,132,195,207,208,225, | ||||
| 	44,27,27,27,10,10,73,86,103,132,132,149,195,208,225,225, | ||||
| 	44,44,44,11,11,57,103,103,120,133,133,166,179,179,225,242, | ||||
| 	28,28,11,11,11,57,70,87,87,133,133,150,192,192,209,226, | ||||
| 	45,45,28,28,58,41,104,104,104,150,150,163,180,209,226,226, | ||||
| 	62,62,45,58,58,58,121,121,121,121,180,180,180,180,243,243, | ||||
| 	62,62,58,58,58,58,121,121,121,121,180,180,180,180,243,243, | ||||
| 	63,46,29,29,12,75,105,105,105,134,151,197,181,227,244,244, | ||||
| 	46,46,29,12,12,75,105,105,134,134,134,181,181,227,244,244, | ||||
| 	46,29,29,12,59,75,88,88,134,134,134,181,181,210,227,244, | ||||
| 	46,29,12,12,59,88,88,88,118,134,134,181,181,210,227,244, | ||||
| 	29,29,12,59,59,88,88,88,118,134,164,181,181,210,227,244, | ||||
| 	29,12,12,59,42,88,88,88,118,118,164,181,193,210,227,244, | ||||
| 	13,13,13,13,26,72,72,72,135,135,148,165,194,211,228,228, | ||||
| 	30,60,60,43,43,72,72,72,102,135,165,165,194,211,228,241, | ||||
| 	14,60,60,60,43,73,73,102,119,119,165,182,195,195,228,241, | ||||
| 	14,14,27,27,27,73,73,73,119,132,149,195,195,212,225,242, | ||||
| 	61,44,44,44,27,90,90,120,120,149,166,166,212,212,242,242, | ||||
| 	61,61,61,11,11,74,74,120,120,133,133,196,196,196,242,242, | ||||
| 	45,45,28,28,28,74,74,104,104,150,150,167,196,209,226,243, | ||||
| 	62,62,45,45,45,91,121,121,121,167,167,184,180,226,243,243, | ||||
| 	62,62,62,62,58,121,121,121,121,184,184,184,180,243,243,243, | ||||
| 	62,62,62,62,58,121,121,121,121,184,184,180,180,243,243,243, | ||||
| 	63,63,46,29,75,75,122,122,151,151,151,197,197,244,244,244, | ||||
| 	63,63,46,29,75,75,122,122,151,151,151,197,197,244,244,244, | ||||
| 	63,46,46,29,75,75,122,122,151,151,151,197,197,244,244,244, | ||||
| 	63,46,29,29,75,75,105,105,134,151,151,197,197,227,244,244, | ||||
| 	46,46,29,12,75,75,105,105,134,151,197,197,210,227,244,244, | ||||
| 	30,30,13,13,76,76,89,135,135,135,198,198,211,228,245,245, | ||||
| 	30,30,13,13,76,89,89,89,135,135,165,182,211,228,245,245, | ||||
| 	47,60,60,60,60,106,106,119,119,119,182,182,228,228,245,245, | ||||
| 	14,14,14,14,77,73,73,119,136,136,182,195,195,212,229,246, | ||||
| 	31,14,14,44,44,90,90,90,136,136,166,166,212,229,246,246, | ||||
| 	15,61,61,61,44,74,74,137,137,166,183,183,196,246,246,242, | ||||
| 	15,15,15,28,91,91,74,137,137,150,183,196,213,213,230,243, | ||||
| 	62,62,62,45,45,91,91,121,167,167,184,184,213,230,243,243, | ||||
| 	62,62,62,62,62,108,121,121,184,184,184,184,230,247,243,243, | ||||
| 	62,62,62,62,62,125,121,121,184,184,184,184,247,243,243,243, | ||||
| 	62,62,62,62,62,121,121,121,184,184,184,184,247,243,243,243, | ||||
| 	63,63,63,46,92,92,122,138,138,168,168,214,214,231,244,244, | ||||
| 	63,63,63,46,92,92,122,138,138,168,168,214,214,231,244,244, | ||||
| 	63,63,46,46,92,92,122,138,151,168,197,197,214,244,244,244, | ||||
| 	63,63,46,29,75,75,122,138,151,168,197,197,214,244,244,244, | ||||
| 	63,46,46,29,75,75,122,122,151,151,197,197,214,244,244,244, | ||||
| 	47,47,30,30,76,76,106,139,152,152,198,198,215,245,245,245, | ||||
| 	48,47,30,30,76,123,123,123,152,152,198,198,228,245,245,245, | ||||
| 	48,31,14,14,77,123,123,136,136,136,199,199,245,245,245,245, | ||||
| 	32,31,31,14,77,90,90,136,136,153,199,199,229,229,246,246, | ||||
| 	32,32,61,61,107,107,107,153,153,153,183,183,229,246,246,246, | ||||
| 	16,15,15,61,78,91,91,137,137,137,183,183,213,246,246,246, | ||||
| 	16,16,16,45,108,108,108,154,154,154,184,213,230,230,247,247, | ||||
| 	33,62,62,62,125,125,125,154,171,184,184,230,230,247,247,243, | ||||
| 	62,62,62,62,125,125,125,125,184,184,184,184,247,247,247,243, | ||||
| 	62,62,62,62,125,125,125,121,184,184,184,184,247,247,243,243, | ||||
| 	62,62,62,62,125,125,125,121,184,184,184,184,247,247,243,243, | ||||
| 	63,63,63,126,109,109,138,155,155,185,185,231,231,248,248,244, | ||||
| 	63,63,63,109,109,109,138,138,138,185,185,231,231,248,248,244, | ||||
| 	63,63,63,109,109,109,138,138,168,185,185,231,231,248,244,244, | ||||
| 	63,63,63,109,109,92,138,138,168,185,214,214,231,248,244,244, | ||||
| 	48,48,47,93,93,93,139,139,139,169,198,215,215,232,245,245, | ||||
| 	48,48,47,93,93,93,139,139,169,169,215,215,232,245,245,245, | ||||
| 	48,48,48,93,93,123,123,140,169,169,215,215,232,245,245,245, | ||||
| 	32,32,31,77,77,77,140,140,153,199,199,216,216,246,246,246, | ||||
| 	49,32,32,94,94,107,107,153,153,170,216,216,246,246,246,246, | ||||
| 	49,49,15,78,78,124,124,137,170,200,200,200,246,246,246,246, | ||||
| 	16,16,16,78,78,124,124,154,154,200,200,217,230,230,247,247, | ||||
| 	33,33,16,95,125,125,125,171,171,171,217,230,247,247,247,247, | ||||
| 	50,33,62,125,125,125,125,171,188,184,184,247,247,247,247,247, | ||||
| 	50,62,62,125,125,125,125,188,188,184,184,247,247,247,247,247, | ||||
| 	50,62,62,125,125,125,125,188,184,184,184,247,247,247,247,247, | ||||
| 	50,62,62,125,125,125,125,188,184,184,184,247,247,247,247,243, | ||||
| 	63,63,63,126,126,126,155,172,172,201,201,248,248,248,248,248, | ||||
| 	63,63,63,126,126,126,155,155,172,201,201,248,248,248,248,248, | ||||
| 	63,63,63,126,126,126,155,155,185,201,201,248,248,248,248,248, | ||||
| 	63,63,63,126,126,126,155,155,185,202,202,248,248,248,248,244, | ||||
| 	48,48,48,110,110,110,139,156,202,202,232,232,249,249,249,245, | ||||
| 	48,48,48,110,110,110,156,156,186,186,232,232,249,249,245,245, | ||||
| 	48,48,48,94,94,140,140,140,186,186,216,216,249,249,245,245, | ||||
| 	49,49,111,111,94,140,140,140,170,216,216,233,233,246,246,246, | ||||
| 	49,49,111,111,111,124,141,170,170,187,233,233,250,246,246,246, | ||||
| 	49,16,95,95,95,141,141,141,187,200,217,217,217,246,246,246, | ||||
| 	33,33,95,95,95,141,141,171,171,217,217,234,247,247,247,247, | ||||
| 	50,50,96,96,125,125,188,188,188,188,234,234,247,247,247,247, | ||||
| 	50,50,50,125,125,125,188,188,188,188,234,247,247,247,247,247, | ||||
| 	50,50,50,125,125,125,188,188,188,188,247,247,247,247,247,247, | ||||
| 	50,50,62,125,125,125,188,188,188,188,247,247,247,247,247,247, | ||||
| 	50,50,62,125,125,125,188,188,188,184,247,247,247,247,247,247, | ||||
| 	63,63,126,126,126,126,189,189,189,218,218,248,248,248,248,248, | ||||
| 	63,63,126,126,126,126,172,172,201,218,218,248,248,248,248,248, | ||||
| 	63,63,126,126,126,172,172,172,201,218,218,248,248,248,248,248, | ||||
| 	48,48,127,127,127,156,173,173,202,202,219,249,249,249,249,249, | ||||
| 	48,48,127,127,127,173,173,173,202,202,249,249,249,249,249,249, | ||||
| 	48,48,127,127,127,173,173,173,186,203,249,249,249,249,249,249, | ||||
| 	49,49,111,111,111,157,157,157,203,203,233,233,250,250,250,246, | ||||
| 	49,49,112,112,112,157,157,157,187,203,233,250,250,250,250,246, | ||||
| 	49,49,112,112,112,141,141,187,187,204,250,250,250,250,246,246, | ||||
| 	50,33,96,96,96,158,158,158,204,217,234,234,234,251,247,247, | ||||
| 	50,50,96,96,96,158,158,188,188,234,234,251,251,247,247,247, | ||||
| 	50,50,113,113,113,175,188,188,188,234,251,251,251,247,247,247, | ||||
| 	50,50,113,113,113,125,188,188,188,251,251,251,247,247,247,247, | ||||
| 	50,50,113,113,125,125,188,188,188,251,251,251,247,247,247,247, | ||||
| 	50,50,113,113,125,125,188,188,188,251,251,247,247,247,247,247, | ||||
| 	50,50,113,125,125,125,188,188,188,251,251,247,247,247,247,247, | ||||
| 	63,126,126,126,126,189,189,189,235,235,235,252,248,248,248,248, | ||||
| 	63,126,126,126,126,189,189,189,218,235,235,235,248,248,248,248, | ||||
| 	63,126,126,126,126,189,189,189,219,219,235,248,248,248,248,248, | ||||
| 	48,127,127,127,127,190,190,190,219,219,236,249,249,249,249,249, | ||||
| 	48,127,127,127,127,190,190,190,219,219,236,249,249,249,249,249, | ||||
| 	48,127,127,127,127,174,174,203,203,220,220,249,249,249,249,249, | ||||
| 	49,112,112,112,112,174,174,174,220,220,250,250,250,250,250,250, | ||||
| 	49,112,112,112,112,174,191,191,204,204,250,250,250,250,250,250, | ||||
| 	49,112,112,112,158,158,158,204,204,204,250,250,250,250,250,250, | ||||
| 	50,113,113,113,113,175,175,175,221,234,251,251,251,251,251,247, | ||||
| 	50,113,113,113,113,175,175,188,188,251,251,251,251,251,251,247, | ||||
| 	50,113,113,113,113,176,176,188,188,251,251,251,251,251,247,247, | ||||
| 	50,113,113,113,113,176,188,188,188,251,251,251,251,251,247,247, | ||||
| 	50,113,113,113,113,176,188,188,188,251,251,251,251,247,247,247, | ||||
| 	50,113,113,113,113,188,188,188,188,251,251,251,251,247,247,247, | ||||
| 	50,113,113,113,113,188,188,188,188,251,251,251,247,247,247,247, | ||||
| 	126,126,126,126,189,189,189,189,235,252,252,252,252,248,248,248, | ||||
| 	126,126,126,126,189,189,189,189,235,252,252,252,252,248,248,248, | ||||
| 	127,127,127,127,190,190,190,190,236,236,253,253,249,249,249,249, | ||||
| 	127,127,127,127,190,190,190,190,236,236,253,253,249,249,249,249, | ||||
| 	127,127,127,127,190,190,190,190,236,236,253,249,249,249,249,249, | ||||
| 	112,112,112,112,191,191,191,220,220,237,237,250,250,250,250,250, | ||||
| 	112,112,112,112,191,191,191,191,237,237,237,250,250,250,250,250, | ||||
| 	112,112,112,112,191,191,191,221,221,221,250,250,250,250,250,250, | ||||
| 	113,113,113,113,175,175,175,221,221,221,251,251,251,251,251,251, | ||||
| 	113,113,113,113,176,176,176,221,238,238,251,251,251,251,251,251, | ||||
| 	113,113,113,113,176,176,176,176,238,251,251,251,251,251,251,251, | ||||
| 	113,113,113,113,176,176,176,176,251,251,251,251,251,251,251,247, | ||||
| 	113,113,113,113,176,176,176,176,251,251,251,251,251,251,251,247, | ||||
| 	113,113,113,113,176,176,176,188,251,251,251,251,251,251,251,247, | ||||
| 	113,113,113,113,176,176,176,188,251,251,251,251,251,251,247,247, | ||||
| 	113,113,113,113,176,176,188,188,251,251,251,251,251,251,247,247, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| 	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255, | ||||
| }; | ||||
|  | ||||
							
								
								
									
										220
									
								
								sys/src/cmd/pict/yuv.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										220
									
								
								sys/src/cmd/pict/yuv.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,220 @@ | ||||
| #include <u.h> | ||||
| #include <libc.h> | ||||
| #include <bio.h> | ||||
| #include <draw.h> | ||||
| #include <event.h> | ||||
| #include <keyboard.h> | ||||
| #include "imagefile.h" | ||||
|  | ||||
| int		cflag = 0; | ||||
| int		dflag = 0; | ||||
| int		eflag = 0; | ||||
| int		nineflag = 0; | ||||
| int		threeflag = 0; | ||||
| int		output = 0; | ||||
| uint32_t	outchan = CMAP8; | ||||
| int		defaultcolor = 1; | ||||
| Image	*image; | ||||
|  | ||||
| enum{ | ||||
| 	Border	= 2, | ||||
| 	Edge		= 5 | ||||
| }; | ||||
|  | ||||
| char	*show(int, char*); | ||||
|  | ||||
| Rawimage** readyuv(int fd, int colorspace); | ||||
|  | ||||
| Rectangle | ||||
| imager(Image *i) | ||||
| { | ||||
| 	Point p1, p2; | ||||
|  | ||||
| 	p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min); | ||||
| 	p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min); | ||||
| 	return rectaddpt(i->r, subpt(p2, p1)); | ||||
| } | ||||
|  | ||||
| void | ||||
| eresized(int new) | ||||
| { | ||||
| 	Rectangle r; | ||||
|  | ||||
| 	if(new && getwindow(display, Refnone) < 0){ | ||||
| 		fprint(2, "yuv: can't reattach to window\n"); | ||||
| 		exits("resize"); | ||||
| 	} | ||||
| 	if(image == nil) | ||||
| 		return; | ||||
| 	r = imager(image); | ||||
| 	border(screen, r, -Border, nil, ZP); | ||||
| 	drawop(screen, r, image, nil, image->r.min, S); | ||||
| 	flushimage(display, 1); | ||||
| } | ||||
|  | ||||
| void | ||||
| main(int argc, char *argv[]) | ||||
| { | ||||
| 	int fd, i; | ||||
| 	char *err; | ||||
|  | ||||
| 	ARGBEGIN{ | ||||
| 	case '3':		/* produce encoded, compressed, three-color bitmap file; no display by default */ | ||||
| 		threeflag++; | ||||
| 		/* fall through */ | ||||
| 	case 't':		/* produce encoded, compressed, true-color bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = RGB24; | ||||
| 		break; | ||||
| 	case 'c':		/* produce encoded, compressed, bitmap file; no display by default */ | ||||
| 		cflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	case 'd':		/* suppress display of image */ | ||||
| 		dflag++; | ||||
| 		break; | ||||
| 	case 'e':		/* disable floyd-steinberg error diffusion */ | ||||
| 		eflag++; | ||||
| 		break; | ||||
| 	case 'k':		/* force black and white */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = GREY8; | ||||
| 		break; | ||||
| 	case 'v':		/* force RGBV */ | ||||
| 		defaultcolor = 0; | ||||
| 		outchan = CMAP8; | ||||
| 		break; | ||||
| 	case '9':		/* produce plan 9, uncompressed, bitmap file; no display by default */ | ||||
| 		nineflag++; | ||||
| 		dflag++; | ||||
| 		output++; | ||||
| 		if(defaultcolor) | ||||
| 			outchan = CMAP8; | ||||
| 		break; | ||||
| 	default: | ||||
| 		fprint(2, "usage: yuv -39cdektv  [file.yuv ...]\n"); | ||||
| 		exits("usage"); | ||||
| 	}ARGEND; | ||||
|  | ||||
| 	err = nil; | ||||
| 	if(argc == 0) | ||||
| 		err = show(0, "<stdin>"); | ||||
| 	else{ | ||||
| 		for(i=0; i<argc; i++){ | ||||
| 			fd = open(argv[i], OREAD); | ||||
| 			if(fd < 0){ | ||||
| 				fprint(2, "yuv: can't open %s: %r\n", argv[i]); | ||||
| 				err = "open"; | ||||
| 			}else{ | ||||
| 				err = show(fd, argv[i]); | ||||
| 				close(fd); | ||||
| 			} | ||||
| 			if((nineflag || cflag) && argc>1 && err==nil){ | ||||
| 				fprint(2, "yuv: exiting after one file\n"); | ||||
| 				break; | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	exits(err); | ||||
| } | ||||
|  | ||||
| int | ||||
| init(void) | ||||
| { | ||||
| 	static int inited; | ||||
|  | ||||
| 	if(inited == 0){ | ||||
| 		if(initdraw(0, 0, 0) < 0){ | ||||
| 			fprint(2, "yuv: initdraw failed: %r"); | ||||
| 			return -1; | ||||
| 		} | ||||
| 		einit(Ekeyboard|Emouse); | ||||
| 		inited++; | ||||
| 	} | ||||
| 	return 1; | ||||
| } | ||||
|  | ||||
| char* | ||||
| show(int fd, char *name) | ||||
| { | ||||
| 	Rawimage **array, *r, *c; | ||||
| 	Image *i; | ||||
| 	int j, ch; | ||||
| 	char buf[32]; | ||||
|  | ||||
| 	array = readyuv(fd, CYCbCr); | ||||
| 	if(array == nil || array[0]==nil){ | ||||
| 		fprint(2, "yuv: decode %s failed: %r\n", name); | ||||
| 		return "decode"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(init() < 0) | ||||
| 			return "initdraw"; | ||||
| 		if(defaultcolor && screen->depth>8) | ||||
| 			outchan = RGB24; | ||||
| 	} | ||||
| 	r = array[0]; | ||||
| 	if(outchan == CMAP8) | ||||
| 		c = torgbv(r, !eflag); | ||||
| 	else{ | ||||
| 		if(outchan==GREY8 || (r->chandesc==CY && threeflag==0)) | ||||
| 			c = totruecolor(r, CY); | ||||
| 		else | ||||
| 			c = totruecolor(r, CRGB24); | ||||
| 	} | ||||
| 	if(c == nil){ | ||||
| 		fprint(2, "yuv: converting %s to local format failed: %r\n", name); | ||||
| 		return "torgbv"; | ||||
| 	} | ||||
| 	if(!dflag){ | ||||
| 		if(r->chandesc == CY) | ||||
| 			i = allocimage(display, c->r, GREY8, 0, 0); | ||||
| 		else | ||||
| 			i = allocimage(display, c->r, outchan, 0, 0); | ||||
| 		if(i == nil){ | ||||
| 			fprint(2, "yuv: allocimage %s failed: %r\n", name); | ||||
| 			return "allocimage"; | ||||
| 		} | ||||
| 		if(loadimage(i, i->r, c->chans[0], c->chanlen) < 0){ | ||||
| 			fprint(2, "yuv: loadimage %s failed: %r\n", name); | ||||
| 			return "loadimage"; | ||||
| 		} | ||||
| 		image = i; | ||||
| 		eresized(0); | ||||
| 		if((ch=ekbd())=='q' || ch==Kdel || ch==Keof) | ||||
| 			exits(nil); | ||||
| 		draw(screen, screen->clipr, display->white, nil, ZP); | ||||
| 		image = nil; | ||||
| 		freeimage(i); | ||||
| 	} | ||||
| 	if(nineflag){ | ||||
| 		chantostr(buf, outchan); | ||||
| 		print("%11s %11d %11d %11d %11d ", buf, | ||||
| 			c->r.min.x, c->r.min.y, c->r.max.x, c->r.max.y); | ||||
| 		if(write(1, c->chans[0], c->chanlen) != c->chanlen){ | ||||
| 			fprint(2, "yuv: %s: write error %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	}else if(cflag){ | ||||
| 		if(writerawimage(1, c) < 0){ | ||||
| 			fprint(2, "yuv: %s: write error: %r\n", name); | ||||
| 			return "write"; | ||||
| 		} | ||||
| 	} | ||||
| 	for(j=0; j<r->nchans; j++) | ||||
| 		free(r->chans[j]); | ||||
| 	free(r->cmap); | ||||
| 	free(r); | ||||
| 	free(array); | ||||
| 	if(c){ | ||||
| 		free(c->chans[0]); | ||||
| 		free(c); | ||||
| 	} | ||||
| 	return nil; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user