Allegro.cc - Online Community

Allegro.cc Forums » Programming Questions » a5 hbitmap to allegro_bitmap

This thread is locked; no one can reply to it. rss feed Print
a5 hbitmap to allegro_bitmap
komons
Member #11,083
June 2009

Hi How to convert from HBITMAP to video ALLEGRO_BITMAP?

I did it by this way, but it's very slow, about few minutes:

#SelectExpand
1HDC _dc = GetWindowDC(GetDesktopWindow()); 2RECT rect; 3GetWindowRect(GetDesktopWindow(),&rect); 4int w = rect.right, h = rect.bottom; //1440x900 5 6bg = al_create_bitmap( w, h ); 7al_lock_bitmap( bg, al_get_bitmap_format(bg), ALLEGRO_LOCK_WRITEONLY ); 8 9for ( unsigned j=0; j<h; j++ ) 10for ( unsigned i=0; i<w; i++ ) 11{ 12 COLORREF clr = GetPixel( _dc, i, j ); 13 al_put_pixel( i,j,al_map_rgb( int(GetRValue(clr)), int(GetGValue(clr)), int(GetBValue(clr)) ) ); 14} 15 16al_unlock_bitmap( bg );

Desmond Taylor
Member #11,943
May 2010
avatar

Use al_set_new_bitmap_flags( ALLEGRO_MEMORY_BITMAP ) and then clone it to a VIDEO bitmap.

Thomas Fjellstrom
Member #476
June 2000
avatar

Use al_set_new_bitmap_flags( ALLEGRO_MEMORY_BITMAP ) and then clone it to a VIDEO bitmap.

He's locking the bitmap, which basically temporarily turns it into a memory bitmap. It really should not take minutes to copy from the HDC to the ALLEGRO_BITMAP.

--
Thomas Fjellstrom - [website] - [email] - [Allegro Wiki] - [Allegro TODO]
"If you can't think of a better solution, don't try to make a better solution." -- weapon_S
"The less evidence we have for what we believe is certain, the more violently we defend beliefs against those who don't agree" -- https://twitter.com/neiltyson/status/592870205409353730

Edgar Reynaldo
Member #8,592
May 2007
avatar

komons
Member #11,083
June 2009

It's still very slow for 1440x900 :<

#SelectExpand
1HDC _dc = GetWindowDC(GetDesktopWindow()); 2RECT rect; 3GetWindowRect(GetDesktopWindow(),&rect); 4int w = rect.right, h = rect.bottom; 5 6ALLEGRO_BITMAP* target = al_get_target_bitmap(); 7 8al_set_new_bitmap_flags( ALLEGRO_MEMORY_BITMAP ); 9bg = al_create_bitmap( w, h ); 10 11al_set_target_bitmap( bg ); 12 13al_lock_bitmap( bg, al_get_bitmap_format(bg), ALLEGRO_LOCK_WRITEONLY ); 14for ( unsigned j=0; j<h; j++ ) 15for ( unsigned i=0; i<w; i++ ) 16{ 17 COLORREF clr = GetPixel( _dc, i, j ); 18 al_put_pixel( i,j,al_map_rgb( int(GetRValue(clr)), int(GetGValue(clr)), int(GetBValue(clr)) ) ); 19} 20al_unlock_bitmap( bg ); 21al_set_new_bitmap_flags( 0 ); 22al_set_target_bitmap( target );

Trent Gamblin
Member #261
April 2000
avatar

You can skip some of the overhead of al_put_pixel and al_map_rgb by locking in a simple format like RGBA_8888. You can skip the overhead of conversion to RGBA_8888 too, which will be even faster, if you create the bitmap in an easy format like that to begin with.

Edit: To be clearer, I mean you'd write the bytes from GetR etc directly to the memory buffer in the ALLEGRO_LOCKED_REGION.

Matthew Leverton
Supreme Loser
January 1999
avatar

Isn't the problem likely to be that GetPixel is slow?

Trent Gamblin
Member #261
April 2000
avatar

That's probably slow too, but I don't know winapi so I can only make Allegro suggestions.

Matthew Leverton
Supreme Loser
January 1999
avatar

Here's something I hacked together from Allegro 4 sources. It assumes going from 32-bit to 32-bit and has a bunch of unused variables (etc), but you can see if it's any better. Obviously for production quality it would need to be cleaned up a bit.

