writeppm.c (3098B)
1 #include <u.h> 2 #include <libc.h> 3 #include <draw.h> 4 #include <memdraw.h> 5 #include <bio.h> 6 #include "imagefile.h" 7 8 #define MAXLINE 70 9 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; 22 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 } 32 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 } 53 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 } 100 101 return nil; 102 } 103 104 static 105 char* 106 writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment) 107 { 108 char *err; 109 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"; 124 } 125 126 if(comment!=nil && comment[0]!='\0'){ 127 Bprint(fd, "# %s", comment); 128 if(comment[strlen(comment)-1] != '\n') 129 Bprint(fd, "\n"); 130 } 131 Bprint(fd, "%d %d\n", Dx(r), Dy(r)); 132 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; 145 } 146 147 err = writedata(fd, image, memimage); 148 149 Bprint(fd, "\n"); 150 Bflush(fd); 151 return err; 152 } 153 154 char* 155 writeppm(Biobuf *fd, Image *image, char *comment) 156 { 157 return writeppm0(fd, image, nil, image->r, image->chan, comment); 158 } 159 160 char* 161 memwriteppm(Biobuf *fd, Memimage *memimage, char *comment) 162 { 163 return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment); 164 }