I moved platform specific code from wxImage to wxBitmap

git-svn-id: https://svn.wxwidgets.org/svn/wx/wxWidgets/trunk@9659 c3d73ce0-8a6f-49c7-b76d-6d57e0e08775
This commit is contained in:
Václav Slavík 2001-04-04 23:25:06 +00:00
parent fd85921189
commit fec19ea9ff
6 changed files with 1516 additions and 1774 deletions

File diff suppressed because it is too large Load Diff

View File

@ -20,6 +20,7 @@
#include "wx/bitmap.h"
#include "wx/icon.h"
#include "wx/log.h"
#include "wx/image.h"
extern "C"
{
@ -516,6 +517,140 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
return handler->Create(this, data, type, width, height, depth);
}
wxBitmap::wxBitmap(const wxImage& image, int depth)
{
wxCHECK_RET( image.Ok(), wxT("invalid image") )
wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") )
m_refData = new wxBitmapRefData();
if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
// width and height of the device-dependent bitmap
int width = image.GetWidth();
int height = image.GetHeight();
// Create picture
Create( width , height , wxDisplayDepth() ) ;
wxBitmap maskBitmap( width, height, 1);
CGrafPtr origPort ;
GDHandle origDevice ;
LockPixels( GetGWorldPixMap(GetHBITMAP()) );
LockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
GetGWorld( &origPort , &origDevice ) ;
SetGWorld( GetHBITMAP() , NULL ) ;
// Render image
wxColour rgb, maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
RGBColor color;
RGBColor white = { 0xffff, 0xffff, 0xffff };
RGBColor black = { 0 , 0 , 0 };
register unsigned char* data = image.GetData();
int index = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
rgb.Set(data[index++], data[index++], data[index++]);
color = rgb.GetPixel();
SetCPixel( x , y , &color ) ;
if (image.HasMask())
{
SetGWorld(maskBitmap.GetHBITMAP(), NULL);
if (rgb == maskcolor) {
SetCPixel(x,y, &white);
}
else {
SetCPixel(x,y, &black);
}
SetGWorld(GetHBITMAP(), NULL);
}
}
} // for height
// Create mask
if ( image.HasMask() ) {
wxMask *mask = new wxMask( maskBitmap );
}
UnlockPixels( GetGWorldPixMap(GetHBITMAP()) );
UnlockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
SetGWorld( origPort, origDevice );
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
int height = GetHeight();
image.Create( width, height );
unsigned char *data = image.GetData();
wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
WXHBITMAP origPort;
GDHandle origDevice;
int index;
RGBColor color;
// background color set to RGB(16,16,16) in consistent with wxGTK
unsigned char mask_r=16, mask_g=16, mask_b=16;
SInt16 r,g,b;
wxMask *mask = GetMask();
GetGWorld( &origPort, &origDevice );
LockPixels(GetGWorldPixMap(GetHBITMAP()));
SetGWorld( GetHBITMAP(), NULL);
// Copy data into image
index = 0;
for (int yy = 0; yy < height; yy++)
{
for (int xx = 0; xx < width; xx++)
{
GetCPixel(xx,yy, &color);
r = ((color.red ) >> 8);
g = ((color.green ) >> 8);
b = ((color.blue ) >> 8);
data[index ] = r;
data[index + 1] = g;
data[index + 2] = b;
if (mask)
{
if (mask->PointMasked(xx,yy))
{
data[index ] = mask_r;
data[index + 1] = mask_g;
data[index + 2] = mask_b;
}
}
index += 3;
}
}
if (mask)
{
image.SetMaskColour( mask_r, mask_g, mask_b );
image.SetMask( true );
}
// Free resources
UnlockPixels(GetGWorldPixMap(GetHBITMAP()));
SetGWorld(origPort, origDevice);
return image;
}
bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
{
wxBitmapHandler *handler = FindHandler(type);

View File

@ -20,6 +20,7 @@
#include "wx/bitmap.h"
#include "wx/icon.h"
#include "wx/log.h"
#include "wx/image.h"
extern "C"
{
@ -516,6 +517,140 @@ bool wxBitmap::Create(void *data, long type, int width, int height, int depth)
return handler->Create(this, data, type, width, height, depth);
}
wxBitmap::wxBitmap(const wxImage& image, int depth)
{
wxCHECK_RET( image.Ok(), wxT("invalid image") )
wxCHECK_RET( depth == -1, wxT("invalid bitmap depth") )
m_refData = new wxBitmapRefData();
if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
// width and height of the device-dependent bitmap
int width = image.GetWidth();
int height = image.GetHeight();
// Create picture
Create( width , height , wxDisplayDepth() ) ;
wxBitmap maskBitmap( width, height, 1);
CGrafPtr origPort ;
GDHandle origDevice ;
LockPixels( GetGWorldPixMap(GetHBITMAP()) );
LockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
GetGWorld( &origPort , &origDevice ) ;
SetGWorld( GetHBITMAP() , NULL ) ;
// Render image
wxColour rgb, maskcolor(image.GetMaskRed(), image.GetMaskGreen(), image.GetMaskBlue());
RGBColor color;
RGBColor white = { 0xffff, 0xffff, 0xffff };
RGBColor black = { 0 , 0 , 0 };
register unsigned char* data = image.GetData();
int index = 0;
for (int y = 0; y < height; y++)
{
for (int x = 0; x < width; x++)
{
rgb.Set(data[index++], data[index++], data[index++]);
color = rgb.GetPixel();
SetCPixel( x , y , &color ) ;
if (image.HasMask())
{
SetGWorld(maskBitmap.GetHBITMAP(), NULL);
if (rgb == maskcolor) {
SetCPixel(x,y, &white);
}
else {
SetCPixel(x,y, &black);
}
SetGWorld(GetHBITMAP(), NULL);
}
}
} // for height
// Create mask
if ( image.HasMask() ) {
wxMask *mask = new wxMask( maskBitmap );
}
UnlockPixels( GetGWorldPixMap(GetHBITMAP()) );
UnlockPixels( GetGWorldPixMap(maskBitmap.GetHBITMAP()) );
SetGWorld( origPort, origDevice );
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
int height = GetHeight();
image.Create( width, height );
unsigned char *data = image.GetData();
wxCHECK_MSG( data, wxNullImage, wxT("Could not allocate data for image") );
WXHBITMAP origPort;
GDHandle origDevice;
int index;
RGBColor color;
// background color set to RGB(16,16,16) in consistent with wxGTK
unsigned char mask_r=16, mask_g=16, mask_b=16;
SInt16 r,g,b;
wxMask *mask = GetMask();
GetGWorld( &origPort, &origDevice );
LockPixels(GetGWorldPixMap(GetHBITMAP()));
SetGWorld( GetHBITMAP(), NULL);
// Copy data into image
index = 0;
for (int yy = 0; yy < height; yy++)
{
for (int xx = 0; xx < width; xx++)
{
GetCPixel(xx,yy, &color);
r = ((color.red ) >> 8);
g = ((color.green ) >> 8);
b = ((color.blue ) >> 8);
data[index ] = r;
data[index + 1] = g;
data[index + 2] = b;
if (mask)
{
if (mask->PointMasked(xx,yy))
{
data[index ] = mask_r;
data[index + 1] = mask_g;
data[index + 2] = mask_b;
}
}
index += 3;
}
}
if (mask)
{
image.SetMaskColour( mask_r, mask_g, mask_b );
image.SetMask( true );
}
// Free resources
UnlockPixels(GetGWorldPixMap(GetHBITMAP()));
SetGWorld(origPort, origDevice);
return image;
}
bool wxBitmap::SaveFile(const wxString& filename, int type, const wxPalette *palette)
{
wxBitmapHandler *handler = FindHandler(type);

View File

@ -26,6 +26,7 @@
#include "wx/control.h"
#include "wx/dcmemory.h"
#include "wx/image.h"
#include "wx/app.h"
#ifdef __VMS__
#pragma message disable nosimpint
@ -40,6 +41,8 @@
#if wxHAVE_LIB_XPM
#include <X11/xpm.h>
#endif
#include <math.h>
IMPLEMENT_DYNAMIC_CLASS(wxBitmap, wxGDIObject)
IMPLEMENT_DYNAMIC_CLASS(wxMask, wxObject)
@ -1065,3 +1068,510 @@ wxBitmap wxCreateMaskedBitmap(const wxBitmap& bitmap, wxColour& colour)
return newBitmap;
}
//-----------------------------------------------------------------------------
// wxImage conversion routines
//-----------------------------------------------------------------------------
/*
Date: Wed, 05 Jan 2000 11:45:40 +0100
From: Frits Boel <boel@niob.knaw.nl>
To: julian.smart@ukonline.co.uk
Subject: Patch for Motif ConvertToBitmap
Hi Julian,
I've been working on a wxWin application for image processing. From the
beginning, I was surprised by the (lack of) speed of ConvertToBitmap,
till I looked in the source code of image.cpp. I saw that converting a
wxImage to a bitmap with 8-bit pixels is done with comparing every pixel
to the 256 colors of the palet. A very time-consuming piece of code!
Because I wanted a faster application, I've made a 'patch' for this. In
short: every pixel of the image is compared to a sorted list with
colors. If the color is found in the list, the palette entry is
returned; if the color is not found, the color palette is searched and
then the palette entry is returned and the color added to the sorted
list.
Maybe there is another method for this, namely changing the palette
itself (if the colors are known, as is the case with tiffs with a
colormap). I did not look at this, maybe someone else did?
The code of the patch is attached, have a look on it, and maybe you will
ship it with the next release of wxMotif?
Regards,
Frits Boel
Software engineer at Hubrecht Laboratory, The Netherlands.
*/
class wxSearchColor
{
public:
wxSearchColor( void );
wxSearchColor( int size, XColor *colors );
~wxSearchColor( void );
int SearchColor( int r, int g, int b );
private:
int AddColor( unsigned int value, int pos );
int size;
XColor *colors;
unsigned int *color;
int *entry;
int bottom;
int top;
};
wxSearchColor::wxSearchColor( void )
{
size = 0;
colors = (XColor*) NULL;
color = (unsigned int *) NULL;
entry = (int*) NULL;
bottom = 0;
top = 0;
}
wxSearchColor::wxSearchColor( int size_, XColor *colors_ )
{
int i;
size = size_;
colors = colors_;
color = new unsigned int[size];
entry = new int [size];
for (i = 0; i < size; i++ ) {
entry[i] = -1;
}
bottom = top = ( size >> 1 );
}
wxSearchColor::~wxSearchColor( void )
{
if ( color ) delete color;
if ( entry ) delete entry;
}
int wxSearchColor::SearchColor( int r, int g, int b )
{
unsigned int value = ( ( ( r * 256 ) + g ) * 256 ) + b;
int begin = bottom;
int end = top;
int middle = 0;
while ( begin <= end ) {
middle = ( begin + end ) >> 1;
if ( value == color[middle] ) {
return( entry[middle] );
} else if ( value < color[middle] ) {
end = middle - 1;
} else {
begin = middle + 1;
}
}
return AddColor( value, middle );
}
int wxSearchColor::AddColor( unsigned int value, int pos )
{
int i;
int pixel = -1;
int max = 3 * (65536);
for ( i = 0; i < 256; i++ ) {
int rdiff = ((value >> 8) & 0xFF00 ) - colors[i].red;
int gdiff = ((value ) & 0xFF00 ) - colors[i].green;
int bdiff = ((value << 8) & 0xFF00 ) - colors[i].blue;
int sum = abs (rdiff) + abs (gdiff) + abs (bdiff);
if (sum < max) { pixel = i; max = sum; }
}
if ( entry[pos] < 0 ) {
color[pos] = value;
entry[pos] = pixel;
} else if ( value < color[pos] ) {
if ( bottom > 0 ) {
for ( i = bottom; i < pos; i++ ) {
color[i-1] = color[i];
entry[i-1] = entry[i];
}
bottom--;
color[pos-1] = value;
entry[pos-1] = pixel;
} else if ( top < size-1 ) {
for ( i = top; i >= pos; i-- ) {
color[i+1] = color[i];
entry[i+1] = entry[i];
}
top++;
color[pos] = value;
entry[pos] = pixel;
}
} else {
if ( top < size-1 ) {
for ( i = top; i > pos; i-- ) {
color[i+1] = color[i];
entry[i+1] = entry[i];
}
top++;
color[pos+1] = value;
entry[pos+1] = pixel;
} else if ( bottom > 0 ) {
for ( i = bottom; i < pos; i++ ) {
color[i-1] = color[i];
entry[i-1] = entry[i];
}
bottom--;
color[pos] = value;
entry[pos] = pixel;
}
}
return( pixel );
}
bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
{
wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
wxCHECK_MSG( depth == -1, FALSE, wxT("invalid bitmap depth") )
m_refData = new wxBitmapRefData();
if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
int width = image.GetWidth();
int height = image.GetHeight();
SetHeight( height );
SetWidth( width );
Display *dpy = (Display*) wxGetDisplay();
Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
// Create image
XImage *data_image = XCreateImage( dpy, vis, bpp, ZPixmap, 0, 0, width, height, 32, 0 );
data_image->data = (char*) malloc( data_image->bytes_per_line * data_image->height );
Create( width, height, bpp );
// Create mask
XImage *mask_image = (XImage*) NULL;
if (image.HasMask())
{
mask_image = XCreateImage( dpy, vis, 1, ZPixmap, 0, 0, width, height, 32, 0 );
mask_image->data = (char*) malloc( mask_image->bytes_per_line * mask_image->height );
}
// Retrieve depth info
XVisualInfo vinfo_template;
XVisualInfo *vi;
vinfo_template.visual = vis;
vinfo_template.visualid = XVisualIDFromVisual( vis );
vinfo_template.depth = bpp;
int nitem = 0;
vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
wxCHECK_MSG( vi, FALSE, wxT("no visual") );
XFree( vi );
if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
if (bpp < 8) bpp = 8;
// Render
enum byte_order { RGB, RBG, BRG, BGR, GRB, GBR };
byte_order b_o = RGB;
if (bpp >= 24)
{
if ((vi->red_mask > vi->green_mask) && (vi->green_mask > vi->blue_mask)) b_o = RGB;
else if ((vi->red_mask > vi->blue_mask) && (vi->blue_mask > vi->green_mask)) b_o = RGB;
else if ((vi->blue_mask > vi->red_mask) && (vi->red_mask > vi->green_mask)) b_o = BRG;
else if ((vi->blue_mask > vi->green_mask) && (vi->green_mask > vi->red_mask)) b_o = BGR;
else if ((vi->green_mask > vi->red_mask) && (vi->red_mask > vi->blue_mask)) b_o = GRB;
else if ((vi->green_mask > vi->blue_mask) && (vi->blue_mask > vi->red_mask)) b_o = GBR;
}
int r_mask = image.GetMaskRed();
int g_mask = image.GetMaskGreen();
int b_mask = image.GetMaskBlue();
XColor colors[256];
if (bpp == 8)
{
Colormap cmap = (Colormap) wxTheApp->GetMainColormap( dpy );
for (int i = 0; i < 256; i++) colors[i].pixel = i;
XQueryColors( dpy, cmap, colors, 256 );
}
wxSearchColor scolor( 256, colors );
unsigned char* data = image.GetData();
bool hasMask = image.HasMask();
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 (hasMask)
{
if ((r == r_mask) && (b == b_mask) && (g == g_mask))
XPutPixel( mask_image, x, y, 0 );
else
XPutPixel( mask_image, x, y, 1 );
}
switch (bpp)
{
case 8:
{
#if 0 // Old, slower code
int pixel = -1;
/*
if (wxTheApp->m_colorCube)
{
pixel = wxTheApp->m_colorCube
[ ((r & 0xf8) << 7) + ((g & 0xf8) << 2) + ((b & 0xf8) >> 3) ];
}
else
{
*/
int max = 3 * (65536);
for (int i = 0; i < 256; 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; }
}
/*
}
*/
#endif
// And this is all to get the 'right' color...
int pixel = scolor.SearchColor( r, g, b );
XPutPixel( data_image, x, y, pixel );
break;
}
case 15:
{
int pixel = ((r & 0xf8) << 7) | ((g & 0xf8) << 2) | ((b & 0xf8) >> 3);
XPutPixel( data_image, x, y, pixel );
break;
}
case 16:
{
int pixel = ((r & 0xf8) << 8) | ((g & 0xfc) << 3) | ((b & 0xf8) >> 3);
XPutPixel( data_image, x, y, pixel );
break;
}
case 32:
case 24:
{
int 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;
}
XPutPixel( data_image, x, y, pixel );
}
default: break;
}
} // for
} // for
// Blit picture
XGCValues gcvalues;
gcvalues.foreground = BlackPixel( dpy, DefaultScreen( dpy ) );
GC gc = XCreateGC( dpy, RootWindow ( dpy, DefaultScreen(dpy) ), GCForeground, &gcvalues );
XPutImage( dpy, (Drawable)GetPixmap(), gc, data_image, 0, 0, 0, 0, width, height );
XDestroyImage( data_image );
XFreeGC( dpy, gc );
// Blit mask
if (image.HasMask())
{
wxBitmap maskBitmap(width, height, 1);
GC gcMask = XCreateGC( dpy, (Pixmap) maskBitmap.GetPixmap(), (XtGCMask) 0, (XGCValues*)NULL );
XPutImage( dpy, (Drawable)maskBitmap.GetPixmap(), gcMask, mask_image, 0, 0, 0, 0, width, height );
XDestroyImage( mask_image );
XFreeGC( dpy, gcMask );
wxMask* mask = new wxMask;
mask->SetPixmap(maskBitmap.GetPixmap());
SetMask(mask);
maskBitmap.SetPixmapNull();
}
return TRUE;
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
Display *dpy = (Display*) wxGetDisplay();
Visual* vis = DefaultVisual( dpy, DefaultScreen( dpy ) );
int bpp = DefaultDepth( dpy, DefaultScreen( dpy ) );
XImage *ximage = XGetImage( dpy,
(Drawable)GetPixmap(),
0, 0,
GetWidth(), GetHeight(),
AllPlanes, ZPixmap );
wxCHECK_MSG( ximage, wxNullImage, wxT("couldn't create image") );
image.Create( GetWidth(), GetHeight() );
char unsigned *data = image.GetData();
if (!data)
{
XDestroyImage( ximage );
wxFAIL_MSG( wxT("couldn't create image") );
return wxNullImage;
}
/*
GdkImage *gdk_image_mask = (GdkImage*) NULL;
if (GetMask())
{
gdk_image_mask = gdk_image_get( GetMask()->GetBitmap(),
0, 0,
GetWidth(), GetHeight() );
image.SetMaskColour( 16, 16, 16 ); // anything unlikely and dividable
}
*/
// Retrieve depth info
XVisualInfo vinfo_template;
XVisualInfo *vi;
vinfo_template.visual = vis;
vinfo_template.visualid = XVisualIDFromVisual( vis );
vinfo_template.depth = bpp;
int nitem = 0;
vi = XGetVisualInfo( dpy, VisualIDMask|VisualDepthMask, &vinfo_template, &nitem );
wxCHECK_MSG( vi, wxNullImage, wxT("no visual") );
if ((bpp == 16) && (vi->red_mask != 0xf800)) bpp = 15;
XFree( vi );
XColor colors[256];
if (bpp == 8)
{
Colormap cmap = (Colormap)wxTheApp->GetMainColormap( dpy );
for (int i = 0; i < 256; i++) colors[i].pixel = i;
XQueryColors( dpy, cmap, colors, 256 );
}
long pos = 0;
for (int j = 0; j < GetHeight(); j++)
{
for (int i = 0; i < GetWidth(); i++)
{
int pixel = XGetPixel( ximage, i, j );
if (bpp <= 8)
{
data[pos] = colors[pixel].red >> 8;
data[pos+1] = colors[pixel].green >> 8;
data[pos+2] = colors[pixel].blue >> 8;
} else if (bpp == 15)
{
data[pos] = (pixel >> 7) & 0xf8;
data[pos+1] = (pixel >> 2) & 0xf8;
data[pos+2] = (pixel << 3) & 0xf8;
} else if (bpp == 16)
{
data[pos] = (pixel >> 8) & 0xf8;
data[pos+1] = (pixel >> 3) & 0xfc;
data[pos+2] = (pixel << 3) & 0xf8;
} else
{
data[pos] = (pixel >> 16) & 0xff;
data[pos+1] = (pixel >> 8) & 0xff;
data[pos+2] = pixel & 0xff;
}
/*
if (gdk_image_mask)
{
int mask_pixel = gdk_image_get_pixel( gdk_image_mask, i, j );
if (mask_pixel == 0)
{
data[pos] = 16;
data[pos+1] = 16;
data[pos+2] = 16;
}
}
*/
pos += 3;
}
}
XDestroyImage( ximage );
/*
if (gdk_image_mask) gdk_image_destroy( gdk_image_mask );
*/
return image;
}

