bitmap.cpp

来自「A*算法 A*算法 A*算法 A*算法A*算法A*算法」· C++ 代码 · 共 1,776 行 · 第 1/4 页

CPP
1,776
字号
                    *dstLine |= mask;

                if ( (mask >>= 1) == 0 )
                {
                    dstLine++;
                    mask = 0x80;
                }
            }
        }

        hbitmap = ::CreateBitmap(w, h, 1, 1, data);
        if ( !hbitmap )
        {
            wxLogLastError(_T("CreateBitmap(mask)"));
        }
        else
        {
            SetMask(new wxMask((WXHBITMAP)hbitmap));
        }

        delete[] data;
    }

    return true;
}

wxImage wxBitmap::ConvertToImage() const
{
    // convert DDB to DIB
    wxDIB dib(*this);

    if ( !dib.IsOk() )
    {
        return wxNullImage;
    }

    // and then DIB to our wxImage
    wxImage image = dib.ConvertToImage();
    if ( !image.Ok() )
    {
        return wxNullImage;
    }

    // now do the same for the mask, if we have any
    HBITMAP hbmpMask = GetMask() ? (HBITMAP) GetMask()->GetMaskBitmap() : NULL;
    if ( hbmpMask )
    {
        wxDIB dibMask(hbmpMask);
        if ( dibMask.IsOk() )
        {
            // TODO: use wxRawBitmap to iterate over DIB

            // we hard code the mask colour for now but we could also make an
            // effort (and waste time) to choose a colour not present in the
            // image already to avoid having to fudge the pixels below --
            // whether it's worth to do it is unclear however
            static const int MASK_RED = 1;
            static const int MASK_GREEN = 2;
            static const int MASK_BLUE = 3;
            static const int MASK_BLUE_REPLACEMENT = 2;

            const int h = dibMask.GetHeight();
            const int w = dibMask.GetWidth();
            const int bpp = dibMask.GetDepth();
            const int maskBytesPerPixel = bpp >> 3;
            const int maskBytesPerLine = wxDIB::GetLineSize(w, bpp);
            unsigned char *data = image.GetData();

            // remember that DIBs are stored in bottom to top order
            unsigned char *
                maskLineStart = dibMask.GetData() + ((h - 1) * maskBytesPerLine);

            for ( int y = 0; y < h; y++, maskLineStart -= maskBytesPerLine )
            {
                // traverse one mask DIB line
                unsigned char *mask = maskLineStart;
                for ( int x = 0; x < w; x++, mask += maskBytesPerPixel )
                {
                    // should this pixel be transparent?
                    if ( *mask )
                    {
                        // no, check that it isn't transparent by accident
                        if ( (data[0] == MASK_RED) &&
                                (data[1] == MASK_GREEN) &&
                                    (data[2] == MASK_BLUE) )
                        {
                            // we have to fudge the colour a bit to prevent
                            // this pixel from appearing transparent
                            data[2] = MASK_BLUE_REPLACEMENT;
                        }

                        data += 3;
                    }
                    else // yes, transparent pixel
                    {
                        *data++ = MASK_RED;
                        *data++ = MASK_GREEN;
                        *data++ = MASK_BLUE;
                    }
                }
            }

            image.SetMaskColour(MASK_RED, MASK_GREEN, MASK_BLUE);
        }
    }

    return image;
}

#endif // wxUSE_WXDIB

#endif // wxUSE_IMAGE

// ----------------------------------------------------------------------------
// loading and saving bitmaps
// ----------------------------------------------------------------------------

bool wxBitmap::LoadFile(const wxString& filename, long type)
{
    UnRef();

    wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);

    if ( handler )
    {
        m_refData = new wxBitmapRefData;

        return handler->LoadFile(this, filename, type, -1, -1);
    }
#if wxUSE_IMAGE && wxUSE_WXDIB
    else // no bitmap handler found
    {
        wxImage image;
        if ( image.LoadFile( filename, type ) && image.Ok() )
        {
            *this = wxBitmap(image);

            return true;
        }
    }
