aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/jpg/writeppm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/jpg/writeppm.c')
-rw-r--r--src/cmd/jpg/writeppm.c164
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);
+}