Bitmap/C++: Difference between revisions
< Bitmap
Content added Content deleted
m (moved Basic bitmap storage/C++ to Bitmap/C++) |
(Applied DRY priciple. Switched from pass-by-reference to pass-by-value where applicable. Added Copy constructor, assignment op. Fixed indexing bugs. Changed SetPixel to not be equal to GetPixel.) |
||
Line 2:
<lang cpp>#include <cstddef>
#include <stdexcept>
// CBitmap as found below is a class that represents bitmap images
// in main memory, alternatively the images could be stored in
// memory in a graphics system (OpenGL, DirectX, ...), but this
// would not be generic, nor simple.
class CBitmap
{
private:
enum { red_index, green_index, blue_index, num_channels };
private:
char* m_pImageData;
unsigned int m_width;
unsigned int m_height;
public:
//
// For automatic variables, the result is that all accesses to the
// class' members are skipped, by leaving the scope where the object
// is created, and visible.
// For dynamic variables, created on the heap, this will not result
// in a memory leak, because the memory allocated for the CBitmap
// is freed as a result of the exception in this case. It is the
// responsability of the client not to access the class' members
// after such a failed allocation.
// The result of this is that the m_pImageData member variable
// will never be 0 in a legal access through the class' member
// functions, and thus we can be certain of the invariant (m_pImageData != 0).
CBitmap(unsigned int width, unsigned int height):
m_width(width),
m_height(height)
{
}
// The presence of this copy constructor enables pass-by-value,
// which is strongly discouraged, due to large amount of work
// involved in copying. Use pass-by-reference to avoid the copy.
CBitmap(CBitmap const &original):
m_pImageData(new char[num_channels * original.m_width * original.m_height]),
m_width(original.m_width),
m_height(original.m_height)
{
CopyImageDataFrom(original.m_pImageData);
}
Line 56 ⟶ 55:
}
public:
// An assignment operator is defined with copy-semantics. When an
// allocation error occurs, an exception is thrown (which should
// be caught by the client, and the object destructed) and the
// original data is preserved, to satisfy the invariant (m_pImageData != 0).
// post-condition: this bitmap becomes a uniform copy of the original.
// exception: failed allocation will cause the image data to be unchanged.
CBitmap& operator=(CBitmap const &original)
{
char *new_image_data = new char[num_channels * original.m_width * original.m_height];
CopyImageDataFrom(original.m_pImageData);
}
catch ( ... )
{
throw std::runtime_error( "assignment failed, original data conserved" );
}
}
public:
bool SetPixel(unsigned int x, unsigned int y, char R, char G, char B)
{
if ( ! IsWithinBitmap(x, y) )
{
return false;
}
unsigned int pixel_index = ImageCoordinateToPixelIndex(x, y);
SetColorValueAtIndex( pixel_index, R, G, B );
return true;
}
bool GetPixel(unsigned int x, unsigned int y, char& R, char& G, char& B)
{
{
return false;
}
}
void Fill(char R, char G, char B)
{
for(unsigned int pixel_index = 0;
pixel_index < m_height * m_width * num_channels;
pixel_index += num_channels)
SetColorValueAtIndex( pixel_index, R, G, B );
}
private:
// An alternative to status flags is the use of exceptions.
bool IsWithinBitmap(unsigned int x, unsigned int y)
{
return y < m_height && x < m_width;
}
unsigned int ImageCoordinateToPixelIndex(unsigned int x, unsigned int y)
return (y * m_width + x) * num_channels;
}
{
m_pImageData[pixel_index + red_index] = R;
m_pImageData[pixel_index + green_index] = G;
m_pImageData[pixel_index + blue_index] = B;
void GetColorValueAtIndex(unsigned int pixel_index, char R, char G, char B)
{
R = m_pImageData[pixel_index + red_index];
G = m_pImageData[pixel_index + green_index];
B = m_pImageData[pixel_index + blue_index];
}
void CopyImageDataFrom(char *source)
{
// An alternative implementation using memcpy would be more efficient
for (unsigned int i = 0; i < num_channels * m_width * m_height; ++i)
m_pImageData[i] = source[i];
}
};</lang>
|
Revision as of 10:30, 13 May 2011
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>
- include <stdexcept>
// CBitmap as found below is a class that represents bitmap images // in main memory, alternatively the images could be stored in // memory in a graphics system (OpenGL, DirectX, ...), but this // would not be generic, nor simple.
class CBitmap { private:
enum { red_index, green_index, blue_index, num_channels };
private:
char* m_pImageData; unsigned int m_width; unsigned int m_height;
public:
// If allocation fails, "new" will throw a std::bad_alloc exception. // For automatic variables, the result is that all accesses to the // class' members are skipped, by leaving the scope where the object // is created, and visible. // For dynamic variables, created on the heap, this will not result // in a memory leak, because the memory allocated for the CBitmap // is freed as a result of the exception in this case. It is the // responsability of the client not to access the class' members // after such a failed allocation. // The result of this is that the m_pImageData member variable // will never be 0 in a legal access through the class' member // functions, and thus we can be certain of the invariant (m_pImageData != 0). CBitmap(unsigned int width, unsigned int height): m_pImageData(new char[num_channels * width * height]), m_width(width), m_height(height) { }
// The presence of this copy constructor enables pass-by-value, // which is strongly discouraged, due to large amount of work // involved in copying. Use pass-by-reference to avoid the copy. CBitmap(CBitmap const &original): m_pImageData(new char[num_channels * original.m_width * original.m_height]), m_width(original.m_width), m_height(original.m_height) { CopyImageDataFrom(original.m_pImageData); }
~CBitmap() { delete [] m_pImageData; }
public:
// An assignment operator is defined with copy-semantics. When an // allocation error occurs, an exception is thrown (which should // be caught by the client, and the object destructed) and the // original data is preserved, to satisfy the invariant (m_pImageData != 0).
// post-condition: this bitmap becomes a uniform copy of the original. // exception: failed allocation will cause the image data to be unchanged. CBitmap& operator=(CBitmap const &original) { if ( this == &original ) { return *this; }
try { char *new_image_data = new char[num_channels * original.m_width * original.m_height]; delete [] m_pImageData; m_pImageData = new_image_data; m_width = original.m_width; m_height = original.m_height; CopyImageDataFrom(original.m_pImageData); } catch ( ... ) { throw std::runtime_error( "assignment failed, original data conserved" ); }
return *this; }
public:
bool SetPixel(unsigned int x, unsigned int y, char R, char G, char B) { if ( ! IsWithinBitmap(x, y) ) { return false; }
unsigned int pixel_index = ImageCoordinateToPixelIndex(x, y); SetColorValueAtIndex( pixel_index, R, G, B );
return true; }
bool GetPixel(unsigned int x, unsigned int y, char& R, char& G, char& B) { if ( ! IsWithinBitmap(x, y) ) { return false; }
unsigned int pixel_index = ImageCoordinateToPixelIndex(x, y); GetColorValueAtIndex( pixel_index, R, G, B );
return true; }
void Fill(char R, char G, char B) { for(unsigned int pixel_index = 0; pixel_index < m_height * m_width * num_channels; pixel_index += num_channels) SetColorValueAtIndex( pixel_index, R, G, B ); }
private:
// An alternative to status flags is the use of exceptions. bool IsWithinBitmap(unsigned int x, unsigned int y) { return y < m_height && x < m_width; }
unsigned int ImageCoordinateToPixelIndex(unsigned int x, unsigned int y) { return (y * m_width + x) * num_channels; }
void SetColorValueAtIndex(unsigned int pixel_index, char R, char G, char B) { m_pImageData[pixel_index + red_index] = R; m_pImageData[pixel_index + green_index] = G; m_pImageData[pixel_index + blue_index] = B; }
void GetColorValueAtIndex(unsigned int pixel_index, char R, char G, char B) { R = m_pImageData[pixel_index + red_index]; G = m_pImageData[pixel_index + green_index]; B = m_pImageData[pixel_index + blue_index]; }
void CopyImageDataFrom(char *source) { // An alternative implementation using memcpy would be more efficient // on almost all platforms. for (unsigned int i = 0; i < num_channels * m_width * m_height; ++i) m_pImageData[i] = source[i]; }
};</lang>