Blob


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