iconwriter

iconwriter

I often find myself needing an icon, whether it be for websites or exes. Turns out the ico spec is actually pretty simple. The modern version is pretty much just a list of pngs. So I wrote this quick tool in C to generate ico files from an arbitrary number of pngs:

#include <stdio.h>
#include <stdlib.h>
typedef unsigned char u8;
typedef unsigned short u16;
typedef unsigned int u32;
typedef unsigned long long u64;
typedef signed char i8;
typedef signed short i16;
typedef signed int i32;
typedef signed long long i64;
#define MIN(a,b) ((a) < (b) ? (a) : (b))
#define MAX(a,b) ((a) > (b) ? (a) : (b))
#define COUNT(arr) (sizeof(arr)/sizeof(*arr))
#define FOR(var,count) for(i32 var = 0; var < (count); var++)
typedef struct {
    u32 size;
    u8 *bytes;
}Bytes;
i32 main(i32 argc, u8 **argv){
    if (argc < 2){
        printf("Usage: iconwriter in1.png ... inN.png out.ico\n");
        return 1;
    }
    FILE *out = fopen(argv[argc-1],"wb");
    i32 numImages = argc-2;
    u16 header[3] = {0,1,numImages};
    fwrite(header,sizeof(header),1,out);
    i32 offset = 6+16*numImages;
    Bytes *pngs = malloc(numImages*sizeof(Bytes));
    for (i32 i = 1; i < argc-1; i++){
        Bytes *p = pngs+i-1;
        FILE *in = fopen(argv[i],"rb");
        fseek(in,0,SEEK_END);
        p->size = ftell(in);
        fseek(in,0,SEEK_SET);
        p->bytes = malloc(p->size);
        fread(p->bytes,p->size,1,in);
        fclose(in);
        u8 winfo[4]={p->bytes[16+3],p->bytes[16+4+3],0,0};
        fwrite(winfo,sizeof(winfo),1,out);
        u16 pinfo[2]={0,32};
        fwrite(pinfo,sizeof(pinfo),1,out);
        u32 binfo[2]={p->size,offset};
        fwrite(binfo,sizeof(binfo),1,out);
        offset += p->size;
    }
    for (i32 i = 0; i < numImages; i++){
        fwrite(pngs[i].bytes,pngs[i].size,1,out);
        free(pngs[i].bytes);
    }
    free(pngs);
    fclose(out);
}