Introduction
This article is an adaptation of Christian Graus article on the same topic which was in C#. I was keen to
do the same in C and hence this article. Though simple I had lot of trouble porting the code from C# to C.
I want to take this opportunity to thank Christian for his help in making this program work.
Initializing GDI+
Take the November 2001 platform SDK CD and straight away install the whole thing.
Make sure to have gdiplus.dll in your application directory.
Also go to tools/options/directories in Visual Studio to point to the GDI+ lib and header files.
Important: :They should be at the top of the include list to avoid conflicts.
Includes
- Create a simple Win32 application - select empty project
- Add a new file Main.cpp
- Include the following:
- ws2_32.lib in the project/settings/link
- Add this code to your cpp file:
#define UNICODE
#include <windows.h>
#include <gdiplus.h>
#include <math.h>
#include <stdio.h>
using namespace Gdiplus;
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
- Your
WinMain
should look like this
INT WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR, INT iCmdShow)
{
HWND hWnd;
MSG msg;
WNDCLASS wndClass;
GdiplusStartupInput gdiplusStartupInput;
ULONG_PTR gdiplusToken;
GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
wndClass.style = CS_HREDRAW | CS_VREDRAW;
wndClass.lpfnWndProc = WndProc;
wndClass.cbClsExtra = 0;
wndClass.cbWndExtra = 0;
wndClass.hInstance = hInstance;
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = TEXT("Edge Detection");
RegisterClass(&wndClass);
hWnd = CreateWindow(
TEXT("Edge Detection"), TEXT("Edge Detection"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, iCmdShow);
UpdateWindow(hWnd);
while(GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
GdiplusShutdown(gdiplusToken);
return msg.wParam;
}
- Your Window procedure should look like this:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message,
WPARAM wParam, LPARAM lParam)
{
HDC hdc;
PAINTSTRUCT ps;
switch(message)
{
case WM_CREATE:
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
OnPaint(hdc);
EndPaint(hWnd, &ps);
return 0;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
}
- Your
OnPaint()
looks like this:
VOID OnPaint(HDC hdc)
{
Graphics graphics(hdc);
Bitmap b(L"Calvin.jpg");
Bitmap* b2;
INT iWidth = b.GetWidth();
INT iHeight = b.GetHeight();
Rect rect(0,0,iWidth,iHeight);
b2 = b.Clone(rect,PixelFormat24bppRGB);
BitmapData bmData;
BitmapData bmData2;
b.LockBits(&rect,ImageLockModeRead | ImageLockModeWrite,
PixelFormat24bppRGB,&bmData);
b2->LockBits(&rect,ImageLockModeRead |ImageLockModeWrite,
PixelFormat24bppRGB,&bmData2);
int stride = bmData.Stride;
unsigned char * p = (unsigned char *)bmData.Scan0;
unsigned char * p2 = (unsigned char *)bmData2.Scan0;
int nOffset = stride - iWidth*3;
int nWidth = iWidth * 3;
int nPixel = 0, nPixelMax = 0;
p += stride;
p2 += stride;
int nThreshold = 0;
for(int y=1;y < (iHeight-1);++y)
{
p += 3;
p2 += 3;
for(int x=3; x < (nWidth-3); ++x )
{
nPixelMax = abs((p2 - stride + 3)[0] - (p2+stride-3)[0]);
nPixel = abs((p2 + stride + 3)[0] - (p2 - stride - 3)[0]);
if (nPixel>nPixelMax)
nPixelMax = nPixel;
nPixel = abs((p2 - stride)[0] - (p2 + stride)[0]);
if (nPixel>nPixelMax)
nPixelMax = nPixel;
nPixel = abs((p2+3)[0] - (p2 - 3)[0]);
if (nPixel>nPixelMax)
nPixelMax = nPixel;
if (nPixelMax < nThreshold)
nPixelMax = 0;
p[0] = (byte) nPixelMax;
++ p;
++ p2;
}
p += 3 + nOffset;
p2 += 3 + nOffset;
}
b.UnlockBits(&bmData);
b2->UnlockBits(&bmData2);
graphics.DrawImage(b2,0,0,iWidth,iHeight);
graphics.DrawImage(&b, iWidth+10, 0, iWidth, iHeight);
}
That's It
Write to me for any problems/explanation. I will be glad to respond.