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