microsoft ico format conversion support
This commit is contained in:
parent
ff7d9ab525
commit
0989c2530d
|
@ -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),
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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){
|
||||||
|
|
|
@ -50,6 +50,7 @@ enum{
|
||||||
JPEG,
|
JPEG,
|
||||||
PNG,
|
PNG,
|
||||||
BMP,
|
BMP,
|
||||||
|
ICO,
|
||||||
|
|
||||||
GUNZIP,
|
GUNZIP,
|
||||||
COMPRESS,
|
COMPRESS,
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue