]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dib.cpp
use wxDIB methods instead of old functions for working with DIBs
[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 // declarations
14 // ============================================================================
15
16 // ----------------------------------------------------------------------------
17 // headers
18 // ----------------------------------------------------------------------------
19
20 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
22
23 #ifdef __BORLANDC__
24 #pragma hdrstop
25 #endif
26
27 #ifndef WX_PRECOMP
28 #include "wx/string.h"
29 #include "wx/log.h"
30 #endif //WX_PRECOMP
31
32 #include "wx/bitmap.h"
33 #include "wx/intl.h"
34
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #if !defined(__MWERKS__) && !defined(__SALFORDC__)
39 #include <memory.h>
40 #endif
41
42 #ifdef __GNUWIN32_OLD__
43 #include "wx/msw/gnuwin32/extra.h"
44 #endif
45
46 #include "wx/image.h"
47 #include "wx/msw/dib.h"
48
49 // ============================================================================
50 // implementation
51 // ============================================================================
52
53 // ----------------------------------------------------------------------------
54 // wxDIB creation
55 // ----------------------------------------------------------------------------
56
57 bool wxDIB::Create(int width, int height, int depth)
58 {
59 // we don't handle the palette yet
60 wxASSERT_MSG( depth == 24 || depth == 32,
61 _T("unsupported image depth in wxDIB::Create()") );
62
63 static const int infosize = sizeof(BITMAPINFOHEADER);
64
65 BITMAPINFO *info = (BITMAPINFO *)malloc(infosize);
66 wxCHECK_MSG( info, NULL, _T("malloc(BITMAPINFO) failed") );
67
68 memset(info, 0, infosize);
69
70 info->bmiHeader.biSize = infosize;
71 info->bmiHeader.biWidth = width;
72
73 // we use positive height here which corresponds to a DIB with normal, i.e.
74 // bottom to top, order -- normally using negative height (which means
75 // reversed for MS and hence natural for all the normal people top to
76 // bottom line scan order) could be used to avoid the need for the image
77 // reversal in Create(image) but this doesn't work under NT, only Win9x!
78 info->bmiHeader.biHeight = height;
79
80 info->bmiHeader.biPlanes = 1;
81 info->bmiHeader.biBitCount = depth;
82 info->bmiHeader.biCompression = BI_RGB;
83 info->bmiHeader.biSizeImage = GetLineSize(width, depth)*height;
84
85 // No need to report an error here. If it fails, we just won't use a
86 // file mapping and CreateDIBSection will just allocate memory for us.
87 m_handle = ::CreateDIBSection
88 (
89 0, // hdc (unused with DIB_RGB_COLORS)
90 info, // bitmap description
91 DIB_RGB_COLORS, // use RGB, not palette
92 &m_data, // [out] DIB bits
93 NULL, // don't use file mapping
94 0 // file mapping offset (not used here)
95 );
96
97 free(info);
98
99 if ( !m_handle )
100 {
101 wxLogLastError(wxT("CreateDIBSection"));
102
103 return false;
104 }
105
106 m_width = width;
107 m_height = height;
108 m_depth = depth;
109
110 return true;
111 }
112
113 // ----------------------------------------------------------------------------
114 // Loading/saving the DIBs
115 // ----------------------------------------------------------------------------
116
117 bool wxDIB::Load(const wxString& filename)
118 {
119 m_handle = (HBITMAP)::LoadImage
120 (
121 wxGetInstance(),
122 filename,
123 IMAGE_BITMAP,
124 0, 0, // don't specify the size
125 LR_CREATEDIBSECTION | LR_LOADFROMFILE
126 );
127 if ( !m_handle )
128 {
129 wxLogLastError(_T("LoadImage(LR_CREATEDIBSECTION | LR_LOADFROMFILE)"));
130
131 return false;
132 }
133
134 return true;
135 }
136
137 // ----------------------------------------------------------------------------
138 // wxDIB accessors
139 // ----------------------------------------------------------------------------
140
141 void wxDIB::DoGetObject() const
142 {
143 // only do something if we have a valid DIB but we don't [yet] have valid
144 // data
145 if ( m_handle && !m_data )
146 {
147 // although all the info we need is in BITMAP and so we don't really
148 // need DIBSECTION we still ask for it as modifying the bit values only
149 // works for the real DIBs and not for the bitmaps and it's better to
150 // check for this now rather than trying to find out why it doesn't
151 // work later
152 DIBSECTION ds;
153 if ( !::GetObject(m_handle, sizeof(ds), &ds) )
154 {
155 wxLogLastError(_T("GetObject(hDIB)"));
156 return;
157 }
158
159 wxDIB *self = wxConstCast(this, wxDIB);
160
161 self->m_width = ds.dsBm.bmWidth;
162 self->m_height = ds.dsBm.bmHeight;
163 self->m_depth = ds.dsBm.bmBitsPixel;
164 self->m_data = ds.dsBm.bmBits;
165 }
166 }
167
168 HBITMAP wxDIB::CreateDDB(HDC hdc) const
169 {
170 wxCHECK_MSG( m_handle, 0, _T("wxDIB::CreateDDB(): invalid object") );
171
172 DIBSECTION ds;
173 if ( !::GetObject(m_handle, sizeof(ds), &ds) )
174 {
175 wxLogLastError(_T("GetObject(hDIB)"));
176
177 return 0;
178 }
179
180 HBITMAP hbitmap = ::CreateCompatibleBitmap
181 (
182 hdc ? hdc : ScreenHDC(),
183 ds.dsBm.bmWidth,
184 ds.dsBm.bmHeight
185 );
186 if ( !hbitmap )
187 {
188 wxLogLastError(_T("CreateCompatibleBitmap()"));
189
190 return 0;
191 }
192
193 MemoryHDC hdcMem;
194 SelectInHDC select(hdcMem, hbitmap);
195 if ( !select )
196 {
197 wxLogLastError(_T("SelectObjct(hBitmap)"));
198 }
199
200 if ( !::SetDIBits
201 (
202 hdcMem,
203 hbitmap,
204 0,
205 ds.dsBm.bmHeight,
206 ds.dsBm.bmBits,
207 (BITMAPINFO *)&ds.dsBmih,
208 DIB_RGB_COLORS
209 ) )
210 {
211 wxLogLastError(_T("SetDIBits"));
212
213 return 0;
214 }
215
216 return hbitmap;
217 }
218
219 #if wxUSE_PALETTE
220
221 wxPalette *wxDIB::CreatePalette() const
222 {
223 wxCHECK_MSG( m_handle, NULL, _T("wxDIB::CreatePalette(): invalid object") );
224
225 DIBSECTION ds;
226 if ( !::GetObject(m_handle, sizeof(ds), &ds) )
227 {
228 wxLogLastError(_T("GetObject(hDIB)"));
229
230 return 0;
231 }
232
233 // how many colours are we going to have in the palette?
234 DWORD biClrUsed = ds.dsBmih.biClrUsed;
235 if ( !biClrUsed )
236 {
237 // biClrUsed field might not be set
238 biClrUsed = 1 << ds.dsBmih.biBitCount;
239 }
240
241 if ( biClrUsed > 256 )
242 {
243 // only 8bpp bitmaps (and less) have palettes, so we surely don't
244 //
245 // NB: another possibility would be to return
246 // GetStockObject(DEFAULT_PALETTE) or even CreateHalftonePalette()?
247 return NULL;
248 }
249
250 // LOGPALETTE struct has only 1 element in palPalEntry array, we're
251 // going to have biClrUsed of them so add necessary space
252 LOGPALETTE *pPalette = (LOGPALETTE *)
253 malloc(sizeof(LOGPALETTE) + (biClrUsed - 1)*sizeof(PALETTEENTRY));
254 wxCHECK_MSG( pPalette, NULL, _T("out of memory") );
255
256 // initialize the palette header
257 pPalette->palVersion = 0x300; // magic number, not in docs but works
258 pPalette->palNumEntries = biClrUsed;
259
260 // and the colour table (it starts right after the end of the header)
261 const RGBQUAD *pRGB = (RGBQUAD *)((char *)&ds.dsBmih + ds.dsBmih.biSize);
262 for ( DWORD i = 0; i < biClrUsed; i++, pRGB++ )
263 {
264 pPalette->palPalEntry[i].peRed = pRGB->rgbRed;
265 pPalette->palPalEntry[i].peGreen = pRGB->rgbGreen;
266 pPalette->palPalEntry[i].peBlue = pRGB->rgbBlue;
267 pPalette->palPalEntry[i].peFlags = 0;
268 }
269
270 HPALETTE hPalette = ::CreatePalette(pPalette);
271
272 free(pPalette);
273
274 if ( !hPalette )
275 {
276 wxLogLastError(_T("CreatePalette"));
277
278 return NULL;
279 }
280
281 wxPalette *palette = new wxPalette;
282 palette->SetHPALETTE((WXHPALETTE)hPalette);
283
284 return palette;
285 }
286
287 #endif // wxUSE_PALETTE
288
289 // ----------------------------------------------------------------------------
290 // wxImage support
291 // ----------------------------------------------------------------------------
292
293 #if wxUSE_IMAGE
294
295 bool wxDIB::Create(const wxImage& image)
296 {
297 wxCHECK_MSG( image.Ok(), false, _T("invalid wxImage in wxDIB ctor") );
298
299 const int h = image.GetHeight();
300 const int w = image.GetWidth();
301
302 // if we have alpha channel, we need to create a 32bpp RGBA DIB, otherwise
303 // a 24bpp RGB is sufficient
304 const bool hasAlpha = image.HasAlpha();
305 const int bpp = hasAlpha ? 32 : 24;
306
307 if ( !Create(w, h, bpp) )
308 return false;
309
310 // DIBs are stored in bottom to top order (see also the comment above in
311 // Create()) so we need to copy bits line by line and starting from the end
312 const int srcBytesPerLine = w * 3;
313 const int dstBytesPerLine = GetLineSize(w, bpp);
314 const unsigned char *src = image.GetData() + ((h - 1) * srcBytesPerLine);
315 const unsigned char *alpha = hasAlpha ? image.GetAlpha() + (h - 1)*w : NULL;
316 unsigned char *dstLineStart = (unsigned char *)m_data;
317 for ( int y = 0; y < h; y++ )
318 {
319 // copy one DIB line
320 unsigned char *dst = dstLineStart;
321 for ( int x = 0; x < w; x++ )
322 {
323 // also, the order of RGB is inversed for DIBs
324 *dst++ = src[2];
325 *dst++ = src[1];
326 *dst++ = src[0];
327
328 src += 3;
329
330 if ( alpha )
331 *dst++ = *alpha++;
332 }
333
334 // pass to the previous line in the image
335 src -= 2*srcBytesPerLine;
336 if ( alpha )
337 alpha -= 2*w;
338
339 // and to the next one in the DIB
340 dstLineStart += dstBytesPerLine;
341 }
342
343 return true;
344 }
345
346 #endif // wxUSE_IMAGE
347
348 // ============================================================================
349 // old DIB code, to be integrated in wxDIB class
350 // ============================================================================
351
352 /*
353 * Routines for dealing with Device Independent Bitmaps.
354 *
355 * wxReadDIB() - Reads a DIB
356 * wxWriteDIB() - Writes a global handle in CF_DIB format
357 * to a file.
358 * wxPaletteSize() - Calculates the palette size in bytes
359 * of given DIB
360 * wxDibNumColors() - Determines the number of colors in DIB
361 * wxDibFromBitmap() - Creates a DIB repr. the DDB passed in.
362 * lread() - Private routine to read more than 64k
363 * lwrite() - Private routine to write more than 64k
364 */
365
366 #ifndef SEEK_CUR
367 /* flags for _lseek */
368 #define SEEK_CUR 1
369 #define SEEK_END 2
370 #define SEEK_SET 0
371 #endif
372
373 #define MAXREAD 32768 /* Number of bytes to be read during */
374 /* each read operation. */
375
376 /* Header signatutes for various resources */
377 #define BFT_ICON 0x4349 /* 'IC' */
378 #define BFT_BITMAP 0x4d42 /* 'BM' */
379 #define BFT_CURSOR 0x5450 /* 'PT(' */
380
381 /* macro to determine if resource is a DIB */
382 #define ISDIB(bft) ((bft) == BFT_BITMAP)
383
384 /* Macro to align given value to the closest DWORD (unsigned long ) */
385 #define ALIGNULONG(i) ((i+3)/4*4)
386
387 /* Macro to determine to round off the given value to the closest byte */
388 #define WIDTHBYTES(i) ((i+31)/32*4)
389
390 #define PALVERSION 0x300
391 #define MAXPALETTE 256 /* max. # supported palette entries */
392
393 static DWORD lread(int fh, VOID FAR *pv, DWORD ul);
394 static DWORD lwrite(int fh, VOID FAR *pv, DWORD ul);
395
396 static bool wxWriteDIB (LPTSTR szFile,HANDLE hdib);
397 WORD wxPaletteSize (VOID FAR * pv); // This is non-static as some apps use it externally
398 static WORD wxDibNumColors (VOID FAR * pv);
399 static bool wxMakeBitmapAndPalette(HDC,HANDLE,HPALETTE *,HBITMAP *);
400
401 /*
402 * FUNCTION : wxWriteDIB(LPSTR szFile,HANDLE hdib)
403 * PURPOSE : Write a global handle in CF_DIB format to a file.
404 * RETURNS : TRUE - if successful.
405 * FALSE - otherwise
406 */
407
408 static bool wxWriteDIB(LPTSTR szFile, HANDLE hdib)
409 {
410 BITMAPFILEHEADER hdr;
411 LPBITMAPINFOHEADER lpbi;
412 int fh;
413 OFSTRUCT of;
414
415 if (!hdib)
416 return FALSE;
417
418 fh = OpenFile(wxConvertWX2MB(szFile), &of, OF_CREATE | OF_READWRITE);
419 if (fh == -1)
420 return FALSE;
421
422 lpbi = (LPBITMAPINFOHEADER) GlobalLock(hdib);
423
424 /* Fill in the fields of the file header */
425 hdr.bfType = BFT_BITMAP;
426 hdr.bfSize = GlobalSize(hdib) + sizeof(BITMAPFILEHEADER);
427 hdr.bfReserved1 = 0;
428 hdr.bfReserved2 = 0;
429 hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + lpbi->biSize +
430 wxPaletteSize(lpbi);
431
432 /* Write the file header */
433 _lwrite(fh, (LPSTR) &hdr, sizeof(BITMAPFILEHEADER));
434
435 /* Write the DIB header and the bits */
436 lwrite(fh, (LPSTR) lpbi, GlobalSize(hdib));
437
438 GlobalUnlock(hdib);
439 _lclose(fh);
440 return TRUE;
441 }
442
443 /*
444 * FUNCTION : wxPaletteSize(VOID FAR * pv)
445 * PURPOSE : Calculates the palette size in bytes. If the info. block
446 * is of the BITMAPCOREHEADER type, the number of colors is
447 * multiplied by 3 to give the palette size, otherwise the
448 * number of colors is multiplied by 4.
449 * RETURNS : Palette size in number of bytes.
450 */
451
452 WORD wxPaletteSize(VOID FAR * pv)
453 {
454 LPBITMAPINFOHEADER lpbi;
455 WORD NumColors;
456
457 lpbi = (LPBITMAPINFOHEADER) pv;
458 NumColors = wxDibNumColors(lpbi);
459
460 if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
461 return (WORD)(NumColors * sizeof(RGBTRIPLE));
462 else
463 return (WORD)(NumColors * sizeof(RGBQUAD));
464 }
465
466 /*
467 * FUNCTION : wxDibNumColors(VOID FAR * pv)
468 * PURPOSE : Determines the number of colors in the DIB by looking at
469 * the BitCount filed in the info block.
470 * RETURNS : The number of colors in the DIB. *
471 */
472
473 static WORD wxDibNumColors(VOID FAR *pv)
474 {
475 int bits;
476 BITMAPINFOHEADER *lpbi;
477 BITMAPCOREHEADER *lpbc;
478
479 lpbi = ((BITMAPINFOHEADER*) pv);
480 lpbc = ((BITMAPCOREHEADER*) pv);
481
482 /* With the BITMAPINFO format headers, the size of the palette
483 * is in biClrUsed, whereas in the BITMAPCORE - style headers, it
484 * is dependent on the bits per pixel ( = 2 raised to the power of
485 * bits/pixel).
486 */
487 if (lpbi->biSize != sizeof(BITMAPCOREHEADER)) {
488 if (lpbi->biClrUsed != 0)
489 return (WORD) lpbi->biClrUsed;
490 bits = lpbi->biBitCount;
491 }
492 else
493 bits = lpbc->bcBitCount;
494
495 switch (bits) {
496 case 1:
497 return 2;
498 case 4:
499 return 16;
500 case 8:
501 return 256;
502 default:
503 /* A 24 bitcount DIB has no color table */
504 return 0;
505 }
506 }
507
508 /*
509 * FUNCTION : lread(int fh, VOID FAR *pv, DWORD ul)
510 * PURPOSE : Reads data in steps of 32k till all the data has been read.
511 * RETURNS : 0 - If read did not proceed correctly.
512 * number of bytes read otherwise.
513 */
514
515 static DWORD lread(int fh, void far *pv, DWORD ul)
516 {
517 DWORD ulT = ul;
518 #if defined(WINNT) || defined(__WIN32__) || defined(__WIN32__)
519 BYTE *hp = (BYTE *) pv;
520 #else
521 BYTE huge *hp = (BYTE huge *) pv;
522 #endif
523 while (ul > (DWORD) MAXREAD) {
524 if (_lread(fh, (LPSTR) hp, (WORD) MAXREAD) != MAXREAD)
525 return 0;
526 ul -= MAXREAD;
527 hp += MAXREAD;
528 }
529 if (_lread(fh, (LPSTR) hp, (WXUINT) ul) != (WXUINT) ul)
530 return 0;
531 return ulT;
532 }
533
534 /*
535 * FUNCTION : lwrite(int fh, VOID FAR *pv, DWORD ul)
536 * PURPOSE : Writes data in steps of 32k till all the data is written.
537 * RETURNS : 0 - If write did not proceed correctly.
538 * number of bytes written otherwise.
539 */
540
541 static DWORD lwrite(int fh, VOID FAR *pv, DWORD ul)
542 {
543 DWORD ulT = ul;
544 #if defined(WINNT) || defined(__WIN32__) || defined(__WIN32__)
545 BYTE *hp = (BYTE *) pv;
546 #else
547 BYTE huge *hp = (BYTE huge *) pv;
548 #endif
549 while (ul > MAXREAD) {
550 if (_lwrite(fh, (LPSTR) hp, (WORD) MAXREAD) != MAXREAD)
551 return 0;
552 ul -= MAXREAD;
553 hp += MAXREAD;
554 }
555 if (_lwrite(fh, (LPSTR) hp, (WXUINT) ul) != (WXUINT) ul)
556 return 0;
557 return ulT;
558 }
559
560 /*
561 * FUNCTION : wxReadDIB(hWnd)
562 * PURPOSE : Reads a DIB from a file, obtains a handle to its
563 * BITMAPINFO struct. and loads the DIB. Once the DIB
564 * is loaded, the function also creates a bitmap and
565 * palette out of the DIB for a device-dependent form.
566 * RETURNS : TRUE - DIB loaded and bitmap/palette created
567 * The DIBINIT structure pointed to by pInfo is
568 * filled with the appropriate handles.
569 * FALSE - otherwise
570 */
571
572 bool wxReadDIB(LPTSTR lpFileName, HBITMAP *bitmap, HPALETTE *palette)
573 {
574 int fh;
575 LPBITMAPINFOHEADER lpbi;
576 OFSTRUCT of;
577 BITMAPFILEHEADER bf;
578 WORD nNumColors;
579 bool result = FALSE;
580 WORD offBits;
581 HDC hDC;
582 bool bCoreHead = FALSE;
583 HANDLE hDIB = 0;
584
585 /* Open the file and get a handle to it's BITMAPINFO */
586
587 fh = OpenFile (wxConvertWX2MB(lpFileName), &of, OF_READ);
588 if (fh == -1) {
589 wxLogError(_("Can't open file '%s'"), lpFileName);
590 return (0);
591 }
592
593 hDIB = GlobalAlloc(GHND, (DWORD)(sizeof(BITMAPINFOHEADER) +
594 256 * sizeof(RGBQUAD)));
595 if (!hDIB)
596 return(0);
597
598 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
599
600 /* read the BITMAPFILEHEADER */
601 if (sizeof (bf) != _lread (fh, (LPSTR)&bf, sizeof (bf)))
602 goto ErrExit;
603
604 if (bf.bfType != 0x4d42) /* 'BM' */
605 goto ErrExit;
606
607 if (sizeof(BITMAPCOREHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPCOREHEADER)))
608 goto ErrExit;
609
610 if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
611 {
612 lpbi->biSize = sizeof(BITMAPINFOHEADER);
613 lpbi->biBitCount = ((LPBITMAPCOREHEADER)lpbi)->bcBitCount;
614 lpbi->biPlanes = ((LPBITMAPCOREHEADER)lpbi)->bcPlanes;
615 lpbi->biHeight = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
616 lpbi->biWidth = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
617 bCoreHead = TRUE;
618 }
619 else
620 {
621 // get to the start of the header and read INFOHEADER
622 _llseek(fh,sizeof(BITMAPFILEHEADER),SEEK_SET);
623 if (sizeof(BITMAPINFOHEADER) != _lread (fh, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER)))
624 goto ErrExit;
625 }
626
627 nNumColors = (WORD)lpbi->biClrUsed;
628 if ( nNumColors == 0 )
629 {
630 /* no color table for 24-bit, default size otherwise */
631 if (lpbi->biBitCount != 24)
632 nNumColors = 1 << lpbi->biBitCount; /* standard size table */
633 }
634
635 /* fill in some default values if they are zero */
636 if (lpbi->biClrUsed == 0)
637 lpbi->biClrUsed = nNumColors;
638
639 if (lpbi->biSizeImage == 0)
640 {
641 lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 31) & ~31) >> 3)
642 * lpbi->biHeight;
643 }
644
645 /* get a proper-sized buffer for header, color table and bits */
646 GlobalUnlock(hDIB);
647 hDIB = GlobalReAlloc(hDIB, lpbi->biSize +
648 nNumColors * sizeof(RGBQUAD) +
649 lpbi->biSizeImage, 0);
650 if (!hDIB) /* can't resize buffer for loading */
651 goto ErrExit2;
652
653 lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB);
654
655 /* read the color table */
656 if (!bCoreHead)
657 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBQUAD));
658 else
659 {
660 signed int i;
661 RGBQUAD FAR *pQuad;
662 RGBTRIPLE FAR *pTriple;
663
664 _lread(fh, (LPSTR)(lpbi) + lpbi->biSize, nNumColors * sizeof(RGBTRIPLE));
665
666 pQuad = (RGBQUAD FAR *)((LPSTR)lpbi + lpbi->biSize);
667 pTriple = (RGBTRIPLE FAR *) pQuad;
668 for (i = nNumColors - 1; i >= 0; i--)
669 {
670 pQuad[i].rgbRed = pTriple[i].rgbtRed;
671 pQuad[i].rgbBlue = pTriple[i].rgbtBlue;
672 pQuad[i].rgbGreen = pTriple[i].rgbtGreen;
673 pQuad[i].rgbReserved = 0;
674 }
675 }
676
677 /* offset to the bits from start of DIB header */
678 offBits = (WORD)(lpbi->biSize + nNumColors * sizeof(RGBQUAD));
679
680 if (bf.bfOffBits != 0L)
681 {
682 _llseek(fh,bf.bfOffBits,SEEK_SET);
683 }
684
685 if (lpbi->biSizeImage == lread(fh, (LPSTR)lpbi + offBits, lpbi->biSizeImage))
686 {
687 GlobalUnlock(hDIB);
688
689 hDC = GetDC(NULL);
690 if (!wxMakeBitmapAndPalette(hDC, hDIB, palette,
691 bitmap))
692 {
693 ReleaseDC(NULL,hDC);
694 goto ErrExit2;
695 }
696 else
697 {
698 ReleaseDC(NULL,hDC);
699 GlobalFree(hDIB);
700 result = TRUE;
701 }
702 }
703 else
704 {
705 ErrExit:
706 GlobalUnlock(hDIB);
707 ErrExit2:
708 GlobalFree(hDIB);
709 }
710
711 _lclose(fh);
712 return(result);
713 }
714
715 /*
716 * FUNCTION : wxMakeBitmapAndPalette
717 * PURPOSE : Given a DIB, creates a bitmap and corresponding palette
718 * to be used for a device-dependent representation of
719 * of the image.
720 * RETURNS : TRUE --> success. phPal and phBitmap are filled with
721 * appropriate handles. Caller is responsible
722 * for freeing objects.
723 * FALSE --> unable to create objects. both pointer are
724 * not valid
725 */
726
727 static bool wxMakeBitmapAndPalette(HDC hDC, HANDLE hDIB,
728 HPALETTE * phPal, HBITMAP * phBitmap)
729 {
730 LPBITMAPINFOHEADER lpInfo;
731 bool result = FALSE;
732 HBITMAP hBitmap;
733 HPALETTE hPalette, hOldPal;
734 LPSTR lpBits;
735
736 lpInfo = (LPBITMAPINFOHEADER) GlobalLock(hDIB);
737
738 hPalette = wxMakeDIBPalette(lpInfo);
739 if ( hPalette )
740 {
741 // Need to realize palette for converting DIB to bitmap.
742 hOldPal = SelectPalette(hDC, hPalette, TRUE);
743 RealizePalette(hDC);
744
745 lpBits = (LPSTR)lpInfo + (WORD)lpInfo->biSize +
746 (WORD)lpInfo->biClrUsed * sizeof(RGBQUAD);
747 hBitmap = CreateDIBitmap(hDC, lpInfo, CBM_INIT, lpBits,
748 (LPBITMAPINFO)lpInfo, DIB_RGB_COLORS);
749
750 SelectPalette(hDC, hOldPal, TRUE);
751 RealizePalette(hDC);
752
753 if (!hBitmap)
754 DeleteObject(hPalette);
755 else
756 {
757 *phBitmap = hBitmap;
758 *phPal = hPalette;
759 result = TRUE;
760 }
761 }
762
763 GlobalUnlock (hDIB); // glt
764
765 return(result);
766 }
767
768 /*
769 * FUNCTION : wxMakeDIBPalette(lpInfo)
770 * PURPOSE : Given a BITMAPINFOHEADER, create a palette based on
771 * the color table.
772 * RETURNS : non-zero - handle of a corresponding palette
773 * zero - unable to create palette
774 */
775
776 HPALETTE wxMakeDIBPalette(LPBITMAPINFOHEADER lpInfo)
777 {
778 LPLOGPALETTE npPal;
779 RGBQUAD far *lpRGB;
780 HPALETTE hLogPal;
781 WORD i;
782
783 /* since biClrUsed field was filled during the loading of the DIB,
784 * we know it contains the number of colors in the color table.
785 */
786 if (lpInfo->biClrUsed)
787 {
788 npPal = (LPLOGPALETTE)malloc(sizeof(LOGPALETTE) +
789 (WORD)lpInfo->biClrUsed * sizeof(PALETTEENTRY));
790 if (!npPal)
791 return NULL;
792
793 npPal->palVersion = 0x300;
794 npPal->palNumEntries = (WORD)lpInfo->biClrUsed;
795
796 /* get pointer to the color table */
797 lpRGB = (RGBQUAD FAR *)((LPSTR)lpInfo + lpInfo->biSize);
798
799 /* copy colors from the color table to the LogPalette structure */
800 for (i = 0; (DWORD)i < lpInfo->biClrUsed; i++, lpRGB++)
801 {
802 npPal->palPalEntry[i].peRed = lpRGB->rgbRed;
803 npPal->palPalEntry[i].peGreen = lpRGB->rgbGreen;
804 npPal->palPalEntry[i].peBlue = lpRGB->rgbBlue;
805 npPal->palPalEntry[i].peFlags = 0;
806 }
807
808 hLogPal = CreatePalette((LPLOGPALETTE)npPal);
809 free(npPal);
810
811 return(hLogPal);
812 }
813
814 /* 24-bit DIB with no color table. Return default palette. Another
815 * option would be to create a 256 color "rainbow" palette to provide
816 * some good color choices.
817 */
818 else
819 return((HPALETTE) GetStockObject(DEFAULT_PALETTE));
820 }
821
822 /*
823 *
824 * Function: InitBitmapInfoHeader
825 *
826 * Purpose: Does a "standard" initialization of a BITMAPINFOHEADER,
827 * given the Width, Height, and Bits per Pixel for the
828 * DIB.
829 *
830 * By standard, I mean that all the relevant fields are set
831 * to the specified values. biSizeImage is computed, the
832 * biCompression field is set to "no compression," and all
833 * other fields are 0.
834 *
835 * Note that DIBs only allow BitsPixel values of 1, 4, 8, or
836 * 24. This routine makes sure that one of these values is
837 * used (whichever is most appropriate for the specified
838 * nBPP).
839 *
840 * Parms: lpBmInfoHdr == Far pointer to a BITMAPINFOHEADER structure
841 * to be filled in.
842 * dwWidth == Width of DIB (not in Win 3.0 & 3.1, high
843 * word MUST be 0).
844 * dwHeight == Height of DIB (not in Win 3.0 & 3.1, high
845 * word MUST be 0).
846 * nBPP == Bits per Pixel for the DIB.
847 *
848 */
849
850 static void InitBitmapInfoHeader (LPBITMAPINFOHEADER lpBmInfoHdr,
851 DWORD dwWidth,
852 DWORD dwHeight,
853 int nBPP)
854 {
855 // _fmemset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
856 memset (lpBmInfoHdr, 0, sizeof (BITMAPINFOHEADER));
857
858 lpBmInfoHdr->biSize = sizeof (BITMAPINFOHEADER);
859 lpBmInfoHdr->biWidth = dwWidth;
860 lpBmInfoHdr->biHeight = dwHeight;
861 lpBmInfoHdr->biPlanes = 1;
862
863 if (nBPP <= 1)
864 nBPP = 1;
865 else if (nBPP <= 4)
866 nBPP = 4;
867 else if (nBPP <= 8)
868 nBPP = 8;
869 /* Doesn't work
870 else if (nBPP <= 16)
871 nBPP = 16;
872 */
873 else
874 nBPP = 24;
875
876 lpBmInfoHdr->biBitCount = nBPP;
877 lpBmInfoHdr->biSizeImage = WIDTHBYTES (dwWidth * nBPP) * dwHeight;
878 }
879
880 LPSTR wxFindDIBBits (LPSTR lpbi)
881 {
882 return (lpbi + *(LPDWORD)lpbi + wxPaletteSize (lpbi));
883 }
884
885 /*
886 * Function: BitmapToDIB
887 *
888 * Purpose: Given a device dependent bitmap and a palette, returns
889 * a handle to global memory with a DIB spec in it. The
890 * DIB is rendered using the colors of the palette passed in.
891 *
892 * Parms: hBitmap == Handle to device dependent bitmap compatible
893 * with default screen display device.
894 * hPal == Palette to render the DDB with. If it's NULL,
895 * use the default palette.
896 */
897
898 HANDLE wxBitmapToDIB (HBITMAP hBitmap, HPALETTE hPal)
899 {
900 BITMAP Bitmap;
901 BITMAPINFOHEADER bmInfoHdr;
902 LPBITMAPINFOHEADER lpbmInfoHdr;
903 LPSTR lpBits;
904 HDC hMemDC;
905 HANDLE hDIB;
906 HPALETTE hOldPal = NULL;
907
908 // Do some setup -- make sure the Bitmap passed in is valid,
909 // get info on the bitmap (like its height, width, etc.),
910 // then setup a BITMAPINFOHEADER.
911
912 if (!hBitmap)
913 return NULL;
914
915 if (!GetObject (hBitmap, sizeof (Bitmap), (LPSTR) &Bitmap))
916 return NULL;
917
918 InitBitmapInfoHeader (&bmInfoHdr,
919 Bitmap.bmWidth,
920 Bitmap.bmHeight,
921 Bitmap.bmPlanes * Bitmap.bmBitsPixel);
922
923 // Now allocate memory for the DIB. Then, set the BITMAPINFOHEADER
924 // into this memory, and find out where the bitmap bits go.
925
926 hDIB = GlobalAlloc (GHND, sizeof (BITMAPINFOHEADER) +
927 wxPaletteSize ((LPSTR) &bmInfoHdr) + bmInfoHdr.biSizeImage);
928
929 if (!hDIB)
930 return NULL;
931
932 lpbmInfoHdr = (LPBITMAPINFOHEADER) GlobalLock (hDIB);
933
934 *lpbmInfoHdr = bmInfoHdr;
935 lpBits = wxFindDIBBits ((LPSTR) lpbmInfoHdr);
936
937
938 // Now, we need a DC to hold our bitmap. If the app passed us
939 // a palette, it should be selected into the DC.
940
941 hMemDC = GetDC (NULL);
942
943 if (hPal)
944 {
945 hOldPal = SelectPalette (hMemDC, hPal, FALSE);
946 RealizePalette (hMemDC);
947 }
948
949 // We're finally ready to get the DIB. Call the driver and let
950 // it party on our bitmap. It will fill in the color table,
951 // and bitmap bits of our global memory block.
952
953 if (!GetDIBits (hMemDC, hBitmap, 0, Bitmap.bmHeight, lpBits,
954 (LPBITMAPINFO) lpbmInfoHdr, DIB_RGB_COLORS))
955 {
956 GlobalUnlock (hDIB);
957 GlobalFree (hDIB);
958 hDIB = NULL;
959 }
960 else
961 GlobalUnlock (hDIB);
962
963 // Finally, clean up and return.
964
965 if (hOldPal)
966 SelectPalette (hMemDC, hOldPal, FALSE);
967
968 ReleaseDC (NULL, hMemDC);
969
970 return hDIB;
971 }
972
973 bool wxSaveBitmap(wxChar *filename, wxBitmap *bitmap, wxPalette *palette)
974 {
975 HPALETTE hPalette = 0;
976 #if wxUSE_PALETTE
977 if (palette)
978 hPalette = (HPALETTE) palette->GetHPALETTE();
979 #endif // wxUSE_PALETTE
980
981 HANDLE dibHandle = wxBitmapToDIB((HBITMAP) bitmap->GetHBITMAP(), hPalette);
982 if (dibHandle)
983 {
984 bool success = (wxWriteDIB(filename, dibHandle) != 0);
985 GlobalFree(dibHandle);
986 return success;
987 }
988 else return FALSE;
989 }
990