From 23a4423c025c42fc5131e090afe0df11112443df Mon Sep 17 00:00:00 2001 From: Mike Wey Date: Fri, 30 Dec 2011 18:39:25 +0100 Subject: Add the windows display functionality. --- dmagick/internal/Windows.d | 207 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 207 insertions(+) create mode 100644 dmagick/internal/Windows.d (limited to 'dmagick/internal') diff --git a/dmagick/internal/Windows.d b/dmagick/internal/Windows.d new file mode 100644 index 0000000..1358253 --- /dev/null +++ b/dmagick/internal/Windows.d @@ -0,0 +1,207 @@ +/** + * Copyright: Mike Wey 2011 + * License: zlib (See accompanying LICENSE file) + * Authors: Mike Wey + */ + +module dmagick.internal.Windows; + +import core.sys.windows.windows; + +import dmagick.Image; +import dmagick.Exception; +import dmagick.Geometry; + +Window[HWND] windows; + +class Window +{ + Image image; + size_t height; + size_t width; + + WNDCLASS wndclass; + HINSTANCE hInstance; + HWND hwnd; + MSG msg; + + this(Image image) + { + this.image = image; + + height = image.rows; + width = image.columns; + + hInstance = cast(HINSTANCE) GetModuleHandleA(null); + + wndclass.style = CS_HREDRAW | CS_VREDRAW; + wndclass.lpfnWndProc = &WndProc; + wndclass.cbClsExtra = 0; + wndclass.cbWndExtra = 0; + wndclass.hInstance = hInstance; + wndclass.hIcon = LoadIconA(null, IDI_APPLICATION); + wndclass.hCursor = LoadCursorA(null, IDC_ARROW); + wndclass.hbrBackground = null; + wndclass.lpszMenuName = "DMagick"; + wndclass.lpszClassName = "DMagick"; + + if (!RegisterClassA(&wndclass)) + throw new DMagickException("This program requires Windows NT!"); + + RECT rect = RECT(0,0, width,height); + AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, false); + + hwnd = CreateWindowA("DMagick", "DMagick", WS_OVERLAPPEDWINDOW, + CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, + null, null, hInstance, null); + + windows[hwnd] = this; + } + + void display() + { + ShowWindow(hwnd, SW_SHOWNORMAL); + UpdateWindow(hwnd); + + while (GetMessageA(&msg, null, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessageA(&msg); + } + } + + extern(Windows) static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) + { + static int cxClient, cyClient, cxSource, cySource; + int x, y; + HDC hdc; + PAINTSTRUCT ps; + + static HDC hdcMem; + static HBITMAP hbmMem; + static HANDLE hOld; + RECT rect; + + switch (message) + { + case WM_SIZE: + cxClient = LOWORD(lParam); + cyClient = HIWORD(lParam); + return 0; + + case WM_ERASEBKGND: // don't redraw bg + return 1; + + case WM_PAINT: + { + // Get DC for window + hdc = BeginPaint(hwnd, &ps); + + // Create an off-screen DC for double-buffering + hdcMem = CreateCompatibleDC(hdc); + hbmMem = CreateCompatibleBitmap(hdc, cxClient, cyClient); + hOld = SelectObject(hdcMem, hbmMem); + + // Draw into hdcMem + GetClientRect(hwnd, &rect); + FillRect(hdcMem, &rect, GetStockObject(BLACK_BRUSH)); + + windows[hwnd].DrawAlphaBlend(hwnd, hdcMem); + + // Transfer the off-screen DC to the screen + BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); + + // Free-up the off-screen DC + SelectObject(hdcMem, hOld); + DeleteObject(hbmMem); + DeleteDC (hdcMem); + + EndPaint(hwnd, &ps); + return 0; + } + + case WM_DESTROY: + windows[hwnd] = null; + PostQuitMessage(0); + return 0; + + default: + } + + return DefWindowProcA(hwnd, message, wParam, lParam); + } + + void DrawAlphaBlend(HWND hWnd, HDC hdcwnd) + { + HDC hdc; // handle of the DC we will create + HBITMAP hbitmap; // bitmap handle + BITMAPINFO bmi; // bitmap header + VOID* pvBits; // pointer to DIB section + ULONG ulWindowWidth, ulWindowHeight; // window width/height + RECT rt; // used for getting window dimensions + + // get window dimensions + GetClientRect(hWnd, &rt); + + // calculate window width/height + ulWindowWidth = rt.right - rt.left; + ulWindowHeight = rt.bottom - rt.top; + + // make sure we have at least some window size + if (ulWindowWidth < 1 || ulWindowHeight < 1) + return; + + // create a DC for our bitmap -- the source DC for GdiAlphaBlend + hdc = CreateCompatibleDC(hdcwnd); + + // setup bitmap info + bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // must be inverted so Y axis is at top + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; // four 8-bit components + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = width * height * 4; + + // create our DIB section and select the bitmap into the dc + hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, null, 0x0); + SelectObject(hdc, hbitmap); + + auto area = Geometry(width, height, 0, 0); + enum channels = "BGRA"; // win32 uses BGR(A) + byte[] arr = (cast(byte*)pvBits)[0 .. (area.width * area.height) * channels.length]; + image.exportPixels(area, arr, channels); + + //TODO: Rezize image. + BitBlt(hdcwnd, 0, 0, width, height, hdc, 0, 0, SRCCOPY); + + DeleteObject(hbitmap); + DeleteDC(hdc); + } +} + +pragma(lib, "gdi32.lib"); + +const AC_SRC_OVER = 0x00; +const AC_SRC_ALPHA = 0x01; +const GWLP_USERDATA = -21; + +enum DWORD BI_RGB = 0; +enum UINT DIB_RGB_COLORS = 0; + +struct BLENDFUNCTION +{ + BYTE BlendOp; + BYTE BlendFlags; + BYTE SourceConstantAlpha; + BYTE AlphaFormat; +} + +struct AlphaBlendType +{ + static normal = BLENDFUNCTION(AC_SRC_OVER, 0, 255, AC_SRC_ALPHA); +} + +extern(Windows) BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); +extern(Windows) HBITMAP CreateCompatibleBitmap(HDC, int, int); +extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); \ No newline at end of file -- cgit v1.2.3 From da8674adbf4701ff808bbce0b0a5ae420115726b Mon Sep 17 00:00:00 2001 From: Mike Wey Date: Fri, 30 Dec 2011 21:35:20 +0100 Subject: Some Cleanup. --- dmagick/internal/Windows.d | 84 +++++++++++----------------------------------- examples/draw.d | 2 +- 2 files changed, 20 insertions(+), 66 deletions(-) (limited to 'dmagick/internal') diff --git a/dmagick/internal/Windows.d b/dmagick/internal/Windows.d index 1358253..50dee7b 100644 --- a/dmagick/internal/Windows.d +++ b/dmagick/internal/Windows.d @@ -12,28 +12,28 @@ import dmagick.Image; import dmagick.Exception; import dmagick.Geometry; -Window[HWND] windows; - class Window { Image image; size_t height; size_t width; - + WNDCLASS wndclass; HINSTANCE hInstance; HWND hwnd; MSG msg; + static Window[HWND] windows; + this(Image image) { this.image = image; - + height = image.rows; - width = image.columns; - + width = image.columns; + hInstance = cast(HINSTANCE) GetModuleHandleA(null); - + wndclass.style = CS_HREDRAW | CS_VREDRAW; wndclass.lpfnWndProc = &WndProc; wndclass.cbClsExtra = 0; @@ -49,15 +49,15 @@ class Window throw new DMagickException("This program requires Windows NT!"); RECT rect = RECT(0,0, width,height); - AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, false); - - hwnd = CreateWindowA("DMagick", "DMagick", WS_OVERLAPPEDWINDOW, + AdjustWindowRect(&rect, WS_CAPTION | WS_SYSMENU, false); + + hwnd = CreateWindowA("DMagick", "DMagick", WS_CAPTION | WS_SYSMENU, CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, null, null, hInstance, null); windows[hwnd] = this; } - + void display() { ShowWindow(hwnd, SW_SHOWNORMAL); @@ -69,57 +69,26 @@ class Window DispatchMessageA(&msg); } } - + extern(Windows) static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - static int cxClient, cyClient, cxSource, cySource; - int x, y; HDC hdc; PAINTSTRUCT ps; - static HDC hdcMem; - static HBITMAP hbmMem; - static HANDLE hOld; - RECT rect; - switch (message) { - case WM_SIZE: - cxClient = LOWORD(lParam); - cyClient = HIWORD(lParam); - return 0; - case WM_ERASEBKGND: // don't redraw bg return 1; - + case WM_PAINT: - { // Get DC for window hdc = BeginPaint(hwnd, &ps); - // Create an off-screen DC for double-buffering - hdcMem = CreateCompatibleDC(hdc); - hbmMem = CreateCompatibleBitmap(hdc, cxClient, cyClient); - hOld = SelectObject(hdcMem, hbmMem); - - // Draw into hdcMem - GetClientRect(hwnd, &rect); - FillRect(hdcMem, &rect, GetStockObject(BLACK_BRUSH)); - - windows[hwnd].DrawAlphaBlend(hwnd, hdcMem); - - // Transfer the off-screen DC to the screen - BitBlt(hdc, 0, 0, cxClient, cyClient, hdcMem, 0, 0, SRCCOPY); - - // Free-up the off-screen DC - SelectObject(hdcMem, hOld); - DeleteObject(hbmMem); - DeleteDC (hdcMem); + windows[hwnd].DrawAlphaBlend(hwnd, hdc); EndPaint(hwnd, &ps); return 0; - } - + case WM_DESTROY: windows[hwnd] = null; PostQuitMessage(0); @@ -130,7 +99,7 @@ class Window return DefWindowProcA(hwnd, message, wParam, lParam); } - + void DrawAlphaBlend(HWND hWnd, HDC hdcwnd) { HDC hdc; // handle of the DC we will create @@ -139,7 +108,7 @@ class Window VOID* pvBits; // pointer to DIB section ULONG ulWindowWidth, ulWindowHeight; // window width/height RECT rt; // used for getting window dimensions - + // get window dimensions GetClientRect(hWnd, &rt); @@ -153,7 +122,7 @@ class Window // create a DC for our bitmap -- the source DC for GdiAlphaBlend hdc = CreateCompatibleDC(hdcwnd); - + // setup bitmap info bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; bmi.bmiHeader.biWidth = width; @@ -167,12 +136,11 @@ class Window hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, null, 0x0); SelectObject(hdc, hbitmap); - auto area = Geometry(width, height, 0, 0); enum channels = "BGRA"; // win32 uses BGR(A) + Geometry area = Geometry(width, height); byte[] arr = (cast(byte*)pvBits)[0 .. (area.width * area.height) * channels.length]; image.exportPixels(area, arr, channels); - //TODO: Rezize image. BitBlt(hdcwnd, 0, 0, width, height, hdc, 0, 0, SRCCOPY); DeleteObject(hbitmap); @@ -184,24 +152,10 @@ pragma(lib, "gdi32.lib"); const AC_SRC_OVER = 0x00; const AC_SRC_ALPHA = 0x01; -const GWLP_USERDATA = -21; enum DWORD BI_RGB = 0; enum UINT DIB_RGB_COLORS = 0; -struct BLENDFUNCTION -{ - BYTE BlendOp; - BYTE BlendFlags; - BYTE SourceConstantAlpha; - BYTE AlphaFormat; -} - -struct AlphaBlendType -{ - static normal = BLENDFUNCTION(AC_SRC_OVER, 0, 255, AC_SRC_ALPHA); -} - extern(Windows) BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); extern(Windows) HBITMAP CreateCompatibleBitmap(HDC, int, int); extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); \ No newline at end of file diff --git a/examples/draw.d b/examples/draw.d index 0aced61..6839dba 100644 --- a/examples/draw.d +++ b/examples/draw.d @@ -64,7 +64,7 @@ void main() dc.fill(cylinderTop); dc.roundRectangle(progressXmax - (2 * wc), progressYmin, progressXmax, progressYmax, wc, hc); - dc.font("Arial"); + dc.fontFamily("Sans"); dc.fontSize(fontsize); dc.stroke(textShadow); dc.fill(textColor); -- cgit v1.2.3 From f73f5ad46541647cf80853f4acf146bac492207d Mon Sep 17 00:00:00 2001 From: Mike Wey Date: Sat, 31 Dec 2011 18:54:32 +0100 Subject: Add support for animations. --- dmagick/Array.d | 18 ++++++++++--- dmagick/internal/Windows.d | 63 +++++++++++++++++++++++++++++++++++----------- 2 files changed, 63 insertions(+), 18 deletions(-) (limited to 'dmagick/internal') diff --git a/dmagick/Array.d b/dmagick/Array.d index 62f17fa..339de5c 100644 --- a/dmagick/Array.d +++ b/dmagick/Array.d @@ -31,6 +31,8 @@ import dmagick.c.montage; import dmagick.c.statistic; import dmagick.c.quantize; +version(Windows) import dmagick.internal.Windows; + /// See_Also: $(CXREF layer, _ImageLayerMethod) public alias dmagick.c.layer.ImageLayerMethod ImageLayerMethod; @@ -165,12 +167,20 @@ void compositeLayers( */ void display(Image[] images) { - linkImages(images); - scope(exit) unlinkImages(images); + version(Windows) + { + Window win = new Window(images); + win.display(); + } + else + { + linkImages(images); + scope(exit) unlinkImages(images); - DisplayImages(images[0].options.imageInfo, images[0].imageRef); + DisplayImages(images[0].options.imageInfo, images[0].imageRef); - DMagickException.throwException(&(images[0].imageRef.exception)); + DMagickException.throwException(&(images[0].imageRef.exception)); + } } /** diff --git a/dmagick/internal/Windows.d b/dmagick/internal/Windows.d index 50dee7b..99a2d9e 100644 --- a/dmagick/internal/Windows.d +++ b/dmagick/internal/Windows.d @@ -15,6 +15,8 @@ import dmagick.Geometry; class Window { Image image; + Image[] imageList; + size_t index; size_t height; size_t width; @@ -42,7 +44,7 @@ class Window wndclass.hIcon = LoadIconA(null, IDI_APPLICATION); wndclass.hCursor = LoadCursorA(null, IDC_ARROW); wndclass.hbrBackground = null; - wndclass.lpszMenuName = "DMagick"; + wndclass.lpszMenuName = null; wndclass.lpszClassName = "DMagick"; if (!RegisterClassA(&wndclass)) @@ -57,12 +59,26 @@ class Window windows[hwnd] = this; } + + this(Image[] images) + { + this(images[0]); + + imageList = images; + index = 0; + } void display() { ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); - + + if ( imageList !is null ) + { + UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); + SetTimer(hwnd, 0, delay, null); + } + while (GetMessageA(&msg, null, 0, 0)) { TranslateMessage(&msg); @@ -72,21 +88,17 @@ class Window extern(Windows) static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { - HDC hdc; - PAINTSTRUCT ps; - switch (message) { case WM_ERASEBKGND: // don't redraw bg return 1; case WM_PAINT: - // Get DC for window - hdc = BeginPaint(hwnd, &ps); - - windows[hwnd].DrawAlphaBlend(hwnd, hdc); + windows[hwnd].draw(); + return 0; - EndPaint(hwnd, &ps); + case WM_TIMER: + windows[hwnd].nextFrame(); return 0; case WM_DESTROY: @@ -100,17 +112,19 @@ class Window return DefWindowProcA(hwnd, message, wParam, lParam); } - void DrawAlphaBlend(HWND hWnd, HDC hdcwnd) + void draw() { HDC hdc; // handle of the DC we will create + HDC hdcwnd; // DC for the window HBITMAP hbitmap; // bitmap handle BITMAPINFO bmi; // bitmap header + PAINTSTRUCT ps; VOID* pvBits; // pointer to DIB section ULONG ulWindowWidth, ulWindowHeight; // window width/height RECT rt; // used for getting window dimensions // get window dimensions - GetClientRect(hWnd, &rt); + GetClientRect(hwnd, &rt); // calculate window width/height ulWindowWidth = rt.right - rt.left; @@ -119,8 +133,11 @@ class Window // make sure we have at least some window size if (ulWindowWidth < 1 || ulWindowHeight < 1) return; + + // Get DC for window + hdcwnd = BeginPaint(hwnd, &ps); - // create a DC for our bitmap -- the source DC for GdiAlphaBlend + // create a DC for our bitmap -- the source DC for BitBlt hdc = CreateCompatibleDC(hdcwnd); // setup bitmap info @@ -145,6 +162,23 @@ class Window DeleteObject(hbitmap); DeleteDC(hdc); + EndPaint(hwnd, &ps); + } + + /** + * Setup the next frame, and invalidate the window so its repainted. + */ + void nextFrame() + { + if (++index == imageList.length) + index = 0; + + image = imageList[index]; + + UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); + SetTimer(hwnd, 0, delay, null); + + InvalidateRect(hwnd,null,false); } } @@ -158,4 +192,5 @@ enum UINT DIB_RGB_COLORS = 0; extern(Windows) BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); extern(Windows) HBITMAP CreateCompatibleBitmap(HDC, int, int); -extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); \ No newline at end of file +extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); +extern(Windows) UINT_PTR SetTimer(HWND, UINT_PTR, UINT, TIMERPROC); \ No newline at end of file -- cgit v1.2.3 From c17126a686f8191b19ab8ed6be1b1f4117df3b30 Mon Sep 17 00:00:00 2001 From: Mike Wey Date: Mon, 2 Jan 2012 16:53:51 +0100 Subject: Don't initialize the bitmap info every time the image is drawn. --- dmagick/internal/Windows.d | 64 ++++++++++++++++++++++++++++++---------------- 1 file changed, 42 insertions(+), 22 deletions(-) (limited to 'dmagick/internal') diff --git a/dmagick/internal/Windows.d b/dmagick/internal/Windows.d index 99a2d9e..3d7628e 100644 --- a/dmagick/internal/Windows.d +++ b/dmagick/internal/Windows.d @@ -20,13 +20,17 @@ class Window size_t height; size_t width; - WNDCLASS wndclass; - HINSTANCE hInstance; - HWND hwnd; - MSG msg; + WNDCLASS wndclass; + HINSTANCE hInstance; + BITMAPINFO bmi; // bitmap header + HWND hwnd; + MSG msg; static Window[HWND] windows; + /** + * Create an window foe displaying an image. + */ this(Image image) { this.image = image; @@ -48,7 +52,7 @@ class Window wndclass.lpszClassName = "DMagick"; if (!RegisterClassA(&wndclass)) - throw new DMagickException("This program requires Windows NT!"); + throw new DMagickException("Displaying images requires Windows NT!"); RECT rect = RECT(0,0, width,height); AdjustWindowRect(&rect, WS_CAPTION | WS_SYSMENU, false); @@ -57,28 +61,48 @@ class Window CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, null, null, hInstance, null); + // setup bitmap info + bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; + bmi.bmiHeader.biWidth = width; + bmi.bmiHeader.biHeight = -height; // must be inverted so Y axis is at top + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biBitCount = 32; // four 8-bit components + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biSizeImage = width * height * 4; + windows[hwnd] = this; } - + + /** + * Create an window foe displaying an animation + * or a collection of images. + */ this(Image[] images) { this(images[0]); - + imageList = images; index = 0; } + /** + * Open the window and display the image. + */ void display() { ShowWindow(hwnd, SW_SHOWNORMAL); UpdateWindow(hwnd); - + if ( imageList !is null ) { UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); + + if ( delay == 0 ) + delay = 1000; + SetTimer(hwnd, 0, delay, null); } - + while (GetMessageA(&msg, null, 0, 0)) { TranslateMessage(&msg); @@ -112,12 +136,14 @@ class Window return DefWindowProcA(hwnd, message, wParam, lParam); } + /** + * Draw the image on the window. + */ void draw() { HDC hdc; // handle of the DC we will create HDC hdcwnd; // DC for the window HBITMAP hbitmap; // bitmap handle - BITMAPINFO bmi; // bitmap header PAINTSTRUCT ps; VOID* pvBits; // pointer to DIB section ULONG ulWindowWidth, ulWindowHeight; // window width/height @@ -133,22 +159,13 @@ class Window // make sure we have at least some window size if (ulWindowWidth < 1 || ulWindowHeight < 1) return; - + // Get DC for window hdcwnd = BeginPaint(hwnd, &ps); // create a DC for our bitmap -- the source DC for BitBlt hdc = CreateCompatibleDC(hdcwnd); - // setup bitmap info - bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; - bmi.bmiHeader.biWidth = width; - bmi.bmiHeader.biHeight = -height; // must be inverted so Y axis is at top - bmi.bmiHeader.biPlanes = 1; - bmi.bmiHeader.biBitCount = 32; // four 8-bit components - bmi.bmiHeader.biCompression = BI_RGB; - bmi.bmiHeader.biSizeImage = width * height * 4; - // create our DIB section and select the bitmap into the dc hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, null, 0x0); SelectObject(hdc, hbitmap); @@ -172,12 +189,15 @@ class Window { if (++index == imageList.length) index = 0; - + image = imageList[index]; UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); - SetTimer(hwnd, 0, delay, null); + if ( delay == 0 ) + delay = 1000; + + SetTimer(hwnd, 0, delay, null); InvalidateRect(hwnd,null,false); } } -- cgit v1.2.3