aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/jpg/ico.c
diff options
context:
space:
mode:
authorrsc <devnull@localhost>2004-04-21 22:19:33 +0000
committerrsc <devnull@localhost>2004-04-21 22:19:33 +0000
commit28994509cc11ac6a5443054dfae1fedfb69039bc (patch)
tree9d5adcd11af2708db0ecc246e008c308ca0f97d4 /src/cmd/jpg/ico.c
parenta01e58366c54804f15f84d6e21d13f2e4080977a (diff)
downloadplan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.tar.gz
plan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.tar.bz2
plan9port-28994509cc11ac6a5443054dfae1fedfb69039bc.zip
Why not?
Diffstat (limited to 'src/cmd/jpg/ico.c')
-rw-r--r--src/cmd/jpg/ico.c506
1 files changed, 506 insertions, 0 deletions
diff --git a/src/cmd/jpg/ico.c b/src/cmd/jpg/ico.c
new file mode 100644
index 00000000..31806afb
--- /dev/null
+++ b/src/cmd/jpg/ico.c
@@ -0,0 +1,506 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <draw.h>
+#include <event.h>
+#include <cursor.h>
+
+typedef struct Icon Icon;
+struct Icon
+{
+ Icon *next;
+
+ uchar w; /* icon width */
+ uchar h; /* icon height */
+ ushort ncolor; /* number of colors */
+ ushort nplane; /* number of bit planes */
+ ushort bits; /* bits per pixel */
+ ulong len; /* length of data */
+ ulong offset; /* file offset to data */
+
+ Image *img;
+ Image *mask;
+
+ Rectangle r; /* relative */
+ Rectangle sr; /* abs */
+};
+
+typedef struct Header Header;
+struct Header
+{
+ uint n;
+ Icon *first;
+ Icon *last;
+};
+
+int debug;
+Mouse mouse;
+Header h;
+Image *background;
+
+ushort
+gets(uchar *p)
+{
+ return p[0] | (p[1]<<8);
+}
+
+ulong
+getl(uchar *p)
+{
+ return p[0] | (p[1]<<8) | (p[2]<<16) | (p[3]<<24);
+}
+
+int
+Bgetheader(Biobuf *b, Header *h)
+{
+ Icon *icon;
+ int i;
+ uchar buf[40];
+
+ memset(h, 0, sizeof(*h));
+ if(Bread(b, buf, 6) != 6)
+ goto eof;
+ if(gets(&buf[0]) != 0)
+ goto header;
+ if(gets(&buf[2]) != 1)
+ goto header;
+ h->n = gets(&buf[4]);
+
+ for(i = 0; i < h->n; i++){
+ icon = mallocz(sizeof(*icon), 1);
+ if(icon == nil)
+ sysfatal("malloc: %r");
+ if(Bread(b, buf, 16) != 16)
+ goto eof;
+ icon->w = buf[0];
+ icon->h = buf[1];
+ icon->ncolor = buf[2] == 0 ? 256 : buf[2];
+ if(buf[3] != 0)
+ goto header;
+ icon->nplane = gets(&buf[4]);
+ icon->bits = gets(&buf[6]);
+ icon->len = getl(&buf[8]);
+ icon->offset = getl(&buf[12]);
+
+ if(i == 0)
+ h->first = icon;
+ else
+ h->last->next = icon;
+ h->last = icon;
+ }
+ return 0;
+
+eof:
+ werrstr("unexpected EOF");
+ return -1;
+header:
+ werrstr("unknown header format");
+ return -1;
+}
+
+uchar*
+transcmap(Icon *icon, uchar *map)
+{
+ uchar *m, *p;
+ int i;
+
+ p = m = malloc(sizeof(int)*(1<<icon->bits));
+ for(i = 0; i < icon->ncolor; i++){
+ *p++ = rgb2cmap(map[2], map[1], map[0]);
+ map += 4;
+ }
+ return m;
+}
+
+Image*
+xor2img(Icon *icon, uchar *xor, uchar *map)
+{
+ uchar *data;
+ Image *img;
+ int inxlen;
+ uchar *from, *to;
+ int s, byte, mask;
+ int x, y;
+
+ inxlen = 4*((icon->bits*icon->w+31)/32);
+ to = data = malloc(icon->w*icon->h);
+
+ /* rotate around the y axis, go to 8 bits, and convert color */
+ mask = (1<<icon->bits)-1;
+ for(y = 0; y < icon->h; y++){
+ s = -1;
+ byte = 0;
+ from = xor + (icon->h - 1 - y)*inxlen;
+ for(x = 0; x < icon->w; x++){
+ if(s < 0){
+ byte = *from++;
+ s = 8-icon->bits;
+ }
+ *to++ = map[(byte>>s) & mask];
+ s -= icon->bits;
+ }
+ }
+
+ /* stick in an image */
+ img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill);
+ loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
+
+ free(data);
+ return img;
+}
+
+Image*
+and2img(Icon *icon, uchar *and)
+{
+ uchar *data;
+ Image *img;
+ int inxlen;
+ int outxlen;
+ uchar *from, *to;
+ int x, y;
+
+ inxlen = 4*((icon->w+31)/32);
+ to = data = malloc(inxlen*icon->h);
+
+ /* rotate around the y axis and invert bits */
+ outxlen = (icon->w+7)/8;
+ for(y = 0; y < icon->h; y++){
+ from = and + (icon->h - 1 - y)*inxlen;
+ for(x = 0; x < outxlen; x++){
+ *to++ = ~(*from++);
+ }
+ }
+
+ /* stick in an image */
+ img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill);
+ loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
+
+ free(data);
+ return img;
+}
+
+int
+Bgeticon(Biobuf *b, Icon *icon)
+{
+ ulong l;
+ ushort s;
+ uchar *xor;
+ uchar *and;
+ uchar *cm;
+ uchar *buf;
+ uchar *map2map;
+ Image *img;
+
+ Bseek(b, icon->offset, 0);
+ buf = malloc(icon->len);
+ if(buf == nil)
+ return -1;
+ if(Bread(b, buf, icon->len) != icon->len){
+ werrstr("unexpected EOF");
+ return -1;
+ }
+
+ /* this header's info takes precedence over previous one */
+ if(getl(buf) != 40){
+ werrstr("bad icon header");
+ return -1;
+ }
+ l = getl(buf+4);
+ if(l != icon->w)
+ icon->w = l;
+ l = getl(buf+8);
+ if(l>>1 != icon->h)
+ icon->h = l>>1;
+ s = gets(buf+12);
+ if(s != icon->nplane)
+ icon->nplane = s;
+ s = gets(buf+14);
+ if(s != icon->bits)
+ icon->bits = s;
+
+ /* limit what we handle */
+ switch(icon->bits){
+ case 1:
+ case 2:
+ case 4:
+ case 8:
+ break;
+ default:
+ werrstr("don't support %d bit pixels", icon->bits);
+ return -1;
+ }
+ if(icon->nplane != 1){
+ werrstr("don't support %d planes", icon->nplane);
+ return -1;
+ }
+
+ cm = buf + 40;
+ xor = cm + 4*icon->ncolor;
+ and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
+
+ /* translate the color map to a plan 9 one */
+ map2map = transcmap(icon, cm);
+
+ /* convert the images */
+ icon->img = xor2img(icon, xor, map2map);
+ icon->mask = and2img(icon, and);
+
+ /* so that we save an image with a white background */
+ img = allocimage(display, icon->img->r, CMAP8, 0, DWhite);
+ draw(img, icon->img->r, icon->img, icon->mask, ZP);
+ icon->img = img;
+
+ free(buf);
+ free(map2map);
+ return 0;
+}
+
+void
+usage(void)
+{
+ fprint(2, "usage: %s [file]\n", argv0);
+ exits("usage");
+}
+
+enum
+{
+ Mimage,
+ Mmask,
+ Mexit,
+
+ Up= 1,
+ Down= 0,
+};
+
+char *menu3str[] = {
+ [Mimage] "write image",
+ [Mmask] "write mask",
+ [Mexit] "exit",
+ 0,
+};
+
+Menu menu3 = {
+ menu3str
+};
+
+Cursor sight = {
+ {-7, -7},
+ {0x1F, 0xF8, 0x3F, 0xFC, 0x7F, 0xFE, 0xFB, 0xDF,
+ 0xF3, 0xCF, 0xE3, 0xC7, 0xFF, 0xFF, 0xFF, 0xFF,
+ 0xFF, 0xFF, 0xFF, 0xFF, 0xE3, 0xC7, 0xF3, 0xCF,
+ 0x7B, 0xDF, 0x7F, 0xFE, 0x3F, 0xFC, 0x1F, 0xF8,},
+ {0x00, 0x00, 0x0F, 0xF0, 0x31, 0x8C, 0x21, 0x84,
+ 0x41, 0x82, 0x41, 0x82, 0x41, 0x82, 0x7F, 0xFE,
+ 0x7F, 0xFE, 0x41, 0x82, 0x41, 0x82, 0x41, 0x82,
+ 0x21, 0x84, 0x31, 0x8C, 0x0F, 0xF0, 0x00, 0x00,}
+};
+
+void
+buttons(int ud)
+{
+ while((mouse.buttons==0) != ud)
+ mouse = emouse();
+}
+
+void
+mesg(char *fmt, ...)
+{
+ va_list arg;
+ char buf[1024];
+ static char obuf[1024];
+
+ va_start(arg, fmt);
+ vseprint(buf, buf+sizeof(buf), fmt, arg);
+ va_end(arg);
+ string(screen, screen->r.min, background, ZP, font, obuf);
+ string(screen, screen->r.min, display->white, ZP, font, buf);
+ strcpy(obuf, buf);
+}
+
+void
+doimage(Icon *icon)
+{
+ int rv;
+ char file[256];
+ int fd;
+
+ rv = -1;
+ snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
+ fd = create(file, OWRITE, 0664);
+ if(fd >= 0){
+ rv = writeimage(fd, icon->img, 0);
+ close(fd);
+ }
+ if(rv < 0)
+ mesg("error writing %s: %r", file);
+ else
+ mesg("created %s", file);
+}
+
+void
+domask(Icon *icon)
+{
+ int rv;
+ char file[64];
+ int fd;
+
+ rv = -1;
+ snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
+ fd = create(file, OWRITE, 0664);
+ if(fd >= 0){
+ rv = writeimage(fd, icon->mask, 0);
+ close(fd);
+ }
+ if(rv < 0)
+ mesg("error writing %s: %r", file);
+ else
+ mesg("created %s", file);
+}
+
+void
+apply(void (*f)(Icon*))
+{
+ Icon *icon;
+
+ esetcursor(&sight);
+ buttons(Down);
+ if(mouse.buttons == 4)
+ for(icon = h.first; icon; icon = icon->next)
+ if(ptinrect(mouse.xy, icon->sr)){
+ buttons(Up);
+ f(icon);
+ break;
+ }
+ buttons(Up);
+ esetcursor(0);
+}
+
+void
+menu(void)
+{
+ int sel;
+
+ sel = emenuhit(3, &mouse, &menu3);
+ switch(sel){
+ case Mimage:
+ apply(doimage);
+ break;
+ case Mmask:
+ apply(domask);
+ break;
+ case Mexit:
+ exits(0);
+ break;
+ }
+}
+
+void
+mousemoved(void)
+{
+ Icon *icon;
+
+ for(icon = h.first; icon; icon = icon->next)
+ if(ptinrect(mouse.xy, icon->sr)){
+ mesg("%dx%d", icon->w, icon->h);
+ return;
+ }
+ mesg("");
+}
+
+enum
+{
+ BORDER= 1,
+};
+
+void
+eresized(int new)
+{
+ Icon *icon;
+ Rectangle r;
+
+ if(new && getwindow(display, Refnone) < 0)
+ sysfatal("can't reattach to window");
+ draw(screen, screen->clipr, background, nil, ZP);
+ r.max.x = screen->r.min.x;
+ r.min.y = screen->r.min.y + font->height + 2*BORDER;
+ for(icon = h.first; icon != nil; icon = icon->next){
+ r.min.x = r.max.x + BORDER;
+ r.max.x = r.min.x + Dx(icon->img->r);
+ r.max.y = r.min.y + Dy(icon->img->r);
+ draw(screen, r, icon->img, nil, ZP);
+ border(screen, r, -BORDER, display->black, ZP);
+ icon->sr = r;
+ }
+ flushimage(display, 1);
+}
+
+void
+main(int argc, char **argv)
+{
+ Biobuf in;
+ Icon *icon;
+ int fd;
+ Rectangle r;
+ Event e;
+
+ ARGBEGIN{
+ case 'd':
+ debug = 1;
+ break;
+ }ARGEND;
+
+ fd = -1;
+ switch(argc){
+ case 0:
+ fd = 0;
+ break;
+ case 1:
+ fd = open(argv[0], OREAD);
+ if(fd < 0)
+ sysfatal("opening: %r");
+ break;
+ default:
+ usage();
+ break;
+ }
+
+ Binit(&in, fd, OREAD);
+
+ if(Bgetheader(&in, &h) < 0)
+ sysfatal("reading header: %r");
+
+ initdraw(nil, nil, "ico");
+ background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, (128<<24)|(128<<16)|(128<<8)|0xFF);
+
+ einit(Emouse|Ekeyboard);
+
+ r.min = Pt(4, 4);
+ for(icon = h.first; icon != nil; icon = icon->next){
+ if(Bgeticon(&in, icon) < 0){
+ fprint(2, "bad rectangle: %r\n");
+ continue;
+ }
+ if(debug)
+ fprint(2, "w %ud h %ud ncolor %ud bits %ud len %lud offset %lud\n",
+ icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
+ r.max = addpt(r.min, Pt(icon->w, icon->h));
+ icon->r = r;
+ r.min.x += r.max.x;
+ }
+ eresized(0);
+
+ for(;;)
+ switch(event(&e)){
+ case Ekeyboard:
+ break;
+ case Emouse:
+ mouse = e.mouse;
+ if(mouse.buttons & 4)
+ menu();
+ else
+ mousemoved();
+ break;
+ }
+
+ exits(0);
+}