// RGBpixmap.cc #include "RGBpixmap.h" #include #ifdef _WINDOZ #include //change if using xWindows #include #else #include #endif typedef unsigned short ushort; typedef unsigned long ulong; static fstream inf; // global in this file for convenience static fstream outf; // output file mRGB::mRGB() {r = g = b = 0;} mRGB::mRGB(mRGB& p) {r = p.r; g = p.g; b = p.b;} mRGB::mRGB(uchar rr, uchar gg, uchar bb) {r = rr; g = gg; b = bb;} void mRGB::set(uchar rr, uchar gg, uchar bb) {r = rr; g = gg; b = bb;} //$$$$$$$$$$$$$$$$$ RGBPixmap class methods $$$$$$$$$$$$$$$ RGBpixmap::RGBpixmap() {nRows = nCols = 0; pixel = 0;} RGBpixmap::RGBpixmap(int rows, int cols) //constructor { nRows = rows; nCols = cols; pixel = new mRGB[rows*cols]; } void RGBpixmap::freeIt() // give back memory for this pixmap { delete []pixel; nRows = nCols = 0; } //<<<<<<<<<<<<<<<<<< copy >>>>>>>>>>>>>>>>>>> void RGBpixmap::copy(IntPoint from, IntPoint to, int x, int y, int width, int height) { // copy a region of the display back onto the display if(nRows == 0 || nCols == 0) return; glCopyPixels(x, y, width, height,GL_COLOR); } //<<<<<<<<<<<<<<<<<<< draw >>>>>>>>>>>>>>>>> void RGBpixmap::draw() { // draw this pixmap at current raster position if(nRows == 0 || nCols == 0) return; //tell OpenGL: don't align pixels to 4 byte boundaries in memory glPixelStorei(GL_UNPACK_ALIGNMENT,1); glDrawPixels(nCols, nRows,GL_RGB, GL_UNSIGNED_BYTE,pixel); } //<<<<<<<<<<<<<<<<<<< draw >>>>>>>>>>>>>>>>> void RGBpixmap::draw(int x, int y) { // (x,y) is the origin of the translated image to be drawn // 4 cases, depending on which quadrant (x,y) is in if (x >= 0 && y >= 0) { // drag left and down glRasterPos2i(0, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, y); glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); glDrawPixels(nCols - x, nRows - y, GL_RGB, GL_UNSIGNED_BYTE,pixel); } else if (x >= 0 && y < 0) { // drag left and up glRasterPos2i(0, -y); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, x); glDrawPixels(nCols - x, nRows /* + y */, GL_RGB, GL_UNSIGNED_BYTE,pixel); } else if (x < 0 && y >= 0) { // drag right and down glRasterPos2i(-x, 0); glPixelStorei(GL_UNPACK_SKIP_ROWS, y); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glDrawPixels(nCols /* + x */, nRows - y, GL_RGB, GL_UNSIGNED_BYTE,pixel); } else { // (x < 0 && y < 0), drag right and up glRasterPos2i(-x, -y); glPixelStorei(GL_UNPACK_SKIP_ROWS, 0); glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0); glDrawPixels(nCols /* + x */, nRows /* + y */, GL_RGB, GL_UNSIGNED_BYTE,pixel); } } // draw(x, y) //<<<<<<<<<<<<<<<<< read >>>>>>>>>>>>>>>> int RGBpixmap::read(int x, int y, int wid, int ht) { // read a rectangle of pixels into this pixmap nRows = ht; nCols = wid; delete [] pixel; pixel = new mRGB[nRows *nCols]; if(!pixel) return -1; //tell OpenGL: don't align pixels to 4 byte boundaries in memory glPixelStorei(GL_PACK_ALIGNMENT,1); glPixelStorei(GL_UNPACK_ROW_LENGTH, wid); glReadPixels(x, y, nCols, nRows, GL_RGB,GL_UNSIGNED_BYTE,pixel); return 0; } //<<<<<<<<<<<<<<<<< read from IntRect >>>>>>>>>>>>>>>> int RGBpixmap::read(IntRect r) { // read a rectangle of pixels into this pixmap nRows = r.top - r.bott; nCols = r.right - r.left; delete [] pixel; pixel = new mRGB[nRows *nCols]; if(!pixel) return -1; //tell OpenGL: don't align pixels to 4 byte boundaries in memory glPixelStorei(GL_PACK_ALIGNMENT,1); glPixelStorei(GL_UNPACK_ROW_LENGTH, nCols); glReadPixels(r.left,r.bott, nCols, nRows, GL_RGB, GL_UNSIGNED_BYTE, pixel); return 0; } //<<<<<<<<<<<<<< setPixel >>>>>>>>>>>>> void RGBpixmap::setPixel(int x, int y, mRGB color) { if(x>=0 && x =0 && y < nRows) pixel[nCols * y + x] = color; } //<<<<<<<<<<<<<<<< getPixel >>>>>>>>>>> mRGB RGBpixmap::getPixel(int x, int y) { mRGB bad(255,255,255); assert(x >= 0 && x < nCols); assert(y >= 0 && y < nRows); return pixel[nCols * y + x]; } //<<<<<<<<<<<<<<<<<<<<< getShort >>>>>>>>>>>>>>>>>>>> static ushort getShort() //helper function { //BMP format uses little-endian integer types // get a 2-byte integer stored in little-endian form char ic; ushort ip; inf.get(ic); ip = ic; //first byte is little one inf.get(ic); ip |= ((ushort)ic << 8); // or in high order byte return ip; } //<<<<<<<<<<<<<<<<<<<< getLong >>>>>>>>>>>>>>>>>>> static ulong getLong() //helper function { //BMP format uses little-endian integer types // get a 4-byte integer stored in little-endian form ulong ip = 0; char ic = 0; unsigned char uc = ic; inf.get(ic); uc = ic; ip = uc; inf.get(ic); uc = ic; ip |=((ulong)uc << 8); inf.get(ic); uc = ic; ip |=((ulong)uc << 16); inf.get(ic); uc = ic; ip |=((ulong)uc << 24); return ip; } //<<<<<<<<<<<<<<<<<< RGBPixmap:: readBmpFile>>>>>>>>>>>>> int RGBpixmap:: readBMPFile(string fname) { // Read into memory an mRGB image from an uncompressed BMP file. // return 0 on failure, 1 on success inf.open(fname.c_str(), ios::in|ios::binary); //read binary char's if(!inf){ cout << " can't open file: " << fname << endl; return 0;} int k, row, col, numPadBytes, nBytesInRow; // read the file header information char ch1, ch2; inf.get(ch1); inf.get(ch2); //type: always 'BM' ulong fileSize = getLong(); ushort reserved1 = getShort(); // always 0 ushort reserved2= getShort(); // always 0 ulong offBits = getLong(); // offset to image - unreliable ulong headerSize = getLong(); // always 40 ulong numCols = getLong(); // number of columns in image ulong numRows = getLong(); // number of rows in image ushort planes= getShort(); // always 1 ushort bitsPerPixel= getShort(); //8 or 24; allow 24 here ulong compression = getLong(); // must be 0 for uncompressed ulong imageSize = getLong(); // total bytes in image ulong xPels = getLong(); // always 0 ulong yPels = getLong(); // always 0 ulong numLUTentries = getLong(); // 256 for 8 bit, otherwise 0 ulong impColors = getLong(); // always 0 if(bitsPerPixel != 24) { // error - must be a 24 bit uncompressed image cout << "not a 24 bit/pixelimage, or is compressed!\n"; inf.close(); return 0; } //add bytes at end of each row so total # is a multiple of 4 // round up 3*numCols to next mult. of 4 nBytesInRow = ((3 * numCols + 3)/4) * 4; numPadBytes = nBytesInRow - 3 * numCols; // need this many nRows = numRows; // set class's data members nCols = numCols; if (pixel) delete pixel; // in case we read over an old image pixel = new mRGB[nRows * nCols]; //make space for array if(!pixel) return 0; // out of memory! long count = 0; char dum; for(row = 0; row < nRows; row++) // read pixel values { for(col = 0; col < nCols; col++) { char r,g,b; inf.get(b); inf.get(g); inf.get(r); //read bytes pixel[count].r = r; //place them in colors pixel[count].g = g; pixel[count++].b = b; } for(k = 0; k < numPadBytes ; k++) //skip pad bytes at row's end inf >> dum; } inf.close(); return 1; // success }// readBMPFile // #include "writeBMP.cc" // WRITTEN BY TingJen (it is slow because it writes one // byte at a time! It uses putLong() and putShort() utility: static void putLong(unsigned long ip) { outf.put((unsigned char)(ip & 0xff)); outf.put((unsigned char)((ip>>8) & 0xff)); outf.put((unsigned char)((ip>>16) & 0xff)); outf.put((unsigned char)((ip>>24) & 0xff)); } static void putShort(unsigned short ip) { outf.put((unsigned char)(ip & 0xff)); outf.put((unsigned char)((ip>>8) & 0xff)); } int RGBpixmap::writeBMPFile(char *fname) { outf.open(fname, ios::out | ios::binary); if (!outf) { cerr << "can't open file: " << fname << endl; return -1; } outf.put('B'); outf.put('M'); // file type "BM" putLong(0x36L + nRows * nCols * 3); //file size putLong(0L); //reserved putLong(0x36L); // offset to image putLong(40L); // putLong((unsigned long) nCols); //number of columns putLong((unsigned long) nRows); //number of rows putShort(1); // putShort(24); // bits per pixel putLong(0L); // not compressed putLong((unsigned long)nRows * nCols * 3); // total bytes in image putLong(0L); // putLong(0L); // putLong(0L); // numbers of colors : Not used putLong(0L); // int count = 0; int numPadBytes = ((3 * nCols + 3)/4) * 4 - 3 * nCols; for (int y = 0; y < nRows; y ++) // for each row { for (int x = 0; x < nCols ; x++) // for each pixel { mRGB &p = pixel[count++]; outf.put(p.b); outf.put(p.g); outf.put(p.r); } for (int k = 0; k < numPadBytes; k ++) // padding outf.put(' '); } outf.close(); return 1; }//writeBMPFile