comparison gfxconv.c @ 407:59244a7ae37f

Move c64 utilities to the engine lib, as we benefit from a common framework.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 03 Nov 2012 02:19:51 +0200
parents
children b529b7e8ff83
comparison
equal deleted inserted replaced
406:a0160ffdf7e5 407:59244a7ae37f
1 /*
2 * gfxconv - Convert various graphics formats
3 * Programmed and designed by Matti 'ccr' Hamalainen
4 * (C) Copyright 2012 Tecnic Software productions (TNSP)
5 *
6 * Please read file 'COPYING' for information on license and distribution.
7 */
8 #include <errno.h>
9 #include "dmlib.h"
10 #include "dmargs.h"
11 #include "dmfile.h"
12 #include "dmmutex.h"
13 #include "lib64gfx.h"
14
15 //#define UNFINISHED 1
16
17 #ifdef HAVE_LIBPNG
18 #include <png.h>
19 #endif
20
21 enum
22 {
23 INFMT_AUTO = 0,
24 INFMT_CHAR,
25 INFMT_SPRITE,
26 INFMT_BITMAP,
27 INFMT_IMAGE,
28 };
29
30 enum
31 {
32 OUTFMT_ASCII,
33 OUTFMT_ANSI,
34 OUTFMT_PNG,
35 OUTFMT_PPM,
36 OUTFMT_PCX,
37 OUTFMT_ARAW,
38
39 #ifdef UNFINISHED
40 OUTFMT_SPRITE,
41 OUTFMT_CHAR,
42 #endif
43
44 OUTFMT_LAST
45 };
46
47 char * outFormatList[OUTFMT_LAST] =
48 {
49 "ascii",
50 "ansi",
51 "png",
52 "ppm",
53 "pcx",
54 "araw",
55 #ifdef UNFINISHED
56 "spr",
57 "char",
58 #endif
59 };
60
61 static const int noutFormatList = sizeof(outFormatList) / sizeof(outFormatList[0]);
62
63
64 #define ASC_NBITS 8
65 #define ASC_NCOLORS 4
66 static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#";
67
68
69 char *optInFilename = NULL,
70 *optOutFilename = NULL;
71 int optInFormat = INFMT_AUTO,
72 optOutFormat = OUTFMT_ASCII,
73 optItemCount = -1,
74 optScale = 2,
75 optPlanedWidth = 1,
76 optBPP = 4;
77 int optInSkip = 0;
78 BOOL optInMulticolor = FALSE,
79 optSequential = FALSE,
80 optPaletted = FALSE;
81 int optColors[C64_MAX_COLORS];
82
83
84 static DMOptArg optList[] =
85 {
86 { 0, '?', "help", "Show this help", OPT_NONE },
87 { 3, 'o', "output", "Output filename", OPT_ARGREQ },
88 { 1, 'i', "informat", "Set input format ([s]prite, [c]har, [b]itmap)", OPT_ARGREQ },
89 { 2, 'm', "multicolor", "Input is multicolor", OPT_NONE },
90 { 4, 's', "skip", "Skip bytes in input", OPT_ARGREQ },
91 { 5, 'f', "format", "Output format (see list below)", OPT_ARGREQ },
92 { 8, 'q', "sequential", "Output sequential files (image output only)", OPT_NONE },
93 { 6, 'c', "colormap", "Color mappings (see below for information)", OPT_ARGREQ },
94 { 7, 'n', "numitems", "How many 'items' to view (default: all)", OPT_ARGREQ },
95 { 9, 'S', "scale", "Scale output by x (image output only)", OPT_ARGREQ },
96 #ifdef UNFINISHED
97 {10, 'b', "bformat", "Force input bitmap format (see below)", OPT_ARGREQ },
98 #endif
99 {11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ },
100 {12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE },
101 {13, 'b', "bpp", "Bits per pixel (certain image output formats)", OPT_ARGREQ },
102 };
103
104 static const int optListN = sizeof(optList) / sizeof(optList[0]);
105
106
107 void argShowHelp()
108 {
109 int i;
110
111 dmPrintBanner(stdout, dmProgName, "[options] <input file>");
112 dmArgsPrintHelp(stdout, optList, optListN);
113
114 printf("\nAvailable output formats: ");
115 for (i = 0; i < noutFormatList; i++)
116 {
117 printf("%s", outFormatList[i]);
118 if (i < noutFormatList - 1)
119 printf(", ");
120 else
121 printf("\n");
122 }
123
124 #ifdef UNFINISHED
125 printf("\nAvailable bitmap formats:\n");
126 for (i = 0; i < ndmC64ImageFormats; i++)
127 {
128 DM64ImageFormat *fmt = &dmC64ImageFormats[i];
129 printf("%3d | %-5s | %-15s | %s\n",
130 i, fmt->extension,
131 dmC64ImageTypeNames[fmt->type],
132 fmt->name);
133 }
134 #endif
135
136 printf(
137 "\n"
138 "Color map definitions are used for ANSI, PCX, PPM and PNG output, to declare what\n"
139 "output colors of the C64 palette are used for each single color/multi color\n"
140 "bit-combination. For example, if the input is multi color sprite or char,\n"
141 "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n"
142 "The numbers are palette indexes, and the order is for bit(pair)-values\n"
143 "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n"
144 "special color that can be used for transparency.\n"
145 );
146 }
147
148
149 BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
150 {
151 switch (optN)
152 {
153 case 0:
154 argShowHelp();
155 exit(0);
156 break;
157
158 case 1:
159 switch (tolower(optArg[0]))
160 {
161 case 's':
162 optInFormat = INFMT_SPRITE;
163 break;
164 case 'c':
165 optInFormat = INFMT_CHAR;
166 break;
167 default:
168 dmError("Invalid input format '%s'.\n", optArg);
169 return FALSE;
170 }
171 break;
172
173 case 2:
174 optInMulticolor = TRUE;
175 break;
176
177 case 3:
178 optOutFilename = optArg;
179 break;
180
181 case 4:
182 if (!dmGetIntVal(optArg, &optInSkip))
183 {
184 dmError("Invalid skip value argument '%s'.\n", optArg);
185 return FALSE;
186 }
187 break;
188
189 case 5:
190 {
191 int i, format = -1;
192 for (i = 0; i < noutFormatList; i++)
193 if (strcasecmp(optArg, outFormatList[i]) == 0)
194 {
195 format = i;
196 break;
197 }
198
199 if (format < 0)
200 {
201 dmError("Invalid output format '%s'.\n", optArg);
202 return FALSE;
203 }
204
205 optOutFormat = format;
206 }
207 break;
208
209 case 6:
210 {
211 int index = 0, tmp;
212 char *s, *p = optArg;
213
214 while (index < C64_MAX_COLORS && *p != 0 && (s = strchr(p, ':')) != NULL)
215 {
216 *s = 0;
217 if (sscanf(p, "%d", &tmp) == 1)
218 optColors[index++] = tmp;
219 p = s + 1;
220 }
221
222 if (*p && index < C64_MAX_COLORS)
223 {
224 if (sscanf(p, "%d", &tmp) == 1)
225 optColors[index++] = tmp;
226 }
227
228 dmMsg(1, "Set color table: ");
229 for (tmp = 0; tmp < index; tmp++)
230 {
231 dmPrint(1, "[%d:%d]%s",
232 tmp, optColors[tmp],
233 (tmp < index - 1) ? ", " : "");
234 }
235 dmPrint(1, "\n");
236 }
237 break;
238
239 case 7:
240 if (sscanf(optArg, "%d", &optItemCount) != 1)
241 {
242 dmError("Invalid count value argument '%s'.\n", optArg);
243 return FALSE;
244 }
245 break;
246
247 case 8:
248 optSequential = TRUE;
249 break;
250
251 case 9:
252 {
253 int tmp = atoi(optArg);
254 if (tmp < 1 || tmp > 50)
255 {
256 dmError("Invalid scale value '%s'.\n", optArg);
257 return FALSE;
258 }
259 optScale = tmp;
260 }
261 break;
262
263 case 11:
264 {
265 int tmp = atoi(optArg);
266 if (tmp < 1 || tmp > 512)
267 {
268 dmError("Invalid width value '%s'.\n", optArg);
269 return FALSE;
270 }
271 optPlanedWidth = tmp;
272 }
273 break;
274
275 case 12:
276 optPaletted = TRUE;
277 break;
278
279 default:
280 dmError("Unknown option '%s'.\n", currArg);
281 return FALSE;
282 }
283
284 return TRUE;
285 }
286
287
288 BOOL argHandleFile(char *currArg)
289 {
290 if (!optInFilename)
291 optInFilename = currArg;
292 else
293 {
294 dmError("Source filename already specified, extraneous argument '%s'.\n",
295 currArg);
296 return FALSE;
297 }
298
299 return TRUE;
300 }
301
302
303 void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor)
304 {
305 int i;
306
307 if (multicolor)
308 {
309 for (i = ASC_NBITS; i; i -= 2)
310 {
311 int val = (byte & (3ULL << (i - 2))) >> (i - 2);
312 char ch;
313 switch (format)
314 {
315 case OUTFMT_ASCII:
316 ch = dmASCIIPalette[val];
317 fprintf(out, "%c%c", ch, ch);
318 break;
319 case OUTFMT_ANSI:
320 fprintf(out, "%c[0;%d;%dm##%c[0m",
321 0x1b,
322 1,
323 31 + optColors[val],
324 0x1b);
325 break;
326 }
327 }
328 }
329 else
330 {
331 for (i = ASC_NBITS; i; i--)
332 {
333 int val = (byte & (1ULL << (i - 1))) >> (i - 1);
334 char ch;
335 switch (format)
336 {
337 case OUTFMT_ASCII:
338 ch = val ? '#' : '.';
339 fputc(ch, out);
340 break;
341 case OUTFMT_ANSI:
342 fprintf(out, "%c[0;%d;%dm %c[0m",
343 0x1b,
344 1,
345 31 + optColors[val],
346 0x1b);
347 break;
348 }
349 }
350 }
351 }
352
353
354 void dmDumpCharASCII(FILE *outFile, const uint8_t *buf, int *offs, int format, BOOL multicolor)
355 {
356 int yc;
357
358 for (yc = 0; yc < C64_CHR_HEIGHT; yc++)
359 {
360 fprintf(outFile, "%04x : ", *offs);
361 dmPrintByte(outFile, buf[yc], format, multicolor);
362 fprintf(outFile, "\n");
363 (*offs)++;
364 }
365 }
366
367
368 void dmDumpSpriteASCII(FILE *outFile, const uint8_t *buf, int *offs, int format, BOOL multicolor)
369 {
370 int bufOffs, xc, yc;
371
372 for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++)
373 {
374 fprintf(outFile, "%04x : ", *offs);
375 for (xc = 0; xc < C64_SPR_WIDTH; xc++)
376 {
377 dmPrintByte(outFile, buf[bufOffs], format, multicolor);
378 fprintf(outFile, " ");
379 bufOffs++;
380 (*offs)++;
381 }
382 fprintf(outFile, "\n");
383 }
384 (*offs)++;
385 }
386
387
388 int dmWriteImageData(DMImage *img, void *cbdata, BOOL (*writeRowCB)(void *, uint8_t *, size_t), int scale, int format)
389 {
390 int x, y, yscale, xscale, res = 0, rowSize, rowWidth;
391 uint8_t *row = NULL;
392
393 // Allocate memory for row buffer
394 rowWidth = img->width * scale;
395 rowSize = rowWidth * dmImageGetBytesPerPixel(format);
396
397 if ((row = dmMalloc(rowSize + 16)) == NULL)
398 {
399 res = -16;
400 goto done;
401 }
402
403 // Generate the image
404 for (y = 0; y < img->height; y++)
405 {
406 uint8_t *ptr = row,
407 *ptr1 = row,
408 *ptr2 = ptr1 + rowWidth,
409 *ptr3 = ptr2 + rowWidth;
410
411 for (x = 0; x < img->width; x++)
412 {
413 uint8_t c = img->data[(y * img->pitch) + x], qr, qg, qb, qa;
414 switch (format)
415 {
416 case DM_IFMT_PALETTE:
417 for (xscale = 0; xscale < scale; xscale++)
418 *ptr++ = c;
419 break;
420
421 case DM_IFMT_RGBA:
422 qr = img->pal[c].r;
423 qg = img->pal[c].g;
424 qb = img->pal[c].b;
425 qa = (c == img->ctrans) ? 0 : 255;
426
427 for (xscale = 0; xscale < scale; xscale++)
428 {
429 *ptr++ = qr;
430 *ptr++ = qg;
431 *ptr++ = qb;
432 *ptr++ = qa;
433 }
434 break;
435
436 case DM_IFMT_RGB:
437 qr = img->pal[c].r;
438 qg = img->pal[c].g;
439 qb = img->pal[c].b;
440
441 for (xscale = 0; xscale < scale; xscale++)
442 {
443 *ptr++ = qr;
444 *ptr++ = qg;
445 *ptr++ = qb;
446 }
447 break;
448
449 case DM_IFMT_RGB_PLANE:
450 qr = img->pal[c].r;
451 qg = img->pal[c].g;
452 qb = img->pal[c].b;
453
454 for (xscale = 0; xscale < scale; xscale++)
455 {
456 *ptr1++ = qr;
457 *ptr2++ = qg;
458 *ptr3++ = qb;
459 }
460 break;
461 }
462 }
463
464 for (yscale = 0; yscale < scale; yscale++)
465 {
466 if (!writeRowCB(cbdata, row, rowSize))
467 {
468 res = -32;
469 goto done;
470 }
471 }
472 }
473
474 done:
475 dmFree(row);
476 return res;
477 }
478
479
480 #define DMCOL(x) (((x) >> 4) & 0xf)
481
482 int dmWriteIFFMasterRAWPalette(const char *filename, DMImage *img, int ncolors)
483 {
484 FILE *fp;
485 int i;
486
487 if ((fp = fopen(filename, "w")) == NULL)
488 {
489 dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
490 return -15;
491 }
492
493 for (i = 0; i < ncolors; i++)
494 {
495 int color;
496 if (i < img->ncolors)
497 {
498 color = (DMCOL(img->pal[i].r) << 8) |
499 (DMCOL(img->pal[i].g) << 4) |
500 (DMCOL(img->pal[i].b));
501 }
502 else
503 color = 0;
504
505 fprintf(fp, "\tdc.w $%04X\n", color);
506 }
507
508 return 0;
509 }
510
511
512 typedef struct
513 {
514 int bpp;
515 DMImage *img;
516 FILE *fp;
517 } DMRawData;
518
519
520 static BOOL dmWriteIFFMasterRAWRow(void *cbdata, uint8_t *row, size_t len)
521 {
522 DMRawData *raw = (DMRawData *) cbdata;
523 size_t i;
524
525 for (i = 0; i < len; i++)
526 {
527 }
528
529 return fwrite(row, sizeof(uint8_t), len, raw->fp) == len;
530 }
531
532
533 int dmWriteIFFMasterRAWImageFILE(FILE *fp, DMImage *img, int scale, int bpp)
534 {
535 DMRawData raw;
536
537 raw.fp = fp;
538 raw.img = img;
539 raw.bpp = bpp;
540
541 return dmWriteImageData(img, (void *) &raw, dmWriteIFFMasterRAWRow, scale, DM_IFMT_PALETTE);
542 }
543
544 int dmWriteIFFMasterRAWImage(const char *filename, DMImage *img, int scale, int bpp)
545 {
546 FILE *fp;
547 int res;
548
549 if ((fp = fopen(filename, "wb")) == NULL)
550 {
551 dmError("IFFMasterRAW: Could not open file '%s' for writing.\n", filename);
552 return -15;
553 }
554
555 res = dmWriteIFFMasterRAWImageFILE(fp, img, scale, bpp);
556
557 fclose(fp);
558 return res;
559 }
560
561
562 static BOOL dmWritePPMRow(void *cbdata, uint8_t *row, size_t len)
563 {
564 return fwrite(row, sizeof(uint8_t), len, (FILE *) cbdata) == len;
565 }
566
567
568 int dmWritePPMImageFILE(FILE *fp, DMImage *img, int scale)
569 {
570 // Write PPM header
571 fprintf(fp,
572 "P6\n%d %d\n255\n",
573 img->width * scale, img->height * scale);
574
575 // Write image data
576 return dmWriteImageData(img, (void *) fp, dmWritePPMRow, scale, DM_IFMT_RGB);
577 }
578
579
580 int dmWritePPMImage(const char *filename, DMImage *img, int scale)
581 {
582 FILE *fp;
583 int res;
584
585 // Create output file
586 if ((fp = fopen(filename, "wb")) == NULL)
587 {
588 dmError("PPM: could not open file '%s' for writing.\n", filename);
589 return -15;
590 }
591
592 res = dmWritePPMImageFILE(fp, img, scale);
593
594 fclose(fp);
595 return res;
596 }
597
598
599 #ifdef HAVE_LIBPNG
600 static BOOL dmWritePNGRow(void *cbdata, uint8_t *row, size_t len)
601 {
602 png_structp png_ptr = cbdata;
603 (void) len;
604
605 if (setjmp(png_jmpbuf(png_ptr)))
606 return FALSE;
607
608 png_write_row(png_ptr, row);
609
610 return TRUE;
611 }
612
613
614 int dmWritePNGImageFILE(FILE *fp, DMImage *img, int scale, int format)
615 {
616 png_structp png_ptr = NULL;
617 png_infop info_ptr = NULL;
618 png_colorp palette = NULL;
619 int fmt;
620
621 // Create PNG structures
622 png_ptr = png_create_write_struct(
623 PNG_LIBPNG_VER_STRING,
624 NULL, NULL, NULL);
625
626 if (png_ptr == NULL)
627 {
628 dmError("PNG: png_create_write_struct() failed.\n");
629 goto error;
630 }
631
632 info_ptr = png_create_info_struct(png_ptr);
633 if (info_ptr == NULL)
634 {
635 dmError("PNG: png_create_info_struct(%p) failed.\n", png_ptr);
636 goto error;
637 }
638
639 if (setjmp(png_jmpbuf(png_ptr)))
640 {
641 dmError("PNG: Error during image writing..\n");
642 goto error;
643 }
644
645 png_init_io(png_ptr, fp);
646
647 // Write PNG header info
648 switch (format)
649 {
650 case DM_IFMT_PALETTE: fmt = PNG_COLOR_TYPE_PALETTE; break;
651 case DM_IFMT_RGB : fmt = PNG_COLOR_TYPE_RGB; break;
652 case DM_IFMT_RGBA : fmt = PNG_COLOR_TYPE_RGB_ALPHA; break;
653 default:
654 dmError("PNG: Internal error, unsupported image format %d.\n", format);
655 goto error;
656 }
657
658 png_set_IHDR(png_ptr, info_ptr,
659 img->width * scale,
660 img->height * scale,
661 8, /* bits per component */
662 fmt,
663 PNG_INTERLACE_NONE,
664 PNG_COMPRESSION_TYPE_DEFAULT,
665 PNG_FILTER_TYPE_DEFAULT);
666
667 // Palette
668 if (format == DM_IFMT_PALETTE)
669 {
670 int i;
671
672 palette = png_malloc(png_ptr, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
673 if (palette == NULL)
674 {
675 dmError("PNG: Could not allocate palette structure.");
676 goto error;
677 }
678
679 memset(palette, 0, PNG_MAX_PALETTE_LENGTH * sizeof(png_color));
680
681 for (i = 0; i < img->ncolors; i++)
682 {
683 palette[i].red = img->pal[i].r;
684 palette[i].green = img->pal[i].g;
685 palette[i].blue = img->pal[i].b;
686 }
687
688 png_set_PLTE(png_ptr, info_ptr, palette, PNG_MAX_PALETTE_LENGTH);
689 }
690
691 // png_set_gAMA(png_ptr, info_ptr, 2.2);
692
693 png_write_info(png_ptr, info_ptr);
694
695
696 // Write compressed image data
697 dmWriteImageData(img, (void *) png_ptr, dmWritePNGRow, scale, format);
698
699 // Write footer
700 png_write_end(png_ptr, NULL);
701
702 png_free(png_ptr, palette);
703 palette = NULL;
704
705 // Deallocate shit
706 if (png_ptr && info_ptr)
707 {
708 png_destroy_write_struct(&png_ptr, &info_ptr);
709 }
710
711 return 0;
712
713 error:
714 png_free(png_ptr, palette);
715 palette = NULL;
716
717 if (png_ptr && info_ptr)
718 {
719 png_destroy_write_struct(&png_ptr, &info_ptr);
720 }
721 return -15;
722 }
723
724
725 int dmWritePNGImage(const char *filename, DMImage *img, int scale, int format)
726 {
727 int res;
728 FILE *fp;
729
730 if ((fp = fopen(filename, "wb")) == NULL)
731 {
732 dmError("PNG: could not open file '%s' for writing.\n", filename);
733 return -15;
734 }
735
736 res = dmWritePNGImageFILE(fp, img, scale, format);
737
738 fclose(fp);
739 return res;
740 }
741 #endif
742
743
744 typedef struct
745 {
746 uint8_t r,g,b;
747 } DMPCXColor;
748
749
750 typedef struct
751 {
752 uint8_t manufacturer,
753 version,
754 encoding,
755 bpp;
756 uint16_t xmin, ymin, xmax, ymax;
757 uint16_t hres, vres;
758 DMPCXColor colormap[16];
759 uint8_t reserved;
760 uint8_t nplanes;
761 uint16_t bpl;
762 uint16_t palinfo;
763 uint8_t filler[58];
764 } DMPCXHeader;
765
766 typedef struct
767 {
768 DMPCXHeader *header;
769 uint8_t *buf;
770 size_t bufLen, bufOffs;
771 int format;
772 FILE *fp;
773 } DMPCXData;
774
775
776 static inline uint8_t dmPCXGetByte(uint8_t *row, const size_t len, const size_t soffs)
777 {
778 return (soffs < len) ? row[soffs] : 0;
779 }
780
781 static BOOL dmPCXFlush(DMPCXData *pcx)
782 {
783 BOOL ret = fwrite(pcx->buf, sizeof(uint8_t), pcx->bufOffs, pcx->fp) == pcx->bufOffs;
784 pcx->bufOffs = 0;
785 return ret;
786 }
787
788 static inline BOOL dmPCXPutByte(DMPCXData *pcx, const uint8_t val)
789 {
790 if (pcx->bufOffs < pcx->bufLen)
791 {
792 pcx->buf[pcx->bufOffs++] = val;
793 return TRUE;
794 }
795 else
796 return dmPCXFlush(pcx);
797 }
798
799 BOOL dmWritePCXRow(void *cbdata, uint8_t *row, size_t len)
800 {
801 DMPCXData *pcx = (DMPCXData *) cbdata;
802 int plane;
803 size_t soffs = 0;
804
805 for (plane = 0; plane < pcx->header->nplanes; plane++)
806 {
807 uint8_t data = dmPCXGetByte(row, len, soffs++),
808 count = 1;
809
810 pcx->bufOffs = 0;
811
812 while (soffs < pcx->header->bpl)
813 {
814 if (data == dmPCXGetByte(row, len, soffs) && count < 63)
815 {
816 count++;
817 soffs++;
818 }
819 else
820 {
821 if (count == 1 && (data & 0xC0) != 0xC0)
822 {
823 if (!dmPCXPutByte(pcx, data))
824 return FALSE;
825 }
826 else
827 {
828 if (!dmPCXPutByte(pcx, 0xC0 | count) ||
829 !dmPCXPutByte(pcx, data))
830 return FALSE;
831 }
832
833 data = dmPCXGetByte(row, len, soffs++);
834 count = 1;
835 }
836 }
837
838 if (count > 1)
839 {
840 if (!dmPCXPutByte(pcx, 0xC0 | count) ||
841 !dmPCXPutByte(pcx, data))
842 return FALSE;
843 }
844
845 if (!dmPCXFlush(pcx))
846 return FALSE;
847 }
848
849 return TRUE;
850 }
851
852
853 int dmWritePCXImage(const char *filename, DMImage *img, int scale, BOOL paletted)
854 {
855 DMPCXData pcx;
856 DMPCXHeader hdr;
857 int res;
858
859 // Create output file
860 pcx.buf = NULL;
861 pcx.format = paletted ? DM_IFMT_PALETTE : DM_IFMT_RGB_PLANE;
862 pcx.header = &hdr;
863 if ((pcx.fp = fopen(filename, "wb")) == NULL)
864 {
865 dmError("PCX: Could not open file '%s' for writing.\n", filename);
866 res = -15;
867 goto error;
868 }
869
870 // Create PCX header
871 memset(&hdr, 0, sizeof(hdr));
872 if (paletted)
873 {
874 int i;
875 for (i = 0; i < (img->ncolors > 16 ? 16 : img->ncolors); i++)
876 {
877 hdr.colormap[i].r = img->pal[i].r;
878 hdr.colormap[i].g = img->pal[i].g;
879 hdr.colormap[i].b = img->pal[i].b;
880 }
881 }
882 hdr.manufacturer = 10;
883 hdr.version = 5;
884 hdr.encoding = 1;
885 hdr.bpp = 8;
886 hdr.hres = img->width * scale;
887 hdr.vres = img->height * scale;
888 hdr.xmin = hdr.ymin = 0;
889 hdr.xmax = hdr.hres - 1;
890 hdr.ymax = hdr.vres - 1;
891 hdr.nplanes = dmImageGetBytesPerPixel(pcx.format);
892 hdr.bpl = (((img->width * scale) / 2) + 1) * 2;
893 hdr.palinfo = 1;
894
895 dmMsg(1, "PCX: paletted=%d, nplanes=%d, bpp=%d, bpl=%d\n",
896 paletted, hdr.nplanes, hdr.bpp, hdr.bpl);
897
898 pcx.bufLen = hdr.bpl * 4;
899 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
900 {
901 dmError("PCX: Could not allocate %d bytes for RLE compression buffer.\n",
902 pcx.bufLen);
903 res = -11;
904 goto error;
905 }
906
907 // Write PCX header
908 if (!dm_fwrite_byte(pcx.fp, hdr.manufacturer) ||
909 !dm_fwrite_byte(pcx.fp, hdr.version) ||
910 !dm_fwrite_byte(pcx.fp, hdr.encoding) ||
911 !dm_fwrite_byte(pcx.fp, hdr.bpp))
912 {
913 dmError("PCX: Could not write basic header data.\n");
914 res = -10;
915 goto error;
916 }
917
918 if (!dm_fwrite_le16(pcx.fp, hdr.xmin) ||
919 !dm_fwrite_le16(pcx.fp, hdr.ymin) ||
920 !dm_fwrite_le16(pcx.fp, hdr.xmax) ||
921 !dm_fwrite_le16(pcx.fp, hdr.ymax) ||
922 !dm_fwrite_le16(pcx.fp, hdr.hres) ||
923 !dm_fwrite_le16(pcx.fp, hdr.vres))
924 {
925 dmError("PCX: Could not write image dimensions.\n");
926 res = -9;
927 goto error;
928 }
929
930 if (!dm_fwrite_str(pcx.fp, (uint8_t *) &hdr.colormap, sizeof(hdr.colormap)))
931 {
932 dmError("PCX: Could not write colormap.\n");
933 res = -8;
934 goto error;
935 }
936
937 if (!dm_fwrite_byte(pcx.fp, hdr.reserved) ||
938 !dm_fwrite_byte(pcx.fp, hdr.nplanes) ||
939 !dm_fwrite_le16(pcx.fp, hdr.bpl) ||
940 !dm_fwrite_le16(pcx.fp, hdr.palinfo) ||
941 !dm_fwrite_str(pcx.fp, (uint8_t *) &hdr.filler, sizeof(hdr.filler)))
942 {
943 dmError("PCX: Could not write header remainder.\n");
944 res = -7;
945 goto error;
946 }
947
948 // Write image data
949 res = dmWriteImageData(img, (void *) &pcx, dmWritePCXRow, scale, pcx.format);
950
951 // Write VGA palette
952 if (paletted)
953 {
954 int i;
955 dm_fwrite_byte(pcx.fp, 0x0C);
956
957 for (i = 0; i < img->ncolors; i++)
958 {
959 dm_fwrite_byte(pcx.fp, img->pal[i].r);
960 dm_fwrite_byte(pcx.fp, img->pal[i].g);
961 dm_fwrite_byte(pcx.fp, img->pal[i].b);
962 }
963
964 // Pad the palette, if necessary
965 for (; i < 256; i++)
966 {
967 dm_fwrite_byte(pcx.fp, 0);
968 dm_fwrite_byte(pcx.fp, 0);
969 dm_fwrite_byte(pcx.fp, 0);
970 }
971 }
972
973 error:
974 if (pcx.fp != NULL)
975 fclose(pcx.fp);
976
977 dmFree(pcx.buf);
978
979 return res;
980 }
981
982
983 static BOOL dmPCXDecodeRLERow(FILE *fp, uint8_t *buf, const size_t bufLen)
984 {
985 size_t offs = 0;
986 do
987 {
988 int count;
989 uint8_t data;
990
991 if (!dm_fread_byte(fp, &data))
992 return FALSE;
993
994 if ((data & 0xC0) == 0xC0)
995 {
996 count = data & 0x3F;
997 if (!dm_fread_byte(fp, &data))
998 return FALSE;
999 }
1000 else
1001 count = 1;
1002
1003 while (count-- && offs < bufLen)
1004 buf[offs++] = data;
1005
1006 } while (offs < bufLen);
1007
1008 return TRUE;
1009 }
1010
1011
1012 int dmReadPCXImageFILE(FILE *fp, DMImage **pimg)
1013 {
1014 DMImage *img;
1015 DMPCXData pcx;
1016 DMPCXHeader hdr;
1017 BOOL paletted;
1018 int res = 0, yc, xc;
1019 uint8_t *dp;
1020
1021 pcx.buf = NULL;
1022
1023 // Read PCX header
1024 if (!dm_fread_byte(fp, &hdr.manufacturer) ||
1025 !dm_fread_byte(fp, &hdr.version) ||
1026 !dm_fread_byte(fp, &hdr.encoding) ||
1027 !dm_fread_byte(fp, &hdr.bpp))
1028 {
1029 dmError("PCX: Could not read basic header data.\n");
1030 res = -9;
1031 }
1032
1033 if (hdr.manufacturer != 10 ||
1034 hdr.version != 5 ||
1035 hdr.encoding != 1 ||
1036 hdr.bpp != 8)
1037 {
1038 dmError("PCX: Not a PCX file, or unsupported variant.\n");
1039 res = -11;
1040 goto error;
1041 }
1042
1043 if (!dm_fread_le16(fp, &hdr.xmin) ||
1044 !dm_fread_le16(fp, &hdr.ymin) ||
1045 !dm_fread_le16(fp, &hdr.xmax) ||
1046 !dm_fread_le16(fp, &hdr.ymax) ||
1047 !dm_fread_le16(fp, &hdr.hres) ||
1048 !dm_fread_le16(fp, &hdr.vres))
1049 {
1050 dmError("PCX: Could not read image dimensions.\n");
1051 res = -8;
1052 goto error;
1053 }
1054
1055 if (!dm_fread_str(fp, (uint8_t *) &hdr.colormap, sizeof(hdr.colormap)))
1056 {
1057 dmError("PCX: Could not read colormap.\n");
1058 res = -7;
1059 goto error;
1060 }
1061
1062 if (!dm_fread_byte(fp, &hdr.reserved) ||
1063 !dm_fread_byte(fp, &hdr.nplanes) ||
1064 !dm_fread_le16(fp, &hdr.bpl) ||
1065 !dm_fread_le16(fp, &hdr.palinfo) ||
1066 !dm_fread_str(fp, (uint8_t *) &hdr.filler, sizeof(hdr.filler)))
1067 {
1068 dmError("PCX: Could not read header remainder.\n");
1069 res = -6;
1070 goto error;
1071 }
1072
1073 if (hdr.nplanes != 3 && hdr.nplanes != 1)
1074 {
1075 dmError("PCX: Unsupported number of bitplanes %d.\n", hdr.nplanes);
1076 res = -4;
1077 goto error;
1078 }
1079
1080 // Allocate image
1081 if ((*pimg = img = dmImageAlloc(hdr.xmax - hdr.xmin + 1, hdr.ymax - hdr.ymin + 1)) == NULL)
1082 {
1083 dmError("PCX: Could not allocate image structure.\n");
1084 res = -5;
1085 goto error;
1086 }
1087
1088 paletted = hdr.nplanes == 1;
1089 pcx.bufLen = hdr.nplanes * hdr.bpl;
1090 if ((pcx.buf = dmMalloc(pcx.bufLen)) == NULL)
1091 {
1092 dmError("PCX: Could not allocate RLE buffer.\n");
1093 res = -3;
1094 goto error;
1095 }
1096
1097 // Read image data
1098 dp = img->data;
1099 for (yc = 0; yc < img->height; yc++)
1100 {
1101 // Decode row of RLE'd data
1102 if (!dmPCXDecodeRLERow(fp, pcx.buf, pcx.bufLen))
1103 {
1104 dmError("PCX: Error decoding RLE data.\n");
1105 res = -100;
1106 goto error;
1107 }
1108
1109 // Decode bitplanes
1110 switch (hdr.nplanes)
1111 {
1112 case 1:
1113 memcpy(dp, pcx.buf, img->width);
1114 break;
1115
1116 case 3:
1117 {
1118 uint8_t *dptr = dp,
1119 *sptr1 = pcx.buf,
1120 *sptr2 = sptr1 + hdr.bpl,
1121 *sptr3 = sptr2 + hdr.bpl;
1122
1123 for (xc = 0; xc < img->width; xc++)
1124 {
1125 *dptr++ = *sptr1++;
1126 *dptr++ = *sptr2++;
1127 *dptr++ = *sptr3++;
1128 }
1129 }
1130 break;
1131 }
1132
1133 dp += img->pitch;
1134 }
1135
1136 // Read VGA palette
1137 if (paletted)
1138 {
1139 int i;
1140 uint8_t tmpb;
1141
1142 if (!dm_fread_byte(fp, &tmpb) || tmpb != 0x0C)
1143 goto error;
1144
1145 for (i = 0; i < img->ncolors; i++)
1146 {
1147 if (!dm_fread_byte(fp, &tmpb))
1148 goto error;
1149 img->pal[i].r = tmpb;
1150
1151 if (!dm_fread_byte(fp, &tmpb))
1152 goto error;
1153 img->pal[i].g = tmpb;
1154
1155 if (!dm_fread_byte(fp, &tmpb))
1156 goto error;
1157 img->pal[i].b = tmpb;
1158 }
1159 }
1160
1161 error:
1162 dmFree(pcx.buf);
1163 return res;
1164 }
1165
1166
1167 int dmReadPCXImage(const char *filename, DMImage **pimg)
1168 {
1169 FILE *fp;
1170 int res;
1171
1172 if ((fp = fopen(filename, "rb")) == NULL)
1173 {
1174 dmError("PCX: Could not open file '%s' for reading.\n", filename);
1175 return -15;
1176 }
1177
1178 res = dmReadPCXImageFILE(fp, pimg);
1179
1180 fclose(fp);
1181 return res;
1182 }
1183
1184
1185 int fmtProbePNGImageFILE(FILE *fp)
1186 {
1187 uint8_t buf[6];
1188 // if (!dm_fread_str(fp,
1189 return DM_PROBE_SCORE_FALSE;
1190 }
1191
1192
1193 int fmtProbePCXImageFILE(FILE *fp)
1194 {
1195 DMPCXHeader hdr;
1196
1197 if (!dm_fread_byte(fp, &hdr.manufacturer) ||
1198 !dm_fread_byte(fp, &hdr.version) ||
1199 !dm_fread_byte(fp, &hdr.encoding) ||
1200 !dm_fread_byte(fp, &hdr.bpp))
1201 return DM_PROBE_SCORE_FALSE;
1202
1203 if (hdr.manufacturer == 10 &&
1204 hdr.version == 5 &&
1205 hdr.encoding == 1 &&
1206 hdr.bpp == 8)
1207 return DM_PROBE_SCORE_GOOD;
1208
1209 return DM_PROBE_SCORE_FALSE;
1210 }
1211
1212
1213 #ifdef UNFINISHED
1214 int dmConvertBMP2(DMImage *screen, const DM64Image *img)
1215 {
1216 int yc;
1217 uint8_t *dp = screen->data;
1218
1219 for (yc = 0; yc < screen->height; yc++)
1220 {
1221 uint8_t *d = dp;
1222 const int y = yc / 8, yb = yc & 7;
1223 const int scroffsy = y * C64_SCR_CH_WIDTH;
1224 const int bmoffsy = y * C64_SCR_WIDTH;
1225 int xc;
1226
1227 for (xc = 0; xc < screen->width / 2; xc++)
1228 {
1229 const int x = xc / 4;
1230 const int scroffs = scroffsy + x;
1231 const int b = img->bitmap[0][bmoffsy + (x * 8) + yb];
1232 const int v = 6 - ((xc * 2) & 6);
1233 uint8_t c;
1234
1235 switch ((b >> v) & 3)
1236 {
1237 case 0: c = img->bgcolor; break;
1238 case 1: c = img->screen[0][scroffs] >> 4; break;
1239 case 2: c = img->screen[0][scroffs] & 15; break;
1240 case 3: c = img->color[0][scroffs] & 15; break;
1241 }
1242
1243 *d++ = c;
1244 *d++ = c;
1245 }
1246
1247 dp += screen->pitch;
1248 }
1249
1250 return 0;
1251 }
1252 #endif
1253
1254
1255 int dmWriteImage(char *filename, DMImage *image, int format, BOOL paletted, int scale, int bpp)
1256 {
1257 switch (format)
1258 {
1259 #ifdef HAVE_LIBPNG
1260 case OUTFMT_PNG:
1261 return dmWritePNGImage(filename, image, scale, paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA);
1262 #endif
1263
1264 case OUTFMT_PPM:
1265 return dmWritePPMImage(filename, image, scale);
1266
1267 case OUTFMT_PCX:
1268 return dmWritePCXImage(filename, image, scale, paletted);
1269
1270 case OUTFMT_ARAW:
1271 {
1272 int res;
1273 char *palFilename = dm_strdup_printf("%s.pal", filename);
1274 res = dmWriteIFFMasterRAWPalette(palFilename, image, 1 << bpp);
1275 dmFree(palFilename);
1276 if (res != 0)
1277 return res;
1278
1279 return dmWriteIFFMasterRAWImage(filename, image, scale, bpp);
1280 }
1281
1282 default:
1283 return FALSE;
1284 }
1285 }
1286
1287
1288 int dmDumpSpritesAndChars(FILE *inFile)
1289 {
1290 int dataOffs, itemCount, outWidth, outWidthPX, outHeight;
1291 size_t bufSize;
1292 uint8_t *bufData;
1293
1294 switch (optInFormat)
1295 {
1296 case INFMT_CHAR:
1297 bufSize = C64_CHR_SIZE;
1298 outWidth = C64_CHR_WIDTH;
1299 outWidthPX = C64_CHR_WIDTH_PX;
1300 outHeight = C64_CHR_HEIGHT;
1301 break;
1302 case INFMT_SPRITE:
1303 bufSize = C64_SPR_SIZE;
1304 outWidth = C64_SPR_WIDTH;
1305 outWidthPX = C64_SPR_WIDTH_PX;
1306 outHeight = C64_SPR_HEIGHT;
1307 break;
1308 default:
1309 dmError("Invalid input format %d, internal error.\n", optInFormat);
1310 return -1;
1311 }
1312
1313 if ((bufData = dmMalloc(bufSize)) == NULL)
1314 {
1315 dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize);
1316 return -2;
1317 }
1318
1319
1320 dataOffs = optInSkip;
1321 itemCount = 0;
1322
1323 if (optOutFormat == OUTFMT_ANSI || optOutFormat == OUTFMT_ASCII)
1324 {
1325 BOOL error = FALSE;
1326 FILE *outFile;
1327
1328 if (optOutFilename == NULL)
1329 outFile = stdout;
1330 else
1331 if ((outFile = fopen(optOutFilename, "w")) == NULL)
1332 {
1333 int res = errno;
1334 dmError("Error opening output file '%s'. (%s)\n",
1335 optOutFilename, strerror(res));
1336 goto error;
1337 }
1338
1339 while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount))
1340 {
1341 memset(bufData, 0, bufSize);
1342
1343 if (fread(bufData, 1, bufSize, inFile) != bufSize)
1344 {
1345 dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
1346 bufSize, dataOffs);
1347 error = TRUE;
1348 }
1349
1350 fprintf(outFile, "---- : -------------- #%d\n", itemCount);
1351
1352 switch (optInFormat)
1353 {
1354 case INFMT_CHAR:
1355 dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
1356 break;
1357 case INFMT_SPRITE:
1358 dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor);
1359 break;
1360 }
1361 itemCount++;
1362 }
1363
1364 fclose(outFile);
1365 }
1366 else
1367 if (optOutFormat == OUTFMT_PNG || optOutFormat == OUTFMT_PPM || optOutFormat == OUTFMT_PCX)
1368 {
1369 DMImage *outImage = NULL;
1370 char *outFilename = NULL;
1371 int outX = 0, outY = 0, err;
1372
1373 #ifndef HAVE_LIBPNG
1374 if (optOutFormat == OUTFMT_PNG)
1375 {
1376 dmError("PNG output format support not compiled in, sorry.\n");
1377 goto error;
1378 }
1379 #endif
1380
1381 if (optSequential)
1382 {
1383 if (optOutFilename == NULL)
1384 {
1385 dmError("Sequential image output requires filename template.\n");
1386 goto error;
1387 }
1388
1389 outImage = dmImageAlloc(outWidthPX, outHeight);
1390 dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n",
1391 optItemCount,
1392 outImage->width, outImage->height,
1393 outImage->width * optScale, outImage->height * optScale);
1394 }
1395 else
1396 {
1397 int outIWidth, outIHeight;
1398 if (optItemCount <= 0)
1399 {
1400 dmError("Single-image output requires count to be set (-n).\n");
1401 goto error;
1402 }
1403
1404 outIWidth = optPlanedWidth;
1405 outIHeight = (optItemCount / optPlanedWidth);
1406 if (optItemCount % optPlanedWidth)
1407 outIHeight++;
1408
1409 outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight);
1410 dmMsg(1, "Outputting image %d x %d -> %d x %d.\n",
1411 outImage->width, outImage->height,
1412 outImage->width * optScale, outImage->height * optScale);
1413 }
1414
1415 outImage->constpal = TRUE;
1416 outImage->pal = dmC64Palette;
1417 outImage->ncolors = C64_NCOLORS;
1418 outImage->ctrans = 255;
1419
1420 while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount))
1421 {
1422 memset(bufData, 0, bufSize);
1423
1424 if (fread(bufData, 1, bufSize, inFile) != bufSize)
1425 {
1426 dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n",
1427 bufSize, dataOffs);
1428 break;
1429 }
1430
1431 if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight,
1432 bufData, outWidth, outHeight, optInMulticolor, optColors)) != 0)
1433 {
1434 dmError("Internal error in conversion of raw data to bitmap: %d.\n", err);
1435 break;
1436 }
1437
1438 if (optSequential)
1439 {
1440 outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, outFormatList[optOutFormat]);
1441 if (outFilename == NULL)
1442 {
1443 dmError("Could not allocate memory for filename template?\n");
1444 goto error;
1445 }
1446
1447 dmWriteImage(outFilename, outImage, optOutFormat, optPaletted, optScale, optBPP);
1448 dmFree(outFilename);
1449 }
1450 else
1451 {
1452 if (++outX >= optPlanedWidth)
1453 {
1454 outX = 0;
1455 outY++;
1456 }
1457 }
1458
1459 itemCount++;
1460 }
1461
1462 if (!optSequential)
1463 {
1464 dmWriteImage(optOutFilename, outImage, optOutFormat, optPaletted, optScale, optBPP);
1465 }
1466
1467 dmImageFree(outImage);
1468 }
1469
1470 dmFree(bufData);
1471 return 0;
1472
1473 error:
1474 dmFree(bufData);
1475 return -1;
1476 }
1477
1478
1479 int main(int argc, char *argv[])
1480 {
1481 FILE *inFile;
1482 int i, optInImageFormat;
1483
1484 // Default colors
1485 for (i = 0; i < C64_MAX_COLORS; i++)
1486 optColors[i] = i + 1;
1487
1488 // Initialize and parse commandline
1489 dmInitProg("gfxconv", "Simple c64 graphics converter", "0.4", NULL, NULL);
1490
1491 if (!dmArgsProcess(argc, argv, optList, optListN,
1492 argHandleOpt, argHandleFile, TRUE))
1493 exit(1);
1494
1495 // Determine input format, if not specified'
1496 if (optInFormat == INFMT_AUTO && optInFilename != NULL)
1497 {
1498 char *dext = strrchr(optInFilename, '.');
1499 if (dext)
1500 {
1501 dext++;
1502 if (!strcasecmp(dext, "fnt") || !strcasecmp(dext, "chr"))
1503 optInFormat = INFMT_CHAR;
1504 else if (!strcasecmp(dext, "spr"))
1505 optInFormat = INFMT_SPRITE;
1506 else if (!strcasecmp(dext, "png") || !strcasecmp(dext, "pcx"))
1507 optInFormat = INFMT_IMAGE;
1508 }
1509 }
1510
1511 if (optInFilename == NULL)
1512 {
1513 if (optInFormat == INFMT_AUTO)
1514 {
1515 dmError("Standard input cannot be used without specifying input format.\n");
1516 exit(3);
1517 }
1518 inFile = stdin;
1519 }
1520 else
1521 if ((inFile = fopen(optInFilename, "rb")) == NULL)
1522 {
1523 int res = errno;
1524 dmError("Error opening input file '%s'. (%s)\n",
1525 optInFilename, strerror(res));
1526 exit(3);
1527 }
1528
1529 if (optInFormat == INFMT_AUTO)
1530 {
1531 // Skip, if needed
1532 if (fseek(inFile, optInSkip, SEEK_SET) != 0)
1533 {
1534 int res = errno;
1535 dmError("Could not seek to file position %d (0x%x): %s\n",
1536 optInSkip, optInSkip, strerror(res));
1537 exit(3);
1538 }
1539 #if 0
1540 if (optInFormat == INFMT_AUTO)
1541 {
1542 int ret = dmC64ProbeGeneric
1543 }
1544 #endif
1545
1546 if (optInFormat == INFMT_AUTO || optInFormat == INFMT_IMAGE)
1547 {
1548 if (fmtProbePNGImageFILE(inFile))
1549 {
1550 optInFormat = INFMT_IMAGE;
1551 optInImageFormat = OUTFMT_PNG;
1552 }
1553 else
1554 if (fmtProbePCXImageFILE(inFile))
1555 {
1556 optInFormat = INFMT_IMAGE;
1557 optInImageFormat = OUTFMT_PCX;
1558 }
1559 else
1560 if (optInFormat == INFMT_IMAGE)
1561 {
1562 dmError("Unsupported image input format.\n");
1563 exit(4);
1564 }
1565 }
1566 }
1567
1568 if (optInFormat == INFMT_AUTO)
1569 {
1570 dmError("No input format specified, and could not be determined automatically.\n");
1571 exit(1);
1572 }
1573
1574 // Skip, if needed
1575 if (fseek(inFile, optInSkip, SEEK_SET) != 0)
1576 {
1577 int res = errno;
1578 dmError("Could not seek to file position %d (0x%x): %s\n",
1579 optInSkip, optInSkip, strerror(res));
1580 exit(3);
1581 }
1582
1583 switch (optInFormat)
1584 {
1585 case INFMT_SPRITE:
1586 case INFMT_CHAR:
1587 dmDumpSpritesAndChars(inFile);
1588 break;
1589
1590 case INFMT_BITMAP:
1591 case INFMT_IMAGE:
1592 {
1593 DMImage *img;
1594 int res;
1595
1596 if (optOutFilename == NULL)
1597 {
1598 dmError("Output filename not set, required for image formats.\n");
1599 exit(3);
1600 }
1601
1602 // Read input
1603 switch (optInImageFormat)
1604 {
1605 case OUTFMT_PCX:
1606 res = dmReadPCXImageFILE(inFile, &img);
1607 break;
1608 case OUTFMT_PNG:
1609 // res = dmReadPNGImageFILE(inFile, &img);
1610 break;
1611 }
1612
1613 switch (optOutFormat)
1614 {
1615 case OUTFMT_PCX:
1616 case OUTFMT_PPM:
1617 case OUTFMT_PNG:
1618 case OUTFMT_ARAW:
1619 res = dmWriteImage(optOutFilename, img, optOutFormat, optPaletted, optScale, optBPP);
1620 break;
1621 }
1622 }
1623 break;
1624 }
1625
1626 fclose(inFile);
1627
1628 exit(0);
1629 return 0;
1630 }