|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <draw.h> | 
|  | #include <memdraw.h> | 
|  | #include <bio.h> | 
|  | #include "imagefile.h" | 
|  |  | 
|  | #define	MAXLINE	70 | 
|  |  | 
|  | /* | 
|  | * Write data | 
|  | */ | 
|  | static | 
|  | char* | 
|  | writedata(Biobuf *fd, Image *image, Memimage *memimage) | 
|  | { | 
|  | char *err; | 
|  | uchar *data; | 
|  | int i, x, y, ndata, depth, col, pix, xmask, pmask; | 
|  | ulong chan; | 
|  | Rectangle r; | 
|  |  | 
|  | if(memimage != nil){ | 
|  | r = memimage->r; | 
|  | depth = memimage->depth; | 
|  | chan = memimage->chan; | 
|  | }else{ | 
|  | r = image->r; | 
|  | depth = image->depth; | 
|  | chan = image->chan; | 
|  | } | 
|  |  | 
|  | /* | 
|  | * Read image data into memory | 
|  | * potentially one extra byte on each end of each scan line | 
|  | */ | 
|  | ndata = Dy(r)*(2+Dx(r)*depth/8); | 
|  | data = malloc(ndata); | 
|  | if(data == nil) | 
|  | return "WritePPM: malloc failed"; | 
|  | if(memimage != nil) | 
|  | ndata = unloadmemimage(memimage, r, data, ndata); | 
|  | else | 
|  | ndata = unloadimage(image, r, data, ndata); | 
|  | if(ndata < 0){ | 
|  | err = malloc(ERRMAX); | 
|  | if(err == nil) | 
|  | return "WritePPM: malloc failed"; | 
|  | snprint(err, ERRMAX, "WriteGIF: %r"); | 
|  | free(data); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | /* Encode and emit the data */ | 
|  | col = 0; | 
|  | switch(chan){ | 
|  | case GREY1: | 
|  | case GREY2: | 
|  | case GREY4: | 
|  | pmask = (1<<depth)-1; | 
|  | xmask = 7>>drawlog2[depth]; | 
|  | for(y=r.min.y; y<r.max.y; y++){ | 
|  | i = (y-r.min.y)*bytesperline(r, depth); | 
|  | for(x=r.min.x; x<r.max.x; x++){ | 
|  | pix = (data[i]>>depth*((xmask-x)&xmask))&pmask; | 
|  | if(((x+1)&xmask) == 0) | 
|  | i++; | 
|  | col += Bprint(fd, "%d ", pix); | 
|  | if(col >= MAXLINE-(2+1)){ | 
|  | Bprint(fd, "\n"); | 
|  | col = 0; | 
|  | }else | 
|  | col += Bprint(fd, " "); | 
|  | } | 
|  | } | 
|  | break; | 
|  | case	GREY8: | 
|  | for(i=0; i<ndata; i++){ | 
|  | col += Bprint(fd, "%d ", data[i]); | 
|  | if(col >= MAXLINE-(4+1)){ | 
|  | Bprint(fd, "\n"); | 
|  | col = 0; | 
|  | }else | 
|  | col += Bprint(fd, " "); | 
|  | } | 
|  | break; | 
|  | case RGB24: | 
|  | for(i=0; i<ndata; i+=3){ | 
|  | col += Bprint(fd, "%d %d %d", data[i+2], data[i+1], data[i]); | 
|  | if(col >= MAXLINE-(4+4+4+1)){ | 
|  | Bprint(fd, "\n"); | 
|  | col = 0; | 
|  | }else | 
|  | col += Bprint(fd, " "); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | return "WritePPM: can't handle channel type"; | 
|  | } | 
|  |  | 
|  | return nil; | 
|  | } | 
|  |  | 
|  | static | 
|  | char* | 
|  | writeppm0(Biobuf *fd, Image *image, Memimage *memimage, Rectangle r, int chan, char *comment) | 
|  | { | 
|  | char *err; | 
|  |  | 
|  | switch(chan){ | 
|  | case GREY1: | 
|  | Bprint(fd, "P1\n"); | 
|  | break; | 
|  | case GREY2: | 
|  | case GREY4: | 
|  | case	GREY8: | 
|  | Bprint(fd, "P2\n"); | 
|  | break; | 
|  | case RGB24: | 
|  | Bprint(fd, "P3\n"); | 
|  | break; | 
|  | default: | 
|  | return "WritePPM: can't handle channel type"; | 
|  | } | 
|  |  | 
|  | if(comment!=nil && comment[0]!='\0'){ | 
|  | Bprint(fd, "# %s", comment); | 
|  | if(comment[strlen(comment)-1] != '\n') | 
|  | Bprint(fd, "\n"); | 
|  | } | 
|  | Bprint(fd, "%d %d\n", Dx(r), Dy(r)); | 
|  |  | 
|  | /* maximum pixel value */ | 
|  | switch(chan){ | 
|  | case GREY2: | 
|  | Bprint(fd, "%d\n", 3); | 
|  | break; | 
|  | case GREY4: | 
|  | Bprint(fd, "%d\n", 15); | 
|  | break; | 
|  | case	GREY8: | 
|  | case RGB24: | 
|  | Bprint(fd, "%d\n", 255); | 
|  | break; | 
|  | } | 
|  |  | 
|  | err = writedata(fd, image, memimage); | 
|  |  | 
|  | Bprint(fd, "\n"); | 
|  | Bflush(fd); | 
|  | return err; | 
|  | } | 
|  |  | 
|  | char* | 
|  | writeppm(Biobuf *fd, Image *image, char *comment) | 
|  | { | 
|  | return writeppm0(fd, image, nil, image->r, image->chan, comment); | 
|  | } | 
|  |  | 
|  | char* | 
|  | memwriteppm(Biobuf *fd, Memimage *memimage, char *comment) | 
|  | { | 
|  | return writeppm0(fd, nil, memimage, memimage->r, memimage->chan, comment); | 
|  | } |