/*...sLoadBitmap:0:*/
static BOOL LoadBitmap(
	HWND hwnd,
	const CHAR *szFn, const CHAR *szOpt,
	GBM *gbm, GBMRGB *gbmrgb, BYTE **ppbData
	)
	{
	GBM_ERR rc;
	int fd, ft;
	ULONG cb;
	USHORT usStride;

	if ( gbm_guess_filetype(szFn, &ft) != GBM_ERR_OK )
		{
		Warning(hwnd, "Can't deduce bitmap format from file extension: %s", szFn);
		return ( FALSE );
		}

	if ( (fd = open(szFn, O_RDONLY | O_BINARY)) == -1 )
		{
		Warning(hwnd, "Can't open file: %s", szFn);
		return ( FALSE );
		}

	if ( (rc = gbm_read_header(szFn, fd, ft, gbm, szOpt)) != GBM_ERR_OK )
		{
		close(fd);
		Warning(hwnd, "Can't read file header of %s: %s", szFn, gbm_err(rc));
		return ( FALSE );
		}

	if ( (rc = gbm_read_palette(fd, ft, gbm, gbmrgb)) != GBM_ERR_OK )
		{
		close(fd);
		Warning(hwnd, "Can't read file palette of %s: %s", szFn, gbm_err(rc));
		return ( FALSE );
		}

	usStride = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
	cb = gbm -> h * usStride;
	if ( (*ppbData = malloc((int) cb)) == NULL )
		{
		close(fd);
		Warning(hwnd, "Out of memory requesting %ld bytes", cb);
		return ( FALSE );
		}

	if ( (rc = gbm_read_data(fd, ft, gbm, *ppbData)) != GBM_ERR_OK )
		{
		free(*ppbData);
		close(fd);
		Warning(hwnd, "Can't read file data of %s: %s", szFn, gbm_err(rc));
		return ( FALSE );
		}

	close(fd);

	return ( TRUE );
	}
int main(int argc, char *argv[])
{
   GBMTOOL_FILEARG gbmfilearg;
   char    fn_src[GBMTOOL_FILENAME_MAX+1], fn_dst[GBMTOOL_FILENAME_MAX+1],
           opt_src[GBMTOOL_OPTIONS_MAX+1], opt_dst[GBMTOOL_OPTIONS_MAX+1];

   int   w = -1, h = -1, filterIndex = FILTER_INDEX_SIMPLE;
   int   fd, ft_src, ft_dst, i, flag;
   size_t stride, stride2;
   GBM_ERR  rc;
   GBMFT    gbmft;
   GBM      gbm, gbm2;
   GBMRGB   gbmrgb[0x100];
   gbm_boolean aspect = GBM_FALSE;
   gbm_boolean qualityScalingEnabled = GBM_FALSE;
   gbm_boolean isGrayscale = GBM_FALSE;
   gbm_u8    *data, *data2;

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DATETIME start_time, end_time;
   double   time_s;
#elif defined(WIN32)
   SYSTEMTIME start_time, end_time;
   double     time_s;
#elif defined(LINUX)
   struct timeval start_time, end_time;
   double  time_s;
#endif
#endif

   for ( i = 1; i < argc; i++ )
   {
      if ( argv[i][0] != '-' )
         break;
      else if ( argv[i][1] == '-' )
      { ++i; break; }
      switch ( argv[i][1] )
      {
         case 'w':
            if ( ++i == argc ) usage();
            w = get_opt_value_pos(argv[i], "w");
            break;
         case 'h':
            if ( ++i == argc ) usage();
            h = get_opt_value_pos(argv[i], "h");
            break;
         case 'a':
            aspect = GBM_TRUE;
            break;
         case 'f':
            if ( ++i == argc ) usage();
            filterIndex = get_opt_value_filterIndex(argv[i],
                                                    FILTER_NAME_TABLE,
                                                    FILTER_NAME_TABLE_LENGTH);
            break;
         default:
            usage();
            break;
      }
   }

   if ( aspect && w == -1 && h == -1 )
   {
      fatal("-a can't be used if neither -w or -h is given");
   }
   if (filterIndex == -1)
   {
      fatal("wrong filter type");
   }
   else if (filterIndex != FILTER_INDEX_SIMPLE)
   {
      qualityScalingEnabled = GBM_TRUE;
   }

   if ( i == argc )
      usage();

   /* Split filename and file options. */
   gbmfilearg.argin = argv[i++];
   if (strcmp(gbmfilearg.argin, "\"\"") == 0)
   {
     usage();
   }
   if (gbmtool_parse_argument(&gbmfilearg, GBM_FALSE) != GBM_ERR_OK)
   {
     fatal("can't parse source filename %s", gbmfilearg.argin);
   }
   strcpy(fn_src , gbmfilearg.files->filename);
   strcpy(opt_src, gbmfilearg.options);
   gbmtool_free_argument(&gbmfilearg);

   gbmfilearg.argin = (i == argc) ? argv[i-1] : argv[i++];
   if (strcmp(gbmfilearg.argin, "\"\"") == 0)
   {
     usage();
   }
   if (gbmtool_parse_argument(&gbmfilearg, GBM_FALSE) != GBM_ERR_OK)
   {
     fatal("can't parse destination filename %s", gbmfilearg.argin);
   }
   strcpy(fn_dst , gbmfilearg.files->filename);
   strcpy(opt_dst, gbmfilearg.options);
   gbmtool_free_argument(&gbmfilearg);

   if (i < argc)
      usage();

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&start_time);
#elif defined(WIN32)
   GetSystemTime(&start_time);
