///////////////////////////////////////////////////////////////////////////// // Name: src/qt/bitmap.cpp // Author: Peter Most, Javier Torres, Mariano Reingart, Sean D'Epagnier // Copyright: (c) 2010 wxWidgets dev team // Licence: wxWindows licence ///////////////////////////////////////////////////////////////////////////// // For compilers that support precompilation, includes "wx.h". #include "wx/wxprec.h" #ifdef __BORLANDC__ #pragma hdrstop #endif #include #include #include #ifndef WX_PRECOMP #include "wx/icon.h" #include "wx/image.h" #endif // WX_PRECOMP #include "wx/bitmap.h" #include "wx/cursor.h" #include "wx/rawbmp.h" #include "wx/qt/colour.h" #include "wx/qt/private/converter.h" #include "wx/qt/private/utils.h" static wxImage ConvertImage( QImage qtImage ) { bool hasAlpha = qtImage.hasAlphaChannel(); int numPixels = qtImage.height() * qtImage.width(); //Convert to ARGB32 for scanLine qtImage = qtImage.convertToFormat(QImage::Format_ARGB32); unsigned char *data = (unsigned char *)malloc(sizeof(char) * 3 * numPixels); unsigned char *startData = data; unsigned char *alpha = NULL; if (hasAlpha) alpha = (unsigned char *)malloc(sizeof(char) * numPixels); unsigned char *startAlpha = alpha; for (int y = 0; y < qtImage.height(); y++) { QRgb *line = (QRgb*)qtImage.scanLine(y); for (int x = 0; x < qtImage.width(); x++) { QRgb colour = line[x]; data[0] = qRed(colour); data[1] = qGreen(colour); data[2] = qBlue(colour); if (hasAlpha) { alpha[0] = qAlpha(colour); alpha++; } data += 3; } } if (hasAlpha) return wxImage(wxQtConvertSize(qtImage.size()), startData, startAlpha); else return wxImage(wxQtConvertSize(qtImage.size()), startData); } static QImage ConvertImage( const wxImage &image ) { bool hasAlpha = image.HasAlpha(); bool hasMask = image.HasMask(); QImage qtImage( wxQtConvertSize( image.GetSize() ), ( (hasAlpha || hasMask ) ? QImage::Format_ARGB32 : QImage::Format_RGB32 ) ); unsigned char *data = image.GetData(); unsigned char *alpha = hasAlpha ? image.GetAlpha() : NULL; QRgb colour; QRgb maskedColour; if ( hasMask ) { unsigned char r, g, b; image.GetOrFindMaskColour( &r, &g, &b ); maskedColour = ( r << 16 ) + ( g << 8 ) + b; } for (int y = 0; y < image.GetHeight(); y++) { for (int x = 0; x < image.GetWidth(); x++) { if (hasAlpha) { colour = alpha[0] << 24; alpha++; } else colour = 0; colour += (data[0] << 16) + (data[1] << 8) + data[2]; if ( hasMask && colour != maskedColour ) colour += 0xFF000000; // 255 << 24 qtImage.setPixel(x, y, colour); data += 3; } } return qtImage; } //----------------------------------------------------------------------------- // wxBitmapRefData //----------------------------------------------------------------------------- class wxBitmapRefData: public wxGDIRefData { public: wxBitmapRefData() { m_mask = NULL; } wxBitmapRefData( int width, int height, int depth ) { if (depth == 1) m_qtPixmap = QBitmap( width, height ); else m_qtPixmap = QPixmap( width, height ); m_mask = NULL; } wxBitmapRefData( QPixmap pix ) { m_qtPixmap = pix; m_mask = NULL; } virtual ~wxBitmapRefData() { delete m_mask; } QPixmap m_qtPixmap; QImage m_rawPixelSource; wxMask *m_mask; private: wxBitmapRefData(const wxBitmapRefData&other); wxBitmapRefData& operator=(const wxBitmapRefData&other); }; //----------------------------------------------------------------------------- // wxBitmap //----------------------------------------------------------------------------- wxIMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxObject); #define M_PIXDATA ((wxBitmapRefData *)m_refData)->m_qtPixmap #define M_MASK ((wxBitmapRefData *)m_refData)->m_mask void wxBitmap::InitStandardHandlers() { } wxBitmap::wxBitmap() { } wxBitmap::wxBitmap(QPixmap pix) { m_refData = new wxBitmapRefData(pix); } wxBitmap::wxBitmap(const wxBitmap& bmp) { Ref(bmp); } wxBitmap::wxBitmap(const char bits[], int width, int height, int depth ) { wxASSERT(depth == 1); if (width > 0 && height > 0 && depth == 1) { m_refData = new wxBitmapRefData(); M_PIXDATA = QBitmap(QBitmap::fromData(QSize(width, height), (const uchar*)bits)); } } wxBitmap::wxBitmap(int width, int height, int depth) { Create(width, height, depth); } wxBitmap::wxBitmap(const wxSize& sz, int depth ) { Create(sz, depth); } // Create a wxBitmap from xpm data wxBitmap::wxBitmap(const char* const* bits) { m_refData = new wxBitmapRefData(); M_PIXDATA = QPixmap( bits ); } wxBitmap::wxBitmap(const wxString &filename, wxBitmapType type ) { LoadFile(filename, type); } wxBitmap::wxBitmap(const wxImage& image, int depth, double WXUNUSED(scale) ) { Qt::ImageConversionFlags flags = 0; if (depth == 1) flags = Qt::MonoOnly; m_refData = new wxBitmapRefData(QPixmap::fromImage(ConvertImage(image), flags)); } wxBitmap::wxBitmap(const wxCursor& cursor) { // note that pixmap could be invalid if is not a pixmap cursor QPixmap pix = cursor.GetHandle().pixmap(); m_refData = new wxBitmapRefData(pix); } bool wxBitmap::Create(int width, int height, int depth ) { UnRef(); m_refData = new wxBitmapRefData(width, height, depth); return true; } bool wxBitmap::Create(const wxSize& sz, int depth ) { return Create(sz.GetWidth(), sz.GetHeight(), depth); } bool wxBitmap::Create(int width, int height, const wxDC& WXUNUSED(dc)) { return Create(width, height); } int wxBitmap::GetHeight() const { return M_PIXDATA.height(); } int wxBitmap::GetWidth() const { return M_PIXDATA.width(); } int wxBitmap::GetDepth() const { return M_PIXDATA.depth(); } #if wxUSE_IMAGE wxImage wxBitmap::ConvertToImage() const { QPixmap pixmap(M_PIXDATA); if ( M_MASK && M_MASK->GetHandle() ) pixmap.setMask(*M_MASK->GetHandle()); return ConvertImage(pixmap.toImage()); } #endif // wxUSE_IMAGE wxMask *wxBitmap::GetMask() const { return M_MASK; } void wxBitmap::SetMask(wxMask *mask) { AllocExclusive(); delete M_MASK; M_MASK = mask; } wxBitmap wxBitmap::GetSubBitmap(const wxRect& rect) const { return wxBitmap(M_PIXDATA.copy(wxQtConvertRect(rect))); } bool wxBitmap::SaveFile(const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const { #if wxUSE_IMAGE //Try to save using wx wxImage image = ConvertToImage(); if (image.IsOk() && image.SaveFile(name, type)) return true; #endif //Try to save using Qt const char* type_name = NULL; switch (type) { case wxBITMAP_TYPE_BMP: type_name = "bmp"; break; case wxBITMAP_TYPE_ICO: type_name = "ico"; break; case wxBITMAP_TYPE_JPEG: type_name = "jpeg"; break; case wxBITMAP_TYPE_PNG: type_name = "png"; break; case wxBITMAP_TYPE_GIF: type_name = "gif"; break; case wxBITMAP_TYPE_CUR: type_name = "cur"; break; case wxBITMAP_TYPE_TIFF: type_name = "tif"; break; case wxBITMAP_TYPE_XBM: type_name = "xbm"; break; case wxBITMAP_TYPE_PCX: type_name = "pcx"; break; case wxBITMAP_TYPE_BMP_RESOURCE: case wxBITMAP_TYPE_ICO_RESOURCE: case wxBITMAP_TYPE_CUR_RESOURCE: case wxBITMAP_TYPE_XBM_DATA: case wxBITMAP_TYPE_XPM: case wxBITMAP_TYPE_XPM_DATA: case wxBITMAP_TYPE_TIFF_RESOURCE: case wxBITMAP_TYPE_GIF_RESOURCE: case wxBITMAP_TYPE_PNG_RESOURCE: case wxBITMAP_TYPE_JPEG_RESOURCE: case wxBITMAP_TYPE_PNM: case wxBITMAP_TYPE_PNM_RESOURCE: case wxBITMAP_TYPE_PCX_RESOURCE: case wxBITMAP_TYPE_PICT: case wxBITMAP_TYPE_PICT_RESOURCE: case wxBITMAP_TYPE_ICON: case wxBITMAP_TYPE_ICON_RESOURCE: case wxBITMAP_TYPE_ANI: case wxBITMAP_TYPE_IFF: case wxBITMAP_TYPE_TGA: case wxBITMAP_TYPE_MACCURSOR: case wxBITMAP_TYPE_MACCURSOR_RESOURCE: case wxBITMAP_TYPE_MAX: case wxBITMAP_TYPE_ANY: default: break; } return type_name && M_PIXDATA.save(wxQtConvertString(name), type_name); } bool wxBitmap::LoadFile(const wxString &name, wxBitmapType type) { #if wxUSE_IMAGE //Try to load using wx wxImage image; if (image.LoadFile(name, type) && image.IsOk()) { *this = wxBitmap(image); return true; } else #endif { //Try to load using Qt AllocExclusive(); //TODO: Use passed image type instead of auto-detection return M_PIXDATA.load(wxQtConvertString(name)); } } #if wxUSE_PALETTE wxPalette *wxBitmap::GetPalette() const { wxMISSING_IMPLEMENTATION( "wxBitmap palettes" ); return 0; } void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette)) { wxMISSING_IMPLEMENTATION( "wxBitmap palettes" ); } #endif // wxUSE_PALETTE // copies the contents and mask of the given (colour) icon to the bitmap bool wxBitmap::CopyFromIcon(const wxIcon& icon) { *this = icon; return IsOk(); } #if WXWIN_COMPATIBILITY_3_0 void wxBitmap::SetHeight(int height) { M_PIXDATA = QPixmap(GetWidth(), height); } void wxBitmap::SetWidth(int width) { M_PIXDATA = QPixmap(width, GetHeight()); } void wxBitmap::SetDepth(int depth) { if (depth == 1) M_PIXDATA = QBitmap(GetWidth(), GetHeight()); else M_PIXDATA = QPixmap(GetWidth(), GetHeight()); } #endif void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp) { void* bits = NULL; wxBitmapRefData *refData = static_cast(m_refData); // allow access if bpp is valid if ( !refData->m_qtPixmap.isNull() ) { if ( bpp == 32 ) { refData->m_rawPixelSource = refData->m_qtPixmap.toImage().convertToFormat(QImage::Format_RGBA8888); data.m_height = refData->m_rawPixelSource.height(); data.m_width = refData->m_rawPixelSource.width(); data.m_stride = refData->m_rawPixelSource.bytesPerLine(); bits = refData->m_rawPixelSource.bits(); } } return bits; } void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data)) { wxBitmapRefData *refData = static_cast(m_refData); refData->m_qtPixmap = QPixmap::fromImage(refData->m_rawPixelSource); refData->m_rawPixelSource = QImage(); } QPixmap *wxBitmap::GetHandle() const { return ( m_refData != NULL ) ? &M_PIXDATA : NULL; } wxGDIRefData *wxBitmap::CreateGDIRefData() const { return new wxBitmapRefData; } wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const { const wxBitmapRefData* oldRef = static_cast(data); wxBitmapRefData *d = new wxBitmapRefData; d->m_qtPixmap = oldRef->m_qtPixmap; //.copy();// copy not needed d->m_mask = oldRef->m_mask ? new wxMask(*oldRef->m_mask) : NULL; return d; } bool wxBitmap::HasAlpha() const { return M_PIXDATA.hasAlphaChannel(); } //----------------------------------------------------------------------------- // wxMask //----------------------------------------------------------------------------- wxIMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject); wxMask::wxMask() { m_qtBitmap = NULL; } wxMask::wxMask(const wxMask &mask) { QBitmap *mask_bmp = mask.GetHandle(); m_qtBitmap = mask_bmp ? new QBitmap(*mask_bmp) : NULL; } wxMask& wxMask::operator=(const wxMask &mask) { delete m_qtBitmap; QBitmap *mask_bmp = mask.GetHandle(); m_qtBitmap = mask_bmp ? new QBitmap(*mask_bmp) : NULL; return *this; } wxMask::wxMask(const wxBitmap& bitmap, const wxColour& colour) { m_qtBitmap = NULL; Create(bitmap, colour); } wxMask::wxMask(const wxBitmap& bitmap, int paletteIndex) { m_qtBitmap = NULL; Create(bitmap, paletteIndex); } wxMask::wxMask(const wxBitmap& bitmap) { m_qtBitmap = NULL; Create(bitmap); } wxMask::~wxMask() { delete m_qtBitmap; } // this function is called from Create() to free the existing mask data void wxMask::FreeData() { delete m_qtBitmap; m_qtBitmap = NULL; } bool wxMask::InitFromColour(const wxBitmap& bitmap, const wxColour& colour) { if (!bitmap.IsOk()) return false; delete m_qtBitmap; m_qtBitmap = new QBitmap(bitmap.GetHandle()->createMaskFromColor(colour.GetQColor())); return true; } bool wxMask::InitFromMonoBitmap(const wxBitmap& bitmap) { //Only for mono bitmaps if (!bitmap.IsOk() || bitmap.GetDepth() != 1) return false; delete m_qtBitmap; m_qtBitmap = new QBitmap(*bitmap.GetHandle()); return true; } wxBitmap wxMask::GetBitmap() const { return wxBitmap(*m_qtBitmap); } QBitmap *wxMask::GetHandle() const { return m_qtBitmap; }