diff options
Diffstat (limited to 'src/cmd/jpg/writeppm.c')
-rw-r--r-- | src/cmd/jpg/writeppm.c | 164 |
1 files changed, 164 insertions, 0 deletions
diff --git a/src/cmd/jpg/writeppm.c b/src/cmd/jpg/writeppm.c new file mode 100644 index 00000000..c8378652 --- /dev/null +++ b/src/cmd/jpg/writeppm.c @@ -0,0 +1,164 @@ +#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); +} |