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