#endif // wxUSE_IMAGE

    return false;
}

bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
{
    UnRef();

    wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);

    if ( !handler )
    {
        wxLogDebug(wxT("Failed to create bitmap: no bitmap handler for type %ld defined."), type);

        return false;
    }

    m_refData = new wxBitmapRefData;

    return handler->Create(this, data, type, width, height, depth);
}

bool wxBitmap::SaveFile(const wxString& filename,
                        int type,
                        const wxPalette *palette)
{
    wxBitmapHandler *handler = wxDynamicCast(FindHandler(type), wxBitmapHandler);

    if ( handler )
    {
        return handler->SaveFile(this, filename, type, palette);
    }
#if wxUSE_IMAGE && wxUSE_WXDIB
    else // no bitmap handler found
    {
        // FIXME what about palette? shouldn't we use it?
        wxImage image = ConvertToImage();
        if ( image.Ok() )
        {
            return image.SaveFile(filename, type);
        }
    }
#endif // wxUSE_IMAGE

    return false;
}

// ----------------------------------------------------------------------------
// sub bitmap extraction
// ----------------------------------------------------------------------------

wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
{
    wxCHECK_MSG( Ok() &&
                 (rect.x >= 0) && (rect.y >= 0) &&
                 (rect.x+rect.width <= GetWidth()) &&
                 (rect.y+rect.height <= GetHeight()),
                 wxNullBitmap, wxT("Invalid bitmap or bitmap region") );

    wxBitmap ret( rect.width, rect.height, GetDepth() );
    wxASSERT_MSG( ret.Ok(), wxT("GetSubBitmap error") );

#ifndef __WXMICROWIN__
    // handle alpha channel, if any
    if (HasAlpha())
        ret.UseAlpha();

    // copy bitmap data
    MemoryHDC dcSrc,
              dcDst;

    {
        SelectInHDC selectSrc(dcSrc, GetHbitmap()),
                    selectDst(dcDst, GetHbitmapOf(ret));

        if ( !selectSrc || !selectDst )
        {
            wxLogLastError(_T("SelectObjct(hBitmap)"));
        }

        if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
                       dcSrc, rect.x, rect.y, SRCCOPY) )
        {
            wxLogLastError(_T("BitBlt"));
        }
    }

    // copy mask if there is one
    if ( GetMask() )
    {
        HBITMAP hbmpMask = ::CreateBitmap(rect.width, rect.height, 1, 1, 0);

        SelectInHDC selectSrc(dcSrc, (HBITMAP) GetMask()->GetMaskBitmap()),
                    selectDst(dcDst, hbmpMask);

        if ( !::BitBlt(dcDst, 0, 0, rect.width, rect.height,
                       dcSrc, rect.x, rect.y, SRCCOPY) )
        {
            wxLogLastError(_T("BitBlt"));
        }

        wxMask *mask = new wxMask((WXHBITMAP) hbmpMask);
        ret.SetMask(mask);
    }
#endif // !__WXMICROWIN__

    return ret;
}

// ----------------------------------------------------------------------------
// wxBitmap accessors
// ----------------------------------------------------------------------------

#if wxUSE_PALETTE
wxPalette* wxBitmap::GetPalette() const
{
    return GetBitmapData() ? &GetBitmapData()->m_bitmapPalette
                           : (wxPalette *) NULL;
}
#endif

wxMask *wxBitmap::GetMask() const
{
    return GetBitmapData() ? GetBitmapData()->GetMask() : (wxMask *) NULL;
}

wxBitmap wxBitmap::GetMaskBitmap() const
{
    wxBitmap bmp;
    wxMask *mask = GetMask();
    if ( mask )
        bmp.SetHBITMAP(mask->GetMaskBitmap());
    return bmp;
}

#ifdef __WXDEBUG__

wxDC *wxBitmap::GetSelectedInto() const
{
    return GetBitmapData() ? GetBitmapData()->m_selectedInto : (wxDC *) NULL;
}

#endif

