]> git.saurik.com Git - wxWidgets.git/blame - src/msw/dib.cpp
supporting events also for root control (needed for event handling of mouse and paint...
[wxWidgets.git] / src / msw / dib.cpp
CommitLineData
53eff2a2
VZ
1///////////////////////////////////////////////////////////////////////////////
2// Name: src/msw/dib.cpp
3// Purpose: implements wxDIB class
4// Author: Vadim Zeitlin
5// Modified by:
6// Created: 03.03.03 (replaces the old file with the same name)
7// RCS-ID: $Id$
8// Copyright: (c) 2003 Vadim Zeitlin <vadim@wxwindows.org>
6c9a19aa 9// License: wxWindows licence
53eff2a2
VZ
10///////////////////////////////////////////////////////////////////////////////
11
2b254edf
VZ
12/*
13 TODO: support for palettes is very incomplete, several functions simply
14 ignore them (we should select and realize the palette, if any, before
3692b948 15 caling GetDIBits() in the DC we use with it.
2b254edf
VZ
16 */
17
53eff2a2
VZ
18// ============================================================================
19// declarations
20// ============================================================================
21
22// ----------------------------------------------------------------------------
23// headers
24// ----------------------------------------------------------------------------
25
26// For compilers that support precompilation, includes "wx.h".
27#include "wx/wxprec.h"
28
29#ifdef __BORLANDC__
30 #pragma hdrstop
31#endif
32
33#ifndef WX_PRECOMP
34 #include "wx/string.h"
35 #include "wx/log.h"
36#endif //WX_PRECOMP
37
4676948b
JS
38#if wxUSE_WXDIB
39
1cfa5d8e
JS
40#include "wx/bitmap.h"
41#include "wx/intl.h"
2b254edf 42#include "wx/file.h"
1cfa5d8e
JS
43
44#include <stdio.h>
45#include <stdlib.h>
46
47#if !defined(__MWERKS__) && !defined(__SALFORDC__)
48#include <memory.h>
49#endif
50
51#ifdef __GNUWIN32_OLD__
52 #include "wx/msw/gnuwin32/extra.h"
53#endif
53eff2a2 54
1cfa5d8e 55#include "wx/image.h"
53eff2a2
VZ
56#include "wx/msw/dib.h"
57
22be0335
VZ
58// ----------------------------------------------------------------------------
59// private functions
60// ----------------------------------------------------------------------------
61
62// calculate the number of palette entries needed for the bitmap with this
63// number of bits per pixel
3692b948 64static inline WORD wxGetNumOfBitmapColors(WORD bitsPerPixel)
22be0335
VZ
65{
66 // only 1, 4 and 8bpp bitmaps use palettes (well, they could be used with
67 // 24bpp ones too but we don't support this as I think it's quite uncommon)
68 return bitsPerPixel <= 8 ? 1 << bitsPerPixel : 0;
69}
70
3692b948
VZ
71// wrapper around ::GetObject() for DIB sections
72static inline bool GetDIBSection(HBITMAP hbmp, DIBSECTION *ds)
73{
74 // note that at least under Win9x (this doesn't seem to happen under Win2K
75 // but this doesn't mean anything, of course), GetObject() may return
76 // sizeof(DIBSECTION) for a bitmap which is *not* a DIB section and the way
77 // to check for it is by looking at the bits pointer
78 return ::GetObject(hbmp, sizeof(DIBSECTION), ds) == sizeof(DIBSECTION) &&
79 ds->dsBm.bmBits;
80}
81
53eff2a2
VZ
82// ============================================================================
83// implementation
84// ============================================================================
85
86// ----------------------------------------------------------------------------
87// wxDIB creation
88// ----------------------------------------------------------------------------
89
90bool wxDIB::Create(int width, int height, int depth)
91{
92 // we don't handle the palette yet
93 wxASSERT_MSG( depth == 24 || depth == 32,
94 _T("unsupported image depth in wxDIB::Create()") );
95
96 static const int infosize = sizeof(BITMAPINFOHEADER);
97
98 BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
a1e71b10 99 wxCHECK_MSG( info, false, _T("malloc(BITMAPINFO) failed") );
53eff2a2
VZ
100
101 memset(info, 0, infosize);
102
103 info->bmiHeader.biSize = infosize;
104 info->bmiHeader.biWidth = width;
bbc1265c
VZ
105
106 // we use positive height here which corresponds to a DIB with normal, i.e.
107 // bottom to top, order -- normally using negative height (which means
108 // reversed for MS and hence natural for all the normal people top to
109 // bottom line scan order) could be used to avoid the need for the image
110 // reversal in Create(image) but this doesn't work under NT, only Win9x!
111 info->bmiHeader.biHeight = height;
112
53eff2a2
VZ
113 info->bmiHeader.biPlanes = 1;
114 info->bmiHeader.biBitCount = depth;
53eff2a2
VZ
115 info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
116
53eff2a2
VZ
117 m_handle = ::CreateDIBSection
118 (
119 0, // hdc (unused with DIB_RGB_COLORS)
120 info, // bitmap description
121 DIB_RGB_COLORS, // use RGB, not palette
122 &m_data, // [out] DIB bits
123 NULL, // don't use file mapping
124 0 // file mapping offset (not used here)
125 );
126
127 free(info);
128
129 if ( !m_handle )
130 {
131 wxLogLastError(wxT("CreateDIBSection"));
132
133 return false;
134 }
135
136 m_width = width;
137 m_height = height;
138 m_depth = depth;
139
140 return true;
141}
142
2b254edf
VZ
143bool wxDIB::Create(const wxBitmap& bmp)
144{
145 wxCHECK_MSG( bmp.Ok(), false, _T("wxDIB::Create(): invalid bitmap") );
146
82ac3b0a
VZ
147 // this bitmap could already be a DIB section in which case we don't need
148 // to convert it to DIB
149 HBITMAP hbmp = GetHbitmapOf(bmp);
2b254edf 150
82ac3b0a 151 DIBSECTION ds;
3692b948 152 if ( GetDIBSection(hbmp, &ds) )
2b254edf 153 {
82ac3b0a
VZ
154 m_handle = hbmp;
155
156 // wxBitmap will free it, not we
157 m_ownsHandle = false;
2b254edf 158
82ac3b0a
VZ
159 // copy all the bitmap parameters too as we have them now anyhow
160 m_width = ds.dsBm.bmWidth;
161 m_height = ds.dsBm.bmHeight;
162 m_depth = ds.dsBm.bmBitsPixel;
163
164 m_data = ds.dsBm.bmBits;
165 }
166 else // no, it's a DDB -- convert it to DIB
167 {
168 const int w = bmp.GetWidth();
169 const int h = bmp.GetHeight();
170 int d = bmp.GetDepth();
171 if ( d == -1 )
172 d = wxDisplayDepth();
173
174 if ( !Create(w, h, d) )
175 return false;
176
3692b948
VZ
177 if ( !GetDIBSection(m_handle, &ds) )
178 {
179 // we've just created a new DIB section, why should this fail?
180 wxFAIL_MSG( _T("GetObject(DIBSECTION) unexpectedly failed") );
181
182 return false;
183 }
184
185 if ( !::GetDIBits
82ac3b0a 186 (
3692b948
VZ
187 ScreenHDC(), // the DC to use
188 hbmp, // the source DDB
189 0, // first scan line
190 h, // number of lines to copy
191 ds.dsBm.bmBits, // pointer to the buffer
192 (BITMAPINFO *)&ds.dsBmih, // bitmap header
193 DIB_RGB_COLORS // and not DIB_PAL_COLORS
82ac3b0a
VZ
194 ) )
195 {
196 wxLogLastError(wxT("GetDIBits()"));
197
198 return 0;
199 }
2b254edf
VZ
200 }
201
202 return true;
203}
204
c11bf842
VZ
205// ----------------------------------------------------------------------------
206// Loading/saving the DIBs
207// ----------------------------------------------------------------------------
208
209bool wxDIB::Load(const wxString& filename)
210{
211 m_handle = (HBITMAP)::LoadImage
212 (
213 wxGetInstance(),
214 filename,
215 IMAGE_BITMAP,
216 0, 0, // don't specify the size
217 LR_CREATEDIBSECTION | LR_LOADFROMFILE
218 );
219 if ( !m_handle )
220 {
221 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
222
223 return false;
224 }
225
226 return true;
227}
228
2b254edf
VZ
229bool wxDIB::Save(const wxString& filename)
230{
231 wxCHECK_MSG( m_handle, false, _T("wxDIB::Save(): invalid object") );
232
233 wxFile file(filename, wxFile::write);
234 bool ok = file.IsOpened();
235 if ( ok )
236 {
237 DIBSECTION ds;
3692b948 238 if ( !GetDIBSection(m_handle, &ds) )
2b254edf
VZ
239 {
240 wxLogLastError(_T("GetObject(hDIB)"));
241 }
242 else
243 {
244 BITMAPFILEHEADER bmpHdr;
245 wxZeroMemory(bmpHdr);
246
247 const size_t sizeHdr = ds.dsBmih.biSize;
248 const size_t sizeImage = ds.dsBmih.biSizeImage;
249
250 bmpHdr.bfType = 0x4d42; // 'BM' in little endian
251 bmpHdr.bfOffBits = sizeof(BITMAPFILEHEADER) + ds.dsBmih.biSize;
252 bmpHdr.bfSize = bmpHdr.bfOffBits + sizeImage;
253
254 // first write the file header, then the bitmap header and finally the
255 // bitmap data itself
256 ok = file.Write(&bmpHdr, sizeof(bmpHdr)) == sizeof(bmpHdr) &&
257 file.Write(&ds.dsBmih, sizeHdr) == sizeHdr &&
258 file.Write(ds.dsBm.bmBits, sizeImage) == sizeImage;
259 }
260 }
261
262 if ( !ok )
263 {
264 wxLogError(_("Failed to save the bitmap image to file \"%s\"."),
265 filename.c_str());
266 }
267
268 return ok;
269}
270
53eff2a2
VZ
271// ----------------------------------------------------------------------------
272// wxDIB accessors
273// ----------------------------------------------------------------------------
274
275void wxDIB::DoGetObject() const
276{
277 // only do something if we have a valid DIB but we don't [yet] have valid
278 // data
279 if ( m_handle && !m_data )
280 {
281 // although all the info we need is in BITMAP and so we don't really
282 // need DIBSECTION we still ask for it as modifying the bit values only
283 // works for the real DIBs and not for the bitmaps and it's better to
284 // check for this now rather than trying to find out why it doesn't
285 // work later
286 DIBSECTION ds;
3692b948 287 if ( !GetDIBSection(m_handle, &ds) )
53eff2a2
VZ
288 {
289 wxLogLastError(_T("GetObject(hDIB)"));
53eff2a2
VZ
290 return;
291 }
292
293 wxDIB *self = wxConstCast(this, wxDIB);
294
295 self->m_width = ds.dsBm.bmWidth;
296 self->m_height = ds.dsBm.bmHeight;
297 self->m_depth = ds.dsBm.bmBitsPixel;
298 self->m_data = ds.dsBm.bmBits;
299 }
300}
301
22be0335
VZ
302// ----------------------------------------------------------------------------
303// DDB <-> DIB conversions
304// ----------------------------------------------------------------------------
305
c11bf842
VZ
306HBITMAP wxDIB::CreateDDB(HDC hdc) const
307{
308 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
309
310 DIBSECTION ds;
3692b948 311 if ( !GetDIBSection(m_handle, &ds) )
c11bf842
VZ
312 {
313 wxLogLastError(_T("GetObject(hDIB)"));
314
315 return 0;
316 }
317
22be0335
VZ
318 return ConvertToBitmap((BITMAPINFO *)&ds.dsBmih, hdc, ds.dsBm.bmBits);
319}
320
321/* static */
322HBITMAP wxDIB::ConvertToBitmap(const BITMAPINFO *pbmi, HDC hdc, void *bits)
323{
324 wxCHECK_MSG( pbmi, 0, _T("invalid DIB in ConvertToBitmap") );
325
326 // here we get BITMAPINFO struct followed by the actual bitmap bits and
327 // BITMAPINFO starts with BITMAPINFOHEADER followed by colour info
328 const BITMAPINFOHEADER *pbmih = &pbmi->bmiHeader;
329
330 // get the pointer to the start of the real image data if we have a plain
331 // DIB and not a DIB section (in the latter case the pointer must be passed
332 // to us by the caller)
333 if ( !bits )
c11bf842 334 {
22be0335 335 // we must skip over the colour table to get to the image data
a8beba72
VZ
336 //
337 // colour table either has the real colour data in which case its
338 // number of entries is given by biClrUsed or is used for masks to be
339 // used for extracting colour information from true colour bitmaps in
340 // which case it always have exactly 3 DWORDs
341 int numColors;
342 switch ( pbmih->biCompression )
22be0335 343 {
a8beba72
VZ
344 case BI_BITFIELDS:
345 numColors = 3;
346 break;
347
348 case BI_RGB:
349 // biClrUsed has the number of colors but it may be not initialized at
350 // all
351 numColors = pbmih->biClrUsed;
352 if ( !numColors )
353 {
354 numColors = wxGetNumOfBitmapColors(pbmih->biBitCount);
355 }
356 break;
357
358 default:
359 // no idea how it should be calculated for the other cases
360 numColors = 0;
22be0335
VZ
361 }
362
363 bits = (char *)pbmih + sizeof(*pbmih) + numColors*sizeof(RGBQUAD);
c11bf842 364 }
4b1f929c 365
22be0335
VZ
366 HBITMAP hbmp = ::CreateDIBitmap
367 (
4b1f929c
CE
368 hdc ? hdc // create bitmap compatible
369 : (HDC) ScreenHDC(), // with this DC
22be0335
VZ
370 pbmih, // used to get size &c
371 CBM_INIT, // initialize bitmap bits too
372 bits, // ... using this data
373 pbmi, // this is used for palette only
374 DIB_RGB_COLORS // direct or indexed palette?
375 );
376
377 if ( !hbmp )
c11bf842 378 {
22be0335 379 wxLogLastError(wxT("CreateDIBitmap"));
c11bf842
VZ
380 }
381
22be0335
VZ
382 return hbmp;
383}
384
385/* static */
386size_t wxDIB::ConvertFromBitmap(BITMAPINFO *pbi, HBITMAP hbmp)
387{
388 wxASSERT_MSG( hbmp, wxT("invalid bmp can't be converted to DIB") );
389
390 // prepare all the info we need
391 BITMAP bm;
392 if ( !::GetObject(hbmp, sizeof(bm), &bm) )
393 {
394 wxLogLastError(wxT("GetObject(bitmap)"));
395
396 return 0;
397 }
398
22be0335
VZ
399 // we need a BITMAPINFO anyhow and if we're not given a pointer to it we
400 // use this one
401 BITMAPINFO bi2;
402
2b254edf 403 const bool wantSizeOnly = pbi == NULL;
22be0335
VZ
404 if ( wantSizeOnly )
405 pbi = &bi2;
406
407 // just for convenience
408 const int h = bm.bmHeight;
409
410 // init the header
411 BITMAPINFOHEADER& bi = pbi->bmiHeader;
412 wxZeroMemory(bi);
413 bi.biSize = sizeof(BITMAPINFOHEADER);
414 bi.biWidth = bm.bmWidth;
415 bi.biHeight = h;
416 bi.biPlanes = 1;
2b254edf 417 bi.biBitCount = bm.bmBitsPixel;
22be0335
VZ
418
419 // memory we need for BITMAPINFO only
2b254edf
VZ
420 DWORD dwLen = bi.biSize + wxGetNumOfBitmapColors(bm.bmBitsPixel) * sizeof(RGBQUAD);
421
422 // get either just the image size or the image bits
423 if ( !::GetDIBits
424 (
425 ScreenHDC(), // the DC to use
426 hbmp, // the source DDB
427 0, // first scan line
428 h, // number of lines to copy
429 wantSizeOnly ? NULL // pointer to the buffer or
430 : (char *)pbi + dwLen, // NULL if we don't have it
431 pbi, // bitmap header
432 DIB_RGB_COLORS // or DIB_PAL_COLORS
433 ) )
c11bf842 434 {
2b254edf 435 wxLogLastError(wxT("GetDIBits()"));
c11bf842
VZ
436
437 return 0;
438 }
439
2b254edf
VZ
440 // return the total size
441 return dwLen + bi.biSizeImage;
442}
443
444/* static */
445HGLOBAL wxDIB::ConvertFromBitmap(HBITMAP hbmp)
446{
447 // first calculate the size needed
448 const size_t size = ConvertFromBitmap(NULL, hbmp);
449 if ( !size )
22be0335 450 {
2b254edf
VZ
451 // conversion to DDB failed?
452 return NULL;
453 }
22be0335 454
2b254edf
VZ
455 HGLOBAL hDIB = ::GlobalAlloc(GMEM_MOVEABLE, size);
456 if ( !hDIB )
457 {
458 // this is an error which does risk to happen especially under Win9x
459 // and which the user may understand so let him know about it
460 wxLogError(_("Failed to allocated %luKb of memory for bitmap data."),
461 (unsigned long)(size / 1024));
462
463 return NULL;
22be0335
VZ
464 }
465
3692b948 466 if ( !ConvertFromBitmap((BITMAPINFO *)(void *)GlobalPtr(hDIB), hbmp) )
2b254edf
VZ
467 {
468 // this really shouldn't happen... it worked the first time, why not
469 // now?
470 wxFAIL_MSG( _T("wxDIB::ConvertFromBitmap() unexpectedly failed") );
471
472 return NULL;
473 }
474
475 return hDIB;
c11bf842
VZ
476}
477
22be0335
VZ
478// ----------------------------------------------------------------------------
479// palette support
480// ----------------------------------------------------------------------------
481
c11bf842
VZ
482#if wxUSE_PALETTE
483
484wxPalette *wxDIB::CreatePalette() const
485{
486 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
487
488 DIBSECTION ds;
3692b948 489 if ( !GetDIBSection(m_handle, &ds) )
c11bf842
VZ
490 {
491 wxLogLastError(_T("GetObject(hDIB)"));
492
493 return 0;
494 }
495
496 // how many colours are we going to have in the palette?
497 DWORD biClrUsed = ds.dsBmih.biClrUsed;
498 if ( !biClrUsed )
499 {
500 // biClrUsed field might not be set
2b254edf 501 biClrUsed = wxGetNumOfBitmapColors(ds.dsBmih.biBitCount);
c11bf842
VZ
502 }
503
2b254edf 504 if ( !biClrUsed )
c11bf842 505 {
2b254edf 506 // bitmaps of this depth don't have palettes at all
c11bf842
VZ
507 //
508 // NB: another possibility would be to return
509 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
510 return NULL;
511 }
512
513 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
514 // going to have biClrUsed of them so add necessary space
515 LOGPALETTE *pPalette = (LOGPALETTE *)
516 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
517 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
518
519 // initialize the palette header
520 pPalette->palVersion = 0x300; // magic number, not in docs but works
521 pPalette->palNumEntries = biClrUsed;
522
523 // and the colour table (it starts right after the end of the header)
524 const RGBQUAD *pRGB = (RGBQUAD *)((char *)&ds.dsBmih + ds.dsBmih.biSize);
525 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
526 {
527 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
528 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
529 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
530 pPalette->palPalEntry[i].peFlags = 0;
531 }
532
533 HPALETTE hPalette = ::CreatePalette(pPalette);
534
535 free(pPalette);
536
537 if ( !hPalette )
538 {
539 wxLogLastError(_T("CreatePalette"));
540
541 return NULL;
542 }
543
544 wxPalette *palette = new wxPalette;
545 palette->SetHPALETTE((WXHPALETTE)hPalette);
546
547 return palette;
548}
549
550#endif // wxUSE_PALETTE
551
53eff2a2
VZ
552// ----------------------------------------------------------------------------
553// wxImage support
554// ----------------------------------------------------------------------------
555
556#if wxUSE_IMAGE
557
558bool wxDIB::Create(const wxImage& image)
559{
560 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
561
562 const int h = image.GetHeight();
563 const int w = image.GetWidth();
564
565 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
566 // a 24bpp RGB is sufficient
567 const bool hasAlpha = image.HasAlpha();
568 const int bpp = hasAlpha ? 32 : 24;
569
570 if ( !Create(w, h, bpp) )
571 return false;
572
bbc1265c
VZ
573 // DIBs are stored in bottom to top order (see also the comment above in
574 // Create()) so we need to copy bits line by line and starting from the end
53eff2a2
VZ
575 const int srcBytesPerLine = w * 3;
576 const int dstBytesPerLine = GetLineSize(w, bpp);
577 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
578 const unsigned char *alpha = hasAlpha ? image.GetAlpha() + (h - 1)*w : NULL;
579 unsigned char *dstLineStart = (unsigned char *)m_data;
580 for ( int y = 0; y < h; y++ )
581 {
582 // copy one DIB line
583 unsigned char *dst = dstLineStart;
584 for ( int x = 0; x < w; x++ )
585 {
586 // also, the order of RGB is inversed for DIBs
587 *dst++ = src[2];
588 *dst++ = src[1];
589 *dst++ = src[0];
590
591 src += 3;
592
593 if ( alpha )
594 *dst++ = *alpha++;
595 }
596
597 // pass to the previous line in the image
598 src -= 2*srcBytesPerLine;
599 if ( alpha )
600 alpha -= 2*w;
601
602 // and to the next one in the DIB
603 dstLineStart += dstBytesPerLine;
604 }
605
606 return true;
607}
608
609#endif // wxUSE_IMAGE
610
4676948b
JS
611#endif
612 // wxUSE_WXDIB
613