#elif defined(LINUX)
   gettimeofday(&start_time, NULL);
#endif
#endif

   /* processing */
   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 = gbm_io_open(fn_src, GBM_O_RDONLY)) == -1 )
      fatal("can't open %s", fn_src);

   if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
   {
      gbm_io_close(fd);
      fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
   }

   /* check for color depth supported by algorithms */
   switch ( gbm.bpp )
   {
      case 64:
      case 48:
      case 32:
      case 24:
      case 8:
      case 4:
      case 1:
         break;
      default:
      {
         gbm_io_close(fd);
         fatal("%d bpp file is not supported", gbm.bpp);
      }
   }

   if ( aspect && (w != -1) && (h != -1))
   {
      if (((float)w/gbm.w) <= ((float)h/gbm.h))
      {
          h = ( gbm.h * w ) / gbm.w;
      }
      else
      {
          w = ( gbm.w * h ) / gbm.h;
      }
   }
   else
   {
      if ( w == -1 )
      {
         if ( aspect )
            w = ( gbm.w * h ) / gbm.h;
         else
            w = gbm.w;
      }
      if ( h == -1 )
      {
         if ( aspect )
            h = ( gbm.h * w ) / gbm.w;
         else
            h = gbm.h;
      }
   }

   if (w == 0 || h == 0)
   {
      gbm_io_close(fd);
      fatal("desired bitmap size of %dx%d, is silly", w, h);
   }

   if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
   {
      gbm_io_close(fd);
      fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
   }

   gbm2   = gbm;
   gbm2.w = w;
   gbm2.h = h;

   if (qualityScalingEnabled)
   {
       if (gbm.bpp <= 8)
       {
           isGrayscale = isGrayscalePalette(gbmrgb, 1 << gbm.bpp);
       }
       if ((gbm.bpp <= 8) && (! isGrayscale))
       {
          gbm_io_close(fd);
          fatal("can't use filter '%s' for colour palette images",
                FILTER_NAME_TABLE[filterIndex].name);
       }
       if (isGrayscale)
       {
          gbm2.bpp = 8;
       }
   }

   stride = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
   if ( (data = gbmmem_malloc(stride * gbm.h)) == NULL )
   {
      gbm_io_close(fd);
      #if (ULONG_MAX > UINT_MAX)
      fatal("out of memory allocating %zu bytes for input bitmap", stride * gbm.h);
      #else
      fatal("out of memory allocating %u bytes for input bitmap", stride * gbm.h);
      #endif
   }

   stride2 = ( ((gbm2.w * gbm2.bpp + 31)/32) * 4 );
   if ( (data2 = gbmmem_malloc(stride2 * gbm2.h)) == NULL )
   {
      gbmmem_free(data);
      gbm_io_close(fd);
      #if (ULONG_MAX > UINT_MAX)
      fatal("out of memory allocating %zu bytes for output bitmap", stride2 * gbm2.h);
      #else
      fatal("out of memory allocating %u bytes for output bitmap", stride2 * gbm2.h);
      #endif
   }

   if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
   {
      gbmmem_free(data2);
      gbmmem_free(data);
      gbm_io_close(fd);
      fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
   }

   gbm_io_close(fd);

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&end_time);
   time_s = ((double) (end_time  .minutes * 60) + end_time  .seconds + (end_time  .hundredths/100.0)) -
            ((double) (start_time.minutes * 60) + start_time.seconds + (start_time.hundredths/100.0));
   printf("Elapsed time LOAD : %lf\n", time_s);
