xref: /plan9/sys/src/cmd/jpg/writeppm.c (revision bacfa46c74e1c310aff15aef9cb6bc4e6302513a)
1 #include <u.h>
2 #include <libc.h>
3 #include <draw.h>
4 #include <memdraw.h>
5 #include <bio.h>
6 
7 #define	MAXLINE	70
8 
9 /* imported from libdraw/arith.c to permit an extern log2 function */
10 static int log2[] = {
11 	-1, 0, 1, -1, 2, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, 4,
12 	-1, -1, -1, -1, -1, -1, -1, 4 /* BUG */, -1, -1, -1, -1, -1, -1, -1, 5
13 };
14 
15 /*
16  * Write data
17  */
18 static
19 char*
writedata(Biobuf * fd,Image * image,Memimage * memimage)20 writedata(Biobuf *fd, Image *image, Memimage *memimage)
21 {
22 	char *err;
23 	uchar *data;
24 	int i, x, y, ndata, depth, col, pix, xmask, pmask;
25 	ulong chan;
26 	Rectangle r;
27 
28 	if(memimage != nil){
29 		r = memimage->r;
30 		depth = memimage->depth;
31 		chan = memimage->chan;
32 	}else{
33 		r = image->r;
34 		depth = image->depth;
35 		chan = image->chan;
36 	}
37 
38 	/*
39 	 * Read image data into memory
40 	 * potentially one extra byte on each end of each scan line
41 	 */
42 	ndata = Dy(r)*(2+Dx(r)*depth/8);
43 	data = malloc(ndata);
44 	if(data == nil)
45 		return "WritePPM: malloc failed";
46 	if(memimage != nil)
47 		ndata = unloadmemimage(memimage, r, data, ndata);
48 	else
49 		ndata = unloadimage(image, r, data, ndata);
50 	if(ndata < 0){
51 		err = malloc(ERRMAX);
52 		if(err == nil)
53 			return "WritePPM: malloc failed";
54 		snprint(err, ERRMAX, "WriteGIF: %r");
55 		free(data);
56 		return err;
57 	}
58 
59 	/* Encode and emit the data */
60 	col = 0;
61 	switch(chan){
62 	case GREY1:
63 	case GREY2:
64 	case GREY4:
65 		pmask = (1<<depth)-1;
66 		xmask = 7>>log2[depth];
67 		for(y=r.min.y; y<r.max.y; y++){
68 			i = (y-r.min.y)*bytesperline(r, depth);
69 			for(x=r.min.x; x<r.max.x; x++){
70 				pix = (data[i]>>depth*((xmask-x)&xmask))&pmask;
71 				if(((x+1)&xmask) == 0)
72 					i++;
73 				col += Bprint(fd, "%d ", pix);
74 				if(col >= MAXLINE-(2+1)){
75 					Bprint(fd, "\n");
76 					col = 0;
77 				}else
78 					col += Bprint(fd, " ");
79 			}
80 		}
81 		break;
82 	case	GREY8:
83 		for(i=0; i<ndata; i++){
84 			col += Bprint(fd, "%d ", data[i]);
85 			if(col >= MAXLINE-(4+1)){
86 				Bprint(fd, "\n");
87 				col = 0;
88 			}else
89 				col += Bprint(fd, " ");
90 		}
91 		break;
92 	case RGB24:
93 		for(i=0; i<ndata; i+=3){
94 			col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]);
95 			if(col >= MAXLINE-(4+4+4+1)){
96 				Bprint(fd, "\n");
97 				col = 0;
98 			}else
99 				col += Bprint(fd, " ");
100 		}
101 		break;
102 	default:
103 		return "WritePPM: can't handle channel type";
104 	}
105 
106 	return nil;
107 }
108 
109 static
110 char*
writeppm0(Biobuf * fd,Image * image,Memimage * memimage,Rectangle r,int chan,char * comment)111 writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment)
112 {
113 	char *err;
114 
115 	switch(chan){
116 	case GREY1:
117 		Bprint(fd, "P1\n");
118 		break;
119 	case GREY2:
120 	case GREY4:
121 	case	GREY8:
122 		Bprint(fd, "P2\n");
123 		break;
124 	case RGB24:
125 		Bprint(fd, "P3\n");
126 		break;
127 	default:
128 		return "WritePPM: can't handle channel type";
129 	}
130 
131 	if(comment!=nil && comment[0]!='\0'){
132 		Bprint(fd, "# %s", comment);
133 		if(comment[strlen(comment)-1] != '\n')
134 			Bprint(fd, "\n");
135 	}
136 	Bprint(fd, "%d %d\n", Dx(r), Dy(r));
137 
138 	/* maximum pixel value */
139 	switch(chan){
140 	case GREY2:
141 		Bprint(fd, "%d\n", 3);
142 		break;
143 	case GREY4:
144 		Bprint(fd, "%d\n", 15);
145 		break;
146 	case	GREY8:
147 	case RGB24:
148 		Bprint(fd, "%d\n", 255);
149 		break;
150 	}
151 
152 	err = writedata(fd, image, memimage);
153 
154 	Bprint(fd, "\n");
155 	Bflush(fd);
156 	return err;
157 }
158 
159 char*
writeppm(Biobuf * fd,Image * image,char * comment)160 writeppm(Biobuf *fd, Image *image, char *comment)
161 {
162 	return writeppm0(fd, image, nil, image->r, image->chan, comment);
163 }
164 
165 char*
memwriteppm(Biobuf * fd,Memimage * memimage,char * comment)166 memwriteppm(Biobuf *fd, Memimage *memimage, char *comment)
167 {
168 	return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);
169 }
170