1 /** 2 * Copyright: Mike Wey 2011 3 * License: zlib (See accompanying LICENSE file) 4 * Authors: Mike Wey 5 */ 6 7 module dmagick.internal.Windows; 8 version(Windows): 9 import core.sys.windows.windows; 10 11 import dmagick.Image; 12 import dmagick.Exception; 13 import dmagick.Geometry; 14 15 class Window 16 { 17 Image image; 18 Image[] imageList; 19 size_t index; 20 int height; 21 int width; 22 23 WNDCLASS wndclass; 24 HINSTANCE hInstance; 25 BITMAPINFO bmi; // bitmap header 26 HWND hwnd; 27 MSG msg; 28 29 static Window[HWND] windows; 30 31 /** 32 * Create an window foe displaying an image. 33 */ 34 this(Image image) 35 { 36 this.image = image; 37 38 height = cast(int)image.rows; 39 width = cast(int)image.columns; 40 41 hInstance = cast(HINSTANCE) GetModuleHandleA(null); 42 43 wndclass.style = CS_HREDRAW | CS_VREDRAW; 44 wndclass.lpfnWndProc = &WndProc; 45 wndclass.cbClsExtra = 0; 46 wndclass.cbWndExtra = 0; 47 wndclass.hInstance = hInstance; 48 wndclass.hIcon = LoadIconA(null, IDI_APPLICATION); 49 wndclass.hCursor = LoadCursorA(null, IDC_ARROW); 50 wndclass.hbrBackground = null; 51 wndclass.lpszMenuName = null; 52 wndclass.lpszClassName = "DMagick"; 53 54 if (!RegisterClassA(&wndclass)) 55 throw new DMagickException("Displaying images requires Windows NT!"); 56 57 RECT rect = RECT(0,0, width,height); 58 AdjustWindowRect(&rect, WS_CAPTION | WS_SYSMENU, false); 59 60 hwnd = CreateWindowA("DMagick", "DMagick", WS_CAPTION | WS_SYSMENU, 61 CW_USEDEFAULT, CW_USEDEFAULT, rect.right-rect.left, rect.bottom-rect.top, 62 null, null, hInstance, null); 63 64 // setup bitmap info 65 bmi.bmiHeader.biSize = BITMAPINFOHEADER.sizeof; 66 bmi.bmiHeader.biWidth = width; 67 bmi.bmiHeader.biHeight = -height; // must be inverted so Y axis is at top 68 bmi.bmiHeader.biPlanes = 1; 69 bmi.bmiHeader.biBitCount = 32; // four 8-bit components 70 bmi.bmiHeader.biCompression = BI_RGB; 71 bmi.bmiHeader.biSizeImage = width * height * 4; 72 73 windows[hwnd] = this; 74 } 75 76 /** 77 * Create an window foe displaying an animation 78 * or a collection of images. 79 */ 80 this(Image[] images) 81 { 82 this(images[0]); 83 84 imageList = images; 85 index = 0; 86 } 87 88 /** 89 * Open the window and display the image. 90 */ 91 void display() 92 { 93 ShowWindow(hwnd, SW_SHOWNORMAL); 94 UpdateWindow(hwnd); 95 96 if ( imageList !is null ) 97 { 98 UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); 99 100 if ( delay == 0 ) 101 delay = 1000; 102 103 SetTimer(hwnd, 0, delay, null); 104 } 105 106 while (GetMessageA(&msg, null, 0, 0)) 107 { 108 TranslateMessage(&msg); 109 DispatchMessageA(&msg); 110 } 111 } 112 113 extern(Windows) nothrow static LRESULT WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) 114 { 115 try 116 { 117 switch (message) 118 { 119 case WM_ERASEBKGND: // don't redraw bg 120 return 1; 121 122 case WM_PAINT: 123 windows[hwnd].draw(); 124 return 0; 125 126 case WM_TIMER: 127 windows[hwnd].nextFrame(); 128 return 0; 129 130 case WM_DESTROY: 131 windows[hwnd] = null; 132 PostQuitMessage(0); 133 return 0; 134 135 default: 136 } 137 } 138 catch(Exception e){} 139 140 return DefWindowProcA(hwnd, message, wParam, lParam); 141 } 142 143 /** 144 * Draw the image on the window. 145 */ 146 void draw() 147 { 148 HDC hdc; // handle of the DC we will create 149 HDC hdcwnd; // DC for the window 150 HBITMAP hbitmap; // bitmap handle 151 PAINTSTRUCT ps; 152 VOID* pvBits; // pointer to DIB section 153 ULONG ulWindowWidth, ulWindowHeight; // window width/height 154 RECT rt; // used for getting window dimensions 155 156 // get window dimensions 157 GetClientRect(hwnd, &rt); 158 159 // calculate window width/height 160 ulWindowWidth = rt.right - rt.left; 161 ulWindowHeight = rt.bottom - rt.top; 162 163 // make sure we have at least some window size 164 if (ulWindowWidth < 1 || ulWindowHeight < 1) 165 return; 166 167 // Get DC for window 168 hdcwnd = BeginPaint(hwnd, &ps); 169 170 // create a DC for our bitmap -- the source DC for BitBlt 171 hdc = CreateCompatibleDC(hdcwnd); 172 173 // create our DIB section and select the bitmap into the dc 174 hbitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pvBits, null, 0x0); 175 SelectObject(hdc, hbitmap); 176 177 enum channels = "BGRA"; // win32 uses BGR(A) 178 Geometry area = Geometry(width, height); 179 byte[] arr = (cast(byte*)pvBits)[0 .. (area.width * area.height) * channels.length]; 180 image.exportPixels(area, arr, channels); 181 182 BitBlt(hdcwnd, 0, 0, width, height, hdc, 0, 0, SRCCOPY); 183 184 DeleteObject(hbitmap); 185 DeleteDC(hdc); 186 EndPaint(hwnd, &ps); 187 } 188 189 /** 190 * Setup the next frame, and invalidate the window so its repainted. 191 */ 192 void nextFrame() 193 { 194 if (++index == imageList.length) 195 index = 0; 196 197 image = imageList[index]; 198 199 UINT delay = cast(UINT)image.animationDelay.total!"msecs"(); 200 201 if ( delay == 0 ) 202 delay = 1000; 203 204 SetTimer(hwnd, 0, delay, null); 205 InvalidateRect(hwnd,null,false); 206 } 207 } 208 209 pragma(lib, "gdi32.lib"); 210 211 const AC_SRC_OVER = 0x00; 212 const AC_SRC_ALPHA = 0x01; 213 214 enum DWORD BI_RGB = 0; 215 enum UINT DIB_RGB_COLORS = 0; 216 217 extern(Windows) BOOL BitBlt(HDC, int, int, int, int, HDC, int, int, DWORD); 218 extern(Windows) HBITMAP CreateCompatibleBitmap(HDC, int, int); 219 extern(Windows) HBITMAP CreateDIBSection(HDC, const(BITMAPINFO)*, UINT, void**, HANDLE, DWORD); 220 extern(Windows) UINT_PTR SetTimer(HWND, UINT_PTR, UINT, TIMERPROC);