]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/jpg/writeppm.c
kbdfs: simplfy
[plan9front.git] / sys / src / cmd / jpg / writeppm.c
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*
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*
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*
160 writeppm(Biobuf *fd, Image *image, char *comment)
161 {
162         return writeppm0(fd, image, nil, image->r, image->chan, comment);
163 }
164
165 char*
166 memwriteppm(Biobuf *fd, Memimage *memimage, char *comment)
167 {
168         return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment);
169 }