shithub: pcx

Download patch

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;
+}