📄 image.cpp
字号:
/////////////////////////////////////////////////////////////////////////////
// Name: image.cpp
// Purpose: wxImage
// Author: Robert Roebling
// RCS-ID: $Id: image.cpp,v 1.202.2.3 2006/01/26 12:04:53 RR Exp $
// Copyright: (c) Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
#if defined(__GNUG__) && !defined(NO_GCC_PRAGMA)
#pragma implementation "image.h"
#endif
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#ifdef __BORLANDC__
#pragma hdrstop
#endif
#include "wx/defs.h"
#if wxUSE_IMAGE
#include "wx/image.h"
#include "wx/bitmap.h"
#include "wx/debug.h"
#include "wx/log.h"
#include "wx/app.h"
#include "wx/filefn.h"
#include "wx/wfstream.h"
#include "wx/intl.h"
#include "wx/module.h"
#include "wx/hash.h"
#include "wx/utils.h"
#include "wx/math.h"
#if wxUSE_XPM
#include "wx/xpmdecod.h"
#endif
// For memcpy
#include <string.h>
//-----------------------------------------------------------------------------
// wxImage
//-----------------------------------------------------------------------------
class wxImageRefData: public wxObjectRefData
{
public:
wxImageRefData();
virtual ~wxImageRefData();
int m_width;
int m_height;
unsigned char *m_data;
bool m_hasMask;
unsigned char m_maskRed,m_maskGreen,m_maskBlue;
// alpha channel data, may be NULL for the formats without alpha support
unsigned char *m_alpha;
bool m_ok;
// if true, m_data is pointer to static data and shouldn't be freed
bool m_static;
// same as m_static but for m_alpha
bool m_staticAlpha;
#if wxUSE_PALETTE
wxPalette m_palette;
#endif // wxUSE_PALETTE
wxArrayString m_optionNames;
wxArrayString m_optionValues;
DECLARE_NO_COPY_CLASS(wxImageRefData)
};
wxImageRefData::wxImageRefData()
{
m_width = 0;
m_height = 0;
m_data =
m_alpha = (unsigned char *) NULL;
m_maskRed = 0;
m_maskGreen = 0;
m_maskBlue = 0;
m_hasMask = false;
m_ok = false;
m_static =
m_staticAlpha = false;
}
wxImageRefData::~wxImageRefData()
{
if ( !m_static )
free( m_data );
if ( !m_staticAlpha )
free( m_alpha );
}
wxList wxImage::sm_handlers;
wxImage wxNullImage;
//-----------------------------------------------------------------------------
#define M_IMGDATA ((wxImageRefData *)m_refData)
IMPLEMENT_DYNAMIC_CLASS(wxImage, wxObject)
wxImage::wxImage( int width, int height, bool clear )
{
Create( width, height, clear );
}
wxImage::wxImage( int width, int height, unsigned char* data, bool static_data )
{
Create( width, height, data, static_data );
}
wxImage::wxImage( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
{
Create( width, height, data, alpha, static_data );
}
wxImage::wxImage( const wxString& name, long type, int index )
{
LoadFile( name, type, index );
}
wxImage::wxImage( const wxString& name, const wxString& mimetype, int index )
{
LoadFile( name, mimetype, index );
}
#if wxUSE_STREAMS
wxImage::wxImage( wxInputStream& stream, long type, int index )
{
LoadFile( stream, type, index );
}
wxImage::wxImage( wxInputStream& stream, const wxString& mimetype, int index )
{
LoadFile( stream, mimetype, index );
}
#endif // wxUSE_STREAMS
wxImage::wxImage( const wxImage& image )
: wxObject()
{
Ref(image);
}
wxImage::wxImage( const wxImage* image )
{
if (image) Ref(*image);
}
wxImage::wxImage( const char** xpmData )
{
Create(xpmData);
}
wxImage::wxImage( char** xpmData )
{
Create((const char**) xpmData);
}
bool wxImage::Create( const char** xpmData )
{
#if wxUSE_XPM
UnRef();
wxXPMDecoder decoder;
(*this) = decoder.ReadData(xpmData);
return Ok();
#else
return false;
#endif
}
bool wxImage::Create( int width, int height, bool clear )
{
UnRef();
m_refData = new wxImageRefData();
M_IMGDATA->m_data = (unsigned char *) malloc( width*height*3 );
if (!M_IMGDATA->m_data)
{
UnRef();
return false;
}
if (clear)
memset(M_IMGDATA->m_data, 0, width*height*3);
M_IMGDATA->m_width = width;
M_IMGDATA->m_height = height;
M_IMGDATA->m_ok = true;
return true;
}
bool wxImage::Create( int width, int height, unsigned char* data, bool static_data )
{
UnRef();
wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") );
m_refData = new wxImageRefData();
M_IMGDATA->m_data = data;
M_IMGDATA->m_width = width;
M_IMGDATA->m_height = height;
M_IMGDATA->m_ok = true;
M_IMGDATA->m_static = static_data;
return true;
}
bool wxImage::Create( int width, int height, unsigned char* data, unsigned char* alpha, bool static_data )
{
UnRef();
wxCHECK_MSG( data, false, _T("NULL data in wxImage::Create") );
m_refData = new wxImageRefData();
M_IMGDATA->m_data = data;
M_IMGDATA->m_alpha = alpha;
M_IMGDATA->m_width = width;
M_IMGDATA->m_height = height;
M_IMGDATA->m_ok = true;
M_IMGDATA->m_static = static_data;
return true;
}
void wxImage::Destroy()
{
UnRef();
}
wxImage wxImage::Copy() const
{
wxImage image;
wxCHECK_MSG( Ok(), image, wxT("invalid image") );
image.Create( M_IMGDATA->m_width, M_IMGDATA->m_height, false );
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
image.SetMaskColour( M_IMGDATA->m_maskRed, M_IMGDATA->m_maskGreen, M_IMGDATA->m_maskBlue );
image.SetMask( M_IMGDATA->m_hasMask );
memcpy( data, GetData(), M_IMGDATA->m_width*M_IMGDATA->m_height*3 );
wxImageRefData *imgData = (wxImageRefData *)image.m_refData;
// also copy the alpha channel
if (HasAlpha())
{
image.SetAlpha();
unsigned char* alpha = image.GetAlpha();
memcpy( alpha, GetAlpha(), M_IMGDATA->m_width*M_IMGDATA->m_height );
}
imgData->m_optionNames = M_IMGDATA->m_optionNames;
imgData->m_optionValues = M_IMGDATA->m_optionValues;
return image;
}
wxImage wxImage::ShrinkBy( int xFactor , int yFactor ) const
{
if( xFactor == 1 && yFactor == 1 )
return Copy() ;
wxImage image;
wxCHECK_MSG( Ok(), image, wxT("invalid image") );
// can't scale to/from 0 size
wxCHECK_MSG( (xFactor > 0) && (yFactor > 0), image,
wxT("invalid new image size") );
long old_height = M_IMGDATA->m_height,
old_width = M_IMGDATA->m_width;
wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
wxT("invalid old image size") );
long width = old_width / xFactor ;
long height = old_height / yFactor ;
image.Create( width, height, false );
char unsigned *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
bool hasMask = false ;
unsigned char maskRed = 0;
unsigned char maskGreen = 0;
unsigned char maskBlue =0 ;
unsigned char *source_data = M_IMGDATA->m_data;
unsigned char *target_data = data;
unsigned char *source_alpha = 0 ;
unsigned char *target_alpha = 0 ;
if (M_IMGDATA->m_hasMask)
{
hasMask = true ;
maskRed = M_IMGDATA->m_maskRed;
maskGreen = M_IMGDATA->m_maskGreen;
maskBlue =M_IMGDATA->m_maskBlue ;
image.SetMaskColour( M_IMGDATA->m_maskRed,
M_IMGDATA->m_maskGreen,
M_IMGDATA->m_maskBlue );
}
else
{
source_alpha = M_IMGDATA->m_alpha ;
if ( source_alpha )
{
image.SetAlpha() ;
target_alpha = image.GetAlpha() ;
}
}
for (long y = 0; y < height; y++)
{
for (long x = 0; x < width; x++)
{
unsigned long avgRed = 0 ;
unsigned long avgGreen = 0;
unsigned long avgBlue = 0;
unsigned long avgAlpha = 0 ;
unsigned long counter = 0 ;
// determine average
for ( int y1 = 0 ; y1 < yFactor ; ++y1 )
{
long y_offset = (y * yFactor + y1) * old_width;
for ( int x1 = 0 ; x1 < xFactor ; ++x1 )
{
unsigned char *pixel = source_data + 3 * ( y_offset + x * xFactor + x1 ) ;
unsigned char red = pixel[0] ;
unsigned char green = pixel[1] ;
unsigned char blue = pixel[2] ;
unsigned char alpha = 255 ;
if ( source_alpha )
alpha = *(source_alpha + y_offset + x * xFactor + x1) ;
if ( !hasMask || red != maskRed || green != maskGreen || blue != maskBlue )
{
if ( alpha > 0 )
{
avgRed += red ;
avgGreen += green ;
avgBlue += blue ;
}
avgAlpha += alpha ;
counter++ ;
}
}
}
if ( counter == 0 )
{
*(target_data++) = M_IMGDATA->m_maskRed ;
*(target_data++) = M_IMGDATA->m_maskGreen ;
*(target_data++) = M_IMGDATA->m_maskBlue ;
}
else
{
if ( source_alpha )
*(target_alpha++) = (unsigned char)(avgAlpha / counter ) ;
*(target_data++) = (unsigned char)(avgRed / counter);
*(target_data++) = (unsigned char)(avgGreen / counter);
*(target_data++) = (unsigned char)(avgBlue / counter);
}
}
}
// In case this is a cursor, make sure the hotspot is scalled accordingly:
if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_X) )
image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_X,
(GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_X))/xFactor);
if ( HasOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y) )
image.SetOption(wxIMAGE_OPTION_CUR_HOTSPOT_Y,
(GetOptionInt(wxIMAGE_OPTION_CUR_HOTSPOT_Y))/yFactor);
return image;
}
wxImage wxImage::Scale( int width, int height ) const
{
wxImage image;
wxCHECK_MSG( Ok(), image, wxT("invalid image") );
// can't scale to/from 0 size
wxCHECK_MSG( (width > 0) && (height > 0), image,
wxT("invalid new image size") );
long old_height = M_IMGDATA->m_height,
old_width = M_IMGDATA->m_width;
wxCHECK_MSG( (old_height > 0) && (old_width > 0), image,
wxT("invalid old image size") );
if ( old_width % width == 0 && old_width >= width &&
old_height % height == 0 && old_height >= height )
{
return ShrinkBy( old_width / width , old_height / height ) ;
}
image.Create( width, height, false );
unsigned char *data = image.GetData();
wxCHECK_MSG( data, image, wxT("unable to create image") );
unsigned char *source_data = M_IMGDATA->m_data;
unsigned char *target_data = data;
unsigned char *source_alpha = 0 ;
unsigned char *target_alpha = 0 ;
if (M_IMGDATA->m_hasMask)
{
image.SetMaskColour( M_IMGDATA->m_maskRed,
M_IMGDATA->m_maskGreen,
M_IMGDATA->m_maskBlue );
}
else
{
source_alpha = M_IMGDATA->m_alpha ;
if ( source_alpha )
{
image.SetAlpha() ;
target_alpha = image.GetAlpha() ;
}
}
long x_delta = (old_width<<16) / width;
long y_delta = (old_height<<16) / height;
unsigned char* dest_pixel = target_data;
long y = 0;
for ( long j = 0; j < height; j++ )
{
unsigned char* src_line = &source_data[(y>>16)*old_width*3];
unsigned char* src_alpha_line = source_alpha ? &source_alpha[(y>>16)*old_width] : 0 ;
long x = 0;
for ( long i = 0; i < width; i++ )
{
unsigned char* src_pixel = &src_line[(x>>16)*3];
unsigned char* src_alpha_pixel = source_alpha ? &src_alpha_line[(x>>16)] : 0 ;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -