/* pnmtoxwd.c - read a portable anymap and produce a color X11 window dump ** ** Copyright (C) 1989, 1991 by Jef Poskanzer. ** ** Permission to use, copy, modify, and distribute this software and its ** documentation for any purpose and without fee is hereby granted, provided ** that the above copyright notice appear in all copies and that both that ** copyright notice and this permission notice appear in supporting ** documentation. This software is provided "as is" without express or ** implied warranty. */ #include "pnm.h" #include "x11wd.h" int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; const xel** xels; const char* dumpname; int argn, rows, cols, format, colors, i, row, col; int pseudodepth; int forcedirect, direct, grayscale; xelval maxval; long lmaxval, xmaxval; colorhist_vector chv; colorhash_table cht; X11WDFileHeader h11; X11XColor color; const char* const usage = "[-pseudodepth n] [-directcolor] [pnmfile]"; pnm_init( &argc, argv ); argn = 1; pseudodepth = 8; forcedirect = 0; while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) { if ( pm_keymatch( argv[argn], "-pseudodepth", 2 ) ) { ++argn; if ( argn == argc || sscanf( argv[argn], "%d", &pseudodepth ) != 1 ) pm_usage( usage ); if ( pseudodepth < 1 || pseudodepth > 16 ) pm_usage( usage ); } else if ( pm_keymatch( argv[argn], "-directcolor", 2 ) ) forcedirect = 1; else pm_usage( usage ); ++argn; } if ( argn != argc ) { dumpname = argv[1]; ifp = pm_openr( argv[1] ); ++argn; } else { dumpname = "stdin"; ifp = stdin; } if ( argn != argc ) pm_usage( usage ); xels = (const xel **) pnm_readpnm( ifp, &cols, &rows, &maxval, &format ); lmaxval = (long) maxval; xmaxval = ( 1 << pseudodepth ) - 1; pm_close( ifp ); if ( forcedirect ) direct = 1; else { /* Figure out the colormap. */ switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: direct = 0; pm_message( "computing colormap..." ); chv = ppm_computecolorhist( (xel **) xels, cols, rows, xmaxval+1, &colors ); if ( chv == (colorhist_vector) 0 ) { pm_message( "Too many colors - proceeding to write a 24-bit DirectColor" ); pm_message( "dump file. If you want PseudoColor, try doing a 'pnmquant %ld'.", xmaxval ); direct = 1; } else { pm_message( "%d colors found", colors ); grayscale = 0; direct = 0; /* Make a hash table for fast color lookup. */ cht = ppm_colorhisttocolorhash( chv, colors ); } break; default: direct = 0; grayscale = 1; break; } } /* Set up the header. */ if (strlen(dumpname) > XWDVAL_MAX - sizeof(h11) - 1) pm_error("dumpname is ridiculously long."); h11.header_size = sizeof(h11) + (xwdval) strlen(dumpname) + 1; h11.file_version = X11WD_FILE_VERSION; h11.pixmap_format = ZPixmap; h11.pixmap_width = cols; h11.pixmap_height = rows; h11.xoffset = 0; h11.byte_order = MSBFirst; h11.bitmap_bit_order = MSBFirst; h11.window_width = cols; h11.window_height = rows; h11.window_x = 0; h11.window_y = 0; h11.window_bdrwidth = 0; if ( direct ) { h11.pixmap_depth = 24; h11.bitmap_unit = 32; h11.bitmap_pad = 32; h11.bits_per_pixel = 32; h11.visual_class = DirectColor; h11.colormap_entries = 256; h11.ncolors = 0; h11.red_mask = 0xff0000; h11.green_mask = 0xff00; h11.blue_mask = 0xff; h11.bytes_per_line = cols * 4; } else if ( grayscale ) { if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) { h11.pixmap_depth = 1; h11.bits_per_pixel = 1; colors = 2; h11.colormap_entries = colors; h11.ncolors = colors; h11.bytes_per_line = ( cols + 7 ) / 8; } else { h11.pixmap_depth = pseudodepth; h11.bits_per_pixel = pseudodepth; colors = xmaxval + 1; h11.colormap_entries = colors; h11.ncolors = colors; h11.bytes_per_line = cols; } h11.bitmap_unit = 8; h11.bitmap_pad = 8; h11.visual_class = StaticGray; h11.red_mask = 0; h11.green_mask = 0; h11.blue_mask = 0; } else { h11.pixmap_depth = pseudodepth; h11.bits_per_pixel = pseudodepth; h11.visual_class = PseudoColor; h11.colormap_entries = xmaxval + 1; h11.ncolors = colors; h11.red_mask = 0; h11.green_mask = 0; h11.blue_mask = 0; h11.bytes_per_line = cols; h11.bitmap_unit = 8; h11.bitmap_pad = 8; } h11.bits_per_rgb = h11.pixmap_depth; /* Write out the header in big-endian order. */ pm_writebiglong( stdout, h11.header_size ); pm_writebiglong( stdout, h11.file_version ); pm_writebiglong( stdout, h11.pixmap_format ); pm_writebiglong( stdout, h11.pixmap_depth ); pm_writebiglong( stdout, h11.pixmap_width ); pm_writebiglong( stdout, h11.pixmap_height ); pm_writebiglong( stdout, h11.xoffset ); pm_writebiglong( stdout, h11.byte_order ); pm_writebiglong( stdout, h11.bitmap_unit ); pm_writebiglong( stdout, h11.bitmap_bit_order ); pm_writebiglong( stdout, h11.bitmap_pad ); pm_writebiglong( stdout, h11.bits_per_pixel ); pm_writebiglong( stdout, h11.bytes_per_line ); pm_writebiglong( stdout, h11.visual_class ); pm_writebiglong( stdout, h11.red_mask ); pm_writebiglong( stdout, h11.green_mask ); pm_writebiglong( stdout, h11.blue_mask ); pm_writebiglong( stdout, h11.bits_per_rgb ); pm_writebiglong( stdout, h11.colormap_entries ); pm_writebiglong( stdout, h11.ncolors ); pm_writebiglong( stdout, h11.window_width ); pm_writebiglong( stdout, h11.window_height ); pm_writebiglong( stdout, h11.window_x ); pm_writebiglong( stdout, h11.window_y ); pm_writebiglong( stdout, h11.window_bdrwidth ); /* Write out the dump name. */ fwrite( dumpname, 1, strlen( dumpname ) + 1, stdout ); if ( ! direct ) { /* Write out the colormap, big-endian order. */ color.flags = 7; color.pad = 0; for ( i = 0; i < colors; ++i ) { color.num = i; if ( grayscale ) { /* Stupid hack because xloadimage and xwud disagree on ** how to interpret bitmaps. */ if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) color.red = (long) ( colors-1-i ) * 65535L / ( colors - 1 ); else color.red = (long) i * 65535L / ( colors - 1 ); color.green = color.red; color.blue = color.red; } else { color.red = PPM_GETR( chv[i].color ); color.green = PPM_GETG( chv[i].color ); color.blue = PPM_GETB( chv[i].color ); if ( lmaxval != 65535L ) { color.red = (long) color.red * 65535L / lmaxval; color.green = (long) color.green * 65535L / lmaxval; color.blue = (long) color.blue * 65535L / lmaxval; } } pm_writebiglong( stdout, color.num ); pm_writebigshort( stdout, color.red ); pm_writebigshort( stdout, color.green ); pm_writebigshort( stdout, color.blue ); (void) putc( color.flags, stdout ); (void) putc( color.pad, stdout ); } } /* Finally, write out the data. */ for ( row = 0; row < rows; ++row ) if ( direct ) { switch ( PNM_FORMAT_TYPE(format) ) { case PPM_TYPE: for ( col = 0; col < cols; ++col ) { unsigned long ul; ul = ( ( PPM_GETR( xels[row][col] ) * xmaxval / lmaxval ) << 16 ) | ( ( PPM_GETG( xels[row][col] ) * xmaxval / lmaxval ) << 8 ) | ( PPM_GETB( xels[row][col] ) * xmaxval / lmaxval ); fwrite( &ul, sizeof(ul), 1, stdout ); } break; default: for ( col = 0; col < cols; ++col ) { unsigned long ul; register unsigned long val; val = PNM_GET1( xels[row][col] ); ul = ( ( val * xmaxval / lmaxval ) << 16 ) | ( ( val * xmaxval / lmaxval ) << 8 ) | ( val * xmaxval / lmaxval ); fwrite( &ul, sizeof(ul), 1, stdout ); } break; } } else if ( grayscale ) { register xelval bigger_maxval; register int bitshift; unsigned char byte; register xelval s; bigger_maxval = pm_bitstomaxval( h11.bits_per_pixel ); bitshift = 8 - h11.bits_per_pixel; byte = 0; for ( col = 0; col < cols; ++col ) { s = PNM_GET1( xels[row][col] ); /* More stupid hack. */ if ( PNM_FORMAT_TYPE(format) == PBM_TYPE ) s = 1 - s; if ( maxval != bigger_maxval ) s = (long) s * bigger_maxval / maxval; byte |= s << bitshift; bitshift -= h11.bits_per_pixel; if ( bitshift < 0 ) { putchar( byte ); bitshift = 8 - h11.bits_per_pixel; byte = 0; } } if ( bitshift < 8 - h11.bits_per_pixel ) putchar( byte ); } else { for ( col = 0; col < cols; ++col) putchar( ppm_lookupcolor( cht, &xels[row][col] ) ); } exit( 0 ); }