home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
rexx
/
library2
/
gbmrexx
/
gbm
/
gbmbpp.c
< prev
next >
Wrap
C/C++ Source or Header
|
1993-09-14
|
15KB
|
604 lines
/*
GBMBPP.C Change bits per pixel in a General Bitmap
*/
/*...sincludes:0:*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdarg.h>
#include <memory.h>
#include <malloc.h>
#ifdef AIX
#include <unistd.h>
#else
#include <io.h>
#endif
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifndef O_BINARY
#define O_BINARY 0
#endif
#include "standard.h"
#include "gbm.h"
#include "gbmerr.h"
#include "gbmtrunc.h"
#include "gbmht.h"
#include "gbmhist.h"
/*...vgbm\46\h:0:*/
/*...vgbmerr\46\h:0:*/
/*...vgbmtrunc\46\h:0:*/
/*...vgbmht\46\h:0:*/
/*...vgbmhist\46\h:0:*/
/*...e*/
static char progname [] = "gbmbpp";
static char sccs_id [] = "@(#)Change bits per pixel in a General Bitmap 1/3/93";
/*...sfatal:0:*/
static void fatal(const char *fmt, ...)
{
va_list vars;
char s [256+1];
va_start(vars, fmt);
vsprintf(s, fmt, vars);
va_end(vars);
fprintf(stderr, "%s: %s\n", progname, s);
exit(1);
}
/*...e*/
/*...susage:0:*/
static void usage(void)
{
int ft, n_ft;
fprintf(stderr, "usage: %s [-m map] [-e] [-h] fn1.ext{,opt} [fn2.ext{,opt}]\n", progname);
fprintf(stderr, "flags: -m map mapping to perform (default 7x8x4)\n");
fprintf(stderr, " bw black and white\n");
fprintf(stderr, " vga 16 colour VGA\n");
fprintf(stderr, " 8 8 colour (in 4 bit file)\n");
fprintf(stderr, " 4g 4 bit greyscale\n");
fprintf(stderr, " 7x8x4 7 levels red, 8 green, 4 blue 8514/A\n");
fprintf(stderr, " 6x6x6 6 levels red, 6 green, 6 blue\n");
fprintf(stderr, " 8g 8 bit greyscale\n");
fprintf(stderr, " tripel 64 reds, 64 greens, 64 blues tripel\n");
fprintf(stderr, " freqR:G:B:N keep R red, G green, b blue bits, and map to\n");
fprintf(stderr, " N most used colours in 8 bit palette\n");
fprintf(stderr, " R:G:B keep R red, G green, B blue bits (eg: 8:8:8)\n");
fprintf(stderr, " -e enable error-diffusion (default is to truncate)\n");
fprintf(stderr, " -e not with -m 8g or tripel or freq or -h\n");
fprintf(stderr, " -h enable halftoning (default is to truncate)\n");
fprintf(stderr, " -h only with -m 7x8x4, 6x6x6, 8, vga or R:G:B, with no -e\n");
fprintf(stderr, " fn1.ext{,opt} input filename (with any format specific options)\n");
fprintf(stderr, " fn2.ext{,opt} optional output filename (or will use fn1 if not present)\n");
fprintf(stderr, " ext's are used to deduce desired bitmap file formats\n");
gbm_init();
gbm_query_n_filetypes(&n_ft);
for ( ft = 0; ft < n_ft; ft++ )
{
GBMFT gbmft;
gbm_query_filetype(ft, &gbmft);
fprintf(stderr, " %s when ext in [%s]\n",
gbmft.short_name, gbmft.extensions);
}
gbm_deinit();
fprintf(stderr, " opt's bitmap format specific options\n");
exit(1);
}
/*...e*/
/*...ssame:0:*/
static BOOLEAN same(char *s1, char *s2, int n)
{
for ( ; n--; s1++, s2++ )
if ( tolower(*s1) != tolower(*s2) )
return ( FALSE );
return ( TRUE );
}
/*...e*/
/*...smain:0:*/
/*...smapinfos:0:*/
#define CVT_BW 0
#define CVT_VGA 1
#define CVT_8 2
#define CVT_4G 3
#define CVT_784 4
#define CVT_666 5
#define CVT_8G 6
#define CVT_TRIPEL 7
#define CVT_RGB 8
#define CVT_FREQ 9
#define CVT_ERRDIFF 0x4000
#define CVT_HALFTONE 0x2000
typedef struct { char *name; int m; int dest_bpp; } MAPINFO;
static MAPINFO mapinfos [] =
{
"bw", CVT_BW, 1,
"vga", CVT_VGA, 4,
"8", CVT_8, 4,
"4g", CVT_4G, 4,
"7x8x4", CVT_784, 8,
"6x6x6", CVT_666, 8,
"8g", CVT_8G, 8,
"tripel", CVT_TRIPEL, 8,
};
#define N_MAPINFOS (sizeof(mapinfos)/sizeof(mapinfos [0]))
/*...e*/
/*...sget_masks:0:*/
/*
Returns TRUE if a set of masks given at map.
Also sets *rm, *gm, *bm from these.
Else returns FALSE.
*/
static byte mask [] = { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
static BOOLEAN get_masks(char *map, byte *rm, byte *gm, byte *bm)
{
if ( map [0] < '0' || map [0] > '8' ||
map [1] != ':' ||
map [2] < '0' || map [2] > '8' ||
map [3] != ':' ||
map [4] < '0' || map [4] > '8' )
return ( FALSE );
*rm = mask [map [0] - '0'];
*gm = mask [map [2] - '0'];
*bm = mask [map [4] - '0'];
return ( TRUE );
}
/*...e*/
/*...sexpand_to_24bit:0:*/
static void expand_to_24bit(GBM *gbm, GBMRGB *gbmrgb, byte **data)
{
int stride = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
int new_stride = ((gbm -> w * 3 + 3) & ~3);
int bytes, y;
byte *new_data;
if ( gbm -> bpp == 24 )
return;
bytes = new_stride * gbm -> h;
if ( (new_data = malloc(bytes)) == NULL )
fatal("out of memory allocating %d bytes", bytes);
for ( y = 0; y < gbm -> h; y++ )
{
byte *src = *data + y * stride;
byte *dest = new_data + y * new_stride;
int x;
switch ( gbm -> bpp )
{
/*...s1:24:*/
case 1:
{
byte c;
for ( x = 0; x < gbm -> w; x++ )
{
if ( (x & 7) == 0 )
c = *src++;
else
c <<= 1;
*dest++ = gbmrgb [c >> 7].b;
*dest++ = gbmrgb [c >> 7].g;
*dest++ = gbmrgb [c >> 7].r;
}
}
break;
/*...e*/
/*...s4:24:*/
case 4:
for ( x = 0; x + 1 < gbm -> w; x += 2 )
{
byte c = *src++;
*dest++ = gbmrgb [c >> 4].b;
*dest++ = gbmrgb [c >> 4].g;
*dest++ = gbmrgb [c >> 4].r;
*dest++ = gbmrgb [c & 15].b;
*dest++ = gbmrgb [c & 15].g;
*dest++ = gbmrgb [c & 15].r;
}
if ( x < gbm -> w )
{
byte c = *src;
*dest++ = gbmrgb [c >> 4].b;
*dest++ = gbmrgb [c >> 4].g;
*dest++ = gbmrgb [c >> 4].r;
}
break;
/*...e*/
/*...s8:24:*/
case 8:
for ( x = 0; x < gbm -> w; x++ )
{
byte c = *src++;
*dest++ = gbmrgb [c].b;
*dest++ = gbmrgb [c].g;
*dest++ = gbmrgb [c].r;
}
break;
/*...e*/
}
}
free(*data);
*data = new_data;
gbm -> bpp = 24;
}
/*...e*/
/*...sto_grey_pal:0:*/
static void to_grey_pal(GBMRGB *gbmrgb)
{
int i;
for ( i = 0; i < 0x100; i++ )
gbmrgb [i].r =
gbmrgb [i].g =
gbmrgb [i].b = (byte) i;
}
/*...e*/
/*...sto_grey:0:*/
static void to_grey(GBM *gbm, byte *src_data, byte *dest_data)
{
int src_stride = ((gbm -> w * 3 + 3) & ~3);
int dest_stride = ((gbm -> w + 3) & ~3);
int y;
for ( y = 0; y < gbm -> h; y++ )
{
byte *src = src_data;
byte *dest = dest_data;
int x;
for ( x = 0; x < gbm -> w; x++ )
{
byte b = *src++;
byte g = *src++;
byte r = *src++;
*dest++ = (byte) (((word) r * 77 + (word) g * 151 + (word) b * 28) >> 8);
}
src_data += src_stride;
dest_data += dest_stride;
}
gbm -> bpp = 8;
}
/*...e*/
/*...stripel_pal:0:*/
static void tripel_pal(GBMRGB *gbmrgb)
{
int i;
memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
for ( i = 0; i < 0x40; i++ )
{
gbmrgb [i ].r = (byte) (i << 2);
gbmrgb [i + 0x40].g = (byte) (i << 2);
gbmrgb [i + 0x80].b = (byte) (i << 2);
}
}
/*...e*/
/*...stripel:0:*/
static void tripel(GBM *gbm, byte *src_data, byte *dest_data)
{
int src_stride = ((gbm -> w * 3 + 3) & ~3);
int dest_stride = ((gbm -> w + 3) & ~3);
int y;
for ( y = 0; y < gbm -> h; y++ )
{
byte *src = src_data;
byte *dest = dest_data;
int x;
for ( x = 0; x < gbm -> w; x++ )
{
byte b = *src++;
byte g = *src++;
byte r = *src++;
switch ( (x+y)%3 )
{
case 0: *dest++ = (byte) (r >> 2) ; break;
case 1: *dest++ = (byte) (0x40 + (g >> 2)); break;
case 2: *dest++ = (byte) (0x80 + (b >> 2)); break;
}
}
src_data += src_stride;
dest_data += dest_stride;
}
gbm -> bpp = 8;
}
/*...e*/
int main(int argc, char *argv [])
{
BOOLEAN errdiff = FALSE, halftone = FALSE, ok = TRUE;
char *map = "7x8x4";
char fn_src [500+1], fn_dst [500+1], *opt_src, *opt_dst;
int fd, ft_src, ft_dst, i, stride, bytes, flag, m, dest_bpp;
byte rm, gm, bm;
int ncols;
GBM_ERR rc;
GBMFT gbmft;
GBM gbm;
GBMRGB gbmrgb [0x100];
byte *data;
/*...sprocess command line options:8:*/
for ( i = 1; i < argc; i++ )
{
if ( argv [i][0] != '-' )
break;
switch ( argv [i][1] )
{
case 'e': errdiff = TRUE;
break;
case 'h': halftone = TRUE;
break;
case 'm': if ( ++i == argc )
fatal("expected map argument");
map = argv [i];
break;
default: usage();
break;
}
}
if ( errdiff && halftone )
fatal("error-diffusion and halftoning can't both be done at once");
/*...e*/
/*...sdeduce mapping and bits per pixel etc\46\:8:*/
if ( get_masks(map, &rm, &gm, &bm) && map [5] == '\0' )
{
m = CVT_RGB;
dest_bpp = 24;
}
else if ( same(map, "freq", 4) )
{
m = CVT_FREQ;
dest_bpp = 8;
if ( !get_masks(map + 4, &rm, &gm, &bm) )
fatal("freqR:G:B:N has bad/missing R:G:B");
if ( map [9] != ':' )
fatal("freqR:G:B:N has bad/missing :N");
sscanf(map + 10, "%i", &ncols);
if ( ncols < 1 || ncols > 256 )
fatal("freqR:G:B:N N number between 1 and 256 required");
}
else
{
int j;
for ( j = 0; j < N_MAPINFOS; j++ )
if ( same(map, mapinfos [j].name, strlen(map) + 1) )
break;
if ( j == N_MAPINFOS )
fatal("unrecognised mapping %s", map);
m = mapinfos [j].m;
dest_bpp = mapinfos [j].dest_bpp;
}
/*...e*/
if ( i == argc )
usage();
strcpy(fn_src, argv [i++]);
strcpy(fn_dst, ( i == argc ) ? fn_src : argv [i++]);
if ( i < argc )
usage();
if ( (opt_src = strchr(fn_src, ',')) != NULL )
*opt_src++ = '\0';
else
opt_src = "";
if ( (opt_dst = strchr(fn_dst, ',')) != NULL )
*opt_dst++ = '\0';
else
opt_dst = "";
gbm_init();
if ( gbm_guess_filetype(fn_src, &ft_src) != GBM_ERR_OK )
fatal("can't guess bitmap file format for %s", fn_src);
if ( gbm_guess_filetype(fn_dst, &ft_dst) != GBM_ERR_OK )
fatal("can't guess bitmap file format for %s", fn_dst);
if ( (fd = open(fn_src, O_RDONLY | O_BINARY)) == -1 )
fatal("can't open %s", fn_src);
if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
{
close(fd);
fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
}
gbm_query_filetype(ft_dst, &gbmft);
switch ( dest_bpp )
{
case 24: flag = GBM_FT_W24; break;
case 8: flag = GBM_FT_W8; break;
case 4: flag = GBM_FT_W4; break;
case 1: flag = GBM_FT_W1; break;
}
if ( (gbmft.flags & flag) == 0 )
{
close(fd);
fatal("output bitmap format %s does not support writing %d bpp data",
gbmft.short_name, dest_bpp);
}
if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
{
close(fd);
fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
}
stride = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
bytes = stride * gbm.h;
if ( (data = malloc(bytes)) == NULL )
{
close(fd);
fatal("out of memory allocating %d bytes", bytes);
}
if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
{
free(data);
close(fd);
fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
}
close(fd);
/* Now expand bits per pixel if necessary */
expand_to_24bit(&gbm, gbmrgb, &data);
if ( errdiff )
m |= CVT_ERRDIFF;
if ( halftone )
m |= CVT_HALFTONE;
switch ( m )
{
case CVT_BW:
gbm_trunc_pal_BW(gbmrgb);
gbm_trunc_BW(&gbm, data, data);
break;
case CVT_4G:
gbm_trunc_pal_4G(gbmrgb);
gbm_trunc_4G(&gbm, data, data);
break;
case CVT_8:
gbm_trunc_pal_8(gbmrgb);
gbm_trunc_8(&gbm, data, data);
break;
case CVT_VGA:
gbm_trunc_pal_VGA(gbmrgb);
gbm_trunc_VGA(&gbm, data, data);
break;
case CVT_784:
gbm_trunc_pal_7R8G4B(gbmrgb);
gbm_trunc_7R8G4B(&gbm, data, data);
break;
case CVT_666:
gbm_trunc_pal_6R6G6B(gbmrgb);
gbm_trunc_6R6G6B(&gbm, data, data);
break;
case CVT_8G:
to_grey_pal(gbmrgb);
to_grey(&gbm, data, data);
break;
case CVT_TRIPEL:
tripel_pal(gbmrgb);
tripel(&gbm, data, data);
break;
case CVT_FREQ:
memset(gbmrgb, 0, sizeof(gbmrgb));
gbm_hist(&gbm, data, gbmrgb, data, ncols, rm, gm, bm);
break;
case CVT_RGB:
gbm_trunc_24(&gbm, data, data, rm, gm, bm);
break;
case CVT_BW | CVT_ERRDIFF:
gbm_errdiff_pal_BW(gbmrgb);
ok = gbm_errdiff_BW(&gbm, data, data);
break;
case CVT_4G | CVT_ERRDIFF:
gbm_errdiff_pal_4G(gbmrgb);
ok = gbm_errdiff_4G(&gbm, data, data);
break;
case CVT_8 | CVT_ERRDIFF:
gbm_errdiff_pal_8(gbmrgb);
ok = gbm_errdiff_8(&gbm, data, data);
break;
case CVT_VGA | CVT_ERRDIFF:
gbm_errdiff_pal_VGA(gbmrgb);
ok = gbm_errdiff_VGA(&gbm, data, data);
break;
case CVT_784 | CVT_ERRDIFF:
gbm_errdiff_pal_7R8G4B(gbmrgb);
ok = gbm_errdiff_7R8G4B(&gbm, data, data);
break;
case CVT_666 | CVT_ERRDIFF:
gbm_errdiff_pal_6R6G6B(gbmrgb);
ok = gbm_errdiff_6R6G6B(&gbm, data, data);
break;
case CVT_RGB | CVT_ERRDIFF:
ok = gbm_errdiff_24(&gbm, data, data, rm, gm, bm);
break;
case CVT_784 | CVT_HALFTONE:
gbm_ht_pal_7R8G4B(gbmrgb);
gbm_ht_7R8G4B_2x2(&gbm, data, data);
break;
case CVT_666 | CVT_HALFTONE:
gbm_ht_pal_6R6G6B(gbmrgb);
gbm_ht_6R6G6B_2x2(&gbm, data, data);
break;
case CVT_8 | CVT_HALFTONE:
gbm_ht_pal_8(gbmrgb);
gbm_ht_8_3x3(&gbm, data, data);
break;
case CVT_VGA | CVT_HALFTONE:
gbm_ht_pal_VGA(gbmrgb);
gbm_ht_VGA_3x3(&gbm, data, data);
break;
case CVT_RGB | CVT_HALFTONE:
gbm_ht_24_2x2(&gbm, data, data, rm, gm, bm);
break;
default:
fatal("bad mapping/error-diffusion/halftone combination");
}
if ( !ok )
fatal("unable to perform mapping");
gbm.bpp = dest_bpp;
if ( (fd = open(fn_dst, O_CREAT | O_TRUNC | O_WRONLY | O_BINARY, S_IREAD | S_IWRITE)) == -1 )
fatal("can't create %s", fn_dst);
if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm, gbmrgb, data, opt_dst)) != GBM_ERR_OK )
{
close(fd);
fatal("can't write %s: %s", fn_dst, gbm_err(rc));
}
close(fd);
free(data);
gbm_deinit();
return ( 0 );
}
/*...e*/