I only ran it on a VM, so I don't know how fast it is.

#SelectExpand
1#include <Windows.h> 2 3#include <allegro5/allegro.h> 4 5#define BYTES_PER_PIXEL(bpp) (((int)(bpp) + 7) / 8) 6 7/* get_bitmap_from_dib: 8 * Creates an Allegro BITMAP from a Windows device-independent bitmap (DIB). 9 */ 10static ALLEGRO_BITMAP *get_bitmap_from_dib(int bpp, int w, int h, BYTE *pixels) 11{ 12 int x, y; 13 int pitch; 14 int col; 15 int b, g, r; 16 BYTE *src; 17 ALLEGRO_BITMAP *bitmap; 18 ALLEGRO_LOCKED_REGION *lock; 19 uint8_t *dst; 20 21 pitch = w * BYTES_PER_PIXEL(bpp); 22 pitch = (pitch + 3) & ~3; /* align on dword */ 23 24 bitmap = al_create_bitmap(w, h); 25 lock = al_lock_bitmap(bitmap, ALLEGRO_PIXEL_FORMAT_ARGB_8888, ALLEGRO_LOCK_WRITEONLY); 26 27 dst = (uint8_t *) lock->data; 28 29 for (y = 0; y < h; ++y) 30 { 31 memcpy(dst, pixels + y * pitch, w * BYTES_PER_PIXEL(bpp)); 32 dst += lock->pitch; 33 } 34 35 al_unlock_bitmap(bitmap); 36 37 return bitmap; 38} 39 40/* get_dib_from_hbitmap: 41 * Creates a Windows device-independent bitmap (DIB) from a Windows BITMAP. 42 * You have to free the memory allocated by this function. 43 */ 44static BYTE *get_dib_from_hbitmap(int bpp, HBITMAP hbitmap) 45{ 46 BITMAPINFOHEADER bi; 47 BITMAPINFO *binfo; 48 HDC hdc; 49 HPALETTE hpal, holdpal; 50 int col; 51 BITMAP bm; 52 int pitch; 53 BYTE *pixels; 54 BYTE *ptr; 55 int x, y; 56 57 if (!hbitmap) 58 return NULL; 59 60 if (bpp == 15) 61 bpp = 16; 62 63 if (!GetObject(hbitmap, sizeof(bm), (LPSTR) & bm)) 64 return NULL; 65 66 pitch = bm.bmWidth * BYTES_PER_PIXEL(bpp); 67 pitch = (pitch + 3) & ~3; /* align on dword */ 68 69 pixels = (BYTE *) al_malloc(bm.bmHeight * pitch); 70 if (!pixels) 71 return NULL; 72 73 ZeroMemory(&bi, sizeof(BITMAPINFOHEADER)); 74 75 bi.biSize = sizeof(BITMAPINFOHEADER); 76 bi.biBitCount = bpp; 77 bi.biPlanes = 1; 78 bi.biWidth = bm.bmWidth; 79 bi.biHeight = -abs(bm.bmHeight); 80 bi.biClrUsed = 256; 81 bi.biCompression = BI_RGB; 82 83 binfo = (BITMAPINFO *) al_malloc(sizeof(BITMAPINFO) + sizeof(RGBQUAD) * 256); 84 binfo->bmiHeader = bi; 85 86 hdc = GetDC(NULL); 87 88 GetDIBits(hdc, hbitmap, 0, bm.bmHeight, pixels, binfo, DIB_RGB_COLORS); 89 90 ptr = pixels; 91 92 al_free(binfo); 93 94 95 ReleaseDC(NULL, hdc); 96 97 return pixels; 98} 99 100/* convert_hbitmap_to_bitmap: 101 * Converts a Windows BITMAP to an Allegro BITMAP. 102 */ 103ALLEGRO_BITMAP *convert_hbitmap_to_bitmap(HBITMAP bitmap) 104{ 105 BYTE *pixels; 106 ALLEGRO_BITMAP *bmp; 107 BITMAP bm; 108 int bpp; 109 110 if (!GetObject(bitmap, sizeof(bm), (LPSTR) & bm)) 111 return NULL; 112 113 if (bm.bmBitsPixel == 8) { 114 /* ask windows to save truecolor image, then convert to our format */ 115 bpp = 24; 116 } 117 else 118 bpp = bm.bmBitsPixel; 119 120 /* get the DIB first */ 121 pixels = get_dib_from_hbitmap(bpp, bitmap); 122 123 /* now that we have the DIB, convert it to a BITMAP */ 124 bmp = get_bitmap_from_dib(bpp, bm.bmWidth, bm.bmHeight, pixels); 125 126 al_free(pixels); 127 128 return bmp; 129} 130 131ALLEGRO_BITMAP *convert_hdc_to_bitmap(HDC dc) 132{ 133 ALLEGRO_BITMAP *bg; 134 const int w = GetDeviceCaps(dc, HORZRES); 135 const int h = GetDeviceCaps(dc, VERTRES); 136 137 HDC hmemdc = CreateCompatibleDC(dc); 138 HBITMAP hbmp = CreateCompatibleBitmap(dc, w, h); 139 HBITMAP holdbmp = (HBITMAP) SelectObject(hmemdc, hbmp); 140 141 StretchBlt(hmemdc, 0, 0, w, h, dc, 0, 0, w, h, SRCCOPY); 142 SelectObject(hmemdc, holdbmp); 143 144 bg = convert_hbitmap_to_bitmap(hbmp); 145 146 DeleteObject(hbmp); 147 DeleteDC(hmemdc); 148 149 return bg; 150} 151 152int main() 153{ 154 al_init(); 155 156 ALLEGRO_DISPLAY *display = al_create_display(800, 600); 157 if (!display) return -1; 158 159 ALLEGRO_BITMAP *bmp = convert_hdc_to_bitmap(GetWindowDC(GetDesktopWindow())); 160 161 al_draw_bitmap(bmp, 0, 0, 0); 162 al_flip_display(); 163 164 al_rest(1); 165 166 return 0; 167}

