xref: /reactos/base/applications/mspaint/dib.cpp (revision cdf90707)
1 /*
2  * PROJECT:     PAINT for ReactOS
3  * LICENSE:     LGPL
4  * FILE:        base/applications/mspaint/dib.cpp
5  * PURPOSE:     Some DIB related functions
6  * PROGRAMMERS: Benedikt Freisen
7  */
8 
9 /* INCLUDES *********************************************************/
10 
11 #include "precomp.h"
12 #include <math.h>
13 
14 /* FUNCTIONS ********************************************************/
15 
16 HBITMAP
17 CreateDIBWithProperties(int width, int height)
18 {
19     BITMAPINFO bmi;
20     ZeroMemory(&bmi, sizeof(BITMAPINFO));
21     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
22     bmi.bmiHeader.biWidth = width;
23     bmi.bmiHeader.biHeight = height;
24     bmi.bmiHeader.biPlanes = 1;
25     bmi.bmiHeader.biBitCount = 24;
26     bmi.bmiHeader.biCompression = BI_RGB;
27     return CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
28 }
29 
30 HBITMAP
31 CreateColorDIB(int width, int height, COLORREF rgb)
32 {
33     HBITMAP ret = CreateDIBWithProperties(width, height);
34     if (!ret)
35         return NULL;
36 
37     if (rgb)
38     {
39         HDC hdc = CreateCompatibleDC(NULL);
40         HGDIOBJ hbmOld = SelectObject(hdc, ret);
41         RECT rc;
42         SetRect(&rc, 0, 0, width, height);
43         HBRUSH hbr = CreateSolidBrush(rgb);
44         FillRect(hdc, &rc, hbr);
45         DeleteObject(hbr);
46         SelectObject(hdc, hbmOld);
47         DeleteDC(hdc);
48     }
49 
50     return ret;
51 }
52 
53 int
54 GetDIBWidth(HBITMAP hBitmap)
55 {
56     BITMAP bm;
57     GetObject(hBitmap, sizeof(BITMAP), &bm);
58     return bm.bmWidth;
59 }
60 
61 int
62 GetDIBHeight(HBITMAP hBitmap)
63 {
64     BITMAP bm;
65     GetObject(hBitmap, sizeof(BITMAP), &bm);
66     return bm.bmHeight;
67 }
68 
69 BOOL SaveDIBToFile(HBITMAP hBitmap, LPTSTR FileName, HDC hDC)
70 {
71     CImage img;
72     img.Attach(hBitmap);
73     img.Save(FileName);  // TODO: error handling
74     img.Detach();
75 
76     WIN32_FIND_DATA find;
77     HANDLE hFind = FindFirstFile(FileName, &find);
78     if (hFind == INVALID_HANDLE_VALUE)
79     {
80         ShowFileLoadError(FileName);
81         return FALSE;
82     }
83     FindClose(hFind);
84 
85     // update time and size
86     FILETIME ft;
87     FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
88     FileTimeToSystemTime(&ft, &fileTime);
89     fileSize = find.nFileSizeLow;
90 
91     // TODO: update hRes and vRes
92 
93     registrySettings.SetMostRecentFile(FileName);
94 
95     isAFile = TRUE;
96     imageSaved = TRUE;
97     return TRUE;
98 }
99 
100 void ShowFileLoadError(LPCTSTR name)
101 {
102     CString strText;
103     strText.Format(IDS_LOADERRORTEXT, (LPCTSTR) name);
104     CString strProgramName;
105     strProgramName.LoadString(IDS_PROGRAMNAME);
106     mainWindow.MessageBox(strText, strProgramName, MB_OK | MB_ICONEXCLAMATION);
107 }
108 
109 HBITMAP SetBitmapAndInfo(HBITMAP hBitmap, LPCTSTR name, DWORD dwFileSize, BOOL isFile)
110 {
111     if (hBitmap == NULL)
112     {
113         COLORREF white = RGB(255, 255, 255);
114         hBitmap = CreateColorDIB(registrySettings.BMPWidth,
115                                  registrySettings.BMPHeight, white);
116         if (hBitmap == NULL)
117             return FALSE;
118 
119         fileHPPM = fileVPPM = 2834;
120         ZeroMemory(&fileTime, sizeof(fileTime));
121         isFile = FALSE;
122     }
123     else
124     {
125         // update PPMs
126         HDC hScreenDC = GetDC(NULL);
127         fileHPPM = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSX) * 1000 / 25.4);
128         fileVPPM = (int)(GetDeviceCaps(hScreenDC, LOGPIXELSY) * 1000 / 25.4);
129         ReleaseDC(NULL, hScreenDC);
130     }
131 
132     // update image
133     imageModel.Insert(hBitmap);
134     imageModel.ClearHistory();
135 
136     // update fileSize
137     fileSize = dwFileSize;
138 
139     // update filepathname
140     if (name && name[0])
141         GetFullPathName(name, _countof(filepathname), filepathname, NULL);
142     else
143         LoadString(hProgInstance, IDS_DEFAULTFILENAME, filepathname, _countof(filepathname));
144 
145     // set title
146     CString strTitle;
147     strTitle.Format(IDS_WINDOWTITLE, PathFindFileName(filepathname));
148     mainWindow.SetWindowText(strTitle);
149 
150     // update file info and recent
151     isAFile = isFile;
152     if (isAFile)
153         registrySettings.SetMostRecentFile(filepathname);
154 
155     imageSaved = TRUE;
156 
157     return hBitmap;
158 }
159 
160 HBITMAP DoLoadImageFile(HWND hwnd, LPCTSTR name, BOOL fIsMainFile)
161 {
162     // find the file
163     WIN32_FIND_DATA find;
164     HANDLE hFind = FindFirstFile(name, &find);
165     if (hFind == INVALID_HANDLE_VALUE)
166     {
167         // does not exist
168         CStringW strText;
169         strText.Format(IDS_LOADERRORTEXT, name);
170         MessageBoxW(hwnd, strText, NULL, MB_ICONERROR);
171         return NULL;
172     }
173     DWORD dwFileSize = find.nFileSizeLow; // get file size
174     FindClose(hFind);
175 
176     // is file empty?
177     if (dwFileSize == 0)
178     {
179         if (fIsMainFile)
180         {
181             FILETIME ft;
182             FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
183             FileTimeToSystemTime(&ft, &fileTime);
184             return SetBitmapAndInfo(NULL, name, dwFileSize, TRUE);
185         }
186     }
187 
188     // load the image
189     CImage img;
190     img.Load(name);
191     HBITMAP hBitmap = img.Detach();
192 
193     if (hBitmap == NULL)
194     {
195         // cannot open
196         CStringW strText;
197         strText.Format(IDS_LOADERRORTEXT, name);
198         MessageBoxW(hwnd, strText, NULL, MB_ICONERROR);
199         return NULL;
200     }
201 
202     if (fIsMainFile)
203     {
204         FILETIME ft;
205         FileTimeToLocalFileTime(&find.ftLastWriteTime, &ft);
206         FileTimeToSystemTime(&ft, &fileTime);
207         SetBitmapAndInfo(hBitmap, name, dwFileSize, TRUE);
208     }
209 
210     return hBitmap;
211 }
212 
213 HBITMAP Rotate90DegreeBlt(HDC hDC1, INT cx, INT cy, BOOL bRight)
214 {
215     HBITMAP hbm2 = CreateDIBWithProperties(cy, cx);
216     if (!hbm2)
217         return NULL;
218 
219     HDC hDC2 = CreateCompatibleDC(NULL);
220     HGDIOBJ hbm2Old = SelectObject(hDC2, hbm2);
221     if (bRight)
222     {
223         for (INT y = 0; y < cy; ++y)
224         {
225             for (INT x = 0; x < cx; ++x)
226             {
227                 COLORREF rgb = GetPixel(hDC1, x, y);
228                 SetPixelV(hDC2, cy - (y + 1), x, rgb);
229             }
230         }
231     }
232     else
233     {
234         for (INT y = 0; y < cy; ++y)
235         {
236             for (INT x = 0; x < cx; ++x)
237             {
238                 COLORREF rgb = GetPixel(hDC1, x, y);
239                 SetPixelV(hDC2, y, cx - (x + 1), rgb);
240             }
241         }
242     }
243     SelectObject(hDC2, hbm2Old);
244     DeleteDC(hDC2);
245     return hbm2;
246 }
247 
248 #ifndef M_PI
249     #define M_PI 3.14159265
250 #endif
251 
252 HBITMAP SkewDIB(HDC hDC1, HBITMAP hbm, INT nDegree, BOOL bVertical)
253 {
254     if (nDegree == 0)
255         return CopyDIBImage(hbm);
256 
257     const double eTan = tan(abs(nDegree) * M_PI / 180);
258 
259     BITMAP bm;
260     GetObjectW(hbm, sizeof(bm), &bm);
261     INT cx = bm.bmWidth, cy = bm.bmHeight, dx = 0, dy = 0;
262     if (bVertical)
263         dy = INT(cx * eTan);
264     else
265         dx = INT(cy * eTan);
266 
267     if (dx == 0 && dy == 0)
268         return CopyDIBImage(hbm);
269 
270     HBITMAP hbmNew = CreateColorDIB(cx + dx, cy + dy, RGB(255, 255, 255));
271     if (!hbmNew)
272         return NULL;
273 
274     HDC hDC2 = CreateCompatibleDC(NULL);
275     HGDIOBJ hbm2Old = SelectObject(hDC2, hbmNew);
276     if (bVertical)
277     {
278         for (INT x = 0; x < cx; ++x)
279         {
280             INT delta = INT(x * eTan);
281             if (nDegree > 0)
282                 BitBlt(hDC2, x, (dy - delta), 1, cy, hDC1, x, 0, SRCCOPY);
283             else
284                 BitBlt(hDC2, x, delta, 1, cy, hDC1, x, 0, SRCCOPY);
285         }
286     }
287     else
288     {
289         for (INT y = 0; y < cy; ++y)
290         {
291             INT delta = INT(y * eTan);
292             if (nDegree > 0)
293                 BitBlt(hDC2, (dx - delta), y, cx, 1, hDC1, 0, y, SRCCOPY);
294             else
295                 BitBlt(hDC2, delta, y, cx, 1, hDC1, 0, y, SRCCOPY);
296         }
297     }
298     SelectObject(hDC2, hbm2Old);
299     DeleteDC(hDC2);
300     return hbmNew;
301 }
302