| #include <u.h> | 
 | #include <libc.h> | 
 | #include <draw.h> | 
 | #include <memdraw.h> | 
 | #include <bio.h> | 
 | #include "imagefile.h" | 
 |  | 
 | #define	MAXLINE	70 | 
 |  | 
 | /* | 
 |  * Write data | 
 |  */ | 
 | static | 
 | char* | 
 | writedata(Biobuf *fd, Image *image, Memimage *memimage) | 
 | { | 
 | 	char *err; | 
 | 	uchar *data; | 
 | 	int i, x, y, ndata, depth, col, pix, xmask, pmask; | 
 | 	ulong 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, "WriteGIF: %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>>drawlog2[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++; | 
 | 				col += Bprint(fd, "%d ", pix); | 
 | 				if(col >= MAXLINE-(2+1)){ | 
 | 					Bprint(fd, "\n"); | 
 | 					col = 0; | 
 | 				}else | 
 | 					col += Bprint(fd, " "); | 
 | 			} | 
 | 		} | 
 | 		break; | 
 | 	case	GREY8: | 
 | 		for(i=0; i<ndata; i++){ | 
 | 			col += Bprint(fd, "%d ", data[i]); | 
 | 			if(col >= MAXLINE-(4+1)){ | 
 | 				Bprint(fd, "\n"); | 
 | 				col = 0; | 
 | 			}else | 
 | 				col += Bprint(fd, " "); | 
 | 		} | 
 | 		break; | 
 | 	case RGB24: | 
 | 		for(i=0; i<ndata; i+=3){ | 
 | 			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 | 
 | 				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) | 
 | { | 
 | 	char *err; | 
 |  | 
 | 	switch(chan){ | 
 | 	case GREY1: | 
 | 		Bprint(fd, "P1\n"); | 
 | 		break; | 
 | 	case GREY2: | 
 | 	case GREY4: | 
 | 	case	GREY8: | 
 | 		Bprint(fd, "P2\n"); | 
 | 		break; | 
 | 	case RGB24: | 
 | 		Bprint(fd, "P3\n"); | 
 | 		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); | 
 |  | 
 | 	Bprint(fd, "\n"); | 
 | 	Bflush(fd); | 
 | 	return err; | 
 | } | 
 |  | 
 | char* | 
 | writeppm(Biobuf *fd, Image *image, char *comment) | 
 | { | 
 | 	return writeppm0(fd, image, nil, image->r, image->chan, comment); | 
 | } | 
 |  | 
 | char* | 
 | memwriteppm(Biobuf *fd, Memimage *memimage, char *comment) | 
 | { | 
 | 	return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment); | 
 | } |