aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/jpg/readppm.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/jpg/readppm.c')
-rw-r--r--src/cmd/jpg/readppm.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/src/cmd/jpg/readppm.c b/src/cmd/jpg/readppm.c
new file mode 100644
index 00000000..28b7f4ea
--- /dev/null
+++ b/src/cmd/jpg/readppm.c
@@ -0,0 +1,238 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <ctype.h>
+#include "imagefile.h"
+
+Rawimage *readppm(Biobuf*, Rawimage*);
+
+/*
+ * fetch a non-comment character.
+ */
+static
+int
+Bgetch(Biobuf *b)
+{
+ int c;
+
+ for(;;) {
+ c = Bgetc(b);
+ if(c == '#') {
+ while((c = Bgetc(b)) != Beof && c != '\n')
+ ;
+ }
+ return c;
+ }
+}
+
+/*
+ * fetch a nonnegative decimal integer.
+ */
+static
+int
+Bgetint(Biobuf *b)
+{
+ int c;
+ int i;
+
+ while((c = Bgetch(b)) != Beof && !isdigit(c))
+ ;
+ if(c == Beof)
+ return -1;
+
+ i = 0;
+ do {
+ i = i*10 + (c-'0');
+ } while((c = Bgetch(b)) != Beof && isdigit(c));
+
+ return i;
+}
+
+static
+int
+Bgetdecimalbit(Biobuf *b)
+{
+ int c;
+ while((c = Bgetch(b)) != Beof && c != '0' && c != '1')
+ ;
+ if(c == Beof)
+ return -1;
+ return c == '1';
+}
+
+static int bitc, nbit;
+
+static
+int
+Bgetbit(Biobuf *b)
+{
+ if(nbit == 0) {
+ nbit = 8;
+ bitc = Bgetc(b);
+ if(bitc == -1)
+ return -1;
+ }
+ nbit--;
+ return (bitc >> (nbit-1)) & 0x1;
+}
+
+static
+void
+Bflushbit(Biobuf *b)
+{
+ USED(b);
+ nbit = 0;
+}
+
+
+Rawimage**
+readpixmap(int fd, int colorspace)
+{
+ Rawimage **array, *a;
+ Biobuf b;
+ char buf[ERRMAX];
+ int i;
+ char *e;
+
+ USED(colorspace);
+ if(Binit(&b, fd, OREAD) < 0)
+ return nil;
+
+ werrstr("");
+ e = "out of memory";
+ if((array = malloc(sizeof *array)) == nil)
+ goto Error;
+ if((array[0] = malloc(sizeof *array[0])) == nil)
+ goto Error;
+ memset(array[0], 0, sizeof *array[0]);
+
+ for(i=0; i<3; i++)
+ array[0]->chans[i] = nil;
+
+ e = "bad file format";
+ switch(Bgetc(&b)) {
+ case 'P':
+ Bungetc(&b);
+ a = readppm(&b, array[0]);
+ break;
+ default:
+ a = nil;
+ break;
+ }
+ if(a == nil)
+ goto Error;
+ array[0] = a;
+
+ return array;
+
+Error:
+ if(array)
+ free(array[0]);
+ free(array);
+
+ errstr(buf, sizeof buf);
+ if(buf[0] == 0)
+ strcpy(buf, e);
+ errstr(buf, sizeof buf);
+
+ return nil;
+}
+
+typedef struct Pix Pix;
+struct Pix {
+ char magic;
+ int maxcol;
+ int (*fetch)(Biobuf*);
+ int nchan;
+ int chandesc;
+ int invert;
+ void (*flush)(Biobuf*);
+};
+
+static Pix pix[] = {
+ { '1', 1, Bgetdecimalbit, 1, CY, 1, nil }, /* portable bitmap */
+ { '4', 1, Bgetbit, 1, CY, 1, Bflushbit }, /* raw portable bitmap */
+ { '2', 0, Bgetint, 1, CY, 0, nil }, /* portable greymap */
+ { '5', 0, Bgetc, 1, CY, 0, nil }, /* raw portable greymap */
+ { '3', 0, Bgetint, 3, CRGB, 0, nil }, /* portable pixmap */
+ { '6', 0, Bgetc, 3, CRGB, 0, nil }, /* raw portable pixmap */
+ { 0 },
+};
+
+Rawimage*
+readppm(Biobuf *b, Rawimage *a)
+{
+ int i, ch, wid, ht, r, c;
+ int maxcol, nchan, invert;
+ int (*fetch)(Biobuf*);
+ uchar *rgb[3];
+ char buf[ERRMAX];
+ char *e;
+ Pix *p;
+
+ e = "bad file format";
+ if(Bgetc(b) != 'P')
+ goto Error;
+
+ c = Bgetc(b);
+ for(p=pix; p->magic; p++)
+ if(p->magic == c)
+ break;
+ if(p->magic == 0)
+ goto Error;
+
+
+ wid = Bgetint(b);
+ ht = Bgetint(b);
+ if(wid <= 0 || ht <= 0)
+ goto Error;
+ a->r = Rect(0,0,wid,ht);
+
+ maxcol = p->maxcol;
+ if(maxcol == 0) {
+ maxcol = Bgetint(b);
+ if(maxcol <= 0)
+ goto Error;
+ }
+
+ e = "out of memory";
+ for(i=0; i<p->nchan; i++)
+ if((rgb[i] = a->chans[i] = malloc(wid*ht)) == nil)
+ goto Error;
+ a->nchans = p->nchan;
+ a->chanlen = wid*ht;
+ a->chandesc = p->chandesc;
+
+ e = "error reading file";
+
+ fetch = p->fetch;
+ nchan = p->nchan;
+ invert = p->invert;
+ for(r=0; r<ht; r++) {
+ for(c=0; c<wid; c++) {
+ for(i=0; i<nchan; i++) {
+ if((ch = (*fetch)(b)) < 0)
+ goto Error;
+ if(invert)
+ ch = maxcol - ch;
+ *rgb[i]++ = (ch * 255)/maxcol;
+ }
+ }
+ if(p->flush)
+ (*p->flush)(b);
+ }
+
+ return a;
+
+Error:
+ errstr(buf, sizeof buf);
+ if(buf[0] == 0)
+ strcpy(buf, e);
+ errstr(buf, sizeof buf);
+
+ for(i=0; i<3; i++)
+ free(a->chans[i]);
+ free(a->cmap);
+ return nil;
+}