/* xwdtopnm.c - read an X11 or X10 window dump file and write a portable anymap ** ** Copyright (C) 1989, 1991, 1993 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 "x10wd.h" #include "x11wd.h" static void getinit( FILE* file, int* colsP, int* rowsP, int* padrightP, long* maxvalP, long* visualclassP, int* formatP, xel** colorsP ); static unsigned long getpixnum( FILE* file ); #ifdef notdef static short bs_short( short s ); #endif /* notdef */ static long bs_long( long l ); static unsigned long red_mask, green_mask, blue_mask; static int bits_per_item, bits_used, bit_shift, bits_per_pixel; static char buf[4]; static char* byteP; static short* shortP; static long* longP; static unsigned long pixel_mask; static int byte_swap, byte_order, bit_order; int main( int argc, char* argv[] ) { FILE* ifp; xel* xelrow; register xel* xP; xel* colors; int rows, cols, format, padright, row; register int col; long maxval, visualclass; pnm_init( &argc, argv ); if ( argc > 2 ) pm_usage( "[xwdfile]" ); if ( argc == 2 ) ifp = pm_openr( argv[1] ); else ifp = stdin; getinit( ifp, &cols, &rows, &padright, &maxval, &visualclass, &format, &colors ); pnm_writepnminit( stdout, cols, rows, (xelval) maxval, format, 0 ); xelrow = pnm_allocrow( cols ); switch ( PNM_FORMAT_TYPE(format) ) { case PBM_TYPE: pm_message( "writing PBM file" ); break; case PGM_TYPE: pm_message( "writing PGM file" ); break; case PPM_TYPE: pm_message( "writing PPM file" ); break; default: pm_error( "shouldn't happen" ); } for ( row = 0; row < rows; ++row ) { switch ( visualclass ) { case StaticGray: case GrayScale: case StaticColor: case PseudoColor: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) *xP = colors[getpixnum( ifp )]; break; case TrueColor: case DirectColor: for ( col = 0, xP = xelrow; col < cols; ++col, ++xP ) { register unsigned long ul; ul = getpixnum( ifp ); switch ( bits_per_pixel ) { case 16: PPM_ASSIGN( *xP, ( ( ul & red_mask ) >> 0 ), ( ( ul & green_mask ) >> 5 ), ( ( ul & blue_mask ) >> 10 ) ); break; case 24: case 32: PPM_ASSIGN( *xP, ( ( ul & 0xff0000 ) >> 16 ), ( ( ul & 0xff00 ) >> 8 ), ( ul & 0xff ) ); break; default: pm_error( "True/Direct only supports 16, 24, and 32 bits" ); } } break; default: pm_error( "unknown visual class" ); } for ( col = 0; col < padright; ++col ) (void) getpixnum( ifp ); pnm_writepnmrow( stdout, xelrow, cols, (xelval) maxval, format, 0 ); } pm_closer( ifp ); pm_closew( stdout ); exit( 0 ); } static void getinit( FILE* file, int* colsP, int* rowsP, int* padrightP, long* maxvalP, long* visualclassP, int* formatP, xel** colorsP ) { int grayscale; unsigned long header_size, file_version; if ( PNM_MAXMAXVAL < 65535L ) *maxvalP = PNM_MAXMAXVAL; else *maxvalP = 65535L; /* Try reading the first two longs in big-endian order. */ pm_readbiglong(file, &header_size); pm_readbiglong(file, &file_version); if ( file_version == X10WD_FILE_VERSION || bs_long( file_version ) == X10WD_FILE_VERSION ) { int i; X10WDFileHeader h10; X10Color* x10colors; byte_swap = ( file_version != X10WD_FILE_VERSION ); if ( ! byte_swap ) { h10.header_size = header_size; h10.file_version = file_version; pm_readbiglong(file, (unsigned long*)&h10.display_type); pm_readbiglong(file, (unsigned long*)&h10.display_planes); pm_readbiglong(file, (unsigned long*)&h10.pixmap_format); pm_readbiglong(file, (unsigned long*)&h10.pixmap_width); pm_readbiglong(file, (unsigned long*)&h10.pixmap_height); pm_readbigshort(file, (unsigned short*)&h10.window_width); pm_readbigshort(file, (unsigned short*)&h10.window_height); pm_readbigshort(file, (unsigned short*)&h10.window_x); pm_readbigshort(file, (unsigned short*)&h10.window_y); pm_readbigshort(file, (unsigned short*)&h10.window_bdrwidth); pm_readbigshort(file, (unsigned short*)&h10.window_ncolors); } else { h10.header_size = bs_long( header_size ); h10.file_version = bs_long( file_version ); pm_readlittlelong(file, (unsigned long*)&h10.display_type); pm_readlittlelong(file, (unsigned long*)&h10.display_planes); pm_readlittlelong(file, (unsigned long*)&h10.pixmap_format); pm_readlittlelong(file, (unsigned long*)&h10.pixmap_width); pm_readlittlelong(file, (unsigned long*)&h10.pixmap_height); pm_readlittleshort(file, (unsigned short*)&h10.window_width); pm_readlittleshort(file, (unsigned short*)&h10.window_height); pm_readlittleshort(file, (unsigned short*)&h10.window_x); pm_readlittleshort(file, (unsigned short*)&h10.window_y); pm_readlittleshort(file, (unsigned short*)&h10.window_bdrwidth); pm_readlittleshort(file, (unsigned short*)&h10.window_ncolors); } for ( i = 0; i < h10.header_size - X10WD_HEADER_SIZE; ++i ) if ( getc( file ) == EOF ) pm_error( "couldn't read rest of X10 XWD file header" ); /* Check whether we can handle this dump. */ if ( h10.window_ncolors > 256 ) pm_error( "can't handle X10 window_ncolors > %d", 256 ); if ( h10.pixmap_format != ZFormat && h10.display_planes != 1 ) pm_error( "can't handle X10 pixmap_format %d with planes != 1", h10.pixmap_format ); grayscale = 1; if ( h10.window_ncolors != 0 ) { /* Read X10 colormap. */ x10colors = (X10Color*) malloc( h10.window_ncolors * sizeof(X10Color) ); if ( x10colors == (X10Color*) 0 ) pm_error( "out of memory" ); for ( i = 0; i < h10.window_ncolors; ++i ) { if ( ! byte_swap ) { pm_readbiglong(file, (unsigned long*)&x10colors[i].pixel); pm_readbigshort(file, (unsigned short*)&x10colors[i].red); pm_readbigshort(file, (unsigned short*)&x10colors[i].green); pm_readbigshort(file, (unsigned short*)&x10colors[i].blue); } else { pm_readlittlelong(file, (unsigned long*)&x10colors[i].pixel); pm_readlittleshort(file, (unsigned short*)&x10colors[i].red); pm_readlittleshort(file, (unsigned short*)&x10colors[i].green); pm_readlittleshort(file, (unsigned short*)&x10colors[i].blue); } if ( *maxvalP != 65535L ) { x10colors[i].red = (long) x10colors[i].red * (long) *maxvalP / 65535L; x10colors[i].green = (long) x10colors[i].green * (long) *maxvalP / 65535L; x10colors[i].blue = (long) x10colors[i].blue * (long) *maxvalP / 65535L; } if ( x10colors[i].red != x10colors[i].green || x10colors[i].green != x10colors[i].blue ) grayscale = 0; } } if ( h10.display_planes == 1 ) { *formatP = PBM_TYPE; *visualclassP = StaticGray; *maxvalP = 1; *colorsP = pnm_allocrow( 2 ); PNM_ASSIGN1( (*colorsP)[0], 0 ); PNM_ASSIGN1( (*colorsP)[1], *maxvalP ); *padrightP = ( ( h10.pixmap_width + 15 ) / 16 ) * 16 - h10.pixmap_width; bits_per_item = 16; bits_per_pixel = 1; } else if ( h10.window_ncolors == 0 ) { /* Must be grayscale. */ *formatP = PGM_TYPE; *visualclassP = StaticGray; *maxvalP = ( 1 << h10.display_planes ) - 1; *colorsP = pnm_allocrow( *maxvalP + 1 ); for ( i = 0; i <= *maxvalP; ++i ) PNM_ASSIGN1( (*colorsP)[i], i ); *padrightP = ( ( h10.pixmap_width + 15 ) / 16 ) * 16 - h10.pixmap_width; bits_per_item = 16; bits_per_pixel = 1; } else { *colorsP = pnm_allocrow( h10.window_ncolors ); *visualclassP = PseudoColor; if ( grayscale ) { *formatP = PGM_TYPE; for ( i = 0; i < h10.window_ncolors; ++i ) PNM_ASSIGN1( (*colorsP)[i], x10colors[i].red ); } else { *formatP = PPM_TYPE; for ( i = 0; i < h10.window_ncolors; ++i ) PPM_ASSIGN( (*colorsP)[i], x10colors[i].red, x10colors[i].green, x10colors[i].blue); } *padrightP = h10.pixmap_width & 1; bits_per_item = 8; bits_per_pixel = 8; } bits_used = bits_per_item; *colsP = h10.pixmap_width; *rowsP = h10.pixmap_height; if ( bits_per_pixel == sizeof(pixel_mask) * 8 ) pixel_mask = -1; else pixel_mask = ( 1 << bits_per_pixel ) - 1; byte_order = MSBFirst; bit_order = LSBFirst; } else if ( file_version == X11WD_FILE_VERSION || bs_long( file_version ) == X11WD_FILE_VERSION ) { int i; X11WDFileHeader h11; X11XColor* x11colors; byte_swap = ( file_version != X11WD_FILE_VERSION ); if ( ! byte_swap ) { h11.header_size = header_size; h11.file_version = file_version; pm_readbiglong(file, (unsigned long*)&h11.pixmap_format); pm_readbiglong(file, (unsigned long*)&h11.pixmap_depth); pm_readbiglong(file, (unsigned long*)&h11.pixmap_width); pm_readbiglong(file, (unsigned long*)&h11.pixmap_height); pm_readbiglong(file, (unsigned long*)&h11.xoffset); pm_readbiglong(file, (unsigned long*)&h11.byte_order); pm_readbiglong(file, (unsigned long*)&h11.bitmap_unit); pm_readbiglong(file, (unsigned long*)&h11.bitmap_bit_order); pm_readbiglong(file, (unsigned long*)&h11.bitmap_pad); pm_readbiglong(file, (unsigned long*)&h11.bits_per_pixel); pm_readbiglong(file, (unsigned long*)&h11.bytes_per_line); pm_readbiglong(file, (unsigned long*)&h11.visual_class); pm_readbiglong(file, (unsigned long*)&h11.red_mask); pm_readbiglong(file, (unsigned long*)&h11.green_mask); pm_readbiglong(file, (unsigned long*)&h11.blue_mask); pm_readbiglong(file, (unsigned long*)&h11.bits_per_rgb); pm_readbiglong(file, (unsigned long*)&h11.colormap_entries); pm_readbiglong(file, (unsigned long*)&h11.ncolors); pm_readbiglong(file, (unsigned long*)&h11.window_width); pm_readbiglong(file, (unsigned long*)&h11.window_height); pm_readbiglong(file, (unsigned long*)&h11.window_x); pm_readbiglong(file, (unsigned long*)&h11.window_y); pm_readbiglong(file, (unsigned long*)&h11.window_bdrwidth); } else { h11.header_size = bs_long( header_size ); h11.file_version = bs_long( file_version ); pm_readlittlelong(file, (unsigned long*)&h11.pixmap_format); pm_readlittlelong(file, (unsigned long*)&h11.pixmap_depth); pm_readlittlelong(file, (unsigned long*)&h11.pixmap_width); pm_readlittlelong(file, (unsigned long*)&h11.pixmap_height); pm_readlittlelong(file, (unsigned long*)&h11.xoffset); pm_readlittlelong(file, (unsigned long*)&h11.byte_order); pm_readlittlelong(file, (unsigned long*)&h11.bitmap_unit); pm_readlittlelong(file, (unsigned long*)&h11.bitmap_bit_order); pm_readlittlelong(file, (unsigned long*)&h11.bitmap_pad); pm_readlittlelong(file, (unsigned long*)&h11.bits_per_pixel); pm_readlittlelong(file, (unsigned long*)&h11.bytes_per_line); pm_readlittlelong(file, (unsigned long*)&h11.visual_class); pm_readlittlelong(file, (unsigned long*)&h11.red_mask); pm_readlittlelong(file, (unsigned long*)&h11.green_mask); pm_readlittlelong(file, (unsigned long*)&h11.blue_mask); pm_readlittlelong(file, (unsigned long*)&h11.bits_per_rgb); pm_readlittlelong(file, (unsigned long*)&h11.colormap_entries); pm_readlittlelong(file, (unsigned long*)&h11.ncolors); pm_readlittlelong(file, (unsigned long*)&h11.window_width); pm_readlittlelong(file, (unsigned long*)&h11.window_height); pm_readlittlelong(file, (unsigned long*)&h11.window_x); pm_readlittlelong(file, (unsigned long*)&h11.window_y); pm_readlittlelong(file, (unsigned long*)&h11.window_bdrwidth); } for ( i = 0; i < h11.header_size - X11WD_HEADER_SIZE; ++i ) if ( getc( file ) == EOF ) pm_error( "couldn't read rest of X11 XWD file header" ); /* Check whether we can handle this dump. */ if ( h11.pixmap_depth > 32 ) pm_error( "can't handle X11 pixmap_depth > 32" ); if ( h11.bits_per_rgb > 32 ) pm_error( "can't handle X11 bits_per_rgb > 32" ); if ( h11.pixmap_format != ZPixmap && h11.pixmap_depth != 1 ) pm_error( "can't handle X11 pixmap_format %d with depth != 1", h11.pixmap_format ); if ( h11.bitmap_unit != 8 && h11.bitmap_unit != 16 && h11.bitmap_unit != 32 ) pm_error( "X11 bitmap_unit (%d) is non-standard - can't handle", h11.bitmap_unit ); grayscale = 1; if ( h11.ncolors > 0 ) { /* Read X11 colormap. */ x11colors = (X11XColor*) malloc( h11.ncolors * sizeof(X11XColor) ); if ( x11colors == (X11XColor*) 0 ) pm_error( "out of memory" ); for ( i = 0; i < h11.ncolors; ++i ) { if ( ! byte_swap ) { pm_readbiglong(file, (unsigned long*)&x11colors[i].num); pm_readbigshort(file, (unsigned short*)&x11colors[i].red); pm_readbigshort(file, (unsigned short*)&x11colors[i].green); pm_readbigshort(file, (unsigned short*)&x11colors[i].blue); } else { pm_readlittlelong(file, (unsigned long*)&x11colors[i].num); pm_readlittleshort(file, (unsigned short*)&x11colors[i].red); pm_readlittleshort(file, (unsigned short*)&x11colors[i].green); pm_readlittleshort(file, (unsigned short*)&x11colors[i].blue); } x11colors[i].flags = getc( file ); x11colors[i].pad = getc( file ); if ( *maxvalP != 65535L ) { x11colors[i].red = (long) x11colors[i].red * (long) *maxvalP / 65535L; x11colors[i].green = (long) x11colors[i].green * (long) *maxvalP / 65535L; x11colors[i].blue = (long) x11colors[i].blue * (long) *maxvalP / 65535L; } if ( x11colors[i].red != x11colors[i].green || x11colors[i].green != x11colors[i].blue ) grayscale = 0; } } *visualclassP = h11.visual_class; if ( *visualclassP == TrueColor || *visualclassP == DirectColor ) { *formatP = PPM_TYPE; if ( h11.bits_per_pixel == 16 ) *maxvalP = 31; else *maxvalP = 255; } else if ( *visualclassP == StaticGray && h11.bits_per_pixel == 1 ) { *formatP = PBM_TYPE; *maxvalP = 1; *colorsP = pnm_allocrow( 2 ); PNM_ASSIGN1( (*colorsP)[0], *maxvalP ); PNM_ASSIGN1( (*colorsP)[1], 0 ); } else if ( *visualclassP == StaticGray ) { *formatP = PGM_TYPE; *maxvalP = ( 1 << h11.bits_per_pixel ) - 1; *colorsP = pnm_allocrow( *maxvalP + 1 ); for ( i = 0; i <= *maxvalP; ++i ) PNM_ASSIGN1( (*colorsP)[i], i ); } else { *colorsP = pnm_allocrow( h11.ncolors ); if ( grayscale ) { *formatP = PGM_TYPE; for ( i = 0; i < h11.ncolors; ++i ) PNM_ASSIGN1( (*colorsP)[i], x11colors[i].red ); } else { *formatP = PPM_TYPE; for ( i = 0; i < h11.ncolors; ++i ) PPM_ASSIGN( (*colorsP)[i], x11colors[i].red, x11colors[i].green, x11colors[i].blue); } } *colsP = h11.pixmap_width; *rowsP = h11.pixmap_height; *padrightP = h11.bytes_per_line * 8 / h11.bits_per_pixel - h11.pixmap_width; bits_per_item = h11.bitmap_unit; bits_used = bits_per_item; bits_per_pixel = h11.bits_per_pixel; byte_order = h11.byte_order; bit_order = h11.bitmap_bit_order; if ( bits_per_pixel == sizeof(pixel_mask) * 8 ) pixel_mask = -1; else pixel_mask = ( 1 << bits_per_pixel ) - 1; red_mask = h11.red_mask; green_mask = h11.green_mask; blue_mask = h11.blue_mask; } else pm_error( "unknown XWD file version: %d", file_version ); byteP = (char*) buf; shortP = (short*) buf; longP = (long*) buf; } static unsigned long getpixnum( FILE* file ) { int n; if ( bits_used == bits_per_item ) { switch ( bits_per_item ) { case 8: *byteP = getc( file ); break; case 16: if ( byte_order == MSBFirst ) { if ( pm_readbigshort( file, (unsigned short*) shortP ) == -1 ) pm_error( "error reading image" ); } else { if ( pm_readlittleshort( file, (unsigned short*) shortP ) == -1 ) pm_error( "error reading image" ); } break; case 32: if ( byte_order == MSBFirst ) { if ( pm_readbiglong( file, (unsigned long*) longP ) == -1 ) pm_error( "error reading image" ); } else { if ( pm_readlittlelong( file, (unsigned long*) longP ) == -1 ) pm_error( "error reading image" ); } break; default: pm_error( "can't happen" ); } bits_used = 0; if ( bit_order == MSBFirst ) bit_shift = bits_per_item - bits_per_pixel; else bit_shift = 0; } switch ( bits_per_item ) { case 8: n = ( *byteP >> bit_shift) & pixel_mask; break; case 16: n = ( *shortP >> bit_shift) & pixel_mask; break; case 32: n = ( *longP >> bit_shift) & pixel_mask; break; default: pm_error( "can't happen" ); } if ( bit_order == MSBFirst ) bit_shift -= bits_per_pixel; else bit_shift += bits_per_pixel; bits_used += bits_per_pixel; return n; } /* Byte-swapping junk. */ union cheat { long l; short s; unsigned char c[4]; }; #ifdef notdef static short bs_short( short s ) { union cheat u; unsigned char t; u.s = s; t = u.c[0]; u.c[0] = u.c[1]; u.c[1] = t; return u.s; } #endif /* notdef */ static long bs_long( long l ) { union cheat u; unsigned char t; u.l = l; t = u.c[0]; u.c[0] = u.c[3]; u.c[3] = t; t = u.c[1]; u.c[1] = u.c[2]; u.c[2] = t; return u.l; }