//------------------------------------------------------------------- // pcxphoto.cpp // // This Linux program must be run from a 'text mode' console. // It will display the truecolor image stored in a .pcx file. // // compile using: user$ make pcxphoto // // NOTE: The following preliminary steps are needed in order // to run this program, and may require system administrator // setup (or 'sudo' privileges): // (1) device-node '/dev/vram' is created with rw privileges // root# mknod /dev/vram c 99 0 // root# chmod a+rw /dev/vram // (2) program 'mode3' (from svgalib) has 'setuid' attribute // root# gcc mode3.c lrmi.c -o mode3 // root# chmod a+s mode3 // (3) module 'vram.c' is compiled in current user directory // user# make vram.o // Here step 3 may require installing a suitable 'Make' file // that specifies the proper Linux kernel 'build' directory. // // programmer: ALLAN CRUSE // written on: 01 SEP 2003 //------------------------------------------------------------------- #include // for printf(), perror() #include // for open() #include // for exit() #include // for read(), write(), close() #include // for mman() #include "pcx.h" // for PCX_FILE_HEADER #define VRAM_BASE_ADDRESS 0xB0000000 #define VESA_DISPLAY_MODE 0x413A typedef unsigned long PEL; PEL *fb = (PEL*)VRAM_BASE_ADDRESS; int hres = 640, vres = 480; char devname[] = "/dev/vram"; char pcxname[] = "issxmas.pcx"; void draw_rectangle( int x, int y, int h, int v, PEL color ); void fill_rectangle( int x, int y, int h, int v, PEL color ); int main( int argc, char **argv ) { PCX_FILE_HEADER pcx; // read the image file's header int fd = open( pcxname, O_RDONLY ); if ( fd < 0 ) { perror( pcxname ); exit(1); } if ( read( fd, &pcx, sizeof( pcx ) ) < 128 ) { perror( "read" ); exit(1); } // allocate storage for the image data int wide = pcx.x2 - pcx.x1; int high = pcx.y2 - pcx.y1; int npixels = wide * high; int *image = (int*)calloc( npixels, sizeof( int ) ); if ( !image ) { perror( "calloc" ); exit(1); } // read (and uncompress) the .pcx file's image data int i = 0; while ( i < npixels ) { int datum = 0; read( fd, &datum, 1 ); if ( datum < 0xC0 ) image[ i++ ] = datum; else { int reps = datum & 0x3F; read( fd, &datum, 1 ); do { image[ i++ ] = datum; } while ( --reps > 0 ); } } // read the image-file's colors unsigned char rgb[ 768 ]; lseek( fd, -768, SEEK_END ); read( fd, rgb, 768 ); // build the color lookup-table PEL colortable[ 256 ]; for (i = 0; i < 256; i++) { PEL color = 0; color |= ( rgb[ 3*i + 0 ] << 16 ); // red intensity color |= ( rgb[ 3*i + 1 ] << 8 ); // green intensity color |= ( rgb[ 3*i + 2 ] << 0 ); // blue intensity colortable[ i ] = color; } close( fd ); // report image file statistics printf( "\ngraphic image filename: \'%s\' ", pcxname ); printf( "\nimage size (in pixels): wide=%d high=%d ", wide, high ); printf( "\n\n" ); getchar(); // install our 'vram' device-driver module into the Linux kernel system( "/sbin/insmod ./vram.o ; clear" ); // and then map the vram device's display-memory into user-space fd = open( devname, O_RDWR ); if ( fd < 0 ) { perror( devname ); exit(1); } int size = (2 << 20); // 2-megabytes int prot = PROT_READ | PROT_WRITE; int flag = MAP_FIXED | MAP_SHARED; void *mm = (void*)VRAM_BASE_ADDRESS; if ( mmap( mm, size, prot, flag, fd, 0 ) == MAP_FAILED ) { perror( "mmap" ); exit(1); } // enter graphics mode char command[ 40 ] = ""; sprintf( command, "mode3 %d", VESA_DISPLAY_MODE ); system( command ); // draw red and green screen borders PEL red = 0xFF0000, green = 0x00FF00; int x = 0, y = 0, h = hres, v = vres; draw_rectangle( x, y, h, v, red ); // outer border x += 8; y += 8; h -= 16; v -= 16; draw_rectangle( x, y, h, v, green ); // inner border getchar(); // draw color lookup-table grid int xindent = ( hres - 160 )/2, yindent = ( vres - 160 )/2; for (i = 0; i < 256; i++) { x = xindent + (i % 16)*10; y = yindent + (i / 16)*10; fill_rectangle( x, y, 8, 8, colortable[ i ] ); } getchar(); // draw the uncompressed image xindent = ( hres - wide )/2; yindent = ( vres - high )/2; for (i = 0; i < npixels; i++) { x = xindent + (i % pcx.bplin); y = yindent + (i / pcx.bplin); fb[ y*hres + x ] = colortable[ image[i] ]; } getchar(); // restore the video display system to standard text mode system( "mode3" ); } void draw_rectangle( int x, int y, int h, int v, PEL color ) { int minx = x, maxx = x+h-1, miny = y, maxy = y+v-1; do { fb[ y*hres + x ] = color; ++x; } while ( x < maxx ); do { fb[ y*hres + x ] = color; ++y; } while ( y < maxy ); do { fb[ y*hres + x ] = color; --x; } while ( x > minx ); do { fb[ y*hres + x ] = color; --y; } while ( y > miny ); } void fill_rectangle( int x, int y, int h, int v, PEL color ) { int minx = x, maxx = x+h-1, miny = y, maxy = y+v-1; for (y = miny; y <= maxy; y++) for (x = minx; x <= maxx; x++) fb[ y*hres + x ] = color; }