microsoft ico format conversion support

This commit is contained in:
cinap_lenrek 2012-04-01 04:57:11 +02:00
parent ff7d9ab525
commit 0989c2530d
6 changed files with 93 additions and 45 deletions

View file

@ -98,6 +98,8 @@ jpg, gif, png, ppm, bmp, v210, yuv, ico, tga, togif, toppm, topng, toico \- view
.PP .PP
.B ico .B ico
[ [
.B -c
] [
.I file .I file
] ]
.br .br
@ -232,12 +234,18 @@ translates files that contain a `transparency' index by attaching
an alpha channel to the converted image. an alpha channel to the converted image.
.PP .PP
.I Ico .I Ico
displays a Windows icon (.ico) file. If no file is displays or converts a Windows icon (.ico) file. If no file is
specified, specified,
.I ico .I ico
reads from standard input. reads from standard input.
Icon files Icon files
contain sets of icons represented by an image and a mask. contain sets of icons represented by an image and a mask. The
.B -c
option causes
.I ico
to convert the first icon in the set and write it to standard
output in compressed Plan 9 image format. Otherwise, the whole
icon set is displayed.
Clicking the right button pops up a menu that lets you Clicking the right button pops up a menu that lets you
write any icon's image as a Plan 9 image (\fIwidth\fBx\fIheight\fB.image\fR), write any icon's image as a Plan 9 image (\fIwidth\fBx\fIheight\fB.image\fR),
write any icon's mask as a Plan 9 image (\fIwidth\fBx\fIheight\fB.mask\fR), write any icon's mask as a Plan 9 image (\fIwidth\fBx\fIheight\fB.mask\fR),

View file

@ -2,6 +2,7 @@
#include <libc.h> #include <libc.h>
#include <bio.h> #include <bio.h>
#include <draw.h> #include <draw.h>
#include <memdraw.h>
#include <event.h> #include <event.h>
#include <cursor.h> #include <cursor.h>
@ -18,8 +19,8 @@ struct Icon
ulong len; /* length of data */ ulong len; /* length of data */
ulong offset; /* file offset to data */ ulong offset; /* file offset to data */
Image *img; Memimage *img;
Image *mask; Memimage *mask;
Rectangle r; /* relative */ Rectangle r; /* relative */
Rectangle sr; /* abs */ Rectangle sr; /* abs */
@ -34,6 +35,7 @@ struct Header
}; };
int debug; int debug;
int cflag;
Mouse mouse; Mouse mouse;
Header h; Header h;
Image *background; Image *background;
@ -53,9 +55,9 @@ getl(uchar *p)
int int
Bgetheader(Biobuf *b, Header *h) Bgetheader(Biobuf *b, Header *h)
{ {
uchar buf[40];
Icon *icon; Icon *icon;
int i; int i;
uchar buf[40];
memset(h, 0, sizeof(*h)); memset(h, 0, sizeof(*h));
if(Breadn(b, buf, 6) != 6) if(Breadn(b, buf, 6) != 6)
@ -65,7 +67,6 @@ Bgetheader(Biobuf *b, Header *h)
if(gets(&buf[2]) != 1) if(gets(&buf[2]) != 1)
goto header; goto header;
h->n = gets(&buf[4]); h->n = gets(&buf[4]);
for(i = 0; i < h->n; i++){ for(i = 0; i < h->n; i++){
icon = mallocz(sizeof(*icon), 1); icon = mallocz(sizeof(*icon), 1);
if(icon == nil) if(icon == nil)
@ -81,7 +82,6 @@ Bgetheader(Biobuf *b, Header *h)
icon->bits = gets(&buf[6]); icon->bits = gets(&buf[6]);
icon->len = getl(&buf[8]); icon->len = getl(&buf[8]);
icon->offset = getl(&buf[12]); icon->offset = getl(&buf[12]);
if(i == 0) if(i == 0)
h->first = icon; h->first = icon;
else else
@ -112,11 +112,11 @@ transcmap(Icon *icon, uchar *map)
return m; return m;
} }
Image* Memimage*
xor2img(Icon *icon, uchar *xor, uchar *map) xor2img(Icon *icon, uchar *xor, uchar *map)
{ {
uchar *data; uchar *data;
Image *img; Memimage *img;
int inxlen; int inxlen;
uchar *from, *to; uchar *from, *to;
int s, byte, mask; int s, byte, mask;
@ -142,18 +142,18 @@ xor2img(Icon *icon, uchar *xor, uchar *map)
} }
/* stick in an image */ /* stick in an image */
img = allocimage(display, Rect(0,0,icon->w,icon->h), CMAP8, 0, DNofill); img = allocmemimage(Rect(0,0,icon->w,icon->h), CMAP8);
loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w); loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*icon->w);
free(data); free(data);
return img; return img;
} }
Image* Memimage*
and2img(Icon *icon, uchar *and) and2img(Icon *icon, uchar *and)
{ {
uchar *data; uchar *data;
Image *img; Memimage *img;
int inxlen; int inxlen;
int outxlen; int outxlen;
uchar *from, *to; uchar *from, *to;
@ -172,8 +172,8 @@ and2img(Icon *icon, uchar *and)
} }
/* stick in an image */ /* stick in an image */
img = allocimage(display, Rect(0,0,icon->w,icon->h), GREY1, 0, DNofill); img = allocmemimage(Rect(0,0,icon->w,icon->h), GREY1);
loadimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen); loadmemimage(img, Rect(0,0,icon->w,icon->h), data, icon->h*outxlen);
free(data); free(data);
return img; return img;
@ -183,14 +183,18 @@ int
Bgeticon(Biobuf *b, Icon *icon) Bgeticon(Biobuf *b, Icon *icon)
{ {
ulong l; ulong l;
ushort s; uchar *end;
uchar *xor; uchar *xor;
uchar *and; uchar *and;
uchar *cm; uchar *cm;
uchar *buf; uchar *buf;
uchar *map2map; uchar *map2map;
Image *img; Memimage *img;
if(icon->len < 40){
werrstr("bad icon header length");
return -1;
}
Bseek(b, icon->offset, 0); Bseek(b, icon->offset, 0);
buf = malloc(icon->len); buf = malloc(icon->len);
if(buf == nil) if(buf == nil)
@ -199,24 +203,16 @@ Bgeticon(Biobuf *b, Icon *icon)
werrstr("unexpected EOF"); werrstr("unexpected EOF");
return -1; return -1;
} }
/* this header's info takes precedence over previous one */ /* this header's info takes precedence over previous one */
if(getl(buf) != 40){ if(getl(buf) != 40){
werrstr("bad icon header"); werrstr("bad icon header");
return -1; return -1;
} }
l = getl(buf+4); icon->w = getl(buf+4);
if(l != icon->w)
icon->w = l;
l = getl(buf+8); l = getl(buf+8);
if(l>>1 != icon->h)
icon->h = l>>1; icon->h = l>>1;
s = gets(buf+12); icon->nplane = gets(buf+12);
if(s != icon->nplane) icon->bits = gets(buf+14);
icon->nplane = s;
s = gets(buf+14);
if(s != icon->bits)
icon->bits = s;
/* limit what we handle */ /* limit what we handle */
switch(icon->bits){ switch(icon->bits){
@ -237,6 +233,11 @@ Bgeticon(Biobuf *b, Icon *icon)
cm = buf + 40; cm = buf + 40;
xor = cm + 4*icon->ncolor; xor = cm + 4*icon->ncolor;
and = xor + icon->h*4*((icon->bits*icon->w+31)/32); and = xor + icon->h*4*((icon->bits*icon->w+31)/32);
end = and + icon->h*4*((icon->w+31)/32);
if(end < buf || end > buf+icon->len){
werrstr("bad icon length %lux != %lux", end - buf, icon->len);
return -1;
}
/* translate the color map to a plan 9 one */ /* translate the color map to a plan 9 one */
map2map = transcmap(icon, cm); map2map = transcmap(icon, cm);
@ -246,9 +247,12 @@ Bgeticon(Biobuf *b, Icon *icon)
icon->mask = and2img(icon, and); icon->mask = and2img(icon, and);
/* so that we save an image with a white background */ /* so that we save an image with a white background */
img = allocimage(display, icon->img->r, CMAP8, 0, DWhite); if(img = allocmemimage(icon->img->r, icon->img->chan)){
draw(img, icon->img->r, icon->img, icon->mask, ZP); memfillcolor(img, DWhite);
memimagedraw(img, icon->img->r, icon->img, ZP, icon->mask, ZP, SoverD);
freememimage(icon->img);
icon->img = img; icon->img = img;
}
free(buf); free(buf);
free(map2map); free(map2map);
@ -258,7 +262,7 @@ Bgeticon(Biobuf *b, Icon *icon)
void void
usage(void) usage(void)
{ {
fprint(2, "usage: %s [file]\n", argv0); fprint(2, "usage: %s [ -c ] [ file ]\n", argv0);
exits("usage"); exits("usage");
} }
@ -328,7 +332,7 @@ doimage(Icon *icon)
snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h); snprint(file, sizeof(file), "%dx%d.img", icon->w, icon->h);
fd = create(file, OWRITE, 0664); fd = create(file, OWRITE, 0664);
if(fd >= 0){ if(fd >= 0){
rv = writeimage(fd, icon->img, 0); rv = writememimage(fd, icon->img);
close(fd); close(fd);
} }
if(rv < 0) if(rv < 0)
@ -348,7 +352,7 @@ domask(Icon *icon)
snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h); snprint(file, sizeof(file), "%dx%d.mask", icon->w, icon->h);
fd = create(file, OWRITE, 0664); fd = create(file, OWRITE, 0664);
if(fd >= 0){ if(fd >= 0){
rv = writeimage(fd, icon->mask, 0); rv = writememimage(fd, icon->mask);
close(fd); close(fd);
} }
if(rv < 0) if(rv < 0)
@ -412,10 +416,28 @@ enum
BORDER= 1, BORDER= 1,
}; };
Image*
screenimage(Memimage *m)
{
Rectangle r;
Image *i;
if(i = allocimage(display, m->r, m->chan, 0, DNofill)){
r = m->r;
while(r.min.y < m->r.max.y){
r.max.y = r.min.y+1;
loadimage(i, r, byteaddr(m, r.min), Dx(r));
r.min.y++;
}
}
return i;
}
void void
eresized(int new) eresized(int new)
{ {
Icon *icon; Icon *icon;
Image *i;
Rectangle r; Rectangle r;
if(new && getwindow(display, Refnone) < 0) if(new && getwindow(display, Refnone) < 0)
@ -427,7 +449,10 @@ eresized(int new)
r.min.x = r.max.x + BORDER; r.min.x = r.max.x + BORDER;
r.max.x = r.min.x + Dx(icon->img->r); r.max.x = r.min.x + Dx(icon->img->r);
r.max.y = r.min.y + Dy(icon->img->r); r.max.y = r.min.y + Dy(icon->img->r);
draw(screen, r, icon->img, nil, ZP); if(i = screenimage(icon->img)){
draw(screen, r, i, nil, ZP);
freeimage(i);
}
border(screen, r, -BORDER, display->black, ZP); border(screen, r, -BORDER, display->black, ZP);
icon->sr = r; icon->sr = r;
} }
@ -447,6 +472,11 @@ main(int argc, char **argv)
case 'd': case 'd':
debug = 1; debug = 1;
break; break;
case 'c':
cflag = 1;
break;
default:
usage();
}ARGEND; }ARGEND;
fd = -1; fd = -1;
@ -464,16 +494,12 @@ main(int argc, char **argv)
break; break;
} }
memimageinit();
Binit(&in, fd, OREAD); Binit(&in, fd, OREAD);
if(Bgetheader(&in, &h) < 0) if(Bgetheader(&in, &h) < 0)
sysfatal("reading header: %r"); 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);
num = 0; num = 0;
r.min = Pt(4, 4); r.min = Pt(4, 4);
for(icon = h.first; icon != nil; icon = icon->next){ for(icon = h.first; icon != nil; icon = icon->next){
@ -486,14 +512,21 @@ main(int argc, char **argv)
icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset); icon->w, icon->h, icon->ncolor, icon->bits, icon->len, icon->offset);
r.max = addpt(r.min, Pt(icon->w, icon->h)); r.max = addpt(r.min, Pt(icon->w, icon->h));
icon->r = r; icon->r = r;
if(cflag){
writememimage(1, icon->img);
exits(0);
}
r.min.x += r.max.x; r.min.x += r.max.x;
num++; num++;
} }
if(num == 0) if(num == 0 || cflag)
exits("no images"); sysfatal("no images");
eresized(0);
initdraw(nil, nil, "ico");
background = allocimage(display, Rect(0, 0, 1, 1), screen->chan, 1, 0x808080FF);
eresized(0);
einit(Emouse|Ekeyboard);
for(;;) for(;;)
switch(event(&e)){ switch(event(&e)){
case Ekeyboard: case Ekeyboard:

View file

@ -19,6 +19,7 @@ char *pixcmd[]={
[JPEG] "jpg -9t", [JPEG] "jpg -9t",
[PNG] "png -9t", [PNG] "png -9t",
[BMP] "bmp -9t", [BMP] "bmp -9t",
[ICO] "ico -c",
}; };
void getimage(Rtext *t, Www *w){ void getimage(Rtext *t, Www *w){

View file

@ -50,6 +50,7 @@ enum{
JPEG, JPEG,
PNG, PNG,
BMP, BMP,
ICO,
GUNZIP, GUNZIP,
COMPRESS, COMPRESS,

View file

@ -100,6 +100,7 @@ snooptype(int fd)
"image/gif", GIF, "image/gif", GIF,
"image/png", PNG, "image/png", PNG,
"image/bmp", BMP, "image/bmp", BMP,
"image/x-icon", ICO,
"application/x-gzip", GUNZIP, "application/x-gzip", GUNZIP,
"application/x-compress", COMPRESS, "application/x-compress", COMPRESS,

View file

@ -290,6 +290,9 @@ popenimg(Page *p)
seek(fd, 0, 0); seek(fd, 0, 0);
if(p->data){ if(p->data){
p->ext = p->data; p->ext = p->data;
if(strcmp(p->ext, "ico") == 0)
snprint(nam, sizeof(nam), "%s -c", p->ext);
else
snprint(nam, sizeof(nam), "%s -t9", p->ext); snprint(nam, sizeof(nam), "%s -t9", p->ext);
pipeline(fd, "%s", nam); pipeline(fd, "%s", nam);
} }
@ -674,6 +677,7 @@ popenfile(Page *p)
"image/png", popenimg, "png", "image/png", popenimg, "png",
"image/ppm", popenimg, "ppm", "image/ppm", popenimg, "ppm",
"image/bmp", popenimg, "bmp", "image/bmp", popenimg, "bmp",
"image/x-icon", popenimg, "ico",
"image/p9bit", popenimg, nil, "image/p9bit", popenimg, nil,
}; };