From b9bcaf117a45df3088e6cfad17941585dcbef3a5 Mon Sep 17 00:00:00 2001 From: Vadim Zeitlin Date: Mon, 28 Apr 2003 01:46:05 +0000 Subject: [PATCH] new template-based more flexible and hopefully more efficient raw bitmap implementation git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@20363 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775 --- include/wx/msw/bitmap.h | 6 +- include/wx/rawbmp.h | 632 ++++++++++++++++++++++++++++++---------- src/msw/bitmap.cpp | 105 ++++--- src/msw/dc.cpp | 16 +- 4 files changed, 556 insertions(+), 203 deletions(-) diff --git a/include/wx/msw/bitmap.h b/include/wx/msw/bitmap.h index 75efef8d65..c545d275ec 100644 --- a/include/wx/msw/bitmap.h +++ b/include/wx/msw/bitmap.h @@ -31,7 +31,7 @@ class WXDLLEXPORT wxIcon; class WXDLLEXPORT wxImage; class WXDLLEXPORT wxMask; class WXDLLEXPORT wxPalette; -class WXDLLEXPORT wxRawBitmapData; +class WXDLLEXPORT wxPixelDataBase; // ---------------------------------------------------------------------------- // wxBitmap: a mono or colour bitmap @@ -132,8 +132,8 @@ public: { return (wxBitmapRefData *)m_refData; } // raw bitmap access support functions - bool GetRawData(wxRawBitmapData *data); - void UngetRawData(wxRawBitmapData *); + void *GetRawData(wxPixelDataBase& data, int bpp); + void UngetRawData(wxPixelDataBase& data); #if wxUSE_PALETTE wxPalette* GetPalette() const; diff --git a/include/wx/rawbmp.h b/include/wx/rawbmp.h index 4edd08843c..7967318a03 100644 --- a/include/wx/rawbmp.h +++ b/include/wx/rawbmp.h @@ -32,28 +32,30 @@ /* Usage example: + typedef wxPixelData PixelData; + wxBitmap bmp; - wxRawBitmapData data(bitmap); + PixelData data(bmp); if ( !data ) { ... raw access to bitmap data unavailable, do something else ... return; } - if ( data.m_width < 20 || data.m_height < 20 ) + if ( data.GetWidth() < 20 || data.GetHeight() < 20 ) { ... complain: the bitmap it too small ... return; } - wxRawBitmapIterator p(data); + PixelData::Iterator p(data); // we draw a (10, 10)-(20, 20) rect manually using the given r, g, b - p.Offset(10, 10); + p.Offset(data, 10, 10); for ( int y = 0; y < 10; ++y ) { - wxRawBitmapIterator rowStart = p; + PixelData::Iterator rowStart = p; for ( int x = 0; x < 10; ++x, ++p ) { @@ -63,60 +65,131 @@ } p = rowStart; - p.OffsetY(1); + p.OffsetY(data, 1); } */ -// this struct represents a pointer to raw bitmap data -class wxRawBitmapData +#ifdef __VISUALC__ + // VC++ gives an absolutely harmless warning for wxPixelData ctor + #pragma warning(disable: 4355) // 'this' used in initializer list +#endif + +// ---------------------------------------------------------------------------- +// wxPixelFormat +// ---------------------------------------------------------------------------- + +/* + wxPixelFormat is a template class describing the bitmap data format. It + contains the constants describing the format of pixel data, but does not + describe how the entire bitmap is stored (i.e. top-to-bottom, + bottom-to-top, ...). It is also a "traits"-like class, i.e. it only + contains some constants and maybe static methods but nothing more, so it + can be safely used without incurring any overhead as all accesses to it are + done at compile-time. + + Current limitations: we don't support RAGABA and ARAGAB formats supported + by Mac OS X. If there is sufficient interest, these classes could be + extended to deal with them. Neither do we support alpha channel having + different representation from the RGB ones (happens under QNX/Photon I + think), but again this could be achieved with some small extra effort. + + Template parameters are: + - type of a single pixel component + - size of the single pixel in bits + - indices of red, green and blue pixel components inside the pixel + - index of the alpha component or -1 if none + - type which can contain the full pixel value (all channels) + */ +template +struct WXDLLEXPORT wxPixelFormat { -public: - // ctor associates this pointer with a bitmap and locks the bitmap for raw - // access, it will be unlocked only by our dtor and so these objects should - // normally be only created on the stack, i.e. have limited life-time - wxRawBitmapData(wxBitmap bmp) : m_bmp(bmp) - { - if ( !bmp.GetRawData(this) ) - m_pixels = NULL; - } + // iterator over pixels is usually of type "ChannelType *" + typedef Channel ChannelType; + + // the type which may hold the entire pixel value + typedef Pixel PixelType; - // we evaluate to true only if we could get access to bitmap data - // successfully - operator bool() const { return m_pixels != NULL; } + // NB: using static ints initialized inside the class declaration is not + // portable as it doesn't work with VC++ 6, so we must use enums - // dtor unlocks the bitmap - ~wxRawBitmapData() + // size of one pixel in bits + enum { BitsPerPixel = Bpp }; + + // size of one pixel in ChannelType units (usually bytes) + enum { SizePixel = BitsPerPixel / (8 * sizeof(ChannelType)) }; + + // the channels indices inside the pixel + enum { - m_bmp.UngetRawData(this); - } + RED = R, + GREEN = G, + BLUE = B, + ALPHA = A + }; - // call this to indicate that we should use the alpha channel - void UseAlpha() { m_bmp.UseAlpha(); } + // true if we have an alpha channel (together with the other channels, this + // doesn't cover the case of wxImage which stores alpha separately) + enum { HasAlpha = A != -1 }; +}; + +// some "predefined" pixel formats +// ------------------------------- + +// wxImage format is common to all platforms +typedef wxPixelFormat wxImagePixelFormat; + +// the (most common) native bitmap format without alpha support +typedef wxPixelFormat wxNativePixelFormat; + +// the (most common) native format for bitmaps with alpha channel +typedef wxPixelFormat wxAlphaPixelFormat; + +// we also define the (default/best) pixel format for the given class: this is +// used as default value for the pixel format in wxPixelIterator template +template struct wxPixelFormatFor; + +// wxPixelFormatFor is only defined for wxImage, attempt to use it with other +// classes (wxBitmap...) will result in compile errors which is exactly what we +// want +template <> +struct WXDLLEXPORT wxPixelFormatFor +{ + typedef wxImagePixelFormat Format; +}; + +// ---------------------------------------------------------------------------- +// wxPixelData +// ---------------------------------------------------------------------------- - // accessors - unsigned char *GetPixels() const { return m_pixels; } +/* + wxPixelDataBase is just a helper for wxPixelData: it contains things common + to both wxImage and wxBitmap specializations. + */ +class WXDLLEXPORT wxPixelDataBase +{ +public: int GetWidth() const { return m_width; } int GetHeight() const { return m_height; } - int GetByPP() const { return m_bypp; } - int GetBPP() const { return 8*GetByPP(); } int GetRowStride() const { return m_stride; } -// private: -- public because accessed by the macros below but still mustn't be -// used directly - - // the bitmap we're associated with - wxBitmap m_bmp; - - // pointer to the start of the data - unsigned char *m_pixels; +// private: -- see comment in the beginning of the file // the size of the image we address, in pixels int m_width, m_height; - // number of bytes (NOT bits) per pixel, including alpha channel if any - int m_bypp; - // this parameter is the offset of the start of the (N+1)st row from the // Nth one and can be different from m_bypp*width in some cases: // a) the most usual one is to force 32/64 bit alignment of rows @@ -124,139 +197,406 @@ public: // c) finally, it could conceivably be 0 for the images with all // lines being identical int m_stride; -}; - -// this is the type for the iterator over raw bitmap data -class wxRawBitmapIterator -{ -public: - // ctors and such - // -------------- - // we must be associated/initialized with some bitmap data object - wxRawBitmapIterator(const wxRawBitmapData& data) : m_data(&data) +protected: + // ctor is protected because this class is only meant to be used as the + // base class by wxPixelData + wxPixelDataBase() { - m_ptr = m_data->GetPixels(); - } - - // default copy ctor, assignment operator and dtor are ok - - - // navigation - // ---------- - - // move x pixels to the right and y down - // - // note that the rows don't wrap! - void Offset(int x, int y) - { - m_ptr += m_data->GetRowStride()*y + m_data->GetByPP()*x; + m_width = + m_height = + m_stride = 0; } +}; - // move x pixels to the right (again, no row wrapping) - void OffsetX(int x) - { - m_ptr += m_data->GetByPP()*x; - } +/* + wxPixelData represents the entire bitmap data, i.e. unlike + wxPixelFormat (which it uses) it also stores the global bitmap + characteristics such as its size, inter-row separation and so on. + + Because of this it can be used to move the pixel iterators (which don't + have enough information about the bitmap themselves). This may seem a bit + unnatural but must be done in this way to keep the iterator objects as + small as possible for maximum efficiency as otherwise they wouldn't be put + into the CPU registers by the compiler any more. + + Implementation note: we use the standard workaround for lack of partial + template specialization support in VC (both 6 and 7): instead of partly + specializing the class Foo for some T we introduce FooOut and + FooIn nested in it, make Foo equivalent to FooOut::FooIn and + fully specialize FooOut. + + Also note that this class doesn't have any default definition because we + can't really do anything without knowing the exact image class. We do + provide wxPixelDataBase to make it simpler to write new wxPixelData + specializations. + */ - // move y rows to the bottom - void OffsetY(int y) +// we need to define this skeleton template to mollify VC++ +template +struct WXDLLEXPORT wxPixelDataOut +{ + template + class WXDLLEXPORT wxPixelDataIn { - m_ptr += m_data->GetRowStride()*y; - } + public: + class Iterator { }; + }; +}; - // go back to (0, 0) - void Reset() +// wxPixelData specialization for wxImage: this is the simplest case as we +// don't have to care about different pixel formats here +template <> +struct WXDLLEXPORT wxPixelDataOut +{ + // NB: this is a template class even though it doesn't use its template + // parameter because otherwise wxPixelData couldn't compile + template + class WXDLLEXPORT wxPixelDataIn : public wxPixelDataBase { - m_ptr = m_data->GetPixels(); - } + // the type of the class we're working with + typedef wxImage ImageType; - // go to the given position - void MoveTo(int x, int y) - { - Reset(); - Offset(x, y); - } + // the iterator which should be used for working with data in this + // format + class Iterator + { + public: + // the pixel format we use + typedef wxImagePixelFormat PixelFormat; + + // the type of the pixel components + typedef typename PixelFormat::ChannelType ChannelType; + + // the pixel data we're working with + typedef + wxPixelDataOut::wxPixelDataIn PixelData; + + // go back to (0, 0) + void Reset(const PixelData& data) + { + *this = data.GetPixels(); + } + + // creates the iterator pointing to the beginning of data + Iterator(PixelData& data) + { + Reset(data); + } + + // creates the iterator initially pointing to the image origin + Iterator(const wxImage& image) + { + m_pRGB = image.GetData(); + + if ( image.HasAlpha() ) + { + m_pAlpha = image.GetAlpha(); + } + else // alpha is not used at all + { + m_pAlpha = NULL; + } + } + + // true if the iterator is valid + bool IsOk() const { return m_pRGB != NULL; } + + + // navigation + // ---------- + + // advance the iterator to the next pixel, prefix version + Iterator& operator++() + { + m_pRGB += PixelFormat::SizePixel; + if ( m_pAlpha ) + m_pAlpha += PixelFormat::SizePixel; + + return *this; + } + + // postfix (hence less efficient -- don't use unless you must) version + Iterator operator++(int) + { + Iterator p(*this); + ++*this; + return p; + } + + // move x pixels to the right and y down + // + // note that the rows don't wrap! + void Offset(const PixelData& data, int x, int y) + { + m_pRGB += data.GetRowStride()*y + PixelFormat::SizePixel*x; + if ( m_pAlpha ) + m_pAlpha += data.GetWidth() + x; + } + + // move x pixels to the right (again, no row wrapping) + void OffsetX(const PixelData& WXUNUSED(data), int x) + { + m_pRGB += PixelFormat::SizePixel*x; + if ( m_pAlpha ) + m_pAlpha += x; + } + + // move y rows to the bottom + void OffsetY(const PixelData& data, int y) + { + m_pRGB += data.GetRowStride()*y; + if ( m_pAlpha ) + m_pAlpha += data.GetWidth(); + } + + // go to the given position + void MoveTo(const PixelData& data, int x, int y) + { + Reset(data); + Offset(data, x, y); + } + + + // data access + // ----------- + + // access to invidividual colour components + ChannelType& Red() { return m_ptr[PixelFormat::RED]; } + ChannelType& Green() { return m_ptr[PixelFormat::GREEN]; } + ChannelType& Blue() { return m_ptr[PixelFormat::BLUE]; } + ChannelType& Alpha() { return *m_pAlpha; } + + // private: -- see comment in the beginning of the file + + // pointer into RGB buffer + unsigned char *m_pRGB; + + // pointer into alpha buffer or NULL if alpha isn't used + unsigned char *m_pAlpha; + }; + + // initializes us with the data of the given image + wxPixelDataIn(ImageType& image) : m_image(image), m_pixels(image) + { + m_width = image.GetWidth(); + m_height = image.GetHeight(); + m_stride = Iterator::SizePixel * m_width; + } - // same as OffsetX(1) for convenience - wxRawBitmapIterator& operator++() - { - OffsetX(1); - return *this; - } + // we evaluate to true only if we could get access to bitmap data + // successfully + operator bool() const { return m_pixels.IsOk(); } - // postfix (hence less efficient) version - wxRawBitmapIterator operator++(int) - { - wxRawBitmapIterator p(*this); - OffsetX(1); - return p; - } + // get the iterator pointing to the origin + Iterator GetPixels() const { return m_pixels; } - // data access - // ----------- + private: + // the image we're working with + ImageType& m_image; - // DIBs store data in BGR format, i.e. "little endian" RGB - enum - { -#ifdef __WXMSW__ - BLUE, GREEN, RED, -#else // !__WXMSW__ - RED, GREEN, BLUE, -#endif // __WXMSW__/!__WXMSW__ - ALPHA + // the iterator pointing to the image origin + Iterator m_pixels; }; +}; - // access to invidividual colour components - unsigned char& Red() { return m_ptr[RED]; } - unsigned char& Green() { return m_ptr[GREEN]; } - unsigned char& Blue() { return m_ptr[BLUE]; } - unsigned char& Alpha() { return m_ptr[ALPHA]; } - - // address the pixel contents directly - // - // warning: the format is platform dependent - wxUint32& Data() { return *(wxUint32 *)m_ptr; } +// wxPixelData specialization for wxBitmap: here things are more interesting as +// we also have to support different pixel formats +template <> +struct WXDLLEXPORT wxPixelDataOut +{ + template + class WXDLLEXPORT wxPixelDataIn : public wxPixelDataBase + { + public: + // the type of the class we're working with + typedef wxBitmap ImageType; -// private: -- don't access these fields directly, same as as above - unsigned char *m_ptr; + class Iterator + { + public: + // the pixel format we use + typedef Format PixelFormat; + + // the type of the pixel components + typedef typename PixelFormat::ChannelType ChannelType; + + // the pixel data we're working with + typedef wxPixelDataOut::wxPixelDataIn PixelData; + + + // go back to (0, 0) + void Reset(const PixelData& data) + { + *this = data.GetPixels(); + } + + // initializes the iterator to point to the origin of the given pixel + // data + Iterator(PixelData& data) + { + Reset(data); + } + + // initializes the iterator to point to the origin of the given bitmap + Iterator(wxBitmap& bmp, PixelData& data) + { + // using cast here is ugly but it should be safe as GetRawData() + // real return type should be consistent with BitsPerPixel (which + // is in turn defined by ChannelType) and this is the only thing we + // can do without making GetRawData() a template function which is + // undesirable + m_ptr = (ChannelType *) + bmp.GetRawData(data, PixelFormat::BitsPerPixel); + } + + // return true if this iterator is valid + bool IsOk() const { return m_ptr != NULL; } + + + // navigation + // ---------- + + // advance the iterator to the next pixel, prefix version + Iterator& operator++() + { + m_ptr += PixelFormat::SizePixel; + + return *this; + } + + // postfix (hence less efficient -- don't use unless you must) version + Iterator operator++(int) + { + Iterator p(*this); + ++*this; + return p; + } + + // move x pixels to the right and y down + // + // note that the rows don't wrap! + void Offset(const PixelData& data, int x, int y) + { + m_ptr += data.GetRowStride()*y + PixelFormat::SizePixel*x; + } + + // move x pixels to the right (again, no row wrapping) + void OffsetX(const PixelData& WXUNUSED(data), int x) + { + m_ptr += PixelFormat::SizePixel*x; + } + + // move y rows to the bottom + void OffsetY(const PixelData& data, int y) + { + m_ptr += data.GetRowStride()*y; + } + + // go to the given position + void MoveTo(const PixelData& data, int x, int y) + { + Reset(data); + Offset(data, x, y); + } + + + // data access + // ----------- + + // access to invidividual colour components + ChannelType& Red() { return m_ptr[PixelFormat::RED]; } + ChannelType& Green() { return m_ptr[PixelFormat::GREEN]; } + ChannelType& Blue() { return m_ptr[PixelFormat::BLUE]; } + ChannelType& Alpha() { return m_ptr[PixelFormat::ALPHA]; } + + // address the pixel contents directly + // + // warning: the format is platform dependent + typename PixelFormat::PixelType& Data() + { return *(typename PixelFormat::PixelType *)m_ptr; } + + // private: -- see comment in the beginning of the file + + // NB: for efficiency reasons this class must *not* have any other + // fields, otherwise it won't be put into a CPU register (as it + // should inside the inner loops) by some compilers, notably gcc + ChannelType *m_ptr; + }; + + // ctor associates this pointer with a bitmap and locks the bitmap for raw + // access, it will be unlocked only by our dtor and so these objects should + // normally be only created on the stack, i.e. have limited life-time + wxPixelDataIn(wxBitmap bmp) : m_bmp(bmp), m_pixels(bmp, *this) + { + } - const wxRawBitmapData *m_data; -}; + // we evaluate to true only if we could get access to bitmap data + // successfully + operator bool() const { return m_pixels.IsOk(); } + // get the iterator pointing to the origin + Iterator GetPixels() const { return m_pixels; } -// these macros are used to change the current location in the bitmap -// ------------------------------------------------------------------ + // dtor unlocks the bitmap + ~wxPixelDataIn() + { + m_bmp.UngetRawData(*this); + } -// move x pixels to the right and y down -// -// note that the rows don't wrap! -#define wxBMP_OFFSET(p, x, y) \ - p.m_ptr += p.m_data->m_stride * (y) + p.m_data->m_bypp * (x) + // call this to indicate that we should use the alpha channel + void UseAlpha() { m_bmp.UseAlpha(); } -// move x pixels to the right (again, no row wrapping) -#define wxBMP_OFFSET_X(p, x) p.m_ptr += p.m_data->m_bypp * (x) + // private: -- see comment in the beginning of the file -// move y rows to the bottom -#define wxBMP_OFFSET_Y(p, y) p.m_ptr += p.m_data->m_stride * (y) + // the bitmap we're associated with + wxBitmap m_bmp; + // the iterator pointing to the image origin + Iterator m_pixels; + }; +}; +template > +class wxPixelData : + public wxPixelDataOut::template wxPixelDataIn +{ +public: + wxPixelData(const Image& image) + : wxPixelDataOut::template wxPixelDataIn(image) + { + } +}; -// these macros are used to work with the pixel values -// -// all of them can be used as either lvalues or rvalues. -// ---------------------------------------------------- +// some "predefined" pixel data classes +typedef wxPixelData wxImagePixelData; +typedef wxPixelData wxNativePixelData; +typedef wxPixelData wxAlphaPixelData; -#define wxBMP_RED(p) (p.m_ptr[wxRawBitmapIterator::RED]) -#define wxBMP_GREEN(p) (p.m_ptr[wxRawBitmapIterator::GREEN]) -#define wxBMP_BLUE(p) (p.m_ptr[wxRawBitmapIterator::BLUE]) +// ---------------------------------------------------------------------------- +// wxPixelIterator +// ---------------------------------------------------------------------------- -#define wxBMP_ALPHA(p) (p.m_ptr[wxRawBitmapIterator::ALPHA]) +/* + wxPixel::Iterator represents something which points to the pixel data and + allows us to iterate over it. In the simplest case of wxBitmap it is, + indeed, just a pointer, but it can be something more complicated and, + moreover, you are free to specialize it for other image classes and bitmap + formats. + + Note that although it would have been much more intuitive to have a real + class here instead of what we have now, this class would need two template + parameters, and this can't be done because we'd need compiler support for + partial template specialization then and neither VC6 nor VC7 provide it. + */ +template < class Image, class PixelFormat = wxPixelFormatFor > +struct WXDLLEXPORT wxPixelIterator : wxPixelData::Iterator +{ +}; -// these macros are most efficient but return the buffer contents in -// platform-specific format, e.g. RGB on all sane platforms and BGR under Win32 -#define wxBMP_RGB(p) *(wxUint32 *)(p.m_ptr) -#define wxBMP_RGBA(p) *(wxUint32 *)(p.m_ptr) +#ifdef __VISUALC__ + #pragma warning(default: 4355) +#endif #endif // _WX_RAWBMP_H_BASE_ diff --git a/src/msw/bitmap.cpp b/src/msw/bitmap.cpp index b34424a5fe..1cccec1980 100644 --- a/src/msw/bitmap.cpp +++ b/src/msw/bitmap.cpp @@ -1185,14 +1185,12 @@ void wxBitmap::SetQuality(int WXUNUSED(quality)) // raw bitmap access support // ---------------------------------------------------------------------------- -bool wxBitmap::GetRawData(wxRawBitmapData *data) +void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) { - wxCHECK_MSG( data, FALSE, _T("NULL pointer in wxBitmap::GetRawData") ); - if ( !Ok() ) { // no bitmap, no data (raw or otherwise) - return FALSE; + return NULL; } // if we're already a DIB we can access our data directly, but if not we @@ -1209,7 +1207,7 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) { delete dib; - return FALSE; + return NULL; } // we'll free it in UngetRawData() @@ -1227,79 +1225,94 @@ bool wxBitmap::GetRawData(wxRawBitmapData *data) { wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") ); - return FALSE; + return NULL; + } + + // check that the bitmap is in correct format + if ( ds.dsBm.bmBitsPixel != bpp ) + { + wxFAIL_MSG( _T("incorrect bitmap type in wxBitmap::GetRawData()") ); + + return NULL; } - // ok, store the relevant info in wxRawBitmapData + // ok, store the relevant info in wxPixelDataBase const LONG h = ds.dsBm.bmHeight; - data->m_width = ds.dsBm.bmWidth; - data->m_height = h; - data->m_bypp = ds.dsBm.bmBitsPixel / 8; + data.m_width = ds.dsBm.bmWidth; + data.m_height = h; // remember that DIBs are stored in top to bottom order! const LONG bytesPerRow = ds.dsBm.bmWidthBytes; - data->m_stride = -bytesPerRow; - data->m_pixels = (unsigned char *)ds.dsBm.bmBits; + data.m_stride = -bytesPerRow; + + char *bits = (char *)ds.dsBm.bmBits; if ( h > 1 ) { - data->m_pixels += (h - 1)*bytesPerRow; + bits += (h - 1)*bytesPerRow; } - return TRUE; + return bits; } -void wxBitmap::UngetRawData(wxRawBitmapData *data) +void wxBitmap::UngetRawData(wxPixelDataBase& dataBase) { - wxCHECK_RET( data, _T("NULL pointer in wxBitmap::UngetRawData()") ); - if ( !Ok() ) return; - if ( !*data ) + // the cast is ugly but we can't do without it and without making this + // function template (and hence inline) unfortunately + typedef wxPixelData PixelData; + PixelData& data = (PixelData &)dataBase; + + if ( !data ) { // invalid data, don't crash -- but don't assert neither as we're - // called automatically from wxRawBitmapData dtor and so there is no + // called automatically from wxPixelDataBase dtor and so there is no // way to prevent this from happening return; } - // AlphaBlend() wants to have premultiplied source alpha but wxRawBitmap - // API uses normal, not premultiplied, colours, so adjust them here now - wxRawBitmapIterator p(*data); - - const int w = data->GetWidth(); - const int h = data->GetHeight(); - - for ( int y = 0; y < h; y++ ) + if ( GetBitmapData()->m_hasAlpha ) { - wxRawBitmapIterator rowStart = p; + // AlphaBlend() wants to have premultiplied source alpha but + // wxRawBitmap API uses normal, not premultiplied, colours, so adjust + // them here now + PixelData::Iterator p(data); - for ( int x = 0; x < w; x++ ) + const int w = data.GetWidth(); + const int h = data.GetHeight(); + + for ( int y = 0; y < h; y++ ) { - const unsigned alpha = p.Alpha(); + PixelData::Iterator rowStart = p; - p.Red() = (p.Red() * alpha + 127) / 255; - p.Blue() = (p.Blue() * alpha + 127) / 255; - p.Green() = (p.Green() * alpha + 127) / 255; + for ( int x = 0; x < w; x++ ) + { + const unsigned alpha = p.Alpha(); - ++p; - } + p.Red() = (p.Red() * alpha + 127) / 255; + p.Blue() = (p.Blue() * alpha + 127) / 255; + p.Green() = (p.Green() * alpha + 127) / 255; - p = rowStart; - p.OffsetY(1); - } + ++p; + } - // if we're a DDB we need to convert DIB back to DDB now to make the - // changes made via wxRawBitmapData effective - if ( !GetBitmapData()->m_isDIB ) - { - wxDIB *dib = GetBitmapData()->m_dib; - GetBitmapData()->m_dib = NULL; + p = rowStart; + p.OffsetY(data, 1); + } + + // if we're a DDB we need to convert DIB back to DDB now to make the + // changes made via raw bitmap access effective + if ( !GetBitmapData()->m_isDIB ) + { + wxDIB *dib = GetBitmapData()->m_dib; + GetBitmapData()->m_dib = NULL; - // TODO: convert + // TODO: convert - delete dib; + delete dib; + } } } diff --git a/src/msw/dc.cpp b/src/msw/dc.cpp index e44692390d..ab92546271 100644 --- a/src/msw/dc.cpp +++ b/src/msw/dc.cpp @@ -2313,19 +2313,19 @@ wxAlphaBlend(wxDC& dc, int xDst, int yDst, int w, int h, const wxBitmap& bmpSrc) } // combine them with the source bitmap using alpha - wxRawBitmapData dataDst(bmpDst), - dataSrc(bmpSrc); + wxAlphaPixelData dataDst(bmpDst), + dataSrc(bmpSrc); wxCHECK_RET( dataDst && dataSrc, _T("failed to get raw data in wxAlphaBlend") ); - wxRawBitmapIterator pDst(dataDst), - pSrc(dataSrc); + wxAlphaPixelData::Iterator pDst(dataDst), + pSrc(dataSrc); for ( int y = 0; y < h; y++ ) { - wxRawBitmapIterator pDstRowStart = pDst, - pSrcRowStart = pSrc; + wxAlphaPixelData::Iterator pDstRowStart = pDst, + pSrcRowStart = pSrc; for ( int x = 0; x < w; x++ ) { @@ -2343,8 +2343,8 @@ wxAlphaBlend(wxDC& dc, int xDst, int yDst, int w, int h, const wxBitmap& bmpSrc) pDst = pDstRowStart; pSrc = pSrcRowStart; - pDst.OffsetY(1); - pSrc.OffsetY(1); + pDst.OffsetY(dataDst, 1); + pSrc.OffsetY(dataSrc, 1); } // and finally blit them back to the destination DC -- 2.45.2