Bitmap/C++: Difference between revisions
< Bitmap
(moved from Basic bitmap storage) |
m (moved Basic bitmap storage/C++ to Bitmap/C++) |
(No difference)
|
Revision as of 12:31, 6 February 2010
Bitmap/C++ is part of Basic bitmap storage. You may find other members of Basic bitmap storage at Category:Basic bitmap storage.
<lang cpp>#include <cstddef>
// This class does not implement a copy constructor, nor // does it override the = operatior. If an instance of this object // needs to survive outside the scope it was created in, allocate it // on the heap (e.g. pBitmap = new CBitmap(x,y) ), and pass the pointer // around.
class CBitmap {
// symbolic constants for the red/green/blue indices. The explicit values // are given for clarity, because the program relies on them; omitting them // would not change the values of the enumerators enum { red_index = 0, green_index = 1, blue_index = 2, num_channels = 3 };
protected:
// This pointer will point to the region of memory that will hold the // image data. char* m_pImageData;
// The "pitch" is the amount of memory a single horizontal line of an // image takes in memory. This is NOT necessarily equal to the width // of the image, and certainly not in our case, because each pixel // takes up three bytes. unsigned int m_pitch;
// The height will correspond to the number of rows in the image. unsigned int m_height;
public:
// Specify the width and height in our constructor. CBitmap(unsigned int width, unsigned int height): // if allocation fails, "new" will throw a std::bad_alloc exception. // This exception propagates out of the constructor and causes the // object to be disposed of (without even running the destructor). // Since this pointer will never again be changed during the lifetime // of objects of this class, this means it will never be NULL in any // object of this class. Tests for NULL are therefore not needed // anywhere in this class. m_pImageData(new char[num_channels*width*height]),
// Since we use num_channels bytes of memory for each pixel, // then our pitch is our width * num_channels. m_pitch(width * num_channels),
// Save our height off so we can perform sanity checks // when SetPixel() and GetPixel() are called. m_height(height) { }
~CBitmap() { delete [] m_pImageData; }
// Using references because handling image data with function calls // on a per-pixel basis is slow enough. No need to make copies of all // the arguments. bool SetPixel(const unsigned int& x, const unsigned int& y, char& R, char& G, char& B) { // Trying to access a pixel outside the image data's dimensions // may cause an access violations on architectures with memory // protection. ( Such as x86 and PPC.) On systems without // memory protection, or where it's disabled, or in situations // where the program happens to have legal access to the // calculated memory address, you'll get garbage data at best. // At worst, you may be returning values that represent // sensitive data. if( (y >= m_height) || (x * num_channels >= m_pitch) ) // Indicate that we were not successful. return false;
// Calculate the start of the pixel in our image buffer, so we // don't perform a multiply and add for each subpixel. // Some optimizing compilers will store off this value in // advance. Some might have a better way of doing things. // But this is both fast without optimizations enabled, and // easy to debug. unsigned int pixel_index = (y * m_pitch + x) * num_channels;
// The red byte sits at the beginning of the pixel. R = m_pImageData[pixel_index + red_index];
// The green byte sits at the byte following the red byte. G = m_pImageData[pixel_index + green_index];
// The blue byte sits at the byte following the green byte. B = m_pImageData[pixel_index + blue_index];
// Indicate that we were successful. return true; }
// Using references because handling image data with function calls // on a per-pixel basis is slow enough already. No need to make copies // of all of the arguments. bool GetPixel(const unsigned int& x, const unsigned int& y, char& R, char& G, char& B) { // As with SetPixel(), trying to access a pixel outside the data's // dimensions will cause problems. However, when you're writing // data, as opposed to reading it, if memory protections fail or // aren't available, you can cause memory corruption, which can // be a particularly difficult type of bug to track down. if( (y >= m_height) || (x * num_channels >= m_pitch) ) // Indicate that we were not successful. return false;
// Calculate the start of the pixel in our image buffer, for the same // reasons as in SetPixel() unsigned int pixel_index = (y * m_pitch + x) * num_channels;
// The red byte sits at the beginning of the pixel. R = m_pImageData[pixel_index + red_index];
// The green byte sits at the byte following the red byte. G = m_pImageData[pixel_index + green_index];
// The blue byte sits at the byte following the green byte. B = m_pImageData[pixel_index + blue_index];
// Indicate that we were successful. return true; }
bool Fill(const char& R, const char& G, const char& B) { // Since we fill the whole image with the same color, we don't care about the actual image dimensions. // All we need to know is that the pixels are densely packed, and where to stop. for(unsigned int pixel_index = 0; pixel_index < m_height * m_pitch; pixel_index += num_channels) { m_pImageData[pixel_index + red_index] = R; m_pImageData[pixel_index + green_index] = G; m_pImageData[pixel_index + blue_index] = B; }
return true; }
private:
// Prevent the compiler from creating implicit copy constructor and copy assignment // operators. Those defauls would have incorrect semantics for this class. CBitmap(CBitmap const&); // not implemented CBitmap& operator=(CBitmap const&); // not implemented
};</lang>