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