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