Files
wxWidgets/src/gtk1/bitmap.cpp
Vadim Zeitlin 41b1ba3c9e Replace many identical wxBitmap::CopyFromIcon() with a single one
Define CopyFromIcon() directly in wxBitmapBase for the non-MSW ports, as
it was implemented exactly in the same way in all ports using this class
anyhow.

This means this function is not virtual any longer, but this shouldn't
be a problem as it was never supposed to be overridden in application
code and this couldn't be done with wxMSW, where it never was virtual in
the first place, anyhow.

No real changes, just a simplification.
2021-10-25 23:36:45 +02:00

1389 lines
37 KiB
C++

/////////////////////////////////////////////////////////////////////////////
// Name: src/gtk1/bitmap.cpp
// Purpose:
// Author: Robert Roebling
// Copyright: (c) 1998 Robert Roebling
// Licence: wxWindows licence
/////////////////////////////////////////////////////////////////////////////
// For compilers that support precompilation, includes "wx.h".
#include "wx/wxprec.h"
#include "wx/bitmap.h"
#ifndef WX_PRECOMP
#include "wx/app.h"
#include "wx/dcmemory.h"
#include "wx/palette.h"
#include "wx/icon.h"
#include "wx/math.h"
#include "wx/image.h"
#include "wx/cursor.h"
#endif // WX_PRECOMP
#include "wx/filefn.h"
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <gdk/gdkrgb.h>
extern
void gdk_wx_draw_bitmap (GdkDrawable *drawable,
GdkGC *gc,
GdkDrawable *src,
gint xsrc,
gint ysrc,
gint xdest,
gint ydest,
gint width,
gint height);
//-----------------------------------------------------------------------------
// data
//-----------------------------------------------------------------------------
extern GtkWidget *wxGetRootWindow();
//-----------------------------------------------------------------------------
// wxMask
//-----------------------------------------------------------------------------
wxIMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject);
wxMask::wxMask()
{
m_bitmap = NULL;
}
wxMask::wxMask( const wxBitmap& bitmap, const wxColour& colour )
{
m_bitmap = NULL;
Create( bitmap, colour );
}
#if wxUSE_PALETTE
wxMask::wxMask( const wxBitmap& bitmap, int paletteIndex )
{
m_bitmap = NULL;
Create( bitmap, paletteIndex );
}
#endif // wxUSE_PALETTE
wxMask::wxMask( const wxBitmap& bitmap )
{
m_bitmap = NULL;
Create( bitmap );
}
wxMask::~wxMask()
{
if (m_bitmap)
gdk_bitmap_unref( m_bitmap );
}
bool wxMask::Create( const wxBitmap& bitmap,
const wxColour& colour )
{
if (m_bitmap)
{
gdk_bitmap_unref( m_bitmap );
m_bitmap = NULL;
}
wxImage image = bitmap.ConvertToImage();
if (!image.IsOk()) return false;
m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, image.GetWidth(), image.GetHeight(), 1 );
GdkGC *gc = gdk_gc_new( m_bitmap );
GdkColor color;
color.red = 65000;
color.green = 65000;
color.blue = 65000;
color.pixel = 1;
gdk_gc_set_foreground( gc, &color );
gdk_gc_set_fill( gc, GDK_SOLID );
gdk_draw_rectangle( m_bitmap, gc, TRUE, 0, 0, image.GetWidth(), image.GetHeight() );
unsigned char *data = image.GetData();
int index = 0;
unsigned char red = colour.Red();
unsigned char green = colour.Green();
unsigned char blue = colour.Blue();
GdkVisual *visual = wxTheApp->GetGdkVisual();
int bpp = visual->depth;
if ((bpp == 16) && (visual->red_mask != 0xf800))
bpp = 15;
if (bpp == 15)
{
red = red & 0xf8;
green = green & 0xf8;
blue = blue & 0xf8;
}
else if (bpp == 16)
{
red = red & 0xf8;
green = green & 0xfc;
blue = blue & 0xf8;
}
else if (bpp == 12)
{
red = red & 0xf0;
green = green & 0xf0;
blue = blue & 0xf0;
}
color.red = 0;
color.green = 0;
color.blue = 0;
color.pixel = 0;
gdk_gc_set_foreground( gc, &color );
for (int j = 0; j < image.GetHeight(); j++)
{
int start_x = -1;
int i;
for (i = 0; i < image.GetWidth(); i++)
{
if ((data[index] == red) &&
(data[index+1] == green) &&
(data[index+2] == blue))
{
if (start_x == -1)
start_x = i;
}
else
{
if (start_x != -1)
{
gdk_draw_line( m_bitmap, gc, start_x, j, i-1, j );
start_x = -1;
}
}
index += 3;
}
if (start_x != -1)
gdk_draw_line( m_bitmap, gc, start_x, j, i, j );
}
gdk_gc_unref( gc );
m_width = bitmap.GetWidth();
m_height = bitmap.GetHeight();
return true;
}
#if wxUSE_PALETTE
bool wxMask::Create( const wxBitmap& bitmap, int paletteIndex )
{
unsigned char r,g,b;
wxPalette *pal = bitmap.GetPalette();
wxCHECK_MSG( pal, false, wxT("Cannot create mask from bitmap without palette") );
pal->GetRGB(paletteIndex, &r, &g, &b);
return Create(bitmap, wxColour(r, g, b));
}
#endif // wxUSE_PALETTE
bool wxMask::Create( const wxBitmap& bitmap )
{
if (m_bitmap)
{
gdk_bitmap_unref( m_bitmap );
m_bitmap = NULL;
}
if (!bitmap.IsOk()) return false;
wxCHECK_MSG( bitmap.GetBitmap(), false, wxT("Cannot create mask from colour bitmap") );
m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, bitmap.GetWidth(), bitmap.GetHeight(), 1 );
if (!m_bitmap) return false;
GdkGC *gc = gdk_gc_new( m_bitmap );
gdk_wx_draw_bitmap( m_bitmap, gc, bitmap.GetBitmap(), 0, 0, 0, 0, bitmap.GetWidth(), bitmap.GetHeight() );
gdk_gc_unref( gc );
m_width = bitmap.GetWidth();
m_height = bitmap.GetHeight();
return true;
}
wxBitmap wxMask::GetBitmap() const
{
wxBitmap bitmap;
if (m_bitmap)
{
bitmap.SetBitmap( m_bitmap );
bitmap.SetWidth( m_width );
bitmap.SetHeight( m_height );
}
return bitmap;
}
//-----------------------------------------------------------------------------
// wxBitmapRefData
//-----------------------------------------------------------------------------
class wxBitmapRefData : public wxGDIRefData
{
public:
wxBitmapRefData();
wxBitmapRefData(const wxBitmapRefData& data);
bool Create(int width, int height, int bpp);
virtual ~wxBitmapRefData();
virtual bool IsOk() const { return m_pixmap || m_bitmap; }
GdkPixmap *m_pixmap;
GdkBitmap *m_bitmap;
wxMask *m_mask;
int m_width;
int m_height;
int m_bpp;
#if wxUSE_PALETTE
wxPalette *m_palette;
#endif // wxUSE_PALETTE
};
wxBitmapRefData::wxBitmapRefData()
{
m_pixmap = NULL;
m_bitmap = NULL;
m_mask = NULL;
m_width = 0;
m_height = 0;
m_bpp = 0;
#if wxUSE_PALETTE
m_palette = NULL;
#endif // wxUSE_PALETTE
}
wxBitmapRefData::wxBitmapRefData(const wxBitmapRefData& data)
{
Create(data.m_width, data.m_height, data.m_bpp);
m_mask = data.m_mask ? new wxMask(*data.m_mask) : NULL;
#if wxUSE_PALETTE
wxASSERT_MSG( !data.m_palette,
wxT("copying bitmaps palette not implemented") );
#endif // wxUSE_PALETTE
// copy the bitmap data by simply drawing the source bitmap on this one
GdkPixmap **dst;
if ( data.m_pixmap )
{
dst = &m_pixmap;
}
else if ( data.m_bitmap )
{
dst = &m_bitmap;
}
else // invalid bitmap?
{
return;
}
GdkGC *gc = gdk_gc_new(*dst);
if ( m_bpp == 1 )
{
gdk_wx_draw_bitmap(m_bitmap, gc, data.m_bitmap, 0, 0, 0, 0, -1, -1);
}
else // colour pixmap
{
gdk_draw_pixmap(m_pixmap, gc, data.m_pixmap, 0, 0, 0, 0, -1, -1);
}
gdk_gc_unref(gc);
}
bool wxBitmapRefData::Create(int width, int height, int bpp)
{
m_width = width;
m_height = height;
m_bpp = bpp;
m_mask = NULL;
#if wxUSE_PALETTE
m_palette = NULL;
#endif
// to understand how this compiles you should know that GdkPixmap and
// GdkBitmap are one and the same type in GTK+ 1
GdkPixmap **ppix;
if ( m_bpp != 1 )
{
const GdkVisual * const visual = wxTheApp->GetGdkVisual();
wxCHECK_MSG( (bpp == -1) || (bpp == visual->depth) || (bpp == 32), false,
wxT("invalid bitmap depth") );
m_bpp = visual->depth;
ppix = &m_pixmap;
m_bitmap = NULL;
}
else // mono bitmap
{
ppix = &m_bitmap;
m_pixmap = NULL;
}
*ppix = gdk_pixmap_new( wxGetRootWindow()->window, width, height, m_bpp );
return *ppix != NULL;
}
wxBitmapRefData::~wxBitmapRefData()
{
if (m_pixmap)
gdk_pixmap_unref( m_pixmap );
if (m_bitmap)
gdk_bitmap_unref( m_bitmap );
delete m_mask;
#if wxUSE_PALETTE
delete m_palette;
#endif // wxUSE_PALETTE
}
//-----------------------------------------------------------------------------
// wxBitmap
//-----------------------------------------------------------------------------
#define M_BMPDATA ((wxBitmapRefData *)m_refData)
wxIMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject);
wxGDIRefData *wxBitmap::CreateGDIRefData() const
{
return new wxBitmapRefData;
}
wxGDIRefData *wxBitmap::CloneGDIRefData(const wxGDIRefData *data) const
{
return new wxBitmapRefData(*static_cast<const wxBitmapRefData *>(data));
}
bool wxBitmap::Create( int width, int height, int depth )
{
UnRef();
if ( width <= 0 || height <= 0 )
{
return false;
}
m_refData = new wxBitmapRefData();
return M_BMPDATA->Create(width, height, depth);
}
wxBitmap::wxBitmap(const char* const* bits)
{
wxCHECK2_MSG(bits != NULL, return, wxT("invalid bitmap data"));
GdkVisual *visual = wxTheApp->GetGdkVisual();
m_refData = new wxBitmapRefData();
GdkBitmap *mask = NULL;
M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm_d( wxGetRootWindow()->window, &mask, NULL, (gchar **) bits );
wxCHECK2_MSG(M_BMPDATA->m_pixmap, return, wxT("couldn't create pixmap"));
if (mask)
{
M_BMPDATA->m_mask = new wxMask();
M_BMPDATA->m_mask->m_bitmap = mask;
}
gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
M_BMPDATA->m_bpp = visual->depth; // Can we get a different depth from create_from_xpm_d() ?
}
wxBitmap wxBitmap::Rescale( int clipx, int clipy, int clipwidth, int clipheight, int newx, int newy )
{
wxCHECK_MSG( IsOk(), wxNullBitmap, wxT("invalid bitmap") );
if (newy==M_BMPDATA->m_width && newy==M_BMPDATA->m_height)
return *this;
int width = wxMax(newx, 1);
int height = wxMax(newy, 1);
width = wxMin(width, clipwidth);
height = wxMin(height, clipheight);
wxBitmap bmp;
GdkImage *img = NULL;
if (GetPixmap())
img = gdk_image_get( GetPixmap(), 0, 0, GetWidth(), GetHeight() );
else if (GetBitmap())
img = gdk_image_get( GetBitmap(), 0, 0, GetWidth(), GetHeight() );
else
wxFAIL_MSG( wxT("Ill-formed bitmap") );
wxCHECK_MSG( img, wxNullBitmap, wxT("couldn't create image") );
int bpp = -1;
GdkGC *gc = NULL;
GdkPixmap *dstpix = NULL;
if (GetPixmap())
{
GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
if (visual == NULL)
visual = wxTheApp->GetGdkVisual();
bpp = visual->depth;
bmp = wxBitmap(width,height,bpp);
dstpix = bmp.GetPixmap();
gc = gdk_gc_new( dstpix );
}
char *dst = NULL;
long dstbyteperline = 0;
if (GetBitmap())
{
bpp = 1;
dstbyteperline = width/8*M_BMPDATA->m_bpp;
if (width*M_BMPDATA->m_bpp % 8 != 0)
dstbyteperline++;
dst = (char*) malloc(dstbyteperline*height);
}
// be careful to use the right scaling factor
float scx = (float)M_BMPDATA->m_width/(float)newx;
float scy = (float)M_BMPDATA->m_height/(float)newy;
// prepare accel-tables
int *tablex = (int *)calloc(width,sizeof(int));
int *tabley = (int *)calloc(height,sizeof(int));
// accel table filled with clipped values
for (int x = 0; x < width; x++)
tablex[x] = (int) (scx * (x+clipx));
for (int y = 0; y < height; y++)
tabley[y] = (int) (scy * (y+clipy));
// Main rescaling routine starts here
for (int h = 0; h < height; h++)
{
char outbyte = 0;
int old_x = -1;
guint32 old_pixval = 0;
for (int w = 0; w < width; w++)
{
guint32 pixval;
int x = tablex[w];
if (x == old_x)
pixval = old_pixval;
else
{
pixval = gdk_image_get_pixel( img, x, tabley[h] );
old_pixval = pixval;
old_x = x;
}
if (bpp == 1)
{
if (!pixval)
{
char bit=1;
char shift = bit << (w % 8);
outbyte |= shift;
}
if ((w+1)%8==0)
{
dst[h*dstbyteperline+w/8] = outbyte;
outbyte = 0;
}
}
else
{
GdkColor col;
col.pixel = pixval;
gdk_gc_set_foreground( gc, &col );
gdk_draw_point( dstpix, gc, w, h);
}
}
// do not forget the last byte
if ((bpp == 1) && (width % 8 != 0))
dst[h*dstbyteperline+width/8] = outbyte;
}
gdk_image_destroy( img );
if (gc) gdk_gc_unref( gc );
if (bpp == 1)
{
bmp = wxBitmap( (const char *)dst, width, height, 1 );
free( dst );
}
if (GetMask())
{
dstbyteperline = width/8;
if (width % 8 != 0)
dstbyteperline++;
dst = (char*) malloc(dstbyteperline*height);
img = gdk_image_get( GetMask()->m_bitmap, 0, 0, GetWidth(), GetHeight() );
for (int h = 0; h < height; h++)
{
char outbyte = 0;
int old_x = -1;
guint32 old_pixval = 0;
for (int w = 0; w < width; w++)
{
guint32 pixval;
int x = tablex[w];
if (x == old_x)
pixval = old_pixval;
else
{
pixval = gdk_image_get_pixel( img, x, tabley[h] );
old_pixval = pixval;
old_x = x;
}
if (pixval)
{
char bit=1;
char shift = bit << (w % 8);
outbyte |= shift;
}
if ((w+1)%8 == 0)
{
dst[h*dstbyteperline+w/8] = outbyte;
outbyte = 0;
}
}
// do not forget the last byte
if (width % 8 != 0)
dst[h*dstbyteperline+width/8] = outbyte;
}
wxMask* mask = new wxMask;
mask->m_bitmap = gdk_bitmap_create_from_data( wxGetRootWindow()->window, (gchar *) dst, width, height );
bmp.SetMask(mask);
free( dst );
gdk_image_destroy( img );
}
free( tablex );
free( tabley );
return bmp;
}
bool wxBitmap::CreateFromImage(const wxImage& image, int depth)
{
UnRef();
wxCHECK_MSG( image.IsOk(), false, wxT("invalid image") );
wxCHECK_MSG( depth == -1 || depth == 1, false, wxT("invalid bitmap depth") );
if (image.GetWidth() <= 0 || image.GetHeight() <= 0)
return false;
m_refData = new wxBitmapRefData();
if (depth == 1)
{
return CreateFromImageAsBitmap(image);
}
else
{
return CreateFromImageAsPixmap(image);
}
}
// conversion to mono bitmap:
bool wxBitmap::CreateFromImageAsBitmap(const wxImage& img)
{
// convert alpha channel to mask, if it is present:
wxImage image(img);
image.ConvertAlphaToMask();
int width = image.GetWidth();
int height = image.GetHeight();
SetHeight( height );
SetWidth( width );
SetBitmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 ) );
SetDepth( 1 );
GdkVisual *visual = wxTheApp->GetGdkVisual();
// Create picture image
unsigned char *data_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
GdkImage *data_image =
gdk_image_new_bitmap( visual, data_data, width, height );
// Create mask image
GdkImage *mask_image = NULL;
if (image.HasMask())
{
unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
wxMask *mask = new wxMask();
mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
SetMask( mask );
}
int r_mask = image.GetMaskRed();
int g_mask = image.GetMaskGreen();
int b_mask = image.GetMaskBlue();
unsigned char* data = image.GetData();
int index = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int r = data[index];
index++;
int g = data[index];
index++;
int b = data[index];
index++;
if (image.HasMask())
{
if ((r == r_mask) && (b == b_mask) && (g == g_mask))
gdk_image_put_pixel( mask_image, x, y, 1 );
else
gdk_image_put_pixel( mask_image, x, y, 0 );
}
if ((r == 255) && (b == 255) && (g == 255))
gdk_image_put_pixel( data_image, x, y, 1 );
else
gdk_image_put_pixel( data_image, x, y, 0 );
} // for
} // for
// Blit picture
GdkGC *data_gc = gdk_gc_new( GetBitmap() );
gdk_draw_image( GetBitmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
gdk_image_destroy( data_image );
gdk_gc_unref( data_gc );
// Blit mask
if (image.HasMask())
{
GdkGC *mask_gc = gdk_gc_new( GetMask()->m_bitmap );
gdk_draw_image( GetMask()->m_bitmap, mask_gc, mask_image, 0, 0, 0, 0, width, height );
gdk_image_destroy( mask_image );
gdk_gc_unref( mask_gc );
}
return true;
}
// conversion to colour bitmap:
bool wxBitmap::CreateFromImageAsPixmap(const wxImage& img)
{
// convert alpha channel to mask, if it is present:
wxImage image(img);
image.ConvertAlphaToMask();
int width = image.GetWidth();
int height = image.GetHeight();
SetHeight( height );
SetWidth( width );
SetPixmap( gdk_pixmap_new( wxGetRootWindow()->window, width, height, -1 ) );
GdkVisual *visual = wxTheApp->GetGdkVisual();
int bpp = visual->depth;
SetDepth( bpp );
if ((bpp == 16) && (visual->red_mask != 0xf800))
bpp = 15;
else if (bpp < 8)
bpp = 8;
// We handle 8-bit bitmaps ourselves using the colour cube, 12-bit
// visuals are not supported by GDK so we do these ourselves, too.
// 15-bit and 16-bit should actually work and 24-bit certainly does.
#ifdef __sgi
if (!image.HasMask() && (bpp > 16))
#else
if (!image.HasMask() && (bpp > 12))
#endif
{
static bool s_hasInitialized = false;
if (!s_hasInitialized)
{
gdk_rgb_init();
s_hasInitialized = true;
}
GdkGC *gc = gdk_gc_new( GetPixmap() );
gdk_draw_rgb_image( GetPixmap(),
gc,
0, 0,
width, height,
GDK_RGB_DITHER_NONE,
image.GetData(),
width*3 );
gdk_gc_unref( gc );
return true;
}
// Create picture image
GdkImage *data_image =
gdk_image_new( GDK_IMAGE_FASTEST, visual, width, height );
// Create mask image
GdkImage *mask_image = NULL;
if (image.HasMask())
{
unsigned char *mask_data = (unsigned char*)malloc( ((width >> 3)+8) * height );
mask_image = gdk_image_new_bitmap( visual, mask_data, width, height );
wxMask *mask = new wxMask();
mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, width, height, 1 );
SetMask( mask );
}
// Render
enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
byte_order b_o = RGB;
if (bpp > 8)
{
if ((visual->red_mask > visual->green_mask) && (visual->green_mask > visual->blue_mask)) b_o = RGB;
else if ((visual->red_mask > visual->blue_mask) && (visual->blue_mask > visual->green_mask)) b_o = RBG;
else if ((visual->blue_mask > visual->red_mask) && (visual->red_mask > visual->green_mask)) b_o = BRG;
else if ((visual->blue_mask > visual->green_mask) && (visual->green_mask > visual->red_mask)) b_o = BGR;
else if ((visual->green_mask > visual->red_mask) && (visual->red_mask > visual->blue_mask)) b_o = GRB;
else if ((visual->green_mask > visual->blue_mask) && (visual->blue_mask > visual->red_mask)) b_o = GBR;
}
int r_mask = image.GetMaskRed();
int g_mask = image.GetMaskGreen();
int b_mask = image.GetMaskBlue();
unsigned char* data = image.GetData();
int index = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
int r = data[index];
index++;
int g = data[index];
index++;
int b = data[index];
index++;
if (image.HasMask())
{
if ((r == r_mask) && (b == b_mask) && (g == g_mask))
gdk_image_put_pixel( mask_image, x, y, 1 );
else
gdk_image_put_pixel( mask_image, x, y, 0 );
}
switch (bpp)
{
case 8:
{
int pixel = -1;
if (wxTheApp->m_colorCube)
{
pixel = wxTheApp->m_colorCube[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
}
else
{
GdkColormap *cmap = gtk_widget_get_default_colormap();
GdkColor *colors = cmap->colors;
int max = 3 * (65536);
for (int i = 0; i < cmap->size; i++)
{
int rdiff = (r << 8) - colors[i].red;
int gdiff = (g << 8) - colors[i].green;
int bdiff = (b << 8) - colors[i].blue;
int sum = ABS (rdiff) + ABS (gdiff) + ABS (bdiff);
if (sum < max) { pixel = i; max = sum; }
}
}
gdk_image_put_pixel( data_image, x, y, pixel );
break;
}
case 12: // SGI only
{
guint32 pixel = 0;
switch (b_o)
{
case RGB: pixel = ((r & 0xf0) << 4) | (g & 0xf0) | ((b & 0xf0) >> 4); break;
case RBG: pixel = ((r & 0xf0) << 4) | (b & 0xf0) | ((g & 0xf0) >> 4); break;
case GRB: pixel = ((g & 0xf0) << 4) | (r & 0xf0) | ((b & 0xf0) >> 4); break;
case GBR: pixel = ((g & 0xf0) << 4) | (b & 0xf0) | ((r & 0xf0) >> 4); break;
case BRG: pixel = ((b & 0xf0) << 4) | (r & 0xf0) | ((g & 0xf0) >> 4); break;
case BGR: pixel = ((b & 0xf0) << 4) | (g & 0xf0) | ((r & 0xf0) >> 4); break;
}
gdk_image_put_pixel( data_image, x, y, pixel );
break;
}
case 15:
{
guint32 pixel = 0;
switch (b_o)
{
case RGB: pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
case RBG: pixel = ((r & 0xf8) << 7) | ((b & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
case GRB: pixel = ((g & 0xf8) << 7) | ((r & 0xf8) << 2) | ((b & 0xf8) >> 3); break;
case GBR: pixel = ((g & 0xf8) << 7) | ((b & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
case BRG: pixel = ((b & 0xf8) << 7) | ((r & 0xf8) << 2) | ((g & 0xf8) >> 3); break;
case BGR: pixel = ((b & 0xf8) << 7) | ((g & 0xf8) << 2) | ((r & 0xf8) >> 3); break;
}
gdk_image_put_pixel( data_image, x, y, pixel );
break;
}
case 16:
{
// I actually don't know if for 16-bit displays, it is alway the green
// component or the second component which has 6 bits.
guint32 pixel = 0;
switch (b_o)
{
case RGB: pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
case RBG: pixel = ((r & 0xf8) << 8) | ((b & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
case GRB: pixel = ((g & 0xf8) << 8) | ((r & 0xfc) << 3) | ((b & 0xf8) >> 3); break;
case GBR: pixel = ((g & 0xf8) << 8) | ((b & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
case BRG: pixel = ((b & 0xf8) << 8) | ((r & 0xfc) << 3) | ((g & 0xf8) >> 3); break;
case BGR: pixel = ((b & 0xf8) << 8) | ((g & 0xfc) << 3) | ((r & 0xf8) >> 3); break;
}
gdk_image_put_pixel( data_image, x, y, pixel );
break;
}
case 32:
case 24:
{
guint32 pixel = 0;
switch (b_o)
{
case RGB: pixel = (r << 16) | (g << 8) | b; break;
case RBG: pixel = (r << 16) | (b << 8) | g; break;
case BRG: pixel = (b << 16) | (r << 8) | g; break;
case BGR: pixel = (b << 16) | (g << 8) | r; break;
case GRB: pixel = (g << 16) | (r << 8) | b; break;
case GBR: pixel = (g << 16) | (b << 8) | r; break;
}
gdk_image_put_pixel( data_image, x, y, pixel );
break;
}
default: break;
}
} // for
} // for
// Blit picture
GdkGC *data_gc = gdk_gc_new( GetPixmap() );
gdk_draw_image( GetPixmap(), data_gc, data_image, 0, 0, 0, 0, width, height );
gdk_image_destroy( data_image );
gdk_gc_unref( data_gc );
// Blit mask
if (image.HasMask())
{
GdkGC *mask_gc = gdk_gc_new( GetMask()->m_bitmap );
gdk_draw_image( GetMask()->m_bitmap, mask_gc, mask_image, 0, 0, 0, 0, width, height );
gdk_image_destroy( mask_image );
gdk_gc_unref( mask_gc );
}
return true;
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( IsOk(), wxNullImage, wxT("invalid bitmap") );
image.Create(GetWidth(), GetHeight());
unsigned char *data = image.GetData();
if (!data)
{
wxFAIL_MSG( wxT("couldn't create image") );
return wxNullImage;
}
// the colour used as transparent one in wxImage and the one it is
// replaced with when it really occurs in the bitmap
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;
GdkImage *gdk_image = NULL;
if (HasPixmap())
{
gdk_image = gdk_image_get( GetPixmap(),
0, 0,
GetWidth(), GetHeight() );
}
else if (GetBitmap())
{
gdk_image = gdk_image_get( GetBitmap(),
0, 0,
GetWidth(), GetHeight() );
}
else
{
wxFAIL_MSG( wxT("Ill-formed bitmap") );
}
wxCHECK_MSG( gdk_image, wxNullImage, wxT("couldn't create image") );
GdkImage *gdk_image_mask = NULL;
if (GetMask())
{
gdk_image_mask = gdk_image_get( GetMask()->m_bitmap,
0, 0,
GetWidth(), GetHeight() );
image.SetMaskColour( MASK_RED, MASK_GREEN, MASK_BLUE );
}
int bpp = -1;
int red_shift_right = 0;
int green_shift_right = 0;
int blue_shift_right = 0;
int red_shift_left = 0;
int green_shift_left = 0;
int blue_shift_left = 0;
bool use_shift = false;
if (GetPixmap())
{
GdkVisual *visual = gdk_window_get_visual( GetPixmap() );
if (visual == NULL)
visual = wxTheApp->GetGdkVisual();
bpp = visual->depth;
if (bpp == 16)
bpp = visual->red_prec + visual->green_prec + visual->blue_prec;
red_shift_right = visual->red_shift;
red_shift_left = 8-visual->red_prec;
green_shift_right = visual->green_shift;
green_shift_left = 8-visual->green_prec;
blue_shift_right = visual->blue_shift;
blue_shift_left = 8-visual->blue_prec;
use_shift = (visual->type == GDK_VISUAL_TRUE_COLOR) || (visual->type == GDK_VISUAL_DIRECT_COLOR);
}
if (GetBitmap())
{
bpp = 1;
}
GdkColormap *cmap = gtk_widget_get_default_colormap();
long pos = 0;
for (int j = 0; j < GetHeight(); j++)
{
for (int i = 0; i < GetWidth(); i++)
{
wxUint32 pixel = gdk_image_get_pixel( gdk_image, i, j );
if (bpp == 1)
{
if (pixel == 0)
{
data[pos] = 0;
data[pos+1] = 0;
data[pos+2] = 0;
}
else
{
data[pos] = 255;
data[pos+1] = 255;
data[pos+2] = 255;
}
}
else if (use_shift)
{
data[pos] = (pixel >> red_shift_right) << red_shift_left;
data[pos+1] = (pixel >> green_shift_right) << green_shift_left;
data[pos+2] = (pixel >> blue_shift_right) << blue_shift_left;
}
else if (cmap->colors)
{
data[pos] = cmap->colors[pixel].red >> 8;
data[pos+1] = cmap->colors[pixel].green >> 8;
data[pos+2] = cmap->colors[pixel].blue >> 8;
}
else
{
wxFAIL_MSG( wxT("Image conversion failed. Unknown visual type.") );
}
if (gdk_image_mask)
{
int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
if (mask_pixel == 0)
{
data[pos] = MASK_RED;
data[pos+1] = MASK_GREEN;
data[pos+2] = MASK_BLUE;
}
else if ( data[pos] == MASK_RED &&
data[pos+1] == MASK_GREEN &&
data[pos+2] == MASK_BLUE )
{
data[pos+2] = MASK_BLUE_REPLACEMENT;
}
}
pos += 3;
}
}
gdk_image_destroy( gdk_image );
if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
return image;
}
wxBitmap::wxBitmap( const wxString &filename, wxBitmapType type )
{
LoadFile( filename, type );
}
wxBitmap::wxBitmap( const char bits[], int width, int height, int WXUNUSED(depth))
{
if ( width > 0 && height > 0 )
{
m_refData = new wxBitmapRefData();
M_BMPDATA->m_mask = NULL;
M_BMPDATA->m_bitmap = gdk_bitmap_create_from_data
(
wxGetRootWindow()->window,
(gchar *) bits,
width,
height
);
M_BMPDATA->m_width = width;
M_BMPDATA->m_height = height;
M_BMPDATA->m_bpp = 1;
wxASSERT_MSG( M_BMPDATA->m_bitmap, wxT("couldn't create bitmap") );
}
}
wxBitmap::wxBitmap(const wxCursor& cursor)
{
wxUnusedVar(cursor);
}
wxBitmap::~wxBitmap()
{
}
int wxBitmap::GetHeight() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return M_BMPDATA->m_height;
}
int wxBitmap::GetWidth() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return M_BMPDATA->m_width;
}
int wxBitmap::GetDepth() const
{
wxCHECK_MSG( IsOk(), -1, wxT("invalid bitmap") );
return M_BMPDATA->m_bpp;
}
wxMask *wxBitmap::GetMask() const
{
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
return M_BMPDATA->m_mask;
}
void wxBitmap::SetMask( wxMask *mask )
{
wxCHECK_RET( IsOk(), wxT("invalid bitmap") );
AllocExclusive();
if (M_BMPDATA->m_mask) delete M_BMPDATA->m_mask;
M_BMPDATA->m_mask = mask;
}
wxBitmap wxBitmap::GetSubBitmap( const wxRect& rect) const
{
wxCHECK_MSG( IsOk() &&
(rect.x >= 0) && (rect.y >= 0) &&
(rect.x+rect.width <= M_BMPDATA->m_width) && (rect.y+rect.height <= M_BMPDATA->m_height),
wxNullBitmap, wxT("invalid bitmap or bitmap region") );
wxBitmap ret( rect.width, rect.height, M_BMPDATA->m_bpp );
wxASSERT_MSG( ret.IsOk(), wxT("GetSubBitmap error") );
if (ret.GetPixmap())
{
GdkGC *gc = gdk_gc_new( ret.GetPixmap() );
gdk_draw_pixmap( ret.GetPixmap(), gc, GetPixmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
gdk_gc_destroy( gc );
}
else
{
GdkGC *gc = gdk_gc_new( ret.GetBitmap() );
GdkColor col;
col.pixel = 0xFFFFFF;
gdk_gc_set_foreground( gc, &col );
col.pixel = 0;
gdk_gc_set_background( gc, &col );
gdk_wx_draw_bitmap( ret.GetBitmap(), gc, GetBitmap(), rect.x, rect.y, 0, 0, rect.width, rect.height );
gdk_gc_destroy( gc );
}
if (GetMask())
{
wxMask *mask = new wxMask;
mask->m_bitmap = gdk_pixmap_new( wxGetRootWindow()->window, rect.width, rect.height, 1 );
GdkGC *gc = gdk_gc_new( mask->m_bitmap );
GdkColor col;
col.pixel = 0xFFFFFF;
gdk_gc_set_foreground( gc, &col );
col.pixel = 0;
gdk_gc_set_background( gc, &col );
gdk_wx_draw_bitmap( mask->m_bitmap, gc, M_BMPDATA->m_mask->m_bitmap, rect.x, rect.y, 0, 0, rect.width, rect.height );
gdk_gc_destroy( gc );
ret.SetMask( mask );
}
return ret;
}
bool wxBitmap::SaveFile( const wxString &name, wxBitmapType type, const wxPalette *WXUNUSED(palette) ) const
{
wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
// Try to save the bitmap via wxImage handlers:
{
wxImage image = ConvertToImage();
if (image.IsOk()) return image.SaveFile( name, type );
}
return false;
}
bool wxBitmap::LoadFile( const wxString &name, wxBitmapType type )
{
UnRef();
if (!wxFileExists(name))
return false;
GdkVisual *visual = wxTheApp->GetGdkVisual();
if (type == wxBITMAP_TYPE_XPM)
{
m_refData = new wxBitmapRefData();
GdkBitmap *mask = NULL;
M_BMPDATA->m_pixmap = gdk_pixmap_create_from_xpm
(
wxGetRootWindow()->window,
&mask,
NULL,
name.fn_str()
);
if (mask)
{
M_BMPDATA->m_mask = new wxMask();
M_BMPDATA->m_mask->m_bitmap = mask;
}
gdk_window_get_size( M_BMPDATA->m_pixmap, &(M_BMPDATA->m_width), &(M_BMPDATA->m_height) );
M_BMPDATA->m_bpp = visual->depth;
}
else // try if wxImage can load it
{
wxImage image;
if ( !image.LoadFile( name, type ) || !image.IsOk() )
return false;
*this = wxBitmap(image);
}
return true;
}
#if wxUSE_PALETTE
wxPalette *wxBitmap::GetPalette() const
{
if (!IsOk())
return NULL;
return M_BMPDATA->m_palette;
}
void wxBitmap::SetPalette(const wxPalette& WXUNUSED(palette))
{
// TODO
}
#endif // wxUSE_PALETTE
void wxBitmap::SetHeight( int height )
{
AllocExclusive();
M_BMPDATA->m_height = height;
}
void wxBitmap::SetWidth( int width )
{
AllocExclusive();
M_BMPDATA->m_width = width;
}
void wxBitmap::SetDepth( int depth )
{
AllocExclusive();
M_BMPDATA->m_bpp = depth;
}
void wxBitmap::SetPixmap( GdkPixmap *pixmap )
{
if (!m_refData)
m_refData = new wxBitmapRefData();
M_BMPDATA->m_pixmap = pixmap;
}
void wxBitmap::SetBitmap( GdkPixmap *bitmap )
{
if (!m_refData)
m_refData = new wxBitmapRefData();
M_BMPDATA->m_bitmap = bitmap;
}
GdkPixmap *wxBitmap::GetPixmap() const
{
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
return M_BMPDATA->m_pixmap;
}
bool wxBitmap::HasPixmap() const
{
wxCHECK_MSG( IsOk(), false, wxT("invalid bitmap") );
return M_BMPDATA->m_pixmap != NULL;
}
GdkBitmap *wxBitmap::GetBitmap() const
{
wxCHECK_MSG( IsOk(), NULL, wxT("invalid bitmap") );
return M_BMPDATA->m_bitmap;
}
void *wxBitmap::GetRawData(wxPixelDataBase& WXUNUSED(data), int WXUNUSED(bpp))
{
return NULL;
}
void wxBitmap::UngetRawData(wxPixelDataBase& WXUNUSED(data))
{
}
bool wxBitmap::HasAlpha() const
{
return false;
}
/* static */ void wxBitmap::InitStandardHandlers()
{
// TODO: Insert handler based on GdkPixbufs handler later
}