bitmap.cpp

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

CPP
1,776
字号
////////////////////////////////////////////////////////////////////////////
// Name:        bitmap.cpp
// Purpose:     wxBitmap
// Author:      Julian Smart
// Modified by:
// Created:     04/01/98
// RCS-ID:      $Id: bitmap.cpp,v 1.134.2.3 2006/01/21 16:46:43 JS Exp $
// Copyright:   (c) Julian Smart
// Licence:     wxWindows licence
/////////////////////////////////////////////////////////////////////////////

// ============================================================================
// declarations
// ============================================================================

// ----------------------------------------------------------------------------
// headers
// ----------------------------------------------------------------------------

#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
    #pragma implementation "bitmap.h"
#endif

// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"

#ifdef __BORLANDC__
    #pragma hdrstop
#endif

#ifndef WX_PRECOMP
    #include <stdio.h>

    #include "wx/list.h"
    #include "wx/utils.h"
    #include "wx/app.h"
    #include "wx/palette.h"
    #include "wx/dcmemory.h"
    #include "wx/bitmap.h"
    #include "wx/icon.h"
#endif

#include "wx/msw/private.h"
#include "wx/log.h"

#if wxUSE_WXDIB
#include "wx/msw/dib.h"
#endif

#include "wx/image.h"
#include "wx/xpmdecod.h"

#ifdef wxHAVE_RAW_BITMAP
#include "wx/rawbmp.h"
#endif

// missing from mingw32 header
#ifndef CLR_INVALID
    #define CLR_INVALID ((COLORREF)-1)
#endif // no CLR_INVALID

// ----------------------------------------------------------------------------
// Bitmap data
// ----------------------------------------------------------------------------

class WXDLLEXPORT wxBitmapRefData : public wxGDIImageRefData
{
public:
    wxBitmapRefData();
    wxBitmapRefData(const wxBitmapRefData& data);
    virtual ~wxBitmapRefData() { Free(); }

    virtual void Free();

    // set the mask object to use as the mask, we take ownership of it
    void SetMask(wxMask *mask)
    {
        delete m_bitmapMask;
        m_bitmapMask = mask;
    }

    // set the HBITMAP to use as the mask
    void SetMask(HBITMAP hbmpMask)
    {
        SetMask(new wxMask((WXHBITMAP)hbmpMask));
    }

    // return the mask
    wxMask *GetMask() const { return m_bitmapMask; }

public:
#if wxUSE_PALETTE
    wxPalette     m_bitmapPalette;
#endif // wxUSE_PALETTE

    // MSW-specific
    // ------------

#ifdef __WXDEBUG__
    // this field is solely for error checking: we detect selecting a bitmap
    // into more than one DC at once or deleting a bitmap still selected into a
    // DC (both are serious programming errors under Windows)
    wxDC         *m_selectedInto;
#endif // __WXDEBUG__

#if wxUSE_WXDIB
    // when GetRawData() is called for a DDB we need to convert it to a DIB
    // first to be able to provide direct access to it and we cache that DIB
    // here and convert it back to DDB when UngetRawData() is called
    wxDIB *m_dib;
#endif

    // true if we have alpha transparency info and can be drawn using
    // AlphaBlend()
    bool m_hasAlpha;

    // true if our HBITMAP is a DIB section, false if it is a DDB
    bool m_isDIB;

private:
    // optional mask for transparent drawing
    wxMask       *m_bitmapMask;


    // not implemented
    wxBitmapRefData& operator=(const wxBitmapRefData&);
};

// ----------------------------------------------------------------------------
// macros
// ----------------------------------------------------------------------------

IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)

IMPLEMENT_DYNAMIC_CLASS(wxBitmapHandler, wxObject)

// ============================================================================
// implementation
// ============================================================================

// ----------------------------------------------------------------------------
// helper functions
// ----------------------------------------------------------------------------

// decide whether we should create a DIB or a DDB for the given parameters
//
// NB: we always use DIBs under Windows CE as this is much simpler (even if
//     also less efficient...) and we obviously can't use them if there is no
//     DIB support compiled in at all
#ifdef __WXWINCE__
    static inline bool wxShouldCreateDIB(int, int, int, WXHDC) { return true; }

    #define ALWAYS_USE_DIB
