Bitmap/C++

From Rosetta Code
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>