X-Git-Url: https://git.saurik.com/wxWidgets.git/blobdiff_plain/e1b998ce2d4e4b54da9ed5b7e34353fecda1c824..3786c8b587f82e406ba9656847b5bff4ed9209c2:/include/wx/rawbmp.h diff --git a/include/wx/rawbmp.h b/include/wx/rawbmp.h index 4edd08843c..f9a8df2ab7 100644 --- a/include/wx/rawbmp.h +++ b/include/wx/rawbmp.h @@ -5,13 +5,15 @@ // Modified by: // Created: 10.03.03 // RCS-ID: $Id$ -// Copyright: (c) 2002 Vadim Zeitlin +// Copyright: (c) 2002 Vadim Zeitlin // Licence: wxWindows licence /////////////////////////////////////////////////////////////////////////////// #ifndef _WX_RAWBMP_H_BASE_ #define _WX_RAWBMP_H_BASE_ +#include "wx/image.h" + // ---------------------------------------------------------------------------- // Abstract Pixel API // @@ -32,28 +34,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 +67,165 @@ } p = rowStart; - p.OffsetY(1); + p.OffsetY(data, 1); } */ -// this struct represents a pointer to raw bitmap data -class wxRawBitmapData +/* + Note: we do not use WXDLLEXPORT with classes in this file because VC++ has + problems with exporting inner class defined inside a specialization of a + template class from a DLL. Besides, as all the methods are inline it's not + really necessary to put them in DLL at all. + */ + +// ---------------------------------------------------------------------------- +// 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 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; + + // 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 + + // size of one pixel in bits + enum { BitsPerPixel = Bpp }; - // we evaluate to true only if we could get access to bitmap data - // successfully - operator bool() const { return m_pixels != NULL; } + // size of one pixel in ChannelType units (usually bytes) + enum { SizePixel = Bpp / (8 * sizeof(Channel)) }; - // dtor unlocks the bitmap - ~wxRawBitmapData() + // 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 +#if defined(__WXMSW__) + // under MSW the RGB components are reversed, they're in BGR order + typedef wxPixelFormat wxNativePixelFormat; + + #define wxPIXEL_FORMAT_ALPHA 3 +#elif defined(__WXMAC__) + // under Mac, first component is unused but still present, hence we use + // 32bpp, not 24 + typedef wxPixelFormat wxNativePixelFormat; + + #define wxPIXEL_FORMAT_ALPHA 0 +#elif defined(__WXCOCOA__) + // Cocoa is standard RGB or RGBA (normally it is RGBA) + typedef wxPixelFormat wxNativePixelFormat; + + #define wxPIXEL_FORMAT_ALPHA 3 +#elif defined(__WXGTK__) + // Under GTK+ 2.X we use GdkPixbuf, which should be RGBA + typedef wxPixelFormat wxNativePixelFormat; + + #define wxPIXEL_FORMAT_ALPHA 3 +#endif + +// the (most common) native format for bitmaps with alpha channel +#ifdef wxPIXEL_FORMAT_ALPHA + typedef wxPixelFormat wxAlphaPixelFormat; +#endif // wxPIXEL_FORMAT_ALPHA + +// 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; + +#if wxUSE_IMAGE +// 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 wxPixelFormatFor +{ + typedef wxImagePixelFormat Format; +}; +#endif //wxUSE_IMAGE + +// ---------------------------------------------------------------------------- +// 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 wxPixelDataBase +{ +public: + // origin of the rectangular region we represent + wxPoint GetOrigin() const { return m_ptOrigin; } + + // width and height of the region we represent 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 + wxSize GetSize() const { return wxSize(m_width, m_height); } + + // the distance between two rows + int GetRowStride() const { return m_stride; } - // the bitmap we're associated with - wxBitmap m_bmp; +// private: -- see comment in the beginning of the file - // pointer to the start of the data - unsigned char *m_pixels; + // the origin of this image inside the bigger bitmap (usually (0, 0)) + wxPoint m_ptOrigin; // 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 +233,475 @@ public: // c) finally, it could conceivably be 0 for the images with all // lines being identical int m_stride; + +protected: + // ctor is protected because this class is only meant to be used as the + // base class by wxPixelData + wxPixelDataBase() + { + m_width = + m_height = + m_stride = 0; + } }; -// this is the type for the iterator over raw bitmap data -class wxRawBitmapIterator +/* + 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. + */ + +// we need to define this skeleton template to mollify VC++ +template +struct wxPixelDataOut { -public: - // ctors and such - // -------------- + template + class wxPixelDataIn + { + public: + class Iterator { }; + }; +}; - // we must be associated/initialized with some bitmap data object - wxRawBitmapIterator(const wxRawBitmapData& data) : m_data(&data) +#if wxUSE_IMAGE +// wxPixelData specialization for wxImage: this is the simplest case as we +// don't have to care about different pixel formats here +template <> +struct wxPixelDataOut +{ + // NB: this is a template class even though it doesn't use its template + // parameter because otherwise wxPixelData couldn't compile + template + class wxPixelDataIn : public wxPixelDataBase { - m_ptr = m_data->GetPixels(); - } + public: + // the type of the class we're working with + typedef wxImage ImageType; - // default copy ctor, assignment operator and dtor are ok + // 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 dummyPixelFormat::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; + + return *this; + } + + // postfix (hence less efficient -- don't use it unless you + // absolutely 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_pRGB[PixelFormat::RED]; } + ChannelType& Green() { return m_pRGB[PixelFormat::GREEN]; } + ChannelType& Blue() { return m_pRGB[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; + } + // initializes us with the given region of the specified image + wxPixelDataIn(ImageType& image, + const wxPoint& pt, + const wxSize& sz) : m_image(image), m_pixels(image) + { + m_stride = Iterator::SizePixel * m_width; - // navigation - // ---------- + InitRect(pt, sz); + } - // 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; - } + // initializes us with the given region of the specified image + wxPixelDataIn(ImageType& image, + const wxRect& rect) : m_image(image), m_pixels(image) + { + m_stride = Iterator::SizePixel * m_width; - // move x pixels to the right (again, no row wrapping) - void OffsetX(int x) - { - m_ptr += m_data->GetByPP()*x; - } + InitRect(rect.GetPosition(), rect.GetSize()); + } - // move y rows to the bottom - void OffsetY(int y) - { - m_ptr += m_data->GetRowStride()*y; - } + // we evaluate to true only if we could get access to bitmap data + // successfully + operator bool() const { return m_pixels.IsOk(); } - // go back to (0, 0) - void Reset() - { - m_ptr = m_data->GetPixels(); - } + // get the iterator pointing to the origin + Iterator GetPixels() const { return m_pixels; } - // go to the given position - void MoveTo(int x, int y) - { - Reset(); - Offset(x, y); - } + private: + void InitRect(const wxPoint& pt, const wxSize& sz) + { + m_width = sz.x; + m_height = sz.y; - // same as OffsetX(1) for convenience - wxRawBitmapIterator& operator++() - { - OffsetX(1); - return *this; - } + m_ptOrigin = pt; + m_pixels.Offset(*this, pt.x, pt.y); + } - // postfix (hence less efficient) version - wxRawBitmapIterator operator++(int) - { - wxRawBitmapIterator p(*this); - OffsetX(1); - return p; - } + // the image we're working with + ImageType& m_image; - // data access - // ----------- + // the iterator pointing to the image origin + Iterator m_pixels; + }; +}; +#endif //wxUSE_IMAGE - // DIBs store data in BGR format, i.e. "little endian" RGB - enum +#if wxUSE_GUI +// wxPixelData specialization for wxBitmap: here things are more interesting as +// we also have to support different pixel formats +template <> +struct wxPixelDataOut +{ + template + class wxPixelDataIn : public wxPixelDataBase { -#ifdef __WXMSW__ - BLUE, GREEN, RED, -#else // !__WXMSW__ - RED, GREEN, BLUE, -#endif // __WXMSW__/!__WXMSW__ - ALPHA - }; + public: + // the type of the class we're working with + typedef wxBitmap ImageType; - // 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]; } + 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 it unless you + // absolutely 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 + + // for efficiency reasons this class should 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) + { + } - // address the pixel contents directly - // - // warning: the format is platform dependent - wxUint32& Data() { return *(wxUint32 *)m_ptr; } + wxPixelDataIn(wxBitmap& bmp, const wxRect& rect) + : m_bmp(bmp), m_pixels(bmp, *this) + { + InitRect(rect.GetPosition(), rect.GetSize()); + } -// private: -- don't access these fields directly, same as as above - unsigned char *m_ptr; + wxPixelDataIn(wxBitmap& bmp, const wxPoint& pt, const wxSize& sz) + : m_bmp(bmp), m_pixels(bmp, *this) + { + InitRect(pt, sz); + } - 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; + private: + void InitRect(const wxPoint& pt, const wxSize& sz) + { + m_pixels.Offset(*this, pt.x, pt.y); -// these macros are used to work with the pixel values -// -// all of them can be used as either lvalues or rvalues. -// ---------------------------------------------------- + m_ptOrigin = pt; + m_width = sz.x; + m_height = sz.y; + } + }; +}; +#endif //wxUSE_GUI -#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]) +template > +class wxPixelData : + public wxPixelDataOut::template wxPixelDataIn +{ +public: + typedef + typename wxPixelDataOut::template wxPixelDataIn + Base; + + wxPixelData(Image& image) : Base(image) { } -#define wxBMP_ALPHA(p) (p.m_ptr[wxRawBitmapIterator::ALPHA]) + wxPixelData(Image& i, const wxRect& rect) : Base(i, rect) { } -// 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) + wxPixelData(Image& i, const wxPoint& pt, const wxSize& sz) + : Base(i, pt, sz) + { + } +}; + + +// some "predefined" pixel data classes +#if wxUSE_IMAGE +typedef wxPixelData wxImagePixelData; +#endif //wxUSE_IMAGE +#if wxUSE_GUI +typedef wxPixelData wxNativePixelData; +typedef wxPixelData wxAlphaPixelData; + +#endif //wxUSE_GUI + +// ---------------------------------------------------------------------------- +// wxPixelIterator +// ---------------------------------------------------------------------------- + +/* + 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 wxPixelIterator : public wxPixelData::Iterator +{ +}; #endif // _WX_RAWBMP_H_BASE_