//============================================================================== // bmpdump.cpp // Reads and dumps the contents of a BMP graphic image file. // // Acknowledgements // Copyright ©2008 by David R. Tribble, all rights reserved. // Permission is granted to any person or entity except those designated // by the United States Department of State as a terrorist, or terrorist // government or agency, to use and distribute this source code provided // that the original copyright notice remains present and unaltered. //============================================================================== // Identification static char REV[] = "@(#)drt/bmp/bmpdump.cpp $Revision: 1.5 $$Date: 2008/06/28 18:00:52 $"; static char BUILT[] = "@(#)Built: " __DATE__ " " __TIME__; // System includes #include #define sys_errno_h 1 #include #define sys_iso646_h 1 #include #define sys_stddef_h 1 #include #define sys_stdint_h 1 #include #define sys_stdio_h 1 #include #define sys_string_h 1 #ifdef errno #define sys_errno errno #else #define sys_errno ::errno #endif // Local includes #include "bmpdefs.h" #include "bmpfile.hpp" //------------------------------------------------------------------------------ // Class Program // Embodies the execution of this program. //------------------------------------------------------------------------------ #define Program_VS 100 // Class version number class Program { public: // Constants enum RCode { RC_OKAY = 0, // Success RC_FILE = 1, // Can't open/read BMP file RC_HEADER = 2, // Can't read BMP file header RC_PALETTE = 3, // Can't read BMP color palette RC_USAGE = 255 // Bad program usage }; private: // Static variables static const char * PROG; // Program name private: // Variables FILE * m_out; // Output stream const char * m_fname; // Image filename DrtBmpFile * m_bmp; // BMP file I/O object const bmp_header * m_hdr; // BMP header info bool opt_palette; // Dump the palette map bool opt_pixels; // Dump the pixel data public: // Functions /**/ ~Program() { } // Destructor /**/ Program(); // Default constructor int main(int argc, const char **argv); private: // Functions /**/ Program(const Program &o); const Program & operator =(const Program *o); int dump_file(const char *fname); }; //------------------------------------------------------------------------------ // Class variables //------------------------------------------------------------------------------ /*static*/ const char * Program::PROG = "bmpdump"; //------------------------------------------------------------------------------ // Program::Program() // Default constructor. // // @since // 1.3, 2008-05-01 //------------------------------------------------------------------------------ /**/ Program::Program(): opt_palette(false), opt_pixels(false), m_fname(NULL), m_bmp(NULL), m_hdr(NULL) { #if Program_VS/100 != 1 #error class Program has changed #endif } //------------------------------------------------------------------------------ // Program::main() // Dump the contents of a BMP graphic image file. // // @return // One of the RC_XXX error codes, or zero if no error occurs. // // @since // 1.3, 2008-05-01 //------------------------------------------------------------------------------ int Program::main(int argc, const char **argv) { #if Program_VS/100 != 1 #error class Program has changed #endif #if DrtBmpFile_VS/100 != 1 #error class DrtBmpFile has changed #endif int nfiles; int rc = RC_OKAY; int i; // Parse the command line options m_out = stdout; for (i = 1; i < argc and argv[i][0] == '-'; i++) { if (::strcmp(argv[i], "-c") == 0) opt_palette = true; else if (::strcmp(argv[i], "-d") == 0) opt_pixels = true; else { ::fprintf(m_out, "%s: Bad command option: '%s'\n", PROG, argv[i]); goto usage; } } // Check the command line args if (i >= argc) { usage: // Display a program usage message ::fprintf(m_out, "Dump the contents of a Windows bitmap image (BMP) " "file.\n\n"); ::fprintf(m_out, "usage: %s [-option...] file.bmp...\n\n", PROG); ::fprintf(m_out, "Options:\n"); ::fprintf(m_out, " -c Display color map table\n"); ::fprintf(m_out, " -d Display image pixel data\n"); // Punt return RC_USAGE; } // Dump the BMP file(s) for (nfiles = 0; i < argc; i++, nfiles++) { int err; // Dump a BMP image file if (nfiles > 0) ::fprintf(m_out, "\n"); err = dump_file(argv[i]); if (err != RC_OKAY and rc != RC_OKAY) rc = err; } // Done return (rc); } //------------------------------------------------------------------------------ // Program::dump_file() // Read and dump the contents of a BMP graphic image file. // // @param fname // Filename of the BMP image file. // // @return // One of the RC_XXX error codes, or zero if no error occurs. // // @since // 1.3, 2008-05-01 //------------------------------------------------------------------------------ int Program::dump_file(const char *fname) { #if Program_VS/100 != 1 #error class Program has changed #endif #if DrtBmpFile_VS/100 != 1 #error class DrtBmpFile has changed #endif // Open the BMP file m_fname = fname; m_bmp = DrtBmpFile::open(m_fname, DrtBmpFile::M_READ); if (m_bmp == NULL) { ::fprintf(m_out, "Can't read (error %d): %s: %s\n", sys_errno, ::strerror(sys_errno), m_fname); return RC_FILE; } ::fprintf(m_out, "%s\n", m_fname); // Read the BMP file header if (not m_bmp->read_header()) { ::fprintf(m_out, "Can't read BMP header (error %d): %s: %s\n", sys_errno, ::strerror(sys_errno), m_fname); return RC_HEADER; } // Dump the contents of the BMP file header ::fprintf(m_out, "Header\n"); m_hdr = m_bmp->get_header(); m_bmp->dump_header(stdout); // Read the BMP color palette if (m_bmp->has_palette()) { if (not m_bmp->read_palette()) { ::fprintf(m_out, "Can't read image palette (error %d): %s: %s\n", sys_errno, ::strerror(sys_errno), m_fname); return RC_PALETTE; } // Dump the contents of the BMP color palette if (opt_palette) { ::fprintf(m_out, "Palette\n"); m_bmp->dump_palette(stdout); } } // Read pixel data from the BMP file if (opt_pixels) { int printsz; const char * fmt; int y; // Set up switch (m_hdr->bits) { case 1: case 2: case 4: printsz = 38; fmt = "%01lX"; break; case 8: default: printsz = 25; fmt = "%02lX"; break; case 24: printsz = 10; fmt = "%06lX"; break; } // Dump the BMP pixel data, one scan line at a time ::fprintf(m_out, "Pixels\n"); for (y = 0; y < m_hdr->depth; y++) { int x; // Read a scan line ::fprintf(m_out, "%u", m_hdr->depth-y-1); for (x = 0; x < m_hdr->width; x++) { int32_t pix; // Read next pixel value pix = m_bmp->read_pixel(); if (pix < 0) { ::fprintf(m_out, "\nPremature end of file\n"); goto End_y; } // Dump the pixel value ::fprintf(m_out, (x%printsz == 0 ? "\n " : " ")); ::fprintf(m_out, fmt, (unsigned long)pix); } // End of the scan line reached ::fprintf(m_out, "\n"); m_bmp->read_eoln(); } // End of the image file reached ::fprintf(m_out, "End\n"); End_y:; } // Clean up m_bmp->close(); return RC_OKAY; } //------------------------------------------------------------------------------ // ::main() // Dump the contents of a BMP graphic image file. // // @return // One of the Program::RC_XXX error codes, or zero if no error occurs. // // @since // 1.3, 2008-05-01 //------------------------------------------------------------------------------ int main(int argc, const char **argv) { Program prog; return (prog.main(argc, argv)); } // End bmpdump.cpp