#if WXWIN_COMPATIBILITY_2_4

int wxBitmap::GetQuality() const
{
    return 0;
}

#endif // WXWIN_COMPATIBILITY_2_4

void wxBitmap::UseAlpha()
{
    if ( GetBitmapData() )
        GetBitmapData()->m_hasAlpha = true;
}

bool wxBitmap::HasAlpha() const
{
    return GetBitmapData() && GetBitmapData()->m_hasAlpha;
}

// ----------------------------------------------------------------------------
// wxBitmap setters
// ----------------------------------------------------------------------------

#ifdef __WXDEBUG__

void wxBitmap::SetSelectedInto(wxDC *dc)
{
    if ( GetBitmapData() )
        GetBitmapData()->m_selectedInto = dc;
}

#endif

#if wxUSE_PALETTE

void wxBitmap::SetPalette(const wxPalette& palette)
{
    AllocExclusive();

    GetBitmapData()->m_bitmapPalette = palette;
}

#endif // wxUSE_PALETTE

void wxBitmap::SetMask(wxMask *mask)
{
    AllocExclusive();

    GetBitmapData()->SetMask(mask);
}

#if WXWIN_COMPATIBILITY_2_4

void wxBitmap::SetQuality(int WXUNUSED(quality))
{
}

#endif // WXWIN_COMPATIBILITY_2_4

// ----------------------------------------------------------------------------
// raw bitmap access support
// ----------------------------------------------------------------------------

#ifdef wxHAVE_RAW_BITMAP
void *wxBitmap::GetRawData(wxPixelDataBase& data, int bpp)
{
#if wxUSE_WXDIB
    if ( !Ok() )
    {
        // no bitmap, no data (raw or otherwise)
        return NULL;
    }

    // if we're already a DIB we can access our data directly, but if not we
    // need to convert this DDB to a DIB section and use it for raw access and
    // then convert it back
    HBITMAP hDIB;
    if ( !GetBitmapData()->m_isDIB )
    {
        wxCHECK_MSG( !GetBitmapData()->m_dib, NULL,
                        _T("GetRawData() may be called only once") );

        wxDIB *dib = new wxDIB(*this);
        if ( !dib->IsOk() )
        {
            delete dib;

            return NULL;
        }

        // we'll free it in UngetRawData()
        GetBitmapData()->m_dib = dib;

        hDIB = dib->GetHandle();
    }
    else // we're a DIB
    {
        hDIB = GetHbitmap();
    }

    DIBSECTION ds;
    if ( ::GetObject(hDIB, sizeof(ds), &ds) != sizeof(DIBSECTION) )
    {
        wxFAIL_MSG( _T("failed to get DIBSECTION from a DIB?") );

        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 wxPixelDataBase
    const LONG h = ds.dsBm.bmHeight;

    data.m_width = ds.dsBm.bmWidth;
    data.m_height = h;

    // remember that DIBs are stored in top to bottom order!
    // (We can't just use ds.dsBm.bmWidthBytes here, because it isn't always a
    // multiple of 2, as required by the documentation.  So we use the official
    // formula, which we already use elsewhere.)
    const LONG bytesPerRow =
        wxDIB::GetLineSize(ds.dsBm.bmWidth, ds.dsBm.bmBitsPixel);
    data.m_stride = -bytesPerRow;

    char *bits = (char *)ds.dsBm.bmBits;
    if ( h > 1 )
    {
        bits += (h - 1)*bytesPerRow;
    }

    return bits;
#else
    return NULL;
#endif
}

void wxBitmap::UngetRawData(wxPixelDataBase& dataBase)
{
#if wxUSE_WXDIB
    if ( !Ok() )
        return;

    if ( !&dataBase )
    {
        // invalid data, don't crash -- but don't assert neither as we're
        // called automatically from wxPixelDataBase dtor and so there is no
        // way to prevent this from happening
        return;
    }

    // if we're a DDB we need to convert DIB back to DDB now to make the
    // changes made via raw bitmap access effective

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?