|
|||||||||||||||||||||
|
|||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
IntroductionThis article is about the 'simple' C++ bitmap manipulation class called So, my decision was to write another (yes, another) bitmap manipulation class that would not be MFC dependent, and would offer some extended features not present in the original MFC implementation. This class can load any 8, 16, 24 or 32bit bitmap, but internally works with 32bit bitmaps. The results can be saved as the 24bit bitmap on the hard disk, or it can be drawn on the provided device context (DC). BackgroundThere are many articles here on Code Project considering this topic, so feel free to browse for them and compare the final results with this implementation. Using the CodeUsing this class is very simply, see below: #include "BitmapEx.h"
// Load bitmap
CBitmapEx bitmapEx;
bitmapEx.Load(_T("Enter bitmap source file path here..."));
// Do whatever you need to do here
bitmapEx.Rotate(45);
bitmapEx.Sepia();
bitmapEx.Scale(50, 50);
// Draw the results on the screen (get hDC somewhere else)
bitmapEx.Draw(hDC);
// Save bitmap
bitmapEx.Save(_T("Enter bitmap destination file path here..."));
There are many public methods available. Please read the rest of the text which explains them all. Create/Load/Save BitmapYou can use this class to load any 8bpp to 32bpp bitmap from the hard disk or the memory stream. Also, you can load any bitmap from the Windows To create/load/save bitmap to the hard disk or a memory stream, or the void Create(long width, long height);
void Create(CBitmapEx& bitmapEx);
void Create(CBitmapEx* pBitmapEx);
void Load(LPTSTR lpszBitmapFile);
void Load(LPBYTE lpBitmapData);
void Load(HBITMAP hBitmap);
void Save(LPTSTR lpszBitmapFile);
void Save(LPBYTE lpBitmapData);
void Save(HBITMAP& hBitmap);
Using the first method you can create the bitmap of almost any size (well, available RAM could be the limiting factor). This is a general 'blank bitmap'. Using the second and the third method you can create new bitmap from the existing one (this is simulating the so called 'copy constructor'). In this way you actually copy the existing bitmap in the memory. This could be useful when you do some bitmap filtering and you need the original bitmap backup. The next three methods give you an option to load the bitmap from the file or memory stream, or the HBITMAP. And finally, the last three methods provide you a simple way to save the bitmap to the file or memory stream or to the General Transformation MethodsThis class offers some general bitmap transformation methods like scaling, rotation, cropping, flipping and mirroring. During the scaling and rotation operation the bitmap details could get lost, so the three basic interpolation methods are implemented:
You can set the interpolation method using the void Scale(long horizontalPercent=100, long verticalPercent=100);
void Rotate(long degrees=0, _PIXEL bgColor=_RGB(0,0,0));
void Crop(long x, long y, long width, long height);
void FlipHorizontal();
void FlipVertical();
void MirrorLeft();
void MirrorRight();
void MirrorTop();
void MirrorBottom();
You can scale the bitmap along the x and/or the y axis, rotate it from 0 to 360 percents, or perform flipping and/or mirroring. When you flip or mirror the bitmap, no interpolation is required since you don't change the original bitmap dimensions. When you perform the bitmap rotation you can set the background color. The default is black. Here are some samples of the described transformation methods (IE only: place mouse pointer above each image to see the applied transformation):
Simple Bitmap FilteringThere are 18 simple filters implemented (and more to come) to do a simple bitmap convolution filtering. The void Clear(_PIXEL clearColor=_RGB(0,0,0));
void Negative();
void Grayscale();
void Sepia(long depth=34);
void Emboss();
void Engrave();
void Pixelize(long size=4);
void Brightness(long brightness=0);
void Contrast(long contrast=0);
void Blur();
void GaussianBlur();
void Sharp();
void Colorize(_PIXEL color);
void Rank(BOOL bMinimum=TRUE);
void Spread(long distanceX=8, long distanceY=8);
void Offset(long offsetX=16, long offsetY=16);
void BlackAndWhite(long offset=128);
void EdgeDetect();
void GlowingEdges(long threshold=2, long scale=5);
For some filters, like Here are some samples of the described filtering methods (IE only: place mouse pointer above each image to see the applied filtering):
Drawing the BitmapThe following list of methods make the core of the void Draw(HDC hDC);
void Draw(HDC hDC, long dstX, long dstY);
void Draw(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY);
void Draw(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, long alpha);
void Draw(long dstX, long dstY, long dstWidth, long dstHeight, CBitmapEx& bitmapEx,
long srcX, long srcY, long srcWidth, long srcHeight);
void Draw(long dstX, long dstY, long dstWidth, long dstHeight, CBitmapEx& bitmapEx,
long srcX, long srcY, long srcWidth, long srcHeight, long alpha);
void Draw(_QUAD dstQuad, CBitmapEx& bitmapEx);
void Draw(_QUAD dstQuad, CBitmapEx& bitmapEx, long alpha);
void Draw(_QUAD dstQuad, CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth,
long srcHeight);
void Draw(_QUAD dstQuad, CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth,
long srcHeight, long alpha);
void DrawTransparent(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, _PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, long alpha, _PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight,
CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight,
_PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(long dstX, long dstY, long dstWidth, long dstHeight,
CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight,
long alpha, _PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(_QUAD dstQuad, CBitmapEx& bitmapEx,
_PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(_QUAD dstQuad, CBitmapEx& bitmapEx, long alpha,
_PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(_QUAD dstQuad, CBitmapEx& bitmapEx, long srcX, long srcY,
long srcWidth, long srcHeight, _PIXEL transparentColor=_RGB(0,0,0));
void DrawTransparent(_QUAD dstQuad, CBitmapEx& bitmapEx, long srcX, long srcY,
long srcWidth, long srcHeight, long alpha, _PIXEL transparentColor=_RGB(0,0,0));
void DrawBlended(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, long startAlpha, long endAlpha, DWORD mode=GM_NONE);
void DrawBlended(long dstX, long dstY, long dstWidth, long dstHeight,
CBitmapEx& bitmapEx, long srcX, long srcY, long srcWidth, long srcHeight,
long startAlpha, long endAlpha, DWORD mode=GM_NONE);
void DrawMasked(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, _PIXEL transparentColor=_RGB(255,255,255));
void DrawAlpha(long dstX, long dstY, long width, long height, CBitmapEx& bitmapEx,
long srcX, long srcY, long alpha, _PIXEL alphaColor=_RGB(0,0,0));
You can see a number of different bitmap drawing methods. The one that has the source and destination size as an input arguments will perform the bitmap drawing with scaling. The final quality and speed will depend on the interpolation method you have selected. In most cases, the bilinear interpolation is a good choice between the speed and the quality. This is similar to the Besides the general drawing methods, there are some special ones. Using the Another group of available bitmap drawing methods is the Finally, the last group is the All the bitmap drawing methods described offer an opacity parameter (alpha) that can be applied during the drawing operation. This is similar to using the By combining the different bitmap drawing methods, some really cool looking effects can be done. To output the bitmap on the screen (or any other device context) use the first two methods, with the Here are some samples of the described drawing methods (IE only: place mouse pointer above each image to see the applied drawing): ![]()
Changing Colors in the BitmapThis is a special method defined in the
The following code snippet is showing how is this done: CBitmapEx bitmap;
bitmap.Load(_T("Original3.bmp"));
bitmap.ReplaceColor(345, 275, _RGB(255,0,0), 10, 150, FALSE); // Sea rock
bitmap.ReplaceColor(105, 305, _RGB(255,255,0), 10, 90, FALSE); // Bottom of the sea
bitmap.Save(_T("Original3_r.bmp"));
This processing could take some time, so please don't expect the final result at the moment. Also, to get the best output bitmap it could request some experimenting with different options. Here is the definition on the void ReplaceColor(long x, long y, _PIXEL newColor, long alpha=20, long error=100,
BOOL bImage=TRUE);
Actually, you take the pixel from the location x and y and change its color with newColor. Also, you specify the transparency level of the new color that is to be applied alpha, as also the 'strength', that is the error value. The last parameter bImage is applying the re-coloring of the whole image or just the region which is defined by the 'strength'. You have to experiment to see how this method is working on different images. This could be useful is you want to change the background color of the image, or to re-color the grayscale images. Creating a Drop Shadow EffectThis is a very popular effect and can be achieved using the
The following code snippet is showing how is this done: CBitmapEx bitmap1, bitmap2, bitmap3;
bitmap1.Load(_T("Original4.bmp"));
bitmap2.Load(_T("Original5.bmp"));
bitmap3.Create(bitmap2.GetWidth(), bitmap2.GetHeight());
bitmap3.DrawMasked(0, 0, bitmap2.GetWidth(), bitmap2.GetHeight(), bitmap2, 0, 0,
bitmap2.GetPixel(0, 0));
bitmap3.Blur();
bitmap3.Blur();
bitmap3.Blur();
bitmap1.DrawAlpha(4, 4, bitmap3.GetWidth(), bitmap3.GetHeight(), bitmap3, 0, 0, 25,
_RGB(0,0,0));
bitmap1.DrawTransparent(0, 0, bitmap2.GetWidth(), bitmap2.GetHeight(), bitmap2, 0, 0,
50, bitmap2.GetPixel(0, 0));
bitmap1.Save(_T("Original4_s.bmp"));
This processing is quite quick so you would not have to wait a long time for the final results. The bottleneck of this process is the number of Creating a Fire EffectThe CBitmapEx bitmap;
bitmap.Create(300, 300);
bitmap.Clear();
bitmap.CreateFireEffect();
// Call the following method for some time (ie. a few seconds)
bitmap.UpdateFireEffect();
See the results below:
Here is the definition of the methods used: void CreateFireEffect();
void UpdateFireEffect(BOOL bLarge=TRUE, long iteration=5, long height=16);
You control the fire (speed and size), by changing the params in the Creating a Water EffectThe CBitmapEx bitmap;
bitmap.Load(_T("Undersea.bmp"));
bitmap.CreateWaterEffect();
bitmap.MakeWaterBlob(100, 100, 20, -500);
bitmap.MakeWaterBlob(150, 150, 20, 500);
bitmap.MakeWaterBlob(200, 200, 20, -500);
// Call the following method for some time (ie. a few seconds)
bitmap.UpdateWaterEffect();
See the results below:
Here is the definition of the methods used: void CreateWaterEffect();
void UpdateWaterEffect(long iteration=5);
void MakeWaterBlob(long x, long y, long size, long height);
You control the water (drops, speed, size), by changing the params in the Bitmap from RGB to HSV and BackHere is the list of methods that can be useful when converting bitmap from RGB color-space to HSV and vice-versa: _PIXEL _RGB2HSV(_PIXEL rgbPixel);
_PIXEL _HSV2RGB(_PIXEL hsvPixel);
void ConvertToHSV();
void ConvertToRGB();
_COLOR_MODE GetColorMode() {return m_ColorMode;}
This color transformations were very useful when implementing the Bitmap Information MethodsVarious bitmap information methods are available, see the list below: LPBITMAPFILEHEADER GetFileInfo() {return &m_bfh;}
LPBITMAPINFOHEADER GetInfo() {return &m_bih;}
long GetWidth() {return m_bih.biWidth;}
long GetHeight() {return m_bih.biHeight;}
long GetPitch() {return m_iPitch;}
long GetBpp() {return m_iBpp;}
long GetPaletteEntries() {return m_iPaletteEntries;}
LPRGBQUAD GetPalette() {return m_lpPalette;}
DWORD GetSize() {return m_dwSize;}
LPBYTE GetData() {return m_lpData;}
void SetResampleMode(RESAMPLE_MODE mode=RM_NEARESTNEIGHBOUR) {m_ResampleMode = mode;}
RESAMPLE_MODE GetResampleMode() {return m_ResampleMode;}
BOOL IsValid() {return (m_lpData != NULL);}
Direct Pixel Access MethodsThese important methods are also provided, look below: _PIXEL GetPixel(long x, long y);
void SetPixel(long x, long y, _PIXEL pixel);
These methods are, however, slower than a direct memory access. You can get the bitmap memory buffer using the Notice on Using the CBitmapEx ClassUsing all these methods you should be able to do any type of drawing and trasformation you need. Well, almost any type. There are surely many more filters to add, and also many more transformations to apply. Also, the comments of the readers were very useful while updating the original source code. New methods, like loading/saving from/to memory stream have been added, as well as another method for drawing on the custom device context (DC) using the insertion point. Many of the original methods for drawing are now written in the 'inline assembler' to obtain the speed increase. The original source code is left commented for the better understanding. All optimizations considering the ASM code (since I am not an expert on this) are welcome. About the Demo ProjectThere is a special class, written just for the demo project, called Points of InterestWorking on this class I have found the perfect way to speed-up any graphical operation many times. It is done using the fixed point arithmetic. It is applied everywhere in the | ||||||||||||||||||||