1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/dfb/bitmap.cpp
3 // Purpose: wxBitmap implementation
4 // Author: Vaclav Slavik
7 // Copyright: (c) 2006 REA Elektronik GmbH
8 // Licence: wxWindows licence
9 /////////////////////////////////////////////////////////////////////////////
11 // For compilers that support precompilation, includes "wx.h".
12 #include "wx/wxprec.h"
23 #include "wx/bitmap.h"
24 #include "wx/colour.h"
26 #include "wx/rawbmp.h"
28 #include "wx/dfb/private.h"
30 //-----------------------------------------------------------------------------
31 // helpers for translating between wx and DFB pixel formats
32 //-----------------------------------------------------------------------------
37 // NB: Most of this conversion code is needed because of differences between
38 // wxImage and wxDFB's wxBitmap representations:
39 // (1) wxImage uses RGB order, while DirectFB uses BGR
40 // (2) wxImage has alpha channel in a separate plane, while DirectFB puts
41 // all components into single BGRA plane
43 // pitch = stride = # of bytes between the start of N-th line and (N+1)-th line
44 // {Src,Dst}PixSize = # of bytes used to represent one pixel
45 template<int SrcPixSize
, int DstPixSize
>
46 void CopyPixelsAndSwapRGB(unsigned w
, unsigned h
,
47 const unsigned char *src
,
52 unsigned src_advance
= src_pitch
- SrcPixSize
* w
;
53 unsigned dst_advance
= dst_pitch
- DstPixSize
* w
;
54 for ( unsigned y
= 0; y
< h
; y
++, src
+= src_advance
, dst
+= dst_advance
)
56 for ( unsigned x
= 0; x
< w
; x
++, src
+= SrcPixSize
, dst
+= DstPixSize
)
58 // copy with RGB -> BGR translation:
66 void CopySurfaceToImage(const wxIDirectFBSurfacePtr
& surface
, wxImage
& image
)
68 wxIDirectFBSurface::Locked
locked(surface
, DSLF_READ
);
69 wxCHECK_RET( locked
.ptr
, "failed to lock surface" );
71 const unsigned width
= image
.GetWidth();
72 const unsigned height
= image
.GetHeight();
73 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
75 // copy RGB data from the surface:
79 CopyPixelsAndSwapRGB
<3,3>
82 (unsigned char*)locked
.ptr
, locked
.pitch
,
83 image
.GetData(), width
* 3
89 CopyPixelsAndSwapRGB
<4,3>
92 (unsigned char*)locked
.ptr
, locked
.pitch
,
93 image
.GetData(), width
* 3
98 wxFAIL_MSG( "unexpected pixel format" );
102 // extract alpha channel if the bitmap has it:
103 if ( format
== DSPF_ARGB
)
105 // create alpha plane:
108 // and copy alpha data to it:
109 const unsigned advance
= locked
.pitch
- 4 * width
;
110 unsigned char *alpha
= image
.GetAlpha();
111 // NB: "+3" is to get pointer to alpha component
112 const unsigned char *src
= ((unsigned char*)locked
.ptr
) + 3;
114 for ( unsigned y
= 0; y
< height
; y
++, src
+= advance
)
115 for ( unsigned x
= 0; x
< width
; x
++, src
+= 4 )
120 void CopyImageToSurface(const wxImage
& image
,
121 const wxIDirectFBSurfacePtr
& surface
)
123 wxIDirectFBSurface::Locked
locked(surface
, DSLF_WRITE
);
124 wxCHECK_RET( locked
.ptr
, "failed to lock surface" );
126 const unsigned width
= image
.GetWidth();
127 const unsigned height
= image
.GetHeight();
128 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
130 // copy RGB data to the surface:
134 CopyPixelsAndSwapRGB
<3,3>
137 image
.GetData(), width
* 3,
138 (unsigned char*)locked
.ptr
, locked
.pitch
144 CopyPixelsAndSwapRGB
<3,4>
147 image
.GetData(), width
* 3,
148 (unsigned char*)locked
.ptr
, locked
.pitch
153 wxFAIL_MSG( "unexpected pixel format" );
157 // if the image has alpha channel, merge it in:
158 if ( format
== DSPF_ARGB
)
160 wxCHECK_RET( image
.HasAlpha(), "logic error - ARGB, but no alpha" );
162 const unsigned advance
= locked
.pitch
- 4 * width
;
163 const unsigned char *alpha
= image
.GetAlpha();
164 // NB: "+3" is to get pointer to alpha component
165 unsigned char *dest
= ((unsigned char*)locked
.ptr
) + 3;
167 for ( unsigned y
= 0; y
< height
; y
++, dest
+= advance
)
168 for ( unsigned x
= 0; x
< width
; x
++, dest
+= 4 )
173 wxIDirectFBSurfacePtr
174 CreateSurfaceWithFormat(int w
, int h
, DFBSurfacePixelFormat format
)
176 DFBSurfaceDescription desc
;
177 desc
.flags
= (DFBSurfaceDescriptionFlags
)
178 (DSDESC_CAPS
| DSDESC_WIDTH
| DSDESC_HEIGHT
);
179 desc
.caps
= DSCAPS_NONE
;
183 if ( format
!= DSPF_UNKNOWN
)
185 desc
.flags
= (DFBSurfaceDescriptionFlags
)(
186 desc
.flags
| DSDESC_PIXELFORMAT
);
187 desc
.pixelformat
= format
;
190 return wxIDirectFB::Get()->CreateSurface(&desc
);
193 // Creates a surface that will use wxImage's pixel data (RGB only)
194 wxIDirectFBSurfacePtr
CreateSurfaceForImage(const wxImage
& image
)
196 wxCHECK_MSG( image
.Ok(), NULL
, "invalid image" );
197 // FIXME_DFB: implement alpha handling by merging alpha buffer with RGB
198 // into a temporary RGBA surface
199 wxCHECK_MSG( !image
.HasAlpha(), NULL
, "alpha channel not supported" );
201 // NB: wxImage uses RGB order of bytes while DirectFB uses BGR, so we
202 // cannot use preallocated surface that shares data with wxImage, we
203 // have to copy the data to temporary surface instead
204 return CreateSurfaceWithFormat(image
.GetWidth(), image
.GetHeight(),
208 bool ConvertSurfaceToFormat(wxIDirectFBSurfacePtr
& surface
,
209 DFBSurfacePixelFormat format
)
211 if ( surface
->GetPixelFormat() == format
)
215 surface
->GetSize(&w
, &h
);
216 wxIDirectFBSurfacePtr s
= CreateSurfaceWithFormat(w
, h
, format
);
220 if ( !s
->SetBlittingFlags(DSBLIT_NOFX
) )
222 if ( !s
->Blit(surface
->GetRaw(), NULL
, 0, 0) )
229 DFBSurfacePixelFormat
DepthToFormat(int depth
)
236 // NB: we treat depth=32 as requesting ARGB for consistency with
240 wxFAIL_MSG( "unsupported depth requested" );
247 // ----------------------------------------------------------------------------
248 // monochrome bitmap functions
249 // ----------------------------------------------------------------------------
251 // this function works with destination buffer of type T and not char (where T
252 // is typically wxUint32 for RGB32, wxUint16 for RGB16 &c) as we don't need
253 // access to the individual pixel components -- and so it's not suitable for
254 // the pixel formats with pixel size not equal to 8, 16 or 32
255 template <typename T
, int White
, int Black
>
259 const unsigned char *src
,
260 const wxIDirectFBSurface::Locked locked
)
262 static const int BITS_PER_BYTE
= 8;
264 // extra padding to add to dst at the end of each row: this works on the
265 // assumption that all rows are aligned at multiples of T (and usually 4
266 // bytes) boundary so check for it (and change the code if this assert is
268 wxASSERT_MSG( !(locked
.pitch
% sizeof(T
)), "image rows not aligned?" );
269 const int padDst
= (locked
.pitch
- width
*sizeof(T
))/sizeof(T
);
271 int x
= 0; // position in the current bitmap row
273 // a single char in src corresponds to 8 destination pixels and the last
274 // char in the row contains padding if necessary, i.e. there is always an
275 // integer number of chars per row
276 const unsigned char * const
277 srcEnd
= src
+ ((width
+ BITS_PER_BYTE
- 1)/BITS_PER_BYTE
)*height
;
279 // we operate with sizeof(T), not 1, bytes at once
280 T
*dst
= static_cast<T
*>(locked
.ptr
);
281 while ( src
< srcEnd
)
283 unsigned char val
= *src
++;
285 for ( int bit
= 0; bit
< BITS_PER_BYTE
; bit
++ )
287 *dst
++ = val
& 1 ? White
: Black
;
300 CopyBitsToSurface(const unsigned char *bits
,
303 wxIDirectFBSurfacePtr
& surface
)
305 wxIDirectFBSurface::Locked
locked(surface
, DSLF_WRITE
);
306 wxCHECK_MSG( locked
.ptr
, false, "failed to lock surface" );
308 const DFBSurfacePixelFormat format
= surface
->GetPixelFormat();
313 // we suppose that these indices correspond to the palette entries
314 // for white and black, respectively, but a better idea would be to
315 // use IDirectFBPalette::FindBestMatch() to determine them
316 CopyBits
<wxUint8
, 0xff, 0>(width
, height
, bits
, locked
);
320 CopyBits
<wxUint16
, 0xffff, 0>(width
, height
, bits
, locked
);
324 CopyBits
<wxUint32
, 0xffffffff, 0>(width
, height
, bits
, locked
);
328 // we don't really have time to implement efficient support for all
329 // the other formats so simply (and awfully slowly, of course...)
330 // convert everything else from RGB32
331 surface
= CreateSurfaceWithFormat(width
, height
, DSPF_RGB32
);
335 if ( !CopyBitsToSurface(bits
, width
, height
, surface
) )
338 if ( !ConvertSurfaceToFormat(surface
, format
) )
345 } // anonymous namespace
347 //-----------------------------------------------------------------------------
349 //-----------------------------------------------------------------------------
351 class wxBitmapRefData
: public wxGDIRefData
362 wxBitmapRefData(const wxBitmapRefData
& data
)
364 m_surface
= data
.m_surface
? data
.m_surface
->Clone() : NULL
;
366 m_mask
= data
.m_mask
? new wxMask(*data
.m_mask
) : NULL
;
368 m_palette
= data
.m_palette
? new wxPalette(*data
.m_palette
) : NULL
;
372 virtual ~wxBitmapRefData()
380 virtual bool IsOk() const { return m_surface
; }
382 wxIDirectFBSurfacePtr m_surface
;
385 wxPalette
*m_palette
;
389 #define M_BITMAP ((wxBitmapRefData *)m_refData)
391 //-----------------------------------------------------------------------------
393 //-----------------------------------------------------------------------------
395 IMPLEMENT_DYNAMIC_CLASS(wxBitmap
, wxBitmapBase
)
397 wxBitmap::wxBitmap(int width
, int height
, int depth
)
399 Create(width
, height
, depth
);
402 bool wxBitmap::Create(const wxIDirectFBSurfacePtr
& surface
)
406 wxCHECK_MSG( surface
, false, "invalid surface" );
408 m_refData
= new wxBitmapRefData();
409 M_BITMAP
->m_surface
= surface
;
413 bool wxBitmap::Create(int width
, int height
, int depth
)
415 return CreateWithFormat(width
, height
, DepthToFormat(depth
));
418 bool wxBitmap::CreateWithFormat(int width
, int height
, int dfbFormat
)
422 wxCHECK_MSG( width
> 0 && height
> 0, false, wxT("invalid bitmap size") );
424 return Create(CreateSurfaceWithFormat(width
, height
,
425 DFBSurfacePixelFormat(dfbFormat
)));
429 wxBitmap::wxBitmap(const wxImage
& imageOrig
, int depth
)
431 wxCHECK_RET( imageOrig
.Ok(), wxT("invalid image") );
433 wxImage
image(imageOrig
);
435 // convert mask to alpha channel, because wxMask isn't implemented yet
436 // FIXME: don't do this, implement proper wxMask support
437 if ( image
.HasMask() )
440 DFBSurfacePixelFormat format
= DepthToFormat(depth
);
441 if ( format
== DSPF_UNKNOWN
&& image
.HasAlpha() )
444 // create surface in screen's format (unless we need alpha channel,
445 // in which case use ARGB):
446 if ( !CreateWithFormat(image
.GetWidth(), image
.GetHeight(), format
) )
449 // then copy the image to it:
450 wxIDirectFBSurfacePtr dst
= M_BITMAP
->m_surface
;
452 switch ( dst
->GetPixelFormat() )
457 CopyImageToSurface(image
, dst
);
462 // wxBitmap uses different pixel format, so we have to use a
463 // temporary surface and blit to the bitmap via it:
464 wxIDirectFBSurfacePtr
src(CreateSurfaceForImage(image
));
465 CopyImageToSurface(image
, src
);
467 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
469 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
475 wxImage
wxBitmap::ConvertToImage() const
477 wxCHECK_MSG( Ok(), wxNullImage
, wxT("invalid bitmap") );
479 wxImage
img(GetWidth(), GetHeight());
480 wxIDirectFBSurfacePtr src
= M_BITMAP
->m_surface
;
482 switch ( src
->GetPixelFormat() )
487 CopySurfaceToImage(src
, img
);
491 // wxBitmap uses different pixel format, so we have to use a
492 // temporary surface and blit to the bitmap via it:
493 wxIDirectFBSurfacePtr
dst(CreateSurfaceForImage(img
));
495 if ( !dst
->SetBlittingFlags(DSBLIT_NOFX
) )
497 if ( !dst
->Blit(src
->GetRaw(), NULL
, 0, 0) )
500 CopySurfaceToImage(dst
, img
);
504 // FIXME: implement mask setting in the image
505 wxASSERT_MSG( GetMask() == NULL
, "bitmap masks are ignored for now" );
509 #endif // wxUSE_IMAGE
511 void *wxBitmap::GetRawData(wxPixelDataBase
& data
, int bpp
)
513 wxCHECK_MSG( Ok(), NULL
, "invalid bitmap" );
517 DFBSurfacePixelFormat format
;
523 // convert the bitmap into format compatible with requested raw access;
524 // note that we don't bother converting the bitmap back in UngetRawData(),
525 // as unpacked formats (RGB24, RGB32) are the common case and converting
526 // between them while blitting is fast enough (FIXME?)
527 if ( !ConvertSurfaceToFormat(M_BITMAP
->m_surface
, format
) )
531 if ( !M_BITMAP
->m_surface
->Lock
533 (DFBSurfaceLockFlags
)(DSLF_READ
| DSLF_WRITE
),
539 M_BITMAP
->m_surface
->GetSize(&data
.m_width
, &data
.m_height
);
544 void wxBitmap::UngetRawData(wxPixelDataBase
& WXUNUSED(data
))
546 M_BITMAP
->m_surface
->Unlock();
549 bool wxBitmap::HasAlpha() const
551 wxCHECK_MSG( Ok(), false, "invalid bitmap" );
553 return M_BITMAP
->m_surface
->GetPixelFormat() == DSPF_ARGB
;
556 wxBitmap::wxBitmap(const wxString
&filename
, wxBitmapType type
)
558 LoadFile(filename
, type
);
561 wxBitmap::wxBitmap(const char bits
[], int width
, int height
, int depth
)
563 wxCHECK_RET( depth
== 1, wxT("can only create mono bitmap from XBM data") );
565 // create bitmap in the device-dependent format
566 if ( !CreateWithFormat(width
, height
, DSPF_UNKNOWN
) )
569 if ( !CopyBitsToSurface((const unsigned char *)bits
,
570 width
, height
, M_BITMAP
->m_surface
) )
574 int wxBitmap::GetHeight() const
576 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
579 M_BITMAP
->m_surface
->GetSize(NULL
, &h
);
583 int wxBitmap::GetWidth() const
585 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
588 M_BITMAP
->m_surface
->GetSize(&w
, NULL
);
592 int wxBitmap::GetDepth() const
594 wxCHECK_MSG( Ok(), -1, wxT("invalid bitmap") );
596 return M_BITMAP
->m_surface
->GetDepth();
599 wxMask
*wxBitmap::GetMask() const
601 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
603 return M_BITMAP
->m_mask
;
606 void wxBitmap::SetMask(wxMask
*mask
)
608 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
611 delete M_BITMAP
->m_mask
;
612 M_BITMAP
->m_mask
= mask
;
615 bool wxBitmap::CopyFromIcon(const wxIcon
& icon
)
617 *this = *((wxBitmap
*)(&icon
));
621 wxBitmap
wxBitmap::GetSubBitmap(const wxRect
& rect
) const
624 rect
.x
>= 0 && rect
.y
>= 0 &&
625 rect
.x
+rect
.width
<= GetWidth() &&
626 rect
.y
+rect
.height
<= GetHeight(),
628 wxT("invalid bitmap or bitmap region") );
630 // NB: DirectFB subsurfaces share the same pixels buffer, so we must
631 // clone the obtained subsurface
632 DFBRectangle r
= { rect
.x
, rect
.y
, rect
.width
, rect
.height
};
633 return wxBitmap(M_BITMAP
->m_surface
->GetSubSurface(&r
)->Clone());
636 #warning "to common code"
637 bool wxBitmap::LoadFile(const wxString
&name
, wxBitmapType type
)
641 wxBitmapHandler
*handler
= FindHandler(type
);
643 if ( handler
== NULL
)
646 if ( !image
.LoadFile(name
, type
) || !image
.Ok() )
648 wxLogError(_("No bitmap handler for type %d defined."), type
);
653 *this = wxBitmap(image
);
658 m_refData
= new wxBitmapRefData();
660 return handler
->LoadFile(this, name
, type
, -1, -1);
663 #warning "to common code"
664 bool wxBitmap::SaveFile(const wxString
& filename
, wxBitmapType type
, const wxPalette
*palette
) const
666 wxCHECK_MSG( Ok(), false, wxT("invalid bitmap") );
668 wxBitmapHandler
*handler
= FindHandler(type
);
670 if ( handler
== NULL
)
672 wxImage image
= ConvertToImage();
675 image
.SetPalette(*palette
);
676 #endif // wxUSE_PALETTE
679 return image
.SaveFile(filename
, type
);
682 wxLogError(_("No bitmap handler for type %d defined."), type
);
687 return handler
->SaveFile(this, filename
, type
, palette
);
691 wxPalette
*wxBitmap::GetPalette() const
693 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
695 return M_BITMAP
->m_palette
;
698 void wxBitmap::SetPalette(const wxPalette
& palette
)
700 wxCHECK_RET( Ok(), wxT("invalid bitmap") );
701 wxCHECK_RET( GetDepth() > 1 && GetDepth() <= 8, wxT("cannot set palette for bitmap of this depth") );
704 delete M_BITMAP
->m_palette
;
705 M_BITMAP
->m_palette
= NULL
;
707 if ( !palette
.Ok() ) return;
709 M_BITMAP
->m_palette
= new wxPalette(palette
);
711 #endif // wxUSE_PALETTE
713 void wxBitmap::SetHeight(int height
)
717 wxFAIL_MSG( "SetHeight not implemented" );
720 void wxBitmap::SetWidth(int width
)
724 wxFAIL_MSG( "SetWidth not implemented" );
727 void wxBitmap::SetDepth(int depth
)
729 DFBSurfacePixelFormat format
= DepthToFormat(depth
);
730 if ( M_BITMAP
->m_surface
->GetPixelFormat() == format
)
736 M_BITMAP
->m_surface
->GetSize(&w
, &h
);
737 wxIDirectFBSurfacePtr s
= CreateSurfaceWithFormat(w
, h
, format
);
740 if ( !s
->SetBlittingFlags(DSBLIT_NOFX
) )
742 if ( !s
->Blit(M_BITMAP
->m_surface
->GetRaw(), NULL
, 0, 0) )
745 M_BITMAP
->m_surface
= s
;
748 wxIDirectFBSurfacePtr
wxBitmap::GetDirectFBSurface() const
750 wxCHECK_MSG( Ok(), NULL
, wxT("invalid bitmap") );
752 return M_BITMAP
->m_surface
;
755 wxGDIRefData
*wxBitmap::CreateGDIRefData() const
757 return new wxBitmapRefData
;
760 wxGDIRefData
*wxBitmap::CloneGDIRefData(const wxGDIRefData
*data
) const
762 return new wxBitmapRefData(*(wxBitmapRefData
*)data
);
767 void wxBitmap::InitStandardHandlers()
769 // not wxBitmap handlers, we rely on wxImage