#elif !wxUSE_WXDIB
    // no sense in defining wxShouldCreateDIB() as we can't compile code
    // executed if it is true, so we have to use #if's anyhow
    #define NEVER_USE_DIB
#else // wxUSE_WXDIB && !__WXWINCE__
    static inline bool wxShouldCreateDIB(int w, int h, int d, WXHDC hdc)
    {
        // here is the logic:
        //
        //  (a) if hdc is specified, the caller explicitly wants DDB
        //  (b) otherwise, create a DIB if depth >= 24 (we don't support 16bpp
        //      or less DIBs anyhow)
        //  (c) finally, create DIBs under Win9x even if the depth hasn't been
        //      explicitly specified but the current display depth is 24 or
        //      more and the image is "big", i.e. > 16Mb which is the
        //      theoretical limit for DDBs under Win9x
        //
        // consequences (all of which seem to make sense):
        //
        //  (i)     by default, DDBs are created (depth == -1 usually)
        //  (ii)    DIBs can be created by explicitly specifying the depth
        //  (iii)   using a DC always forces creating a DDB
        return !hdc &&
                (d >= 24 ||
                    (d == -1 &&
                        wxDIB::GetLineSize(w, wxDisplayDepth())*h > 16*1024*1024));
    }

    #define SOMETIMES_USE_DIB
#endif // different DIB usage scenarious

// ----------------------------------------------------------------------------
// wxBitmapRefData
// ----------------------------------------------------------------------------

wxBitmapRefData::wxBitmapRefData()
{
#ifdef __WXDEBUG__
    m_selectedInto = NULL;
#endif
    m_bitmapMask = NULL;

    m_hBitmap = (WXHBITMAP) NULL;
#if wxUSE_WXDIB
    m_dib = NULL;
#endif

    m_isDIB =
    m_hasAlpha = false;
}

wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
               : wxGDIImageRefData(data)
{
#ifdef __WXDEBUG__
    m_selectedInto = NULL;
#endif

    // can't copy the mask as the other bitmap destroys it
    m_bitmapMask = NULL;

    wxASSERT_MSG( !data.m_isDIB,
                    _T("can't copy bitmap locked for raw access!") );
    m_isDIB = false;

    m_hasAlpha = data.m_hasAlpha;
}

void wxBitmapRefData::Free()
{
    wxASSERT_MSG( !m_selectedInto,
                  wxT("deleting bitmap still selected into wxMemoryDC") );

#if wxUSE_WXDIB
    wxASSERT_MSG( !m_dib, _T("forgot to call wxBitmap::UngetRawData()!") );
#endif

    if ( m_hBitmap)
    {
        if ( !::DeleteObject((HBITMAP)m_hBitmap) )
        {
            wxLogLastError(wxT("DeleteObject(hbitmap)"));
        }
    }

    delete m_bitmapMask;
    m_bitmapMask = NULL;
}

// ----------------------------------------------------------------------------
// wxBitmap creation
// ----------------------------------------------------------------------------

// this function should be called from all wxBitmap ctors
void wxBitmap::Init()
{
    // m_refData = NULL; done in the base class ctor
}

wxGDIImageRefData *wxBitmap::CreateData() const
{
    return new wxBitmapRefData;
}

wxObjectRefData *wxBitmap::CloneRefData(const wxObjectRefData *dataOrig) const
{
    const wxBitmapRefData *
        data = wx_static_cast(const wxBitmapRefData *, dataOrig);
    if ( !data )
        return NULL;

    wxBitmap *self = wx_const_cast(wxBitmap *, this);

#if wxUSE_WXDIB
    // copy the other bitmap
    if ( data->m_hBitmap )
    {
        wxDIB dib((HBITMAP)(data->m_hBitmap));
        self->CopyFromDIB(dib);
    }
    else
#endif // wxUSE_WXDIB
    {
        // don't copy the bitmap data, but do copy the size, depth, ...
        self->m_refData = new wxBitmapRefData(*data);
    }

    return m_refData;
}

#ifdef __WIN32__