komons
Member #11,083
June 2009

It works but result is someidontknow bitmap. Black with some elements of screen.

I did it by another way. Save screen to bmp file, and load it by al_load_bitmap. Loading is little fast, but I wouldn't like do it by this way.

#SelectExpand
1void C_Tools::screen(HWND okno, char* plik) 2{ 3HDC _dc = GetWindowDC(okno); 4RECT re; 5GetWindowRect(okno,&re); 6int w = re.right, h = re.bottom; 7HDC dc = CreateCompatibleDC(0); 8HBITMAP bm = CreateCompatibleBitmap(_dc,w,h); 9SelectObject(dc,bm); 10StretchBlt(dc,0,0,w,h,_dc,0,0,w,h,SRCCOPY); 11void* f = CreateFileA(plik,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,0,0); 12void* buf = new char[w*h*3]; 13GetObject(bm,84,buf); 14HDC ddd = GetDC(0); 15HDC dc2 = CreateCompatibleDC(ddd); 16tagBITMAPINFO bi; 17bi.bmiHeader.biSize = sizeof(bi.bmiHeader); 18bi.bmiHeader.biWidth = w; 19bi.bmiHeader.biHeight = h; 20bi.bmiHeader.biPlanes = 1; 21bi.bmiHeader.biBitCount = 24; 22bi.bmiHeader.biCompression = 0; 23bi.bmiHeader.biSizeImage = 0; 24CreateDIBSection(dc,&bi,DIB_RGB_COLORS,&buf,0,0); 25GetDIBits(dc,bm,0,h,buf,&bi,DIB_RGB_COLORS); 26 27BITMAPFILEHEADER bif; 28bif.bfType = MAKEWORD('B','M'); 29bif.bfSize = w*h*3+54; 30bif.bfOffBits = 54; 31 32BITMAPINFOHEADER bii; 33bii.biSize = 40; 34bii.biWidth = w; 35bii.biHeight = h; 36bii.biPlanes = 1; 37bii.biBitCount = 24; 38bii.biCompression = 0; 39bii.biSizeImage = w*h*3; 40 41DWORD r; 42WriteFile(f,&bif,sizeof(bif),&r,NULL); 43WriteFile(f,&bii,sizeof(bii),&r,NULL); 44WriteFile(f,buf,w*h*3,&r,NULL); 45CloseHandle(f); 46}

Go to: