Added support for alpha channels in interpolated
and non-interpolated image rotation. Added helper method for turning shades of grey into shades of alpha and a colour. git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@30604 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
@@ -211,6 +211,18 @@ public:
|
|||||||
// otherwise:
|
// otherwise:
|
||||||
bool ConvertAlphaToMask(unsigned char threshold = 128);
|
bool ConvertAlphaToMask(unsigned char threshold = 128);
|
||||||
|
|
||||||
|
// This method converts an image where the original alpha
|
||||||
|
// information is only available as a shades of a colour
|
||||||
|
// (actually shades of grey) typically when you draw anti-
|
||||||
|
// aliased text into a bitmap. The DC drawinf routines
|
||||||
|
// draw grey values on the black background although they
|
||||||
|
// actually mean to draw white with differnt alpha values.
|
||||||
|
// This method reverses it, assuming a black (!) background
|
||||||
|
// and white text (actually only the red channel is read).
|
||||||
|
// The method will then fill up the whole image with the
|
||||||
|
// colour given.
|
||||||
|
bool ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b );
|
||||||
|
|
||||||
static bool CanRead( const wxString& name );
|
static bool CanRead( const wxString& name );
|
||||||
static int GetImageCount( const wxString& name, long type = wxBITMAP_TYPE_ANY );
|
static int GetImageCount( const wxString& name, long type = wxBITMAP_TYPE_ANY );
|
||||||
virtual bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 );
|
virtual bool LoadFile( const wxString& name, long type = wxBITMAP_TYPE_ANY, int index = -1 );
|
||||||
|
@@ -804,6 +804,33 @@ unsigned char wxImage::GetAlpha(int x, int y) const
|
|||||||
return M_IMGDATA->m_alpha[y*w + x];
|
return M_IMGDATA->m_alpha[y*w + x];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool wxImage::ConvertColourToAlpha( unsigned char r, unsigned char g, unsigned char b )
|
||||||
|
{
|
||||||
|
SetAlpha( NULL );
|
||||||
|
|
||||||
|
int w = M_IMGDATA->m_width,
|
||||||
|
h = M_IMGDATA->m_height;
|
||||||
|
|
||||||
|
unsigned char *alpha = GetAlpha();
|
||||||
|
unsigned char *data = GetData();
|
||||||
|
|
||||||
|
int x,y;
|
||||||
|
for (y = 0; y < h; y++)
|
||||||
|
for (x = 0; x < w; x++)
|
||||||
|
{
|
||||||
|
*alpha = *data;
|
||||||
|
alpha++;
|
||||||
|
*data = r;
|
||||||
|
data++;
|
||||||
|
*data = g;
|
||||||
|
data++;
|
||||||
|
*data = b;
|
||||||
|
data++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void wxImage::SetAlpha( unsigned char *alpha )
|
void wxImage::SetAlpha( unsigned char *alpha )
|
||||||
{
|
{
|
||||||
wxCHECK_RET( Ok(), wxT("invalid image") );
|
wxCHECK_RET( Ok(), wxT("invalid image") );
|
||||||
@@ -1669,14 +1696,24 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
int i;
|
int i;
|
||||||
angle = -angle; // screen coordinates are a mirror image of "real" coordinates
|
angle = -angle; // screen coordinates are a mirror image of "real" coordinates
|
||||||
|
|
||||||
|
bool has_alpha = HasAlpha();
|
||||||
|
|
||||||
// Create pointer-based array to accelerate access to wxImage's data
|
// Create pointer-based array to accelerate access to wxImage's data
|
||||||
unsigned char ** data = new unsigned char * [GetHeight()];
|
unsigned char ** data = new unsigned char * [GetHeight()];
|
||||||
|
|
||||||
data[0] = GetData();
|
data[0] = GetData();
|
||||||
|
|
||||||
for (i = 1; i < GetHeight(); i++)
|
for (i = 1; i < GetHeight(); i++)
|
||||||
data[i] = data[i - 1] + (3 * GetWidth());
|
data[i] = data[i - 1] + (3 * GetWidth());
|
||||||
|
|
||||||
|
// Same for alpha channel
|
||||||
|
unsigned char ** alpha = NULL;
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
alpha = new unsigned char * [GetHeight()];
|
||||||
|
alpha[0] = GetAlpha();
|
||||||
|
for (i = 1; i < GetHeight(); i++)
|
||||||
|
alpha[i] = alpha[i - 1] + GetWidth();
|
||||||
|
}
|
||||||
|
|
||||||
// precompute coefficients for rotation formula
|
// precompute coefficients for rotation formula
|
||||||
// (sine and cosine of the angle)
|
// (sine and cosine of the angle)
|
||||||
const double cos_angle = cos(angle);
|
const double cos_angle = cos(angle);
|
||||||
@@ -1698,7 +1735,11 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
|
int x2 = (int) ceil (wxMax (wxMax(p1.x, p2.x), wxMax(p3.x, p4.x)));
|
||||||
int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
|
int y2 = (int) ceil (wxMax (wxMax(p1.y, p2.y), wxMax(p3.y, p4.y)));
|
||||||
|
|
||||||
|
// Create rotated image
|
||||||
wxImage rotated (x2 - x1 + 1, y2 - y1 + 1, false);
|
wxImage rotated (x2 - x1 + 1, y2 - y1 + 1, false);
|
||||||
|
// With alpha channel
|
||||||
|
if (has_alpha)
|
||||||
|
rotated.SetAlpha();
|
||||||
|
|
||||||
if (offset_after_rotation != NULL)
|
if (offset_after_rotation != NULL)
|
||||||
{
|
{
|
||||||
@@ -1711,6 +1752,10 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
//
|
//
|
||||||
unsigned char * dst = rotated.GetData();
|
unsigned char * dst = rotated.GetData();
|
||||||
|
|
||||||
|
unsigned char * alpha_dst = NULL;
|
||||||
|
if (has_alpha)
|
||||||
|
alpha_dst = rotated.GetAlpha();
|
||||||
|
|
||||||
// GRG: if the original image has a mask, use its RGB values
|
// GRG: if the original image has a mask, use its RGB values
|
||||||
// as the blank pixel, else, fall back to default (black).
|
// as the blank pixel, else, fall back to default (black).
|
||||||
//
|
//
|
||||||
@@ -1796,28 +1841,52 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
unsigned char *p = data[y1] + (3 * x1);
|
unsigned char *p = data[y1] + (3 * x1);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *p;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *p = alpha[y1] + x1;
|
||||||
|
*(alpha_dst++) = *p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (d2 < gs_Epsilon)
|
else if (d2 < gs_Epsilon)
|
||||||
{
|
{
|
||||||
unsigned char *p = data[y1] + (3 * x2);
|
unsigned char *p = data[y1] + (3 * x2);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *p;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *p = alpha[y1] + x2;
|
||||||
|
*(alpha_dst++) = *p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (d3 < gs_Epsilon)
|
else if (d3 < gs_Epsilon)
|
||||||
{
|
{
|
||||||
unsigned char *p = data[y2] + (3 * x2);
|
unsigned char *p = data[y2] + (3 * x2);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *p;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *p = alpha[y2] + x2;
|
||||||
|
*(alpha_dst++) = *p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (d4 < gs_Epsilon)
|
else if (d4 < gs_Epsilon)
|
||||||
{
|
{
|
||||||
unsigned char *p = data[y2] + (3 * x1);
|
unsigned char *p = data[y2] + (3 * x1);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *p;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *p = alpha[y2] + x1;
|
||||||
|
*(alpha_dst++) = *p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@@ -1843,6 +1912,19 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
( (w1 * *v1 + w2 * *v2 +
|
( (w1 * *v1 + w2 * *v2 +
|
||||||
w3 * *v3 + w4 * *v4) /
|
w3 * *v3 + w4 * *v4) /
|
||||||
(w1 + w2 + w3 + w4) );
|
(w1 + w2 + w3 + w4) );
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *v1 = alpha[y1] + (x1);
|
||||||
|
unsigned char *v2 = alpha[y1] + (x2);
|
||||||
|
unsigned char *v3 = alpha[y2] + (x2);
|
||||||
|
unsigned char *v4 = alpha[y2] + (x1);
|
||||||
|
|
||||||
|
*(alpha_dst++) = (unsigned char)
|
||||||
|
( (w1 * *v1 + w2 * *v2 +
|
||||||
|
w3 * *v3 + w4 * *v4) /
|
||||||
|
(w1 + w2 + w3 + w4) );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -1850,6 +1932,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
*(dst++) = blank_r;
|
*(dst++) = blank_r;
|
||||||
*(dst++) = blank_g;
|
*(dst++) = blank_g;
|
||||||
*(dst++) = blank_b;
|
*(dst++) = blank_b;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
*(alpha_dst++) = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1872,12 +1957,21 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *(p++);
|
*(dst++) = *(p++);
|
||||||
*(dst++) = *p;
|
*(dst++) = *p;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
{
|
||||||
|
unsigned char *p = alpha[ys] + (xs);
|
||||||
|
*(alpha_dst++) = *p;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
*(dst++) = blank_r;
|
*(dst++) = blank_r;
|
||||||
*(dst++) = blank_g;
|
*(dst++) = blank_g;
|
||||||
*(dst++) = blank_b;
|
*(dst++) = blank_b;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
*(alpha_dst++) = 255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1885,6 +1979,9 @@ wxImage wxImage::Rotate(double angle, const wxPoint & centre_of_rotation, bool i
|
|||||||
|
|
||||||
delete [] data;
|
delete [] data;
|
||||||
|
|
||||||
|
if (has_alpha)
|
||||||
|
delete [] alpha;
|
||||||
|
|
||||||
return rotated;
|
return rotated;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user