1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      Allegro bitmap -> Windows icon converter.
12  *
13  *      By Elias Pschernig.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #define ALLEGRO_USE_CONSOLE
20 
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <allegro.h>
25 
26 
27 #define ICON_MAX  16
28 
29 
30 
31 /* save_ico:
32  *  Saves <num> bitmaps as an .ico, using <pal> as palette for 8-bit bitmaps.
33  *  Other color depths are saved as 24-bit.
34  */
save_ico(AL_CONST char * filename,BITMAP * bmp[],int num,PALETTE pal[])35 int save_ico(AL_CONST char *filename, BITMAP *bmp[], int num, PALETTE pal[])
36 {
37    PACKFILE *f;
38    int depth, bpp, bw, bitsw;
39    int size, offset, n, i;
40    int c, x, y, b, m, v;
41 
42    errno = 0;
43 
44    f = pack_fopen(filename, F_WRITE);
45    if (!f)
46       return errno;
47 
48    offset = 6 + num * 16;  /* ICONDIR + ICONDIRENTRYs */
49 
50    /* ICONDIR */
51    pack_iputw(0, f);    /* reserved            */
52    pack_iputw(1, f);    /* resource type: ICON */
53    pack_iputw(num, f);  /* number of icons     */
54 
55    for(n = 0; n < num; n++) {
56       depth = bitmap_color_depth(bmp[n]);
57       bpp = (depth == 8) ? 8 : 24;
58       bw = (((bmp[n]->w * bpp / 8) + 3) / 4) * 4;
59       bitsw = ((((bmp[n]->w + 7) / 8) + 3) / 4) * 4;
60       size = bmp[n]->h * (bw + bitsw) + 40;
61 
62       if (bpp == 8)
63          size += 256 * 4;
64 
65       /* ICONDIRENTRY */
66       pack_putc(bmp[n]->w, f);  /* width                       */
67       pack_putc(bmp[n]->h, f);  /* height                      */
68       pack_putc(0, f);          /* color count                 */
69       pack_putc(0, f);          /* reserved                    */
70       pack_iputw(1, f);         /* color planes                */
71       pack_iputw(bpp, f);       /* bits per pixel              */
72       pack_iputl(size, f);      /* size in bytes of image data */
73       pack_iputl(offset, f);    /* file offset to image data   */
74 
75       offset += size;
76    }
77 
78    for(n = 0; n < num; n++) {
79       depth = bitmap_color_depth(bmp[n]);
80       bpp = (depth == 8) ? 8 : 24;
81       bw = (((bmp[n]->w * bpp / 8) + 3) / 4) * 4;
82       bitsw = ((((bmp[n]->w + 7) / 8) + 3) / 4) * 4;
83       size = bmp[n]->h * (bw + bitsw) + 40;
84 
85       if (bpp == 8)
86          size += 256 * 4;
87 
88       /* BITMAPINFOHEADER */
89       pack_iputl(40, f);             /* size           */
90       pack_iputl(bmp[n]->w, f);      /* width          */
91       pack_iputl(bmp[n]->h * 2, f);  /* height x 2     */
92       pack_iputw(1, f);              /* planes         */
93       pack_iputw(bpp, f);            /* bitcount       */
94       pack_iputl(0, f);              /* unused for ico */
95       pack_iputl(size, f);           /* size           */
96       pack_iputl(0, f);              /* unused for ico */
97       pack_iputl(0, f);              /* unused for ico */
98       pack_iputl(0, f);              /* unused for ico */
99       pack_iputl(0, f);              /* unused for ico */
100 
101       /* PALETTE */
102       if (bpp == 8) {
103          pack_iputl(0, f);  /* color 0 is black, so the XOR mask works */
104 
105          for (i = 1; i<256; i++) {
106             if (pal[n]) {
107                pack_putc(_rgb_scale_6[pal[n][i].b], f);
108                pack_putc(_rgb_scale_6[pal[n][i].g], f);
109                pack_putc(_rgb_scale_6[pal[n][i].r], f);
110                pack_putc(0, f);
111             }
112             else {
113                pack_iputl(0, f);
114             }
115          }
116       }
117 
118       /* XOR MASK */
119       for (y = bmp[n]->h - 1; y >= 0; y--) {
120          for (x = 0; x < bmp[n]->w; x++) {
121             if (bpp == 8) {
122                pack_putc(getpixel(bmp[n], x, y), f);
123             }
124             else {
125                c = getpixel(bmp[n], x, y);
126                pack_putc(getb_depth(depth, c), f);
127                pack_putc(getg_depth(depth, c), f);
128                pack_putc(getr_depth(depth, c), f);
129             }
130          }
131 
132          /* every scanline must be 32-bit aligned */
133          while (x&3) {
134             pack_putc(0, f);
135             x++;
136          }
137       }
138 
139       /* AND MASK */
140       for (y = bmp[n]->h - 1; y >= 0; y--) {
141          for (x = 0; x < (bmp[n]->w + 7)/8; x++) {
142             m = 0;
143             v = 128;
144 
145             for (b = 0; b < 8; b++) {
146                c = getpixel(bmp[n], x * 8 + b, y);
147                if (c == bitmap_mask_color(bmp[n]))
148                   m += v;
149                v /= 2;
150             }
151 
152             pack_putc(m, f);
153          }
154 
155          /* every scanline must be 32-bit aligned */
156          while (x&3) {
157             pack_putc(0, f);
158             x++;
159          }
160       }
161    }
162 
163    pack_fclose(f);
164 
165    return errno;
166 }
167 
168 
169 
usage(void)170 void usage(void)
171 {
172    printf("\nWindows icon converter for Allegro " ALLEGRO_VERSION_STR "\n");
173    printf("By Elias Pschernig, " ALLEGRO_DATE_STR "\n\n");
174    printf("Usage: wfixicon icon [-r[o]] bitmap [bitmap...]\n");
175    printf("        or\n");
176    printf("       wfixicon icon [-r[o]] -d datafile object [palette] [object...]\n");
177    printf("         where each 'object' is a bitmap or a RLE sprite.\n");
178    printf("Options:\n");
179    printf("   -r      output .rc file for the icon\n");
180    printf("   -ro     call the resource compiler on the .rc file\n");
181 
182    exit(1);
183 }
184 
185 
186 
main(int argc,char * argv[])187 int main(int argc, char *argv[])
188 {
189    char dat_name[128], rc_name[128], res_name[128], str[256];
190    int icon_num = 0, pal_start = 0;
191    int create_rc = FALSE, call_windres = FALSE;
192    int i, j, arg;
193    BITMAP *bmp[ICON_MAX];
194    PALETTE pal[ICON_MAX];
195    RLE_SPRITE *sprite;
196    DATAFILE *dat;
197    PACKFILE *f;
198 
199    if (install_allegro(SYSTEM_NONE, &errno, atexit) != 0)
200        exit(EXIT_FAILURE);
201    set_color_conversion(COLORCONV_NONE);
202 
203    if (argc < 3)
204       usage();
205 
206    dat_name[0] = '\0';
207 
208    for (arg = 2; arg < argc; arg++) {
209 
210       if (argv[arg][0] == '-') {
211 
212          switch(argv[arg][1]) {
213 
214             case 'd':  /* datafile argument */
215                if (argc < arg+2)
216                   usage();
217 
218                strcpy(dat_name, argv[++arg]);
219                pal_start = icon_num;
220                break;
221 
222             case 'r':
223                create_rc = TRUE;
224 
225                if (argv[arg][2] == 'o') {
226                   call_windres = TRUE;
227                }
228                break;
229 
230             default:
231                usage();
232          }
233       }  /* end of '-' handling */
234       else {
235          if (dat_name[0]) {
236             dat = load_datafile_object(dat_name, argv[arg]);
237 
238             if (!dat) {
239                printf("Error reading %s from %s.\n", argv[arg], dat_name);
240                exit(EXIT_FAILURE);
241             }
242 
243             switch (dat->type) {
244 
245                case DAT_BITMAP:
246                   bmp[icon_num] = (BITMAP *)dat->dat;
247                   icon_num++;
248                   break;
249 
250                case DAT_RLE_SPRITE:
251                   sprite = (RLE_SPRITE *)dat->dat;
252                   bmp[icon_num] = create_bitmap_ex(sprite->color_depth, sprite->w, sprite->h);
253                   clear_to_color(bmp[icon_num], bitmap_mask_color(bmp[icon_num]));
254                   draw_rle_sprite(bmp[icon_num], sprite, 0, 0);
255                   icon_num++;
256                   break;
257 
258                case DAT_PALETTE:
259                   if (pal_start == icon_num)
260                      usage();
261 
262                   for (j = pal_start; j < icon_num; j++)
263                      for (i = 0; i < PAL_SIZE; i++)
264                         pal[j][i] = ((RGB *)dat->dat)[i];
265 
266                   pal_start = icon_num;
267                   break;
268 
269                default:
270                   usage();
271             }
272          }
273          else {
274             bmp[icon_num] = load_bitmap(argv[arg], pal[icon_num]);
275             if (!bmp[icon_num]) {
276                printf("Error reading %s.\n", argv[arg]);
277                exit(EXIT_FAILURE);
278             }
279 
280             icon_num++;
281          }
282 
283          if (icon_num == ICON_MAX)
284             break;
285       } /* end of normal argument handling */
286    }
287 
288    if (icon_num == 0)
289       usage();
290 
291    /* do the hard work */
292    if (save_ico(argv[1], bmp, icon_num, pal) != 0) {
293       printf("Error writing %s.\n", argv[1]);
294       exit(EXIT_FAILURE);
295    }
296 
297    /* output a .rc file along with the ico, to be processed by the resource compiler */
298    if (create_rc) {
299       replace_extension(rc_name, argv[1], "rc", sizeof(rc_name));
300 
301       f = pack_fopen(rc_name, F_WRITE);
302 
303       sprintf(str, "allegro_icon ICON %s\n", argv[1]);
304       pack_fwrite(str, strlen(str), f);
305 
306       pack_fclose(f);
307 
308       if (call_windres) {
309          replace_extension(res_name, argv[1], "res", sizeof(res_name));
310 
311 #if defined ALLEGRO_MINGW32
312          sprintf(str, "windres -O coff -o %s -i %s", res_name, rc_name);
313 #elif defined ALLEGRO_MSVC
314          sprintf(str, "rc -fo %s %s", res_name, rc_name);
315 #elif defined ALLEGRO_BCC32
316          sprintf(str, "brc32 -r -fo %s %s", res_name, rc_name);
317 #endif
318 
319          system(str);
320          delete_file(argv[1]);
321          delete_file(rc_name);
322       }
323    }
324 
325    return 0;
326 }
327