ref: 2050117574a823625a28699e6735de0ff725ce76
author: qwx <qwx@sciops.net>
date: Mon May 27 19:40:46 EDT 2019
initial import
--- /dev/null
+++ b/README
@@ -1,0 +1,6 @@
+todo:
+- other (common) pcx formats
+- -9, -t and other necessary options a la jpg/*
+- make it work with page
+- better installation shit
+- topcx
--- /dev/null
+++ b/fns.h
@@ -1,0 +1,2 @@
+/* FIXME: nuke header */
+Rawimage** Breadpcx(Biobuf *, int);
--- /dev/null
+++ b/mkfile
@@ -1,0 +1,9 @@
+</$objtype/mkfile
+
+BIN=$home/bin/$objtype
+TARG=pcx
+
+OFILES=pcx.$O readpcx.$O
+HFILES=fns.h
+
+</sys/src/cmd/mkone
--- /dev/null
+++ b/pcx.c
@@ -1,0 +1,152 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include <keyboard.h>
+/* FIXME */
+#include "/sys/src/cmd/jpg/imagefile.h"
+#include "fns.h"
+
+enum{
+ Border = 2
+};
+
+int dflag;
+int nineflag;
+int debug;
+Image *image;
+
+
+static Rectangle
+imager(Image *i)
+{
+ Point p1, p2;
+
+ p1 = addpt(divpt(subpt(i->r.max, i->r.min), 2), i->r.min);
+ p2 = addpt(divpt(subpt(screen->clipr.max, screen->clipr.min), 2), screen->clipr.min);
+ return rectaddpt(i->r, subpt(p2, p1));
+}
+
+void
+eresized(int new)
+{
+ Rectangle r;
+
+ if(new && getwindow(display, Refnone) < 0){
+ fprint(2, "pcx: can't reattach to window\n");
+ exits("resize");
+ }
+ if(image == nil)
+ return;
+ r = imager(image);
+ border(screen, r, -Border, nil, ZP);
+ draw(screen, r, image, nil, image->r.min);
+ flushimage(display, 1);
+}
+
+static char *
+show(int fd, char *name)
+{
+ int c, j;
+ char s[9];
+ Rawimage **ra, *r;
+ Biobuf b;
+ Image *i, *i2;
+
+ if(Binit(&b, fd, OREAD) < 0)
+ return nil;
+ ra = Breadpcx(&b, CRGB);
+ if(ra == nil || ra[0] == nil){
+ fprint(2, "pcx: decode %s failed: %r\n", name);
+ return "decode";
+ }
+ Bterm(&b);
+
+ r = ra[0];
+ /* FIXME: set colorchan for given format (from readpcx) */
+
+ if(!dflag){
+ i = allocimage(display, r->r, RGB24, 0, 0);
+ if(i == nil){
+ fprint(2, "pcx: allocimage %s failed: %r\n", name);
+ return "allocimage";
+ }
+ if(loadimage(i, i->r, r->chans[0], r->chanlen) < 0){
+ fprint(2, "pcx: loadimage %s of %d bytes failed: %r\n",
+ name, r->chanlen);
+ return "loadimage";
+ }
+ i2 = allocimage(display, r->r, RGB24, 0, 0);
+ draw(i2, i2->r, display->black, nil, ZP);
+ draw(i2, i2->r, i, nil, i->r.min);
+ image = i2;
+ eresized(0);
+ if((c = ekbd()) == 'q' || c == Kdel || c == Keof)
+ exits(nil);
+ draw(screen, screen->clipr, display->white, nil, ZP);
+ image = nil;
+ freeimage(i);
+ }
+ if(nineflag){
+ print("%11s %11d %11d %11d %11d ",
+ chantostr(s, RGB24), 0, 0, r->r.max.x, r->r.max.y);
+ write(1, r->chans[0], r->chanlen);
+ }
+ for(j=0; j<r->nchans; j++)
+ free(r->chans[j]);
+ free(r->cmap);
+ free(r);
+ free(ra);
+ return nil;
+}
+
+void
+main(int argc, char *argv[])
+{
+ int i, fd;
+ char *err;
+
+ ARGBEGIN{
+ case 'D':
+ debug++;
+ break;
+ case 'd': /* suppress display of image */
+ dflag++;
+ break;
+ case 't':
+ break;
+ case '9':
+ nineflag++;
+ dflag++;
+ break;
+ default:
+ fprint(2, "usage: pcx [-t9] [file.pcx ...]\n");
+ exits("usage");
+ }ARGEND;
+
+ if(!dflag){
+ if(initdraw(nil, nil, nil) < 0){
+ fprint(2, "pcx: initdraw failed: %r\n");
+ exits("initdraw");
+ }
+ einit(Ekeyboard|Emouse);
+ }
+
+ err = nil;
+ if(argc == 0)
+ err = show(0, "<stdin>");
+ else{
+ for(i=0; i<argc; i++){
+ fd = open(argv[i], OREAD);
+ if(fd < 0){
+ fprint(2, "pcx: can't open %s: %r\n", argv[i]);
+ err = "open";
+ }else{
+ err = show(fd, argv[i]);
+ close(fd);
+ }
+ }
+ }
+ exits(err);
+}
--- /dev/null
+++ b/readpcx.c
@@ -1,0 +1,146 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+/* FIXME */
+#include "/sys/src/cmd/jpg/imagefile.h"
+#include "fns.h"
+
+extern int debug;
+
+typedef struct Header Header;
+struct Header{
+ u8int id;
+ u8int ver;
+ u8int bpp;
+ u16int xmin;
+ u16int ymin;
+ u16int xmax;
+ u16int ymax;
+ u8int egapal[48];
+ u8int np;
+ u16int bpl;
+ u16int ptyp;
+};
+
+enum{
+ Hdrsz = 128
+};
+
+
+static void *
+emalloc(ulong n)
+{
+ void *p;
+
+ p = mallocz(n, 1);
+ if(p == nil)
+ sysfatal("mallocz: %r");
+ return p;
+}
+
+static void
+readheader(Biobuf *b, Header *h)
+{
+ uchar buf[Hdrsz];
+
+ if(Bread(b, buf, sizeof buf) != sizeof buf)
+ sysfatal("ReadPCX: can't read header: %r");
+ h->id = buf[0];
+ if(h->id != 10)
+ sysfatal("ReadPCX: bad id %ux", h->id);
+ h->ver = buf[1];
+ h->bpp = buf[3];
+ h->xmin = buf[4] | buf[5] << 8;
+ h->ymin = buf[6] | buf[7] << 8;
+ h->xmax = buf[8] | buf[9] << 8;
+ h->ymax = buf[10] | buf[11] << 8;
+ memcpy(h->egapal, buf+16, sizeof h->egapal);
+ h->np = buf[65];
+ h->bpl = buf[66] | buf[67] << 8;
+ h->ptyp = buf[68] | buf[69] << 8;
+}
+
+static Rawimage*
+readslave(Biobuf *b)
+{
+ int w, h, t, hlen, pad;
+ uint x;
+ char c;
+ uchar pal[3*256], *p, *end;
+ Rawimage *r;
+ Header *hd;
+
+ hd = emalloc(sizeof *hd);
+ readheader(b, hd);
+
+ w = hd->xmax - hd->xmin + 1;
+ h = hd->ymax - hd->ymin + 1;
+ t = w * h;
+ hlen = hd->np * hd->bpl;
+ pad = 8 / hd->bpp * hlen - w;
+ if(debug)
+ fprint(2, "pcx: v.%d pt.%d %dx%dx%d in %dx%d, %d padded\n",
+ hd->ver, hd->ptyp, w, h, hd->bpp, hd->np, hd->bpl, pad);
+
+ r = emalloc(sizeof *r);
+ r->r = Rect(0, 0, w, h);
+
+ switch(hd->ver){
+ case 5:
+ t *= 3;
+ r->nchans = 1;
+ r->chandesc = CRGB24;
+ r->chanlen = t;
+ r->chans[0] = emalloc(t);
+ p = r->chans[0];
+ end = p + t;
+ while(p < end){
+ x = 1;
+ c = Bgetc(b);
+ if((c & 0xc0) == 0xc0){
+ x = c & 0x3f;
+ c = Bgetc(b);
+ }
+ while(x-- > 0 && p < end){
+ *p = c;
+ p += 3;
+ }
+ }
+
+ Bseek(b, -769, 2);
+ if(Bgetc(b) == 0xc){
+ if(Bread(b, pal, sizeof pal) != sizeof pal)
+ sysfatal("ReadPCX: bad vga palette");
+ p = r->chans[0];
+ while(p < end){
+ x = *p;
+ *p++ = pal[x*3+2];
+ *p++ = pal[x*3+1];
+ *p++ = pal[x*3];
+ }
+ }
+ break;
+ default: /* FIXME: other pcx types */
+ sysfatal("ReadPCX: unsupported version %d\n", hd->ver);
+ }
+
+ free(hd);
+ return r;
+}
+
+Rawimage**
+Breadpcx(Biobuf *b, int colorspace)
+{
+ Rawimage **ra;
+
+ if(colorspace != CRGB){
+ werrstr("ReadPCX: unknown color space %d", colorspace);
+ return nil;
+ }
+ ra = emalloc(2 * sizeof *ra); /* why */
+
+ ra[0] = readslave(b);
+ ra[1] = nil;
+ return ra;
+}