bool wxBitmap::CopyFromIconOrCursor(const wxGDIImage& icon)
{
#if !defined(__WXMICROWIN__) && !defined(__WXWINCE__)
    // it may be either HICON or HCURSOR
    HICON hicon = (HICON)icon.GetHandle();

    ICONINFO iconInfo;
    if ( !::GetIconInfo(hicon, &iconInfo) )
    {
        wxLogLastError(wxT("GetIconInfo"));

        return false;
    }

    wxBitmapRefData *refData = new wxBitmapRefData;
    m_refData = refData;

    int w = icon.GetWidth(),
        h = icon.GetHeight();

    refData->m_width = w;
    refData->m_height = h;
    refData->m_depth = wxDisplayDepth();

    refData->m_hBitmap = (WXHBITMAP)iconInfo.hbmColor;

#if wxUSE_WXDIB
    // If the icon is 32 bits per pixel then it may have alpha channel data,
    // although there are some icons that are 32 bpp but have no alpha... So
    // convert to a DIB and manually check the 4th byte for each pixel.
    BITMAP bm;
    if ( ::GetObject(iconInfo.hbmColor, sizeof(BITMAP), (LPVOID)&bm)
         && bm.bmBitsPixel == 32)
    {
        wxDIB dib(iconInfo.hbmColor);
        if (dib.IsOk())
        {
            unsigned char* pixels = dib.GetData();
            for (int idx=0; idx<w*h*4; idx+=4)
            {
                if (pixels[idx+3] != 0)
                {
                    // If there is an alpha byte that is non-zero then set the
                    // alpha flag and bail out of the loop.
                    refData->m_hasAlpha = true;
                    break;
                }
            }
        }
    }
#endif
    if ( !refData->m_hasAlpha )
    {
        // the mask returned by GetIconInfo() is inverted compared to the usual
        // wxWin convention
        refData->SetMask(wxInvertMask(iconInfo.hbmMask, w, h));
    }

    // delete the old one now as we don't need it any more
    ::DeleteObject(iconInfo.hbmMask);

    return true;
#else
    wxUnusedVar(icon);
    return false;
#endif
}

#endif // Win32

bool wxBitmap::CopyFromCursor(const wxCursor& cursor)
{
    UnRef();

    if ( !cursor.Ok() )
        return false;

    return CopyFromIconOrCursor(cursor);
}

bool wxBitmap::CopyFromIcon(const wxIcon& icon)
{
    UnRef();

    if ( !icon.Ok() )
        return false;

    return CopyFromIconOrCursor(icon);
}

#ifndef NEVER_USE_DIB

bool wxBitmap::CopyFromDIB(const wxDIB& dib)
{
    wxCHECK_MSG( dib.IsOk(), false, _T("invalid DIB in CopyFromDIB") );

#ifdef SOMETIMES_USE_DIB
    HBITMAP hbitmap = dib.CreateDDB();
    if ( !hbitmap )
        return false;
#else // ALWAYS_USE_DIB
    HBITMAP hbitmap = ((wxDIB &)dib).Detach();  // const_cast
#endif // SOMETIMES_USE_DIB/ALWAYS_USE_DIB

    UnRef();

    wxBitmapRefData *refData = new wxBitmapRefData;
    m_refData = refData;

    refData->m_width = dib.GetWidth();
    refData->m_height = dib.GetHeight();
    refData->m_depth = dib.GetDepth();

    refData->m_hBitmap = (WXHBITMAP)hbitmap;

#if wxUSE_PALETTE
    wxPalette *palette = dib.CreatePalette();
    if ( palette )
    {
        refData->m_bitmapPalette = *palette;
    }

    delete palette;
#endif // wxUSE_PALETTE

    return true;
}

#endif // NEVER_USE_DIB

wxBitmap::~wxBitmap()
{
}

wxBitmap::wxBitmap(const char bits[], int width, int height, int depth)
{
    Init();

#ifndef __WXMICROWIN__
    wxBitmapRefData *refData = new wxBitmapRefData;
    m_refData = refData;

    refData->m_width = width;
    refData->m_height = height;
    refData->m_depth = depth;

    char *data;
    if ( depth == 1 )
    {
        // we assume that it is in XBM format which is not quite the same as
        // the format CreateBitmap() wants because the order of bytes in the
        // line is reversed!
        const size_t bytesPerLine = (width + 7) / 8;
        const size_t padding = bytesPerLine % 2;
        const size_t len = height * ( padding + bytesPerLine );
        data = (char *)malloc(len);
        const char *src = bits;
        char *dst = data;

⌨️ 快捷键说明

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