xref: /plan9/sys/src/cmd/jpg/writeppm.c (revision bacfa46c74e1c310aff15aef9cb6bc4e6302513a)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <memdraw.h>
57dd7cddfSDavid du Colombier #include <bio.h>
67dd7cddfSDavid du Colombier 
77dd7cddfSDavid du Colombier #define	MAXLINE	70
87dd7cddfSDavid du Colombier 
9*bacfa46cSDavid du Colombier /* imported from libdraw/arith.c to permit an extern log2 function */
10*bacfa46cSDavid du Colombier static int log2[] = {
11*bacfa46cSDavid du Colombier 	-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
12*bacfa46cSDavid du Colombier 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
13*bacfa46cSDavid du Colombier };
14*bacfa46cSDavid du Colombier 
157dd7cddfSDavid du Colombier /*
167dd7cddfSDavid du Colombier  * Write data
177dd7cddfSDavid du Colombier  */
187dd7cddfSDavid du Colombier static
197dd7cddfSDavid du Colombier char*
writedata(Biobuf * fd,Image * image,Memimage * memimage)207dd7cddfSDavid du Colombier writedata(Biobuf *fd, Image *image, Memimage *memimage)
217dd7cddfSDavid du Colombier {
227dd7cddfSDavid du Colombier 	char *err;
237dd7cddfSDavid du Colombier 	uchar *data;
247dd7cddfSDavid du Colombier 	int i, x, y, ndata, depth, col, pix, xmask, pmask;
257dd7cddfSDavid du Colombier 	ulong chan;
267dd7cddfSDavid du Colombier 	Rectangle r;
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier 	if(memimage != nil){
297dd7cddfSDavid du Colombier 		r = memimage->r;
307dd7cddfSDavid du Colombier 		depth = memimage->depth;
317dd7cddfSDavid du Colombier 		chan = memimage->chan;
327dd7cddfSDavid du Colombier 	}else{
337dd7cddfSDavid du Colombier 		r = image->r;
347dd7cddfSDavid du Colombier 		depth = image->depth;
357dd7cddfSDavid du Colombier 		chan = image->chan;
367dd7cddfSDavid du Colombier 	}
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier 	/*
397dd7cddfSDavid du Colombier 	 * Read image data into memory
407dd7cddfSDavid du Colombier 	 * potentially one extra byte on each end of each scan line
417dd7cddfSDavid du Colombier 	 */
427dd7cddfSDavid du Colombier 	ndata = Dy(r)*(2+Dx(r)*depth/8);
437dd7cddfSDavid du Colombier 	data = malloc(ndata);
447dd7cddfSDavid du Colombier 	if(data == nil)
457dd7cddfSDavid du Colombier 		return "WritePPM: malloc failed";
467dd7cddfSDavid du Colombier 	if(memimage != nil)
477dd7cddfSDavid du Colombier 		ndata = unloadmemimage(memimage, r, data, ndata);
487dd7cddfSDavid du Colombier 	else
497dd7cddfSDavid du Colombier 		ndata = unloadimage(image, r, data, ndata);
507dd7cddfSDavid du Colombier 	if(ndata < 0){
519a747e4fSDavid du Colombier 		err = malloc(ERRMAX);
527dd7cddfSDavid du Colombier 		if(err == nil)
537dd7cddfSDavid du Colombier 			return "WritePPM: malloc failed";
549a747e4fSDavid du Colombier 		snprint(err, ERRMAX, "WriteGIF: %r");
557dd7cddfSDavid du Colombier 		free(data);
567dd7cddfSDavid du Colombier 		return err;
577dd7cddfSDavid du Colombier 	}
587dd7cddfSDavid du Colombier 
597dd7cddfSDavid du Colombier 	/* Encode and emit the data */
607dd7cddfSDavid du Colombier 	col = 0;
617dd7cddfSDavid du Colombier 	switch(chan){
627dd7cddfSDavid du Colombier 	case GREY1:
637dd7cddfSDavid du Colombier 	case GREY2:
647dd7cddfSDavid du Colombier 	case GREY4:
657dd7cddfSDavid du Colombier 		pmask = (1<<depth)-1;
667dd7cddfSDavid du Colombier 		xmask = 7>>log2[depth];
677dd7cddfSDavid du Colombier 		for(y=r.min.y; y<r.max.y; y++){
687dd7cddfSDavid du Colombier 			i = (y-r.min.y)*bytesperline(r, depth);
697dd7cddfSDavid du Colombier 			for(x=r.min.x; x<r.max.x; x++){
707dd7cddfSDavid du Colombier 				pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
717dd7cddfSDavid du Colombier 				if(((x+1)&xmask) == 0)
727dd7cddfSDavid du Colombier 					i++;
737dd7cddfSDavid du Colombier 				col += Bprint(fd, "%d ", pix);
747dd7cddfSDavid du Colombier 				if(col >= MAXLINE-(2+1)){
757dd7cddfSDavid du Colombier 					Bprint(fd, "\n");
767dd7cddfSDavid du Colombier 					col = 0;
777dd7cddfSDavid du Colombier 				}else
787dd7cddfSDavid du Colombier 					col += Bprint(fd, " ");
797dd7cddfSDavid du Colombier 			}
807dd7cddfSDavid du Colombier 		}
817dd7cddfSDavid du Colombier 		break;
827dd7cddfSDavid du Colombier 	case	GREY8:
837dd7cddfSDavid du Colombier 		for(i=0; i<ndata; i++){
847dd7cddfSDavid du Colombier 			col += Bprint(fd, "%d ", data[i]);
857dd7cddfSDavid du Colombier 			if(col >= MAXLINE-(4+1)){
867dd7cddfSDavid du Colombier 				Bprint(fd, "\n");
877dd7cddfSDavid du Colombier 				col = 0;
887dd7cddfSDavid du Colombier 			}else
897dd7cddfSDavid du Colombier 				col += Bprint(fd, " ");
907dd7cddfSDavid du Colombier 		}
917dd7cddfSDavid du Colombier 		break;
927dd7cddfSDavid du Colombier 	case RGB24:
937dd7cddfSDavid du Colombier 		for(i=0; i<ndata; i+=3){
949a747e4fSDavid du Colombier 			col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]);
957dd7cddfSDavid du Colombier 			if(col >= MAXLINE-(4+4+4+1)){
967dd7cddfSDavid du Colombier 				Bprint(fd, "\n");
977dd7cddfSDavid du Colombier 				col = 0;
987dd7cddfSDavid du Colombier 			}else
997dd7cddfSDavid du Colombier 				col += Bprint(fd, " ");
1007dd7cddfSDavid du Colombier 		}
1017dd7cddfSDavid du Colombier 		break;
1027dd7cddfSDavid du Colombier 	default:
1037dd7cddfSDavid du Colombier 		return "WritePPM: can't handle channel type";
1047dd7cddfSDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 
1067dd7cddfSDavid du Colombier 	return nil;
1077dd7cddfSDavid du Colombier }
1087dd7cddfSDavid du Colombier 
1097dd7cddfSDavid du Colombier static
1107dd7cddfSDavid du Colombier char*
writeppm0(Biobuf * fd,Image * image,Memimage * memimage,Rectangle r,int chan,char * comment)1117dd7cddfSDavid du Colombier writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment)
1127dd7cddfSDavid du Colombier {
1137dd7cddfSDavid du Colombier 	char *err;
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	switch(chan){
1167dd7cddfSDavid du Colombier 	case GREY1:
1177dd7cddfSDavid du Colombier 		Bprint(fd, "P1\n");
1187dd7cddfSDavid du Colombier 		break;
1197dd7cddfSDavid du Colombier 	case GREY2:
1207dd7cddfSDavid du Colombier 	case GREY4:
1217dd7cddfSDavid du Colombier 	case	GREY8:
1227dd7cddfSDavid du Colombier 		Bprint(fd, "P2\n");
1237dd7cddfSDavid du Colombier 		break;
1247dd7cddfSDavid du Colombier 	case RGB24:
1257dd7cddfSDavid du Colombier 		Bprint(fd, "P3\n");
1267dd7cddfSDavid du Colombier 		break;
1277dd7cddfSDavid du Colombier 	default:
1287dd7cddfSDavid du Colombier 		return "WritePPM: can't handle channel type";
1297dd7cddfSDavid du Colombier 	}
1307dd7cddfSDavid du Colombier 
1317dd7cddfSDavid du Colombier 	if(comment!=nil && comment[0]!='\0'){
1327dd7cddfSDavid du Colombier 		Bprint(fd, "# %s", comment);
1337dd7cddfSDavid du Colombier 		if(comment[strlen(comment)-1] != '\n')
1347dd7cddfSDavid du Colombier 			Bprint(fd, "\n");
1357dd7cddfSDavid du Colombier 	}
1367dd7cddfSDavid du Colombier 	Bprint(fd, "%d %d\n", Dx(r), Dy(r));
1377dd7cddfSDavid du Colombier 
1387dd7cddfSDavid du Colombier 	/* maximum pixel value */
1397dd7cddfSDavid du Colombier 	switch(chan){
1407dd7cddfSDavid du Colombier 	case GREY2:
1417dd7cddfSDavid du Colombier 		Bprint(fd, "%d\n", 3);
1427dd7cddfSDavid du Colombier 		break;
1437dd7cddfSDavid du Colombier 	case GREY4:
1447dd7cddfSDavid du Colombier 		Bprint(fd, "%d\n", 15);
1457dd7cddfSDavid du Colombier 		break;
1467dd7cddfSDavid du Colombier 	case	GREY8:
1477dd7cddfSDavid du Colombier 	case RGB24:
1487dd7cddfSDavid du Colombier 		Bprint(fd, "%d\n", 255);
1497dd7cddfSDavid du Colombier 		break;
1507dd7cddfSDavid du Colombier 	}
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier 	err = writedata(fd, image, memimage);
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	Bprint(fd, "\n");
1557dd7cddfSDavid du Colombier 	Bflush(fd);
1567dd7cddfSDavid du Colombier 	return err;
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier 
1597dd7cddfSDavid du Colombier char*
writeppm(Biobuf * fd,Image * image,char * comment)1607dd7cddfSDavid du Colombier writeppm(Biobuf *fd, Image *image, char *comment)
1617dd7cddfSDavid du Colombier {
1627dd7cddfSDavid du Colombier 	return writeppm0(fd, image, nil, image->r, image->chan, comment);
1637dd7cddfSDavid du Colombier }
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier char*
memwriteppm(Biobuf * fd,Memimage * memimage,char * comment)1667dd7cddfSDavid du Colombier memwriteppm(Biobuf *fd, Memimage *memimage, char *comment)
1677dd7cddfSDavid du Colombier {
1687dd7cddfSDavid du Colombier 	return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);
1697dd7cddfSDavid du Colombier }
170