source: trunk/JPGPROC/source/gbmsrc/gbmcpal.c@ 2

Last change on this file since 2 was 2, checked in by stevenhl, 8 years ago

Import sources from cwmm-full.zip dated 2005-03-21

File size: 20.3 KB
Line 
1/*
2
3gbmcpal.c - Map to Common Palette
4
5*/
6
7/*...sincludes:0:*/
8#include <stdio.h>
9#include <ctype.h>
10#include <string.h>
11#include <stddef.h>
12#include <stdlib.h>
13#include <stdarg.h>
14#if defined(AIX) || defined(LINUX) || defined(MAC)
15#include <unistd.h>
16#else
17#include <io.h>
18#endif
19#include <fcntl.h>
20#ifdef MAC
21#include <types.h>
22#include <stat.h>
23#else
24#include <sys/types.h>
25#include <sys/stat.h>
26#endif
27#ifndef O_BINARY
28#define O_BINARY 0
29#endif
30#include "gbm.h"
31#include "gbmhist.h"
32#include "gbmmcut.h"
33
34/*...vgbm\46\h:0:*/
35/*...vgbmhist\46\h:0:*/
36/*...vgbmmcut\46\h:0:*/
37/*...e*/
38
39static char progname[] = "gbmcpal";
40
41/*...sfatal:0:*/
42static void fatal(const char *fmt, ...)
43 {
44 va_list vars;
45 char s[256+1];
46
47 va_start(vars, fmt);
48 vsprintf(s, fmt, vars);
49 va_end(vars);
50 fprintf(stderr, "%s: %s\n", progname, s);
51 exit(1);
52 }
53/*...e*/
54/*...susage:0:*/
55static void usage(void)
56 {
57 int ft, n_ft;
58
59 fprintf(stderr, "usage: %s [-m map] [-v] n1 n2 n3 ifspec{,opt} ofspec{,opt}\n", progname);
60 fprintf(stderr, "flags: -m map mapping to perform (default freq6:6:6:256)\n");
61 fprintf(stderr, " freqR:G:B:N map all bitmaps to same palette, worked\n");
62 fprintf(stderr, " out using frequency of use histogram\n");
63 fprintf(stderr, " mcutN map all bitmaps to same palette, worked\n");
64 fprintf(stderr, " out using median cut algorithm\n");
65 fprintf(stderr, " rofreqR:G:B:N:N2 map each bitmap to frequency palette,\n");
66 fprintf(stderr, " reordered to minimise differences\n");
67 fprintf(stderr, " between successive bitmaps\n");
68 fprintf(stderr, " romcutN:N2 map each bitmap to median cut palette,\n");
69 fprintf(stderr, " reordered to minimise differences\n");
70 fprintf(stderr, " between successive bitmaps\n");
71 fprintf(stderr, " R,G,B are bits of red, green and blue\n");
72 fprintf(stderr, " to keep, N is number of unique colours,\n");
73 fprintf(stderr, " N2 is extra palette entries\n");
74 fprintf(stderr, " -v verbose mode\n");
75 fprintf(stderr, " n1 n2 n3 for ( f=n1; f<n2; f+=n3 )\n");
76 fprintf(stderr, " ifspec printf(ifspec, f);\n");
77 fprintf(stderr, " ofspec printf(ofspec, f);\n");
78 fprintf(stderr, " filespecs are of the form fn.ext\n");
79 fprintf(stderr, " ext's are used to deduce desired bitmap file formats\n");
80
81 gbm_init();
82 gbm_query_n_filetypes(&n_ft);
83 for ( ft = 0; ft < n_ft; ft++ )
84 {
85 GBMFT gbmft;
86
87 gbm_query_filetype(ft, &gbmft);
88 fprintf(stderr, " %s when ext in [%s]\n",
89 gbmft.short_name, gbmft.extensions);
90 }
91 gbm_deinit();
92
93 fprintf(stderr, " opt's bitmap format specific options\n");
94 fprintf(stderr, " eg: %s -m mcut256 0 100 1 24bit%%03d.bmp 8bit%%03d.bmp\n", progname);
95
96 exit(1);
97 }
98/*...e*/
99/*...ssame:0:*/
100static BOOLEAN same(const char *s1, const char *s2, int n)
101 {
102 for ( ; n--; s1++, s2++ )
103 if ( tolower(*s1) != tolower(*s2) )
104 return FALSE;
105 return TRUE;
106 }
107/*...e*/
108/*...smain:0:*/
109#define CVT_FREQ 0
110#define CVT_MCUT 1
111#define CVT_ROFREQ 2
112#define CVT_ROMCUT 3
113
114static BOOLEAN verbose = FALSE;
115
116/*...sget_masks:0:*/
117/*
118Returns TRUE if a set of masks given at map.
119Also sets *rm, *gm, *bm from these.
120Else returns FALSE.
121*/
122
123static byte mask[] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
124
125static BOOLEAN get_masks(char *map, byte *rm, byte *gm, byte *bm)
126 {
127 if ( map[0] < '0' || map[0] > '8' ||
128 map[1] != ':' ||
129 map[2] < '0' || map[2] > '8' ||
130 map[3] != ':' ||
131 map[4] < '0' || map[4] > '8' )
132 return FALSE;
133
134 *rm = mask[map[0] - '0'];
135 *gm = mask[map[2] - '0'];
136 *bm = mask[map[4] - '0'];
137 return TRUE;
138 }
139/*...e*/
140/*...salloc_mem:0:*/
141static byte *alloc_mem(const GBM *gbm)
142 {
143 int stride, bytes;
144 byte *p;
145
146 stride = ( ((gbm->w * gbm->bpp + 31)/32) * 4 );
147 bytes = stride * gbm->h;
148 if ( (p = malloc((size_t) bytes)) == NULL )
149 fatal("out of memory allocating %d bytes", bytes);
150
151 return p;
152 }
153/*...e*/
154/*...sread_bitmap:0:*/
155static void read_bitmap(
156 const char *fn, const char *opt,
157 GBM *gbm, GBMRGB gbmrgb[], byte **data
158 )
159 {
160 int ft, fd;
161 GBM_ERR rc;
162
163 if ( verbose )
164 {
165 if ( *opt != '\0' )
166 printf("Reading %s,%s\n", fn, opt);
167 else
168 printf("Reading %s\n", fn);
169 }
170
171 if ( gbm_guess_filetype(fn, &ft) != GBM_ERR_OK )
172 fatal("can't guess bitmap file format for %s", fn);
173
174 if ( (fd = gbm_io_open(fn, O_RDONLY|O_BINARY)) == -1 )
175 fatal("can't open %s", fn);
176
177 if ( (rc = gbm_read_header(fn, fd, ft, gbm, opt)) != GBM_ERR_OK )
178 {
179 gbm_io_close(fd);
180 fatal("can't read header of %s: %s", fn, gbm_err(rc));
181 }
182
183 if ( (rc = gbm_read_palette(fd, ft, gbm, gbmrgb)) != GBM_ERR_OK )
184 {
185 gbm_io_close(fd);
186 fatal("can't read palette of %s: %s", fn, gbm_err(rc));
187 }
188
189 (*data) = alloc_mem(gbm);
190
191 if ( (rc = gbm_read_data(fd, ft, gbm, (*data))) != GBM_ERR_OK )
192 {
193 free(*data);
194 gbm_io_close(fd);
195 fatal("can't read bitmap data of %s: %s", fn, gbm_err(rc));
196 }
197
198 gbm_io_close(fd);
199 }
200/*...e*/
201/*...sread_bitmap_24:0:*/
202/*...sexpand_to_24bit:0:*/
203static void expand_to_24bit(GBM *gbm, GBMRGB *gbmrgb, byte **data)
204 {
205 int stride = ((gbm->w * gbm->bpp + 31)/32) * 4;
206 int new_stride = ((gbm->w * 3 + 3) & ~3);
207 int bytes, y;
208 byte *new_data;
209
210 if ( gbm->bpp == 24 )
211 return;
212
213 bytes = new_stride * gbm->h;
214 if ( (new_data = malloc((size_t) bytes)) == NULL )
215 fatal("out of memory allocating %d bytes", bytes);
216
217 for ( y = 0; y < gbm->h; y++ )
218 {
219 byte *src = *data + y * stride;
220 byte *dest = new_data + y * new_stride;
221 int x;
222
223 switch ( gbm->bpp )
224 {
225/*...s1:24:*/
226case 1:
227 {
228 byte c;
229
230 for ( x = 0; x < gbm->w; x++ )
231 {
232 if ( (x & 7) == 0 )
233 c = *src++;
234 else
235 c <<= 1;
236
237 *dest++ = gbmrgb[c >> 7].b;
238 *dest++ = gbmrgb[c >> 7].g;
239 *dest++ = gbmrgb[c >> 7].r;
240 }
241 }
242 break;
243/*...e*/
244/*...s4:24:*/
245case 4:
246 for ( x = 0; x + 1 < gbm->w; x += 2 )
247 {
248 byte c = *src++;
249
250 *dest++ = gbmrgb[c >> 4].b;
251 *dest++ = gbmrgb[c >> 4].g;
252 *dest++ = gbmrgb[c >> 4].r;
253 *dest++ = gbmrgb[c & 15].b;
254 *dest++ = gbmrgb[c & 15].g;
255 *dest++ = gbmrgb[c & 15].r;
256 }
257
258 if ( x < gbm->w )
259 {
260 byte c = *src;
261
262 *dest++ = gbmrgb[c >> 4].b;
263 *dest++ = gbmrgb[c >> 4].g;
264 *dest++ = gbmrgb[c >> 4].r;
265 }
266 break;
267/*...e*/
268/*...s8:24:*/
269case 8:
270 for ( x = 0; x < gbm->w; x++ )
271 {
272 byte c = *src++;
273
274 *dest++ = gbmrgb[c].b;
275 *dest++ = gbmrgb[c].g;
276 *dest++ = gbmrgb[c].r;
277 }
278 break;
279/*...e*/
280 }
281 }
282 free(*data);
283 *data = new_data;
284 gbm->bpp = 24;
285 }
286/*...e*/
287
288static void read_bitmap_24(
289 const char *fn, const char *opt,
290 GBM *gbm, byte **data
291 )
292 {
293 GBMRGB gbmrgb[0x100];
294 read_bitmap(fn, opt, gbm, gbmrgb, data);
295 if ( gbm->bpp != 24 )
296 {
297 if ( verbose )
298 printf("Expanding to 24 bpp\n");
299 expand_to_24bit(gbm, gbmrgb, data);
300 }
301 }
302/*...e*/
303/*...sread_bitmap_24_f:0:*/
304static void read_bitmap_24_f(
305 const char *fn, int f, const char *opt,
306 GBM *gbm, byte **data
307 )
308 {
309 char fn_f[500+1];
310 sprintf(fn_f, fn, f);
311 read_bitmap_24(fn_f, opt, gbm, data);
312 }
313/*...e*/
314/*...swrite_bitmap:0:*/
315static void write_bitmap(
316 const char *fn, const char *opt,
317 const GBM *gbm, const GBMRGB gbmrgb[], const byte *data
318 )
319 {
320 int ft, fd, flag;
321 GBM_ERR rc;
322 GBMFT gbmft;
323
324 if ( verbose )
325 {
326 if ( *opt != '\0' )
327 printf("Writing %s,%s\n", fn, opt);
328 else
329 printf("Writing %s\n", fn);
330 }
331
332 if ( gbm_guess_filetype(fn, &ft) != GBM_ERR_OK )
333 fatal("can't guess bitmap file format for %s", fn);
334
335 gbm_query_filetype(ft, &gbmft);
336 switch ( gbm->bpp )
337 {
338 case 24: flag = GBM_FT_W24; break;
339 case 8: flag = GBM_FT_W8; break;
340 case 4: flag = GBM_FT_W4; break;
341 case 1: flag = GBM_FT_W1; break;
342 }
343
344 if ( (gbmft.flags & flag) == 0 )
345 fatal("output bitmap format %s does not support writing %d bpp data",
346 gbmft.short_name, gbm->bpp);
347
348 if ( (fd = gbm_io_create(fn, O_WRONLY|O_BINARY)) == -1 )
349 fatal("can't create %s", fn);
350
351 if ( (rc = gbm_write(fn, fd, ft, gbm, gbmrgb, data, opt)) != GBM_ERR_OK )
352 {
353 gbm_io_close(fd);
354 remove(fn);
355 fatal("can't write %s: %s", fn, gbm_err(rc));
356 }
357
358 gbm_io_close(fd);
359 }
360/*...e*/
361/*...swrite_bitmap_f:0:*/
362static void write_bitmap_f(
363 const char *fn, int f, const char *opt,
364 const GBM *gbm, const GBMRGB gbmrgb[], const byte *data
365 )
366 {
367 char fn_f[500+1];
368 sprintf(fn_f, fn, f);
369 write_bitmap(fn_f, opt, gbm, gbmrgb, data);
370 }
371/*...e*/
372/*...sfreq_map:0:*/
373static void freq_map(
374 int first, int last, int step,
375 const char *fn_src, const char *opt_src,
376 const char *fn_dst, const char *opt_dst,
377 int ncols, byte rm, byte gm, byte bm
378 )
379 {
380 int f;
381 GBMHIST *hist;
382 GBMRGB gbmrgb[0x100];
383
384 for ( ;; )
385 {
386 if ( verbose )
387 printf("Attempting to build histogram data with masks 0x%02x 0x%02x 0x%02x\n",
388 rm, gm, bm);
389 if ( (hist = gbm_create_hist(rm, gm, bm)) == NULL )
390 fatal("can't create histogram data");
391 for ( f = first; f < last; f += step )
392 {
393 GBM gbm; byte *data;
394 BOOLEAN ok;
395 read_bitmap_24_f(fn_src, f, opt_src, &gbm, &data);
396 ok = gbm_add_to_hist(hist, &gbm, data);
397 free(data);
398 if ( !ok )
399 {
400 if ( verbose )
401 printf("Too many colours\n");
402 break;
403 }
404 }
405 if ( f == last )
406 break;
407
408 gbm_delete_hist(hist);
409
410 if ( gm > rm )
411 gm <<= 1;
412 else if ( rm > bm )
413 rm <<= 1;
414 else
415 bm <<= 1;
416 }
417
418 if ( verbose )
419 printf("Working out %d colour palette, based on histogram data\n", ncols);
420
421 gbm_pal_hist(hist, gbmrgb, ncols);
422
423 if ( verbose )
424 printf("Converting files to new optimal palette\n");
425
426 for ( f = first; f < last; f += step )
427 {
428 GBM gbm; byte *data, *data8;
429 read_bitmap_24_f(fn_src, f, opt_src, &gbm, &data);
430 gbm.bpp = 8;
431 data8 = alloc_mem(&gbm);
432 if ( verbose )
433 printf("Mapping to optimal palette\n");
434 gbm_map_hist(hist, &gbm, data, data8);
435 free(data);
436 write_bitmap_f(fn_dst, f, opt_dst, &gbm, gbmrgb, data8);
437 free(data8);
438 }
439
440 gbm_delete_hist(hist);
441 }
442/*...e*/
443/*...smcut_map:0:*/
444static void mcut_map(
445 int first, int last, int step,
446 const char *fn_src, const char *opt_src,
447 const char *fn_dst, const char *opt_dst,
448 int ncols
449 )
450 {
451 int f;
452 GBMMCUT *mcut;
453 GBMRGB gbmrgb[0x100];
454
455 if ( verbose )
456 printf("Attempting to build median cut statistics\n");
457
458 if ( (mcut = gbm_create_mcut()) == NULL )
459 fatal("can't create median cut data");
460 for ( f = first; f < last; f += step )
461 {
462 GBM gbm; byte *data;
463 read_bitmap_24_f(fn_src, f, opt_src, &gbm, &data);
464 gbm_add_to_mcut(mcut, &gbm, data);
465 free(data);
466 }
467
468 if ( verbose )
469 printf("Working out %d colour palette, based on median cut statistics\n", ncols);
470
471 gbm_pal_mcut(mcut, gbmrgb, ncols);
472
473 if ( verbose )
474 printf("Converting files to new optimal palette\n");
475
476 for ( f = first; f < last; f += step )
477 {
478 GBM gbm; byte *data, *data8;
479 read_bitmap_24_f(fn_src, f, opt_src, &gbm, &data);
480 gbm.bpp = 8;
481 data8 = alloc_mem(&gbm);
482 if ( verbose )
483 printf("Mapping to optimal palette\n");
484 gbm_map_mcut(mcut, &gbm, data, data8);
485 free(data);
486 write_bitmap_f(fn_dst, f, opt_dst, &gbm, gbmrgb, data8);
487 free(data8);
488 }
489
490 gbm_delete_mcut(mcut);
491 }
492/*...e*/
493/*...srofreq_map\44\ romcut_map:0:*/
494/*
495
496This code has been written primarily to support crude animation schemes.
497Imagine an animation which is a series of (palette, bitmap-bits) pairs.
498
499If the displayer is unable to change both the palette and bitmap-bits in
500the vertical retrace interval, or if ping-pong double buffering is not
501available, there will be a short time where the new palette has been set, but
502the old bits are still on display. This causes a very disturbing flicker.
503(Similarly, this is true if the displaying program sets the bitmap-bits, and
504then the palette).
505
506This code reorders the new palette, so that its entries are close to the
507previous palette. Old palette entries used by the most pixels are considered
508for this matching process first. Hence only small areas of the image flicker.
509
510eg: old palette = { red , green , light green, black }
511 new palette = { green , orange , dark blue , light green }
512 reordered new palette = { orange, light green, green , dark blue }
513
514 Clearly red->orange is less offensive than red->green etc..
515
516*/
517
518/*...sro_map:0:*/
519/*
520
521The palettes returned using gbm_hist/mcut are sorted with most used first.
522(Index through MAP to get palette entries in PAL in order of frequency).
523
524Map first image to palette PAL and bits BITS.
525For i = 0 to ncols-1
526 MAP[i] = i
527Write out image PAL and BITS
528For each subsequent image
529 Map image to PAL' and BITS'
530 For i = 0 to ncols-1
531 MAP'[i] = -1
532 For i = 0 to ncols-1
533 j = index of closest entry to PAL[MAP[i]] in PAL',
534 with MAP'[j] = -1
535 MAP'[j] = MAP[i];
536 For i = 0 to ncols-1
537 PAL[MAP'[i]] = PAL'[i]
538 For each pixel p
539 BITS'[p] = MAP'[BITS'[p]]
540 Write out PAL and BITS'
541 BITS = BITS'
542 MAP = MAP'
543
544*/
545
546/*...scalc_mapP:0:*/
547/*
548For each entry in the old palette, starting with the most used, find the
549closest 'unclaimed' entry in the new palette, and 'claim' it.
550Thus, if you iterate though mapP[0..ncols-1] you get palette indexes
551of close entries in the old palette.
552*/
553
554static void calc_mapP(
555 const GBMRGB gbmrgb [], const word map [],
556 GBMRGB gbmrgbP[], word mapP[],
557 int dists[],
558 int ncols
559 )
560 {
561 int i;
562
563 if ( verbose )
564 printf("Reordering palette to cause least flicker\n");
565
566 for ( i = 0; i < ncols; i++ )
567 mapP[i] = (word) 0xffff;
568
569 /* Go through old palette entries, in descending freq order */
570 for ( i = 0; i < ncols; i++ )
571 {
572 const GBMRGB *p = &(gbmrgb[map[i]]);
573 int mindist = 255*255*3 + 1;
574 int j, minj;
575 /* Find closest entry in new palette */
576 for ( j = 0; j < ncols; j++ )
577 {
578 int dr = (int) ( (unsigned int) p->r - (unsigned int) gbmrgbP[j].r );
579 int dg = (int) ( (unsigned int) p->g - (unsigned int) gbmrgbP[j].g );
580 int db = (int) ( (unsigned int) p->b - (unsigned int) gbmrgbP[j].b );
581 int dist = dr*dr + dg*dg + db*db;
582 if ( dist < mindist && mapP[j] == (word) 0xffff )
583 {
584 minj = j;
585 mindist = dist;
586 }
587 }
588 dists[minj] = mindist;
589 mapP[minj] = map[i];
590 }
591 }
592/*...e*/
593
594static void ro_map(
595 int first, int last, int step,
596 const char *fn_src, const char *opt_src,
597 const char *fn_dst, const char *opt_dst,
598 int ncols, int ncolsextra, byte rm, byte gm, byte bm,
599 void (*get)(
600 const char *fn, int f, const char *opt,
601 int ncols, byte rm, byte gm, byte bm,
602 GBM *gbm, GBMRGB gbmrgb[], byte **data8
603 )
604 )
605 {
606 GBM gbm; GBMRGB gbmrgb[0x100]; byte *data8;
607 word map[0x100], *extra = &(map[ncols]);
608 int i, f;
609
610 if ( first >= last )
611 return;
612
613 (*get)(fn_src, first, opt_src, ncols, rm, gm, bm, &gbm, gbmrgb, &data8);
614 for ( i = 0; i < ncols+ncolsextra; i++ )
615 map[i] = (word) i;
616
617 write_bitmap_f(fn_dst, first, opt_dst, &gbm, gbmrgb, data8);
618
619 for ( f = first + step; f < last; f += step )
620 {
621 GBM gbmP; GBMRGB gbmrgbP[0x100]; byte *data8P, *p;
622 word mapP[0x100]; int dists[0x100];
623 int x, y, stride;
624
625 (*get)(fn_src, f, opt_src, ncols, rm, gm, bm, &gbmP, gbmrgbP, &data8P);
626 calc_mapP(gbmrgb, map, gbmrgbP, mapP, dists, ncols);
627
628/*...shandle ncolsextra worst matches specially:16:*/
629{
630int j;
631
632/* Find the ncolsextra worst palette changes */
633
634for ( i = 0; i < ncolsextra; i++ )
635 {
636 int jmax, maxdist = -1;
637 for ( j = 0; j < ncols; j++ )
638 if ( dists[j] != -1 && dists[j] > maxdist )
639 {
640 jmax = j;
641 maxdist = dists[j];
642 }
643 dists[jmax] = -1;
644 }
645
646/* Use extra palette entries for these instead */
647
648for ( i = 0, j = 0; i < ncolsextra; i++, j++ )
649 {
650 word t;
651 while ( dists[j] != -1 )
652 j++;
653 t = mapP[j]; /* This is a bad palette entry */
654 mapP[j] = extra[i]; /* Use extra entry instead */
655 extra[i] = t; /* So bad one is fair game next loop */
656 }
657}
658/*...e*/
659
660 for ( i = 0; i < ncols; i++ )
661 gbmrgb[mapP[i]] = gbmrgbP[i];
662
663 stride = ((gbmP.w+3)&~3);
664 for ( y = 0, p = data8P; y < gbmP.h; y++, p += stride )
665 for ( x = 0; x < gbmP.w; x++ )
666 p[x] = (byte) mapP[p[x]];
667
668 write_bitmap_f(fn_dst, f, opt_dst, &gbmP, gbmrgb, data8P);
669
670 gbm = gbmP;
671 free(data8);
672 data8 = data8P;
673 memcpy(map, mapP, ncols * sizeof(word));
674 }
675
676 free(data8);
677 }
678/*...e*/
679/*...srofreq_map:0:*/
680/*...sget_and_hist:0:*/
681static void get_and_hist(
682 const char *fn, int f, const char *opt,
683 int ncols, byte rm, byte gm, byte bm,
684 GBM *gbm, GBMRGB gbmrgb[], byte **data8
685 )
686 {
687 byte *data24;
688 read_bitmap_24_f(fn, f, opt, gbm, &data24);
689 gbm->bpp = 8;
690 (*data8) = alloc_mem(gbm);
691 if ( !gbm_hist(gbm, data24, gbmrgb, *data8, ncols, rm, gm, bm) )
692 fatal("can't compute histogram");
693 free(data24);
694 }
695/*...e*/
696
697static void rofreq_map(
698 int first, int last, int step,
699 const char *fn_src, const char *opt_src,
700 const char *fn_dst, const char *opt_dst,
701 int ncols, int ncolsextra, byte rm, byte gm, byte bm
702 )
703 {
704 ro_map(
705 first, last, step,
706 fn_src, opt_src, fn_dst, opt_dst,
707 ncols, ncolsextra, rm, gm, bm,
708 get_and_hist
709 );
710 }
711/*...e*/
712/*...sromcut_map:0:*/
713/*...sget_and_mcut:0:*/
714static void get_and_mcut(
715 const char *fn, int f, const char *opt,
716 int ncols, byte rm, byte gm, byte bm,
717 GBM *gbm, GBMRGB gbmrgb[], byte **data8
718 )
719 {
720 byte *data24;
721 rm=rm; gm=gm; bm=bm; /* Suppress 'unused arg warning' */
722 read_bitmap_24_f(fn, f, opt, gbm, &data24);
723 gbm->bpp = 8;
724 (*data8) = alloc_mem(gbm);
725 if ( !gbm_mcut(gbm, data24, gbmrgb, *data8, ncols) )
726 fatal("can't perform median-cut");
727 free(data24);
728 }
729/*...e*/
730
731static void romcut_map(
732 int first, int last, int step,
733 const char *fn_src, const char *opt_src,
734 const char *fn_dst, const char *opt_dst,
735 int ncols, int ncolsextra
736 )
737 {
738 ro_map(
739 first, last, step,
740 fn_src, opt_src, fn_dst, opt_dst,
741 ncols, ncolsextra, 0, 0, 0,
742 get_and_mcut
743 );
744 }
745/*...e*/
746/*...e*/
747
748int main(int argc, char *argv[])
749 {
750 char *map = "freq6:6:6:256";
751 char fn_src[500+1], fn_dst[500+1], *opt_src, *opt_dst;
752 int i, m, ncols, ncolsextra, first, last, step;
753 byte rm, gm, bm;
754
755/*...sprocess command line options:8:*/
756for ( i = 1; i < argc; i++ )
757 {
758 if ( argv[i][0] != '-' )
759 break;
760 switch ( argv[i][1] )
761 {
762 case 'm': if ( ++i == argc )
763 fatal("expected map argument");
764 map = argv[i];
765 break;
766 case 'v': verbose = TRUE;
767 break;
768 default: usage();
769 break;
770 }
771 }
772/*...e*/
773/*...sframes and filenames etc\46\:8:*/
774if ( i == argc )
775 usage();
776sscanf(argv[i++], "%d", &first);
777
778if ( i == argc )
779 usage();
780sscanf(argv[i++], "%d", &last);
781
782if ( i == argc )
783 usage();
784sscanf(argv[i++], "%d", &step);
785
786if ( i == argc )
787 usage();
788strcpy(fn_src, argv[i++]);
789strcpy(fn_dst, ( i == argc ) ? fn_src : argv[i++]);
790if ( i < argc )
791 usage();
792
793if ( (opt_src = strchr(fn_src, ',')) != NULL )
794 *opt_src++ = '\0';
795else
796 opt_src = "";
797
798if ( (opt_dst = strchr(fn_dst, ',')) != NULL )
799 *opt_dst++ = '\0';
800else
801 opt_dst = "";
802/*...e*/
803/*...sdeduce mapping and bits per pixel etc\46\:8:*/
804if ( same(map, "freq", 4) )
805 {
806 m = CVT_FREQ;
807 if ( !get_masks(map + 4, &rm, &gm, &bm) )
808 fatal("freqR:G:B:N has bad/missing R:G:B");
809 if ( map[9] != ':' )
810 fatal("freqR:G:B:N has bad/missing :N");
811 sscanf(map + 10, "%i", &ncols);
812 if ( ncols < 1 || ncols > 256 )
813 fatal("freqR:G:B:N N number between 1 and 256 required");
814 }
815else if ( same(map, "mcut", 4) )
816 {
817 m = CVT_MCUT;
818 sscanf(map+4, "%i", &ncols);
819 if ( ncols < 1 || ncols > 256 )
820 fatal("mcutN N number between 1 and 256 required");
821 }
822else if ( same(map, "rofreq", 6) )
823 {
824 m = CVT_ROFREQ;
825 if ( !get_masks(map+6, &rm, &gm, &bm) )
826 fatal("rofreqR:G:B:N has bad/missing R:G:B");
827 if ( map[11] != ':' )
828 fatal("rofreqR:G:B:N has bad/missing :N:N2");
829 sscanf(map + 12, "%i:%i", &ncols, &ncolsextra);
830 if ( ncols+ncolsextra < 1 || ncols+ncolsextra > 256 )
831 fatal("rofreqR:G:B:N:N2 N+N2 must be between 1 and 256");
832 }
833else if ( same(map, "romcut", 6) )
834 {
835 m = CVT_ROMCUT;
836 sscanf(map+6, "%i:%i", &ncols, &ncolsextra);
837 if ( ncols+ncolsextra < 1 || ncols+ncolsextra > 256 )
838 fatal("mcutN:N2 N+N2 must be between 1 and 256");
839 }
840else
841 fatal("unrecognised mapping %s", map);
842/*...e*/
843
844 gbm_init();
845
846 switch ( m )
847 {
848 case CVT_FREQ:
849 freq_map(
850 first, last, step,
851 fn_src, opt_src, fn_dst, opt_dst,
852 ncols, rm, gm, bm);
853 break;
854 case CVT_MCUT:
855 mcut_map(
856 first, last, step,
857 fn_src, opt_src, fn_dst, opt_dst,
858 ncols);
859 break;
860 case CVT_ROFREQ:
861 rofreq_map(
862 first, last, step,
863 fn_src, opt_src, fn_dst, opt_dst,
864 ncols, ncolsextra, rm, gm, bm);
865 break;
866 case CVT_ROMCUT:
867 romcut_map(
868 first, last, step,
869 fn_src, opt_src, fn_dst, opt_dst,
870 ncols, ncolsextra);
871 break;
872 }
873
874 gbm_deinit();
875
876 return 0;
877 }
878/*...e*/
Note: See TracBrowser for help on using the repository browser.