#elif defined(WIN32)
   GetSystemTime(&end_time);
   time_s = ((double) (end_time  .wMinute * 60) + end_time  .wSecond + (end_time  .wMilliseconds/1000.0)) -
            ((double) (start_time.wMinute * 60) + start_time.wSecond + (start_time.wMilliseconds/1000.0));
   printf("Elapsed time LOAD : %lf\n", time_s);
#elif defined(LINUX)
   gettimeofday(&end_time, NULL);
   time_s = ((double) (end_time  .tv_sec) + (end_time  .tv_usec/1000000.0)) -
            ((double) (start_time.tv_sec) + (start_time.tv_usec/1000000.0));
   printf("Elapsed time LOAD : %lf\n", time_s);
#endif
#endif

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&start_time);
#elif defined(WIN32)
   GetSystemTime(&start_time);
#elif defined(LINUX)
   gettimeofday(&start_time, NULL);
#endif
#endif

   if (qualityScalingEnabled)
   {
       if (isGrayscale)
       {
           rc = gbm_quality_scale_gray(data , gbm.w , gbm.h , gbm.bpp, gbmrgb,
                                       data2, gbm2.w, gbm2.h, gbmrgb,
                                       FILTER_NAME_TABLE[filterIndex].filter);
       }
       else
       {
           rc = gbm_quality_scale_bgra(data , gbm.w , gbm.h,
                                       data2, gbm2.w, gbm2.h, gbm.bpp,
                                       FILTER_NAME_TABLE[filterIndex].filter);
       }
   }
   else
   {
       rc = gbm_simple_scale(data, gbm.w, gbm.h, data2, gbm2.w, gbm2.h, gbm.bpp);
   }

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&end_time);
   time_s = ((double) (end_time  .minutes * 60) + end_time  .seconds + (end_time  .hundredths/100.0)) -
            ((double) (start_time.minutes * 60) + start_time.seconds + (start_time.hundredths/100.0));
   printf("Elapsed time SCALE: %lf\n", time_s);
#elif defined(WIN32)
   GetSystemTime(&end_time);
   time_s = ((double) (end_time  .wMinute * 60) + end_time  .wSecond + (end_time  .wMilliseconds/1000.0)) -
            ((double) (start_time.wMinute * 60) + start_time.wSecond + (start_time.wMilliseconds/1000.0));
   printf("Elapsed time SCALE: %lf\n", time_s);
#elif defined(LINUX)
   gettimeofday(&end_time, NULL);
   time_s = ((double) (end_time  .tv_sec) + (end_time  .tv_usec/1000000.0)) -
            ((double) (start_time.tv_sec) + (start_time.tv_usec/1000000.0));
   printf("Elapsed time SCALE: %lf\n", time_s);
#endif
#endif

   gbmmem_free(data);

   if (rc != GBM_ERR_OK)
   {
      gbmmem_free(data2);
      fatal("can't scale: %s", gbm_err(rc));
   }

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&start_time);
#elif defined(WIN32)
   GetSystemTime(&start_time);
#elif defined(LINUX)
   gettimeofday(&start_time, NULL);
