8
8
** copyright notice and this permission notice appear in supporting
9
9
** documentation. This software is provided "as is" without express or
10
10
** implied warranty.
14
** 03/2003 - Added 24+32 bpp support.
13
17
#include <string.h>
16
22
#include "winico.h"
18
24
#define MAJVERSION 0
21
static int writeToFile = 0;
22
static int verbose = 0;
23
static int allicons = 0;
24
static int writeands = 0;
25
static int bestqual = 0;
26
static int multippm = 0;
27
static int file_offset = 0; /* not actually used, but useful for debug */
28
static char er_read[] = "%s: read error";
29
static char * infname;
30
static char * outfname;
27
int asprintf(char **strp, const char *fmt, ...);
29
static int file_offset = 0; /* not actually used, but useful for debug */
30
static const char er_read[] = "%s: read error";
31
static const char * infname;
35
/* All the information the user supplied in the command line,
36
in a form easy for the program to use.
38
const char * inputFilespec;
39
const char * outputFilespec;
40
unsigned int allicons;
41
unsigned int bestqual;
42
unsigned int writeands;
43
unsigned int multippm;
51
parseCommandLine ( int argc, char ** argv,
52
struct cmdlineInfo *cmdlineP ) {
53
/*----------------------------------------------------------------------------
54
parse program command line described in Unix standard form by argc
55
and argv. Return the information in the options as *cmdlineP.
57
If command line is internally inconsistent (invalid options, etc.),
58
issue error message to stderr and abort program.
60
Note that the strings we return are stored in the storage that
61
was passed to us as the argv array. We also trash *argv.
62
-----------------------------------------------------------------------------*/
63
optEntry *option_def = malloc(100*sizeof(optEntry));
64
/* Instructions to optParseOptions3 on how to parse our options.
68
unsigned int option_def_index;
70
option_def_index = 0; /* incremented by OPTENT3 */
71
OPTENT3(0, "allicons", OPT_FLAG, NULL,
72
&cmdlineP->allicons, 0 );
73
OPTENT3(0, "bestqual", OPT_FLAG, NULL,
74
&cmdlineP->bestqual, 0 );
75
OPTENT3(0, "writeands", OPT_FLAG, NULL,
76
&cmdlineP->writeands, 0 );
77
OPTENT3(0, "multippm", OPT_FLAG, NULL,
78
&cmdlineP->multippm, 0 );
79
OPTENT3(0, "verbose", OPT_FLAG, NULL,
80
&cmdlineP->verbose, 0 );
82
opt.opt_table = option_def;
83
opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */
84
opt.allowNegNum = FALSE; /* We have no parms that are negative numbers */
86
pm_optParseOptions3( &argc, argv, opt, sizeof(opt), 0);
87
/* Uses and sets argc, argv, and some of *cmdlineP and others. */
91
cmdlineP->inputFilespec = "-";
93
cmdlineP->inputFilespec = argv[1];
96
cmdlineP->outputFilespec = "-";
98
if (cmdlineP->writeands || cmdlineP->allicons)
99
pm_error("If you specify the -writeands or -allicons option, "
100
"you must also specify an output file name argument.");
102
cmdlineP->outputFilespec = argv[2];
105
pm_error("Too many arguments (%d). Input filespec and "
106
"output filespec are the only possible arguments.",
262
352
*(bitmap+((height-tmp-1)*width) + (x)) = row[rowByte];
361
* Read a true color bitmap. (24/32 bits)
363
* The output routine deplanarizes it for us, we keep it flat here.
366
readXBitmap (int width, int height, int bpp)
369
int bytes = bpp >> 3;
370
u1 * bitmap = malloc3 (sizeof(u1)*bytes, width, height);
371
/* remember - bmp (dib) stored upside down, so reverse */
372
u1 * bitcurptr = bitmap + (bytes * width * (height-1) ) * (sizeof (u1));
373
unsigned int xBytes = width * bytes;
374
overflow2(bytes,sizeof(u1));
377
pm_error("out of memory");
379
for (tmp = 0;tmp < height; tmp++, bitcurptr -= xBytes) {
380
u1 * row = readU1String(xBytes);
381
memcpy(bitcurptr, row, xBytes);
388
readIconFile (bool const verbose) {
276
391
MS_Ico MSIconData= malloc( sizeof (* MSIconData) );
302
417
/* After that, we have to read in the infoheader, color map (if
303
418
* any) and the actual bit/pix maps for the icons.
305
if (verbose) fprintf (stderr,"#\tColors\tBPP\tWidth\tHeight\n");
421
fprintf (stderr,"#\tColors\tBPP\tWidth\tHeight\n");
306
422
for (iter = 0;iter < MSIconData->count ; iter++ ) {
308
MSIconData->entries[iter]->ih = readInfoHeader ();
309
MSIconData->entries[iter]->colors =
310
malloc2 (MSIconData->entries[iter]->color_count,
313
iter2 < MSIconData->entries[iter]->color_count ;
315
MSIconData->entries[iter]->colors[iter2] = readICColor();
424
MSIconData->entries[iter]->ih =
425
readInfoHeader (MSIconData->entries[iter]);
427
/* What's the bits per pixel? */
428
bpp = MSIconData->entries[iter]->bitcount;
429
/* Read the palette, if appropriate */
433
/* 24/32 bpp icon has no palette */
436
MSIconData->entries[iter]->colors =
437
malloc2 (MSIconData->entries[iter]->color_count,
439
if (MSIconData->entries[iter]->colors == NULL)
440
pm_error("out of memory");
443
iter2 < MSIconData->entries[iter]->color_count ;
445
MSIconData->entries[iter]->colors[iter2] = readICColor();
317
/* What's the bits per pixel? Bit confusing, since there's a
318
* field in entry, and in the infoheader. I'll use both but
319
* let the entry field take precedence.
321
bpp = MSIconData->entries[iter]->bitcount ?
322
MSIconData->entries[iter]->bitcount :
323
MSIconData->entries[iter]->ih->bitcount;
451
sprintf (cols_text, "%d", MSIconData->entries[iter]->color_count);
326
"%d\t%d\t%d\t%d\t%d\n", iter,
327
MSIconData->entries[iter]->color_count,
453
"%d\t%s\t%d\t%d\t%d\n", iter,
454
MSIconData->entries[iter]->color_count ?
328
456
bpp, MSIconData->entries[iter]->width,
329
457
MSIconData->entries[iter]->height);
330
459
/* Pixels are stored bottom-up, left-to-right. Pixel lines are
331
460
* padded with zeros to end on a 32bit (4byte) boundary. Every
332
461
* line will have the same number of bytes. Color indices are
333
462
* zero based, meaning a pixel color of 0 represents the first
334
463
* color table entry, a pixel color of 255 (if there are that
335
464
* many) represents the 256th entry.
466
* 24+32 bit (16 is an abomination, which I'll avoid, and expect
467
* no-one to mind) are stored 1byte/plane with a spare (alpha?)
375
trimOutputName (char * inputName)
514
trimOutputName(const char inputName[])
378
517
* Just trim off the final ".ppm", if there is one, else return as is.
379
518
* oh, for =~ ... :)
381
char * outFile = malloc ( sizeof (char) * (strlen (inputName) + 1));
382
overflow_add(strlen(inputName), 1);
383
strcpy(outFile, inputName);
520
char * outFile = strdup(inputName);
384
521
if (!strcmp (outFile + (strlen (outFile) - 4), ".ppm")) {
385
522
*(outFile + (strlen (outFile) - 4)) = 0;
436
574
pixel ** ppm_array;
438
577
char *outputFile;
440
overflow_add(strlen(outputFileBase),20);
441
outputFile = malloc(sizeof(char) * (strlen (outputFileBase) + 20));
444
582
outF = multiOutF;
583
outputFile = strdup("");
585
if (outputFileBase) {
448
sprintf(outputFile, "%s%s_%d.ppm",
449
outputFileBase,(xor ? "_xor" : ""), entryNum);
587
asprintf(&outputFile, "%s%s_%d.ppm",
588
outputFileBase,(xor ? "_xor" : ""), entryNum);
451
sprintf(outputFile, "%s%s.ppm",
452
outputFileBase,(xor ? "_xor" : ""));
590
asprintf(&outputFile, "%s%s.ppm",
591
outputFileBase,(xor ? "_xor" : ""));
455
strcpy(outputFile, "-");
594
outputFile = strdup("-");
457
596
outF = pm_openw(outputFile);
465
604
for (row=0; row < entry->height; row++) {
468
xorRow = entry->xorBitmap + row * entry->width;
469
for (col=0; col < entry->width; col++) {
472
colorIndex = xorRow[col];
473
color = entry->colors[colorIndex];
474
PPM_ASSIGN(ppm_array[row][col],
475
color->red,color->green,color->blue);
607
switch (entry->bitcount) {
610
pel_size = entry->bitcount >> 3;
611
xorRow = entry->xorBitmap + row * entry->width * pel_size;
612
for (col=0; col < entry->width*pel_size;col+=pel_size) {
613
PPM_ASSIGN(ppm_array[row][col/pel_size],
614
xorRow[col+2],xorRow[col+1],xorRow[col]);
618
xorRow = entry->xorBitmap + row * entry->width;
619
for (col=0; col < entry->width; col++) {
622
colorIndex = xorRow[col];
623
color = entry->colors[colorIndex];
624
PPM_ASSIGN(ppm_array[row][col],
625
color->red,color->green,color->blue);
478
634
ppm_writeppm(outF,ppm_array,entry->width, entry->height,
635
(pixval) maxval, forcetext);
480
636
ppm_freearray(ppm_array,entry->height);
512
670
char *outputFile;
514
overflow_add(strlen(outputFileBase),20);
515
outputFile = malloc ( sizeof (char) * (strlen (outputFileBase) + 20));
672
assert(outputFileBase);
518
sprintf(outputFile, "%s_and_%d.pbm", outputFileBase, entryNum);
675
asprintf(&outputFile, "%s_and_%d.pbm", outputFileBase, entryNum);
520
sprintf(outputFile, "%s_and.pbm", outputFileBase);
677
asprintf(&outputFile, "%s_and.pbm", outputFileBase);
521
678
outF = pm_openw(outputFile);
522
679
free(outputFile);
536
693
pbm_freearray(pbm_array, entry->height);
544
openMultiXor(char outputFileBase[], FILE ** const multiOutFP) {
701
openMultiXor(char outputFileBase[],
702
bool const writeands,
703
FILE ** const multiOutFP) {
546
705
char *outputFile;
548
overflow_add(strlen(outputFileBase),20);
549
outputFile = malloc ( sizeof (char) * (strlen (outputFileBase) + 20));
707
if (outputFileBase) {
708
asprintf(&outputFile, "%s%s.ppm",
709
outputFileBase, (writeands ? "_xor" : ""));
711
outputFile = strdup("-");
551
714
* Open the output file now, it'll stay open the whole time.
554
sprintf(outputFile, "%s%s.ppm",
555
outputFileBase, (writeands ? "_xor" : ""));
557
sprintf(outputFile,"-");
559
716
*multiOutFP = pm_openw(outputFile);
560
718
free(outputFile);
568
726
char *outputFile;
570
overflow_add(strlen(outputFileBase),20);
571
outputFile = malloc ( sizeof (char) * (strlen (outputFileBase) + 20));
573
sprintf(outputFile, "%s_and.pbm", outputFileBase);
728
assert(outputFileBase);
730
asprintf(&outputFile, "%s_and.pbm", outputFileBase);
575
732
*multiAndOutFP = pm_openw(outputFile);
576
734
free(outputFile);
582
int main (int argc, char *argv[]) {
737
static void free_iconentry(IC_Entry entry) {
739
if (entry->colors && entry->color_count) {
740
for (x=0;x<entry->color_count;x++) free(entry->colors[x]);
743
if (entry->andBitmap) free(entry->andBitmap);
744
if (entry->xorBitmap) free(entry->xorBitmap);
745
if (entry->ih) free(entry->ih);
749
static void free_icondata(MS_Ico MSIconData)
752
for (x=0;x<MSIconData->count;x++) {
753
free_iconentry(MSIconData->entries[x]);
760
main(int argc, char *argv[]) {
762
struct cmdlineInfo cmdline;
585
763
int startEntry, endEntry;
586
char * usage = "[-writeands] [-allicons|-bestqual] [-multippm] "
587
"[-verbose] [iconfile] [ppmdestfile]";
588
764
MS_Ico MSIconData;
589
765
char * outputFileBase;
591
766
FILE * multiOutF;
592
767
FILE * multiAndOutF;
594
769
ppm_init (&argc, argv);
596
* Parse command line arguments.
599
while (argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0') {
600
if (pm_keymatch(argv[argn], "-verbose", 2))
602
else if (pm_keymatch(argv[argn], "-allicons", 2))
604
else if (pm_keymatch(argv[argn], "-bestqual", 2))
606
else if (pm_keymatch(argv[argn], "-writeands", 2))
608
else if (pm_keymatch(argv[argn], "-multippm", 2))
610
else pm_usage(usage);
614
if (bestqual && allicons) {
615
pm_message ("bestqual flag ignored.");
620
ifp = pm_openr(argv[argn]);
621
infname = argv[argn];
628
if (argn < argc && strcmp(argv[argn],"-")) {
629
outputFileBase = trimOutputName(argv[argn]);
630
outfname = argv[argn];
631
overflow_add(strlen(outputFileBase),20);
632
outputFile = malloc ( sizeof (char) * (strlen (outputFileBase) + 20));
637
if (allicons || writeands) {
638
pm_error("When using -allicons or -writeands, "
639
"please supply an output filename.\n");
641
if (argn < argc) argn++;
647
MSIconData = readIconFile ();
771
parseCommandLine(argc, argv, &cmdline);
773
if (cmdline.bestqual && cmdline.allicons)
774
pm_message("-bestqual doesn't make sense with -allicons. "
775
"Ignoring -bestqual.");
777
if (strcmp(cmdline.outputFilespec, "-") == 0)
778
outputFileBase = NULL;
780
outputFileBase = trimOutputName(cmdline.outputFilespec);
782
ifp = pm_openr(cmdline.inputFilespec);
784
infname = cmdline.inputFilespec;
786
MSIconData = readIconFile(cmdline.verbose);
649
788
* Now we've read the icon file in (Hopefully! :)
650
789
* Go through each of the entries, and write out files of the
688
827
for (entryNum = startEntry ; entryNum < endEntry ; entryNum++ ) {
689
828
IC_Entry const entry = MSIconData->entries[entryNum];
691
writeXors(writeToFile, multiOutF, outputFileBase, entry, entryNum,
692
allicons, writeands);
830
writeXors(multiOutF, outputFileBase, entry, entryNum,
831
cmdline.allicons, cmdline.writeands);
832
if (cmdline.writeands)
694
833
writeAnds(multiAndOutF, outputFileBase,
695
entry, entryNum, allicons);
834
entry, entryNum, cmdline.allicons);
699
pm_close (multiOutF);
838
pm_close (multiOutF);
700
839
if (multiAndOutF)
701
840
pm_close(multiAndOutF);
842
/* free up the image data here. */
843
free_icondata(MSIconData);