View File

@ -350,6 +350,360 @@ bool wxBitmap::Create(int w, int h, int d)
return Ok();
}
bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
{
wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
m_refData = new wxBitmapRefData();
// sizeLimit is the MS upper limit for the DIB size
#ifdef WIN32
int sizeLimit = 1024*768*3;
#else
int sizeLimit = 0x7fff ;
#endif
// width and height of the device-dependent bitmap
int width = image.GetWidth();
int bmpHeight = image.GetHeight();
// calc the number of bytes per scanline and padding
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
int lineBoundary = bytePerLine % sizeDWORD;
int padding = 0;
if( lineBoundary > 0 )
{
padding = sizeDWORD - lineBoundary;
bytePerLine += padding;
}
// calc the number of DIBs and heights of DIBs
int numDIB = 1;
int hRemain = 0;
int height = sizeLimit/bytePerLine;
if( height >= bmpHeight )
height = bmpHeight;
else
{
numDIB = bmpHeight / height;
hRemain = bmpHeight % height;
if( hRemain >0 ) numDIB++;
}
// set bitmap parameters
wxCHECK_MSG( Ok(), *this, wxT("invalid image") );
SetWidth( width );
SetHeight( bmpHeight );
if (depth == -1) depth = wxDisplayDepth();
SetDepth( depth );
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER);
BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
// Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = (DWORD)width;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
// the general formula for biSizeImage:
// ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
lpDIBh->bmiHeader.biClrImportant = 0;
lpDIBh->bmiHeader.biXPelsPerMeter = 0;
lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// memory for DIB data
unsigned char *lpBits;
lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits )
{
wxFAIL_MSG( wxT("could not allocate memory for DIB") );
free( lpDIBh );
return FALSE;
}
// create and set the device-dependent bitmap
HDC hdc = ::GetDC(NULL);
HDC memdc = ::CreateCompatibleDC( hdc );
HBITMAP hbitmap;
hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
::SelectObject( memdc, hbitmap);
HPALETTE hOldPalette = 0;
if (image.GetPalette().Ok())
{
hOldPalette = ::SelectPalette(memdc, (HPALETTE) image.GetPalette().GetHPALETTE(), FALSE);
::RealizePalette(memdc);
}
// copy image data into DIB data and then into DDB (in a loop)
unsigned char *data = image.GetData();
int i, j, n;
int origin = 0;
unsigned char *ptdata = data;
unsigned char *ptbits;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits;
for( j=0; j<height; j++ )
{
for( i=0; i<width; i++ )
{
*(ptbits++) = *(ptdata+2);
*(ptbits++) = *(ptdata+1);
*(ptbits++) = *(ptdata );
ptdata += 3;
}
for( i=0; i< padding; i++ ) *(ptbits++) = 0;
}
::StretchDIBits( memdc, 0, origin, width, height,\
0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
origin += height;
// if numDIB = 1, lines below can also be used
// hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
// The above line is equivalent to the following two lines.
// hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
// ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
// or the following lines
// hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
// HDC memdc = ::CreateCompatibleDC( hdc );
// ::SelectObject( memdc, hbitmap);
// ::SetDIBitsToDevice( memdc, 0, 0, width, height,
// 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
// ::SelectObject( memdc, 0 );
// ::DeleteDC( memdc );
}
SetHBITMAP( (WXHBITMAP) hbitmap );
if (hOldPalette)
SelectPalette(memdc, hOldPalette, FALSE);
// similarly, created an mono-bitmap for the possible mask
if( image.HasMask() )
{
hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
HGDIOBJ hbmpOld = ::SelectObject( memdc, hbitmap);
if( numDIB == 1 ) height = bmpHeight;
else height = sizeLimit/bytePerLine;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
origin = 0;
unsigned char r = image.GetMaskRed();
unsigned char g = image.GetMaskGreen();
unsigned char b = image.GetMaskBlue();
unsigned char zero = 0, one = 255;
ptdata = data;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits;
for( int j=0; j<height; j++ )
{
for(i=0; i<width; i++ )
{
// was causing a code gen bug in cw : if( ( cr !=r) || (cg!=g) || (cb!=b) )
unsigned char cr = (*(ptdata++)) ;
unsigned char cg = (*(ptdata++)) ;
unsigned char cb = (*(ptdata++)) ;
if( ( cr !=r) || (cg!=g) || (cb!=b) )
{
*(ptbits++) = one;
*(ptbits++) = one;
*(ptbits++) = one;
}
else
{
*(ptbits++) = zero;
*(ptbits++) = zero;
*(ptbits++) = zero;
}
}
for( i=0; i< padding; i++ ) *(ptbits++) = zero;
}
::StretchDIBits( memdc, 0, origin, width, height,\
0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
origin += height;
}
// create a wxMask object
wxMask *mask = new wxMask();
mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
SetMask( mask );
// It will be deleted when the wxBitmap object is deleted (as of 01/1999)
/* The following can also be used but is slow to run
wxColour colour( GetMaskRed(), GetMaskGreen(), GetMaskBlue());
wxMask *mask = new wxMask( *this, colour );
SetMask( mask );
*/
::SelectObject( memdc, hbmpOld );
}
// free allocated resources
::DeleteDC( memdc );
::ReleaseDC(NULL, hdc);
free(lpDIBh);
free(lpBits);
#if WXWIN_COMPATIBILITY_2
// check the wxBitmap object
GetBitmapData()->SetOk();
#endif // WXWIN_COMPATIBILITY_2
if (wxTheBitmapList) wxTheBitmapList->AddBitmap(this);
return TRUE;
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
int height = GetHeight();
image.Create( width, height );
unsigned char *data = image.GetData();
if( !data )
{
wxFAIL_MSG( wxT("could not allocate data for image") );
return wxNullImage;
}
// calc the number of bytes per scanline and padding in the DIB
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
int lineBoundary = bytePerLine % sizeDWORD;
int padding = 0;
if( lineBoundary > 0 )
{
padding = sizeDWORD - lineBoundary;
bytePerLine += padding;
}
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER);
BITMAPINFO *lpDIBh = (BITMAPINFO *) malloc( headersize );
if( !lpDIBh )
{
wxFAIL_MSG( wxT("could not allocate data for DIB header") );
free( data );
return wxNullImage;
}
// Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = width;
lpDIBh->bmiHeader.biHeight = -height;
lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
lpDIBh->bmiHeader.biClrImportant = 0;
lpDIBh->bmiHeader.biXPelsPerMeter = 0;
lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// memory for DIB data
unsigned char *lpBits;
lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits )
{
wxFAIL_MSG( wxT("could not allocate data for DIB") );
free( data );
free( lpDIBh );
return wxNullImage;
}
// copy data from the device-dependent bitmap to the DIB
HDC hdc = ::GetDC(NULL);
HBITMAP hbitmap;
hbitmap = (HBITMAP) GetHBITMAP();
::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
// copy DIB data into the wxImage object
int i, j;
unsigned char *ptdata = data;
unsigned char *ptbits = lpBits;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{
*(ptdata++) = *(ptbits+2);
*(ptdata++) = *(ptbits+1);
*(ptdata++) = *(ptbits );
ptbits += 3;
}
ptbits += padding;
}
// similarly, set data according to the possible mask bitmap
if( GetMask() && GetMask()->GetMaskBitmap() )
{
hbitmap = (HBITMAP) GetMask()->GetMaskBitmap();
// memory DC created, color set, data copied, and memory DC deleted
HDC memdc = ::CreateCompatibleDC( hdc );
::SetTextColor( memdc, RGB( 0, 0, 0 ) );
::SetBkColor( memdc, RGB( 255, 255, 255 ) );
::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
::DeleteDC( memdc );
// background color set to RGB(16,16,16) in consistent with wxGTK
unsigned char r=16, g=16, b=16;
ptdata = data;
ptbits = lpBits;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{
if( *ptbits != 0 )
ptdata += 3;
else
{
*(ptdata++) = r;
*(ptdata++) = g;
*(ptdata++) = b;
}
ptbits += 3;
}
ptbits += padding;
}
image.SetMaskColour( r, g, b );
image.SetMask( TRUE );
}
else
{
image.SetMask( FALSE );
}
// free allocated resources
::ReleaseDC(NULL, hdc);
free(lpDIBh);
free(lpBits);
return image;
}
bool wxBitmap::LoadFile(const wxString& filename, long type)
{
UnRef();

View File

@ -464,6 +464,341 @@ bool wxBitmap::SaveFile(
}
} // end of wxBitmap::SaveFile
// ----------------------------------------------------------------------------
// wxImage-wxBitmap convertion
// ----------------------------------------------------------------------------
bool wxBitmap::CreateFromImage( const wxImage& image, int depth )
{
wxCHECK_MSG( image.Ok(), FALSE, wxT("invalid image") )
// TODO:
/*
int sizeLimit = 1024*768*3;
// width and height of the device-dependent bitmap
int width = GetWidth();
int bmpHeight = GetHeight();
// calc the number of bytes per scanline and padding
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
int lineBoundary = bytePerLine % sizeDWORD;
int padding = 0;
if( lineBoundary > 0 )
{
padding = sizeDWORD - lineBoundary;
bytePerLine += padding;
}
// calc the number of DIBs and heights of DIBs
int numDIB = 1;
int hRemain = 0;
int height = sizeLimit/bytePerLine;
if( height >= bmpHeight )
height = bmpHeight;
else
{
numDIB = bmpHeight / height;
hRemain = bmpHeight % height;
if( hRemain >0 ) numDIB++;
}
// set bitmap parameters
wxBitmap bitmap;
wxCHECK_MSG( Ok(), bitmap, wxT("invalid image") );
bitmap.SetWidth( width );
bitmap.SetHeight( bmpHeight );
bitmap.SetDepth( wxDisplayDepth() );
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER);
LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
wxCHECK_MSG( lpDIBh, bitmap, wxT("could not allocate memory for DIB header") );
// Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = (DWORD)width;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
// the general formula for biSizeImage:
// ( ( ( ((DWORD)width*24) +31 ) & ~31 ) >> 3 ) * height;
lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
lpDIBh->bmiHeader.biClrImportant = 0;
lpDIBh->bmiHeader.biXPelsPerMeter = 0;
lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// memory for DIB data
unsigned char *lpBits;
lpBits = (unsigned char *)malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits )
{
wxFAIL_MSG( wxT("could not allocate memory for DIB") );
free( lpDIBh );
return bitmap;
}
// create and set the device-dependent bitmap
HDC hdc = ::GetDC(NULL);
HDC memdc = ::CreateCompatibleDC( hdc );
HBITMAP hbitmap;
hbitmap = ::CreateCompatibleBitmap( hdc, width, bmpHeight );
::SelectObject( memdc, hbitmap);
// copy image data into DIB data and then into DDB (in a loop)
unsigned char *data = GetData();
int i, j, n;
int origin = 0;
unsigned char *ptdata = data;
unsigned char *ptbits;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB-1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits;
for( j=0; j<height; j++ )
{
for( i=0; i<width; i++ )
{
*(ptbits++) = *(ptdata+2);
*(ptbits++) = *(ptdata+1);
*(ptbits++) = *(ptdata );
ptdata += 3;
}
for( i=0; i< padding; i++ ) *(ptbits++) = 0;
}
::StretchDIBits( memdc, 0, origin, width, height,\
0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
origin += height;
// if numDIB = 1, lines below can also be used
// hbitmap = CreateDIBitmap( hdc, &(lpDIBh->bmiHeader), CBM_INIT, lpBits, lpDIBh, DIB_RGB_COLORS );
// The above line is equivalent to the following two lines.
// hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
// ::SetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS);
// or the following lines
// hbitmap = ::CreateCompatibleBitmap( hdc, width, height );
// HDC memdc = ::CreateCompatibleDC( hdc );
// ::SelectObject( memdc, hbitmap);
// ::SetDIBitsToDevice( memdc, 0, 0, width, height,
// 0, 0, 0, height, (void *)lpBits, lpDIBh, DIB_RGB_COLORS);
// ::SelectObject( memdc, 0 );
// ::DeleteDC( memdc );
}
bitmap.SetHBITMAP( (WXHBITMAP) hbitmap );
// similarly, created an mono-bitmap for the possible mask
if( HasMask() )
{
hbitmap = ::CreateBitmap( (WORD)width, (WORD)bmpHeight, 1, 1, NULL );
::SelectObject( memdc, hbitmap);
if( numDIB == 1 ) height = bmpHeight;
else height = sizeLimit/bytePerLine;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
origin = 0;
unsigned char r = GetMaskRed();
unsigned char g = GetMaskGreen();
unsigned char b = GetMaskBlue();
unsigned char zero = 0, one = 255;
ptdata = data;
for( n=0; n<numDIB; n++ )
{
if( numDIB > 1 && n == numDIB - 1 && hRemain > 0 )
{
// redefine height and size of the (possibly) last smaller DIB
// memory is not reallocated
height = hRemain;
lpDIBh->bmiHeader.biHeight = (DWORD)(-height);
lpDIBh->bmiHeader.biSizeImage = bytePerLine*height;
}
ptbits = lpBits;
for( int j=0; j<height; j++ )
{
for(i=0; i<width; i++ )
{
if( (*(ptdata++)!=r) | (*(ptdata++)!=g) | (*(ptdata++)!=b) )
{
*(ptbits++) = one;
*(ptbits++) = one;
*(ptbits++) = one;
}
else
{
*(ptbits++) = zero;
*(ptbits++) = zero;
*(ptbits++) = zero;
}
}
for( i=0; i< padding; i++ ) *(ptbits++) = zero;
}
::StretchDIBits( memdc, 0, origin, width, height,\
0, 0, width, height, lpBits, lpDIBh, DIB_RGB_COLORS, SRCCOPY);
origin += height;
}
// create a wxMask object
wxMask *mask = new wxMask();
mask->SetMaskBitmap( (WXHBITMAP) hbitmap );
bitmap.SetMask( mask );
}
// free allocated resources
::SelectObject( memdc, 0 );
::DeleteDC( memdc );
::ReleaseDC(NULL, hdc);
free(lpDIBh);
free(lpBits);
// check the wxBitmap object
if( bitmap.GetHBITMAP() )
bitmap.SetOk( TRUE );
else
bitmap.SetOk( FALSE );
*/
return TRUE;
}
wxImage wxBitmap::ConvertToImage() const
{
wxImage image;
wxCHECK_MSG( Ok(), wxNullImage, wxT("invalid bitmap") );
// create an wxImage object
int width = GetWidth();
int height = GetHeight();
image.Create( width, height );
unsigned char *data = image.GetData();
if( !data )
{
wxFAIL_MSG( wxT("could not allocate data for image") );
return wxNullImage;
}
// calc the number of bytes per scanline and padding in the DIB
int bytePerLine = width*3;
int sizeDWORD = sizeof( DWORD );
int lineBoundary = bytePerLine % sizeDWORD;
int padding = 0;
if( lineBoundary > 0 )
{
padding = sizeDWORD - lineBoundary;
bytePerLine += padding;
}
// TODO:
/*
// create a DIB header
int headersize = sizeof(BITMAPINFOHEADER);
LPBITMAPINFO lpDIBh = (BITMAPINFO *) malloc( headersize );
if( !lpDIBh )
{
wxFAIL_MSG( wxT("could not allocate data for DIB header") );
free( data );
return;
}
// Fill in the DIB header
lpDIBh->bmiHeader.biSize = headersize;
lpDIBh->bmiHeader.biWidth = width;
lpDIBh->bmiHeader.biHeight = -height;
lpDIBh->bmiHeader.biSizeImage = bytePerLine * height;
lpDIBh->bmiHeader.biPlanes = 1;
lpDIBh->bmiHeader.biBitCount = 24;
lpDIBh->bmiHeader.biCompression = BI_RGB;
lpDIBh->bmiHeader.biClrUsed = 0;
// These seem not really needed for our purpose here.
lpDIBh->bmiHeader.biClrImportant = 0;
lpDIBh->bmiHeader.biXPelsPerMeter = 0;
lpDIBh->bmiHeader.biYPelsPerMeter = 0;
// memory for DIB data
unsigned char *lpBits;
lpBits = (unsigned char *) malloc( lpDIBh->bmiHeader.biSizeImage );
if( !lpBits )
{
wxFAIL_MSG( wxT("could not allocate data for DIB") );
free( data );
free( lpDIBh );
return;
}
// copy data from the device-dependent bitmap to the DIB
HDC hdc = ::GetDC(NULL);
HBITMAP hbitmap;
hbitmap = (HBITMAP) bitmap.GetHBITMAP();
::GetDIBits( hdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
// copy DIB data into the wxImage object
int i, j;
unsigned char *ptdata = data;
unsigned char *ptbits = lpBits;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{
*(ptdata++) = *(ptbits+2);
*(ptdata++) = *(ptbits+1);
*(ptdata++) = *(ptbits );
ptbits += 3;
}
ptbits += padding;
}
// similarly, set data according to the possible mask bitmap
if( bitmap.GetMask() && bitmap.GetMask()->GetMaskBitmap() )
{
hbitmap = (HBITMAP) bitmap.GetMask()->GetMaskBitmap();
// memory DC created, color set, data copied, and memory DC deleted
HDC memdc = ::CreateCompatibleDC( hdc );
::SetTextColor( memdc, RGB( 0, 0, 0 ) );
::SetBkColor( memdc, RGB( 255, 255, 255 ) );
::GetDIBits( memdc, hbitmap, 0, height, lpBits, lpDIBh, DIB_RGB_COLORS );
::DeleteDC( memdc );
// background color set to RGB(16,16,16) in consistent with wxGTK
unsigned char r=16, g=16, b=16;
ptdata = data;
ptbits = lpBits;
for( i=0; i<height; i++ )
{
for( j=0; j<width; j++ )
{
if( *ptbits != 0 )
ptdata += 3;
else
{
*(ptdata++) = r;
*(ptdata++) = g;
*(ptdata++) = b;
}
ptbits += 3;
}
ptbits += padding;
}
SetMaskColour( r, g, b );
SetMask( TRUE );
}
else
{
SetMask( FALSE );
}
// free allocated resources
::ReleaseDC(NULL, hdc);
free(lpDIBh);
free(lpBits);
*/
return image;
}
// ----------------------------------------------------------------------------
// sub bitmap extraction
// ----------------------------------------------------------------------------