#endif
#endif

   if ( (fd = gbm_io_create(fn_dst, GBM_O_WRONLY)) == -1 )
   {
      gbmmem_free(data2);
      fatal("can't create %s", fn_dst);
   }

   gbm_query_filetype(ft_dst, &gbmft);
   switch ( gbm2.bpp )
   {
      case 64:   flag = GBM_FT_W64;  break;
      case 48:   flag = GBM_FT_W48;  break;
      case 32:   flag = GBM_FT_W32;  break;
      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;
      default:   flag = 0;           break;
   }
   if ( (gbmft.flags & flag) == 0 )
   {
      gbm_io_close(fd);
      fatal("output bitmap format %s does not support writing %d bpp data",
            gbmft.short_name, gbm2.bpp);
   }

   if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm2, gbmrgb, data2, opt_dst)) != GBM_ERR_OK )
   {
      gbm_io_close(fd);
      remove(fn_dst);
      gbmmem_free(data2);
      fatal("can't write %s: %s", fn_dst, gbm_err(rc));
   }

   gbm_io_close(fd);
   gbmmem_free(data2);

   gbm_deinit();

#ifdef MEASURE_TIME
#if defined(__OS2__)
   DosGetDateTime(&end_time);
   time_s = ((double) (end_time  .minutes * 60) + end_time  .seconds + (end_time  .hundredths/100.0)) -
            ((double) (start_time.minutes * 60) + start_time.seconds + (start_time.hundredths/100.0));
   printf("Elapsed time WRITE: %lf\n", time_s);
#elif defined(WIN32)
   GetSystemTime(&end_time);
   time_s = ((double) (end_time  .wMinute * 60) + end_time  .wSecond + (end_time  .wMilliseconds/1000.0)) -
            ((double) (start_time.wMinute * 60) + start_time.wSecond + (start_time.wMilliseconds/1000.0));
   printf("Elapsed time WRITE: %lf\n", time_s);
#elif defined(LINUX)
   gettimeofday(&end_time, NULL);
   time_s = ((double) (end_time  .tv_sec) + (end_time  .tv_usec/1000000.0)) -
            ((double) (start_time.tv_sec) + (start_time.tv_usec/1000000.0));
   printf("Elapsed time WRITE: %lf\n", time_s);
#endif
#endif

   return 0;
}
Exemple #3
0
int gbmBmpToGif(char *fn_src, char *fn_dst)
	{
	int	w = -1, h = -1;
	char	opt_src[] = "";
   char  opt_dst[] = "";
	int	fd, ft_src, ft_dst, stride, flag;
	GBM_ERR	rc;
	GBMFT	gbmft;
	GBM	gbm;
	GBMRGB	gbmrgb[0x100];
	byte	*data;

	gbm_init();

   ft_src = 0;
   ft_dst = 1;

	if ( (fd = gbm_io_open(fn_src, O_RDONLY|O_BINARY)) == -1 )
      {
//		fatal("can't open %s", fn_src);
      return 1;
      }

	if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
//		fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
      return 2;
		}

   w = gbm.w;
   h = gbm.h;

	gbm_query_filetype(ft_dst, &gbmft);
	switch ( gbm.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 )
		{
		gbm_io_close(fd);
//		fatal("output bitmap format %s does not support writing %d bpp data", gbmft.short_name, gbm.bpp);
      return 3;
		}

	if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
//		fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
      return 4;
		}

	stride = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
	if ( (data = (byte *)malloc((size_t) (stride * gbm.h))) == NULL )
		{
		gbm_io_close(fd);
//		fatal("out of memory allocating %d bytes for input bitmap", stride * gbm.h);
      return 5;
		}

	if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
		{
		free(data);
		gbm_io_close(fd);
//		fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
      return 6;
		}

	gbm_io_close(fd);

extern int bAppendMode;

   if (bAppendMode)
      {
      if ( (fd = gbm_io_open(fn_dst, O_RDWR|O_BINARY)) == -1 )
         {
         free(data);
//       fatal("can't create %s", fn_dst);
         return 7;
         }
      gbm_io_lseek(fd, -1, SEEK_END);
      }
   else
      {
      if ( (fd = gbm_io_create(fn_dst, O_WRONLY|O_BINARY)) == -1 )
         {
         free(data);
//       fatal("can't create %s", fn_dst);
         return 7;
         }
      }

	gbm.w = w;
	gbm.h = h;

	if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm, gbmrgb, data, opt_dst)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
		remove(fn_dst);
		free(data);
