"Bob Powell [MVP]" <bob@_spamkiller_.bobpowell.net> wrote:
If you want to convert an arbitrary bitmap to 1bpp indexed see the GDI+ FAQ.
The GDI+ FAQ says to iterate "for y=0 to height, for x=0 to width"
which is terribly slow. This is a shame, because Windows already
contains built-in functionality to convert from arbitrary pixelformat
into 1bpp pixelformat. And it's fast -- my laptop takes just 50ms to
convert a 1024x768 bitmap into monochrome, or just 5ms to convert a
200x200 bitmap.
Here's the code for it. I've written it in C++ using native win32
calls. Hopefully someone can turn it into C#. (I had trouble turning
it into C#, because I couldn't find how to construct a Bitmap() object
from an existing HBITMAP, and I couldn't find how to BitBlt/DrawImage
onto an existing 1bpp Bitmap object.)
HBITMAP CreateMonochromeCopy(HBITMAP hbm_src)
{
// retrieve the size of the original bitmap
DIBSECTION dibs; GetObject(hbm_src,sizeof(dibs),&dibs);
int width=dibs.dsBm.bmWidth, height=dibs.dsBm.bmHeight;
//
// create a new bitmap of the same dimensions with a 1bpp monchrome
palette
typedef struct {BITMAPINFOHEADER bmiHeader; RGBQUAD bmiColors[2];}
MONOBITMAPINFO;
MONOBITMAPINFO bmi; ZeroMemory(&bmi,sizeof(bmi));
bmi.bmiHeader.biSize=sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth=width;
bmi.bmiHeader.biHeight=height;
bmi.bmiHeader.biPlanes=1;
bmi.bmiHeader.biBitCount=1;
bmi.bmiHeader.biCompression=BI_RGB;
bmi.bmiHeader.biSizeImage=((width+7)&0xFFFFFFF8)*h eight/8;
bmi.bmiHeader.biXPelsPerMeter=1000000;
bmi.bmiHeader.biYPelsPerMeter=1000000;
bmi.bmiHeader.biClrUsed=2;
bmi.bmiHeader.biClrImportant=2;
bmi.bmiColors[0].rgbRed=0; bmi.bmiColors[0].rgbGreen=0;
bmi.bmiColors[0].rgbBlue=0; bmi.bmiColors[0].rgbReserved=0;
bmi.bmiColors[1].rgbRed=255;bmi.bmiColors[1].rgbGreen=255;bmi.bmiColors[1].rgbBlue=255;bmi.bmiColors[1].rgbReserved=0;
void *bits; HBITMAP hbm_dst =
CreateDIBSection(0,(BITMAPINFO*)&bmi,DIB_RGB_COLOR S,&bits,0,0);
//
// BitBlt the original image into the new one. Windows and the
// graphics accelerator will take care of color thresholds &c.
HDC sdc = GetDC(0);
HDC hdc_src = CreateCompatibleDC(sdc);
HDC hdc_dst = CreateCompatibleDC(sdc);
SelectObject(hdc_src,hbm_src);
SelectObject(hdc_dst,hbm_dst);
BitBlt(hdc_dst,0,0,width,height,hdc_src,0,0,SRCCOP Y);
DeleteDC(hdc_src);
DeleteDC(hdc_dst);
ReleaseDC(0,sdc);
//
return hbm_dst;
}
Here's a complete program to watch it in action:
#include <windows.h>
int main()
{ HDC sdc = GetDC(0);
HBITMAP hbm = CreateCompatibleBitmap(sdc,1024,768);
HDC hdc = CreateCompatibleDC(sdc);
SelectObject(hdc,hbm);
RECT rc; rc.left=0; rc.top=0; rc.right=1024; rc.bottom=768;
FillRect(hdc,&rc,(HBRUSH)GetStockObject(WHITE_BRUS H));
SetTextColor(hdc,RGB(255,0,0));
TextOut(hdc,10,10,L"Hello World",11);
DeleteDC(hdc);
//
HBITMAP hbmi[100];
unsigned int time1=GetTickCount();
for (int i=0; i<100; i++) hbmi[i] = CreateMonochromeCopy(hbm);
unsigned int time2=GetTickCount();
unsigned int diff = time2-time1;
//
hdc = CreateCompatibleDC(sdc);
SelectObject(hdc,hbmi[0]);
BitBlt(sdc,0,0,200,200,hdc,0,0,SRCCOPY);
DeleteDC(hdc);
ReleaseDC(0,sdc);
DeleteObject(hbm);
for (int i=0; i<100; i++) DeleteObject(hbmi[i]);
Sleep(2000);
return 0;
}
--
Lucian