//		fatal("can't write %s: %s", fn_dst, gbm_err(rc));
      return 8;
		}

	gbm_io_close(fd);
	free(data);

	gbm_deinit();

	return 0;
	}
int main(int argc, char *argv[])
	{
	char	fn_src[500+1], fn_dst[500+1], *opt_src, *opt_dst;
	int	fd, ft_src, ft_dst, i, stride, bytes, flag, m;
	GBM_ERR	rc;
	GBMFT	gbmft;
	GBM	gbm;
	GBMRGB	gbmrgb[0x100];
	byte	*data;
	char	*map = "none";
	byte	remap[0x100];
	double gam = 2.1, shelf = 0.0;

/*...scommand line arguments:8:*/
for ( i = 1; i < argc; i++ )
	{
	if ( argv[i][0] != '-' )
		break;
	switch ( argv[i][1] )
		{
		case 'm':
			if ( ++i == argc )
				fatal("expected map argument");
			map = argv[i];
			break;
		case 'g':
			if ( ++i == argc ) usage();
			gam = get_opt_double(argv[i], "gam");
			if ( gam < 0.1 || gam > 10.0 )
				fatal("only gammas in the range 0.1 to 10.0 are sensible");
			break;
		case 's':
			if ( ++i == argc ) usage();
			shelf = get_opt_double(argv[i], "shelf");
			break;
		default:
			usage();
			break;
		}
	}
/*...e*/

/*...sdeduce mapping and bits per pixel etc\46\:8:*/
{
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;
}
/*...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 ( gbm.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, gbm.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 for bitmap", bytes);
		}

	if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
		{
		close(fd);
		fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
		}

	close(fd);

	map_compute(m, remap, gam, shelf);

	if ( gbm.bpp == 24 )
		map_data(data, gbm.w, gbm.h, remap);
	else
		map_palette(gbmrgb, 1 << gbm.bpp, remap);

	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);
		remove(fn_dst);
		fatal("can't write %s: %s", fn_dst, gbm_err(rc));
		}

	close(fd);

	free(data);

	gbm_deinit();

	return 0;
	}
Exemple #5
0
/*...smain:0:*/
int main(int argc, char *argv[])
	{
	GBMTOOL_FILEARG gbmfilearg;
	char    fn_src[GBMTOOL_FILENAME_MAX+1], fn_dst[GBMTOOL_FILENAME_MAX+1],
	        opt_src[GBMTOOL_OPTIONS_MAX+1], opt_dst[GBMTOOL_OPTIONS_MAX+1];

	int	x = 0, y = 0, w = -1, h = -1;
	int	fd, ft_src, ft_dst, i, flag;
	size_t	stride_src, bytes;
	GBM_ERR	rc;
	GBMFT	gbmft;
	GBM	gbm;
	GBMRGB	gbmrgb[0x100];
	gbm_u8	*data;

	for ( i = 1; i < argc; i++ )
		{
		if ( argv[i][0] != '-' )
			break;
		else if ( argv[i][1] == '-' )
			{ ++i; break; }
		switch ( argv[i][1] )
			{
			case 'x':
				if ( ++i == argc ) usage();
				x = get_opt_value_pos(argv[i], "x");
				break;
			case 'y':
				if ( ++i == argc ) usage();
				y = get_opt_value_pos(argv[i], "y");
				break;
			case 'w':
				if ( ++i == argc ) usage();
				w = get_opt_value_pos(argv[i], "w");
				break;
			case 'h':
				if ( ++i == argc ) usage();
				h = get_opt_value_pos(argv[i], "h");
				break;
			default:
				usage();
				break;
			}
		}

	if ( i == argc )
		usage();

	/* Split filename and file options. */
	gbmfilearg.argin = argv[i++];
 	if (strcmp(gbmfilearg.argin, "\"\"") == 0)
	{
	  usage();
	}
	if (gbmtool_parse_argument(&gbmfilearg, GBM_FALSE) != GBM_ERR_OK)
	{
	  fatal("can't parse source filename %s", gbmfilearg.argin);
	}
	strcpy(fn_src , gbmfilearg.files->filename);
	strcpy(opt_src, gbmfilearg.options);
	gbmtool_free_argument(&gbmfilearg);

	gbmfilearg.argin = (i == argc) ? argv[i-1] : argv[i++];
 	if (strcmp(gbmfilearg.argin, "\"\"") == 0)
	{
	  usage();
	}
	if (gbmtool_parse_argument(&gbmfilearg, GBM_FALSE) != GBM_ERR_OK)
	{
	  fatal("can't parse destination filename %s", gbmfilearg.argin);
	}
	strcpy(fn_dst , gbmfilearg.files->filename);
	strcpy(opt_dst, gbmfilearg.options);
	gbmtool_free_argument(&gbmfilearg);

	if (i < argc)
		usage();

	/* processing */
	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 = gbm_io_open(fn_src, GBM_O_RDONLY)) == -1 )
		fatal("can't open %s", fn_src);

	if ( (rc = gbm_read_header(fn_src, fd, ft_src, &gbm, opt_src)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
		fatal("can't read header of %s: %s", fn_src, gbm_err(rc));
		}

        /* check for color depth supported by algorithms */
	switch ( gbm.bpp )
		{
		case 64:
		case 48:
		case 32:
		case 24:
		case 8:
		case 4:
		case 1:
                   break;
                default:
 		  {
		     gbm_io_close(fd);
		     fatal("%d bpp file is not supported", gbm.bpp);
		  }
		}

	if ( w == -1 )
		w = gbm.w - x;

	if ( h == -1 )
		h = gbm.h - y;

	if ( w     == 0     ) { gbm_io_close(fd); fatal("w = 0"); }
	if ( h     == 0     ) { gbm_io_close(fd); fatal("h = 0"); }
	if ( x     >= gbm.w ) { gbm_io_close(fd); fatal("x >= bitmap width"); }
	if ( y     >= gbm.h ) { gbm_io_close(fd); fatal("y >= bitmap height"); }
	if ( x + w >  gbm.w ) { gbm_io_close(fd); fatal("x+w > bitmap width"); }
	if ( y + h >  gbm.h ) { gbm_io_close(fd); fatal("y+h > bitmap height"); }

	gbm_query_filetype(ft_dst, &gbmft);
	switch ( gbm.bpp )
		{
		case 64:	flag = GBM_FT_W64;	break;
		case 48:	flag = GBM_FT_W48;	break;
		case 32:	flag = GBM_FT_W32;	break;
		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;
                default:        flag = 0;               break;
		}
	if ( (gbmft.flags & flag) == 0 )
		{
		gbm_io_close(fd);
		fatal("output bitmap format %s does not support writing %d bpp data",
			gbmft.short_name, gbm.bpp);
		}

	if ( (rc = gbm_read_palette(fd, ft_src, &gbm, gbmrgb)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
		fatal("can't read palette of %s: %s", fn_src, gbm_err(rc));
		}

	stride_src = ( ((gbm.w * gbm.bpp + 31)/32) * 4 );
	bytes = stride_src * gbm.h;
	if ( (data = gbmmem_malloc(bytes)) == NULL )
		{
		gbm_io_close(fd);
		#if (ULONG_MAX > UINT_MAX)
		fatal("out of memory allocating %zu bytes for bitmap", bytes);
		#else
		fatal("out of memory allocating %u bytes for bitmap", bytes);
		#endif
		}

	if ( (rc = gbm_read_data(fd, ft_src, &gbm, data)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
		fatal("can't read bitmap data of %s: %s", fn_src, gbm_err(rc));
		}

	gbm_io_close(fd);

	gbm_subrectangle(&gbm, x, y, w, h, data, data);

	if ( (fd = gbm_io_create(fn_dst, GBM_O_WRONLY)) == -1 )
		fatal("can't create %s", fn_dst);

	gbm.w = w;
	gbm.h = h;

	if ( (rc = gbm_write(fn_dst, fd, ft_dst, &gbm, gbmrgb, data, opt_dst)) != GBM_ERR_OK )
		{
		gbm_io_close(fd);
		remove(fn_dst);
		fatal("can't write %s: %s", fn_dst, gbm_err(rc));
		}

	gbm_io_close(fd);

	gbmmem_free(data);

	gbm_deinit();

	return 0;
	}