Difference between revisions of "Binary Tips"

From FM Plugin Wikipedia
Jump to: navigation, search
(New page: {| align="right" | __TOC__ |} This page is about editing and working with Binary data (Images, sound, etc) passed from FileMaker to your plugin.)
 
(Example Image in / out)
 
(15 intermediate revisions by 2 users not shown)
Line 4: Line 4:
  
 
This page is about editing and working with Binary data (Images, sound, etc) passed from FileMaker to your plugin.
 
This page is about editing and working with Binary data (Images, sound, etc) passed from FileMaker to your plugin.
 +
 +
 +
=Binary Public Functions=
 +
*[[BinaryData &operator = ( const BinaryData &source )]]
 +
*[[bool operator == ( const BinaryData &compareData ) const]]
 +
*[[bool operator != ( const BinaryData &compareData ) const]]
 +
*[[int GetCount () const]]
 +
*[[int GetIndex ( const QuadChar& dataType ) const]]
 +
*[[ulong GetTotalSize () const]]
 +
*[[void GetType ( int index, QuadChar& dataType ) const]]
 +
*[[ulong GetSize ( int index ) const]]
 +
*[[errcode GetData ( int index, ulong offset, ulong amount, void *buffer ) const]]
 +
           
 +
 +
*[[errcode Add ( const QuadChar& dataType, ulong amount, void *buffer )]]
 +
*[[bool Remove ( const QuadChar& dataType )]]
 +
*[[void RemoveAll ()]]
 +
 +
 +
*[[errcode GetFNAMData ( Text &filepathlist ) const]]
 +
*[[errcode AddFNAMData ( const Text &filepathlist )]]
 +
*[[errcode GetSIZEData ( short &width, short &height ) const]]
 +
*[[errcode AddSIZEData ( short width, short height )]]
 +
 +
       
 +
*[[void operator delete ( void *obj )]]
 +
 +
 +
 +
*[[BinaryDataAutoPtr ()]]
 +
*[[BinaryDataAutoPtr ( const BinaryData &sourceData )]]
 +
 +
 +
 +
=Example Image in / out=
 +
 +
This example code takes an image as the first parameter - then loops through all 'streams' and then returns only the JPEG or GIF stream (with it's size data) - in effect removing any other data streams.
 +
This can be useful to reduce file size - but removing any unnecessary image data if all you want is to display the image in FileMaker
 +
 +
FMX_PROC(fmx::errcode) Do_Graphics_ImageOnly(short /* funcId */, const fmx::ExprEnv& /* environment */, const fmx::DataVect& dataVect, fmx::Data& results )
 +
{
 +
fmx::errcode err = -1;
 +
fmx::QuadCharAutoPtr bufType;
 +
fmx::BinaryDataAutoPtr out;
 +
 +
void * buffer;
 +
long item, count, size;
 +
short w = 0, h = 0;
 +
bool haveImage = false;
 +
 +
fmx::uint32 nParams = dataVect.Size(); // get the number of Parameters the user has passed.
 +
 +
fmx::QuadCharAutoPtr jpeg('J', 'P', 'E', 'G');
 +
fmx::QuadCharAutoPtr gif('G', 'I', 'F', 'f');
 +
uint32 jpegMacType = jpeg->GetMacType();
 +
uint32 gifMacType = gif->GetMacType();
 +
 +
 +
if( nParams == 1 )
 +
{
 +
const fmx::BinaryData& g = dataVect.AtAsBinaryData( 0 ); // get the container details
 +
 +
count = g.GetCount();
 +
 +
err = g.GetSIZEData(w, h);
 +
 +
if( err == 0)
 +
{
 +
for(item = 0; item <= count; item++)
 +
{
 +
g.GetType(item, *bufType);
 +
uint32 bufMacType = bufType->GetMacType();
 +
 +
if( (bufMacType == jpegMacType) || (bufMacType == gifMacType)  ) // is this a JPEG or GIFf stream ?
 +
{
 +
size = g.GetSize( item );
 +
if( size > 0 )
 +
{
 +
 +
buffer = new void *[ size ];
 +
if( buffer != NULL ) // make sure the memory was allocated
 +
{
 +
err = g.GetData ( item, 0, size, buffer );
 +
 +
if (err == 0)
 +
{
 +
err = out->Add ( *bufType, size, buffer );
 +
haveImage = (err == 0);
 +
}
 +
 +
free( buffer );  // release the memory we just allocated
 +
}
 +
}
 +
}
 +
}
 +
}
 +
}
 +
 +
if( (haveImage) && (err == 0) )
 +
{
 +
err = out->AddSIZEData( w, h ); // all images must have a size specified
 +
if( err == 0) results.SetBinaryData ( *out );
 +
 +
} else {
 +
// No image, handle appropriately
 +
}
 +
 +
 +
return err;
 +
 +
}
 +
 +
=Example Image Creation=
 +
 +
 +
The following example code shows how to create a bitmap image, convert it to PNG and return to FileMaker
 +
 +
 +
FMX_PROC(fmx::errcode) Do_Graphic(short /* funcId */, const fmx::ExprEnv& /* environment */, const fmx::DataVect& dataVect, fmx::Data&  results )
 +
{
 +
 +
fmx::errcode err = 0;
 +
bool            haveImage = false;
 +
fmx::QuadCharAutoPtr png('P', 'N', 'G', 'f');
 +
fmx::BinaryDataAutoPtr outImage;
 +
 +
   
 +
long pixelsWide = 300;
 +
long pixelsHigh = 150;
 +
 
 +
long size = 0;
 +
unsigned char * outBuffer = returnGraphicImage(pixelsWide, pixelsHigh, &size); // Get our image
 +
if( outBuffer != NULL )
 +
{
 +
 +
err = outImage->Add ( *png, size, outBuffer ); // Let FM know the image type is PNG
 +
if (err == 0)
 +
{
 +
fmx::TextAutoPtr temp;
 +
temp->Assign("Picture.png");
 +
const fmx::Text&  name = *temp;
 +
err = outImage->AddFNAMData( name ); // so FileMaker has a name for our image if the user tries to save it or external storage is used
 +
 +
err = outImage->AddSIZEData( pixelsWide, pixelsHigh ); // all images must have a size specified
 +
haveImage = ( err == 0 );
 +
if( haveImage ) results.SetBinaryData ( *outImage ); // Add the image data
 +
}
 +
 +
delete [] outBuffer;
 +
}
 +
 +
return err;
 +
}
 +
 +
WARNING: No error checking is included in the code below !
 +
 +
 +
 +
The 'returnGraphicImage' function for Mac:
 +
 +
#if defined(FMX_MAC_TARGET)
 +
#include <ApplicationServices/ApplicationServices.h>
 +
 +
unsigned char * returnGraphicImage( long width, long height, long *outSize )
 +
{
 +
#define BYTES_PER_PIXEL 4
 +
 +
CFMutableDataRef imgData = CFDataCreateMutable( kCFAllocatorDefault, 0);
 +
if( imgData == NULL ) return NULL;
 +
 +
CGImageDestinationRef destRef = CGImageDestinationCreateWithData(imgData, kUTTypePNG, 1, NULL);
 +
if( destRef == NULL ) { CFRelease( imgData ); return NULL; }
 +
 +
// create an image from the layer
 +
void *buffer = malloc(width * height * BYTES_PER_PIXEL);
 +
if( buffer == NULL ) { CFRelease( destRef ); CFRelease( imgData ); return NULL; }
 +
memset(&buffer, 0, sizeof(buffer));
 +
 +
 +
CGColorSpaceRef colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
 +
CGContextRef context = CGBitmapContextCreate (buffer, width, height, 8, width * BYTES_PER_PIXEL, colorSpace, kCGImageAlphaPremultipliedLast);
 +
CGColorSpaceRelease( colorSpace );
 +
 +
if( context == NULL ) { CFRelease( destRef ); CFRelease( imgData ); free( buffer ); return NULL; }
 +
 +
 +
// Open the image area for drawing
 +
CGContextSaveGState(context);
 +
CGRect rect = CGRectMake(0, 0, width, height); // RECT representing the area available for drawing to.
 +
// ---------------------------------------------------------------------------------------------------------------
 +
 +
CGContextSetRGBStrokeColor(context, 1, 0, 0, 1); // Draw a 'Red' frame around our image.
 +
CGContextStrokeRectWithWidth(context, rect, 6);
 +
 +
CGContextSelectFont(context, "Verdana", 12, kCGEncodingMacRoman); // Add some text to our image
 +
CGContextSetAllowsAntialiasing(context, false);
 +
CGContextSetCharacterSpacing(context, 1.0);
 +
CGContextSetTextDrawingMode(context, kCGTextFill);
 +
CGContextShowTextAtPoint(context, 50.0, 50.0, "Hello and Welcome", 17);
 +
 +
 +
// ---------------------------------------------------------------------------------------------------------------
 +
 +
CGImageRef image = CGBitmapContextCreateImage(context); // We have finished drawing the image
 +
CGContextRestoreGState(context);
 +
 +
  CGImageDestinationAddImage(destRef, image, NULL); // Convert the image to PNG
 +
CGImageDestinationFinalize(destRef);
 +
 +
CGContextRelease(context);
 +
CFRelease(destRef); // have finished with destRef - our image should now be in 'imgData'
 +
free(buffer); // have finished with the image buffer now too
 +
 +
unsigned char * outBuffer = NULL;
 +
long size = (long)CFDataGetLength(imgData);
 +
if( size > 0 )
 +
{
 +
outBuffer = new unsigned char [ size ];
 +
 +
if( outBuffer != NULL ) CFDataGetBytes( imgData, CFRangeMake(0, size), outBuffer );
 +
}
 +
 +
CFRelease(imgData);
 +
 +
*outSize = size; // return the size of our created buffer
 +
return outBuffer; // and the buffer itself
 +
}
 +
#endif
 +
 +
 +
 +
The 'returnGraphicImage' function for Windows:
 +
 +
#if defined(FMX_WIN_TARGET)
 +
#include <gdiplus.h>
 +
#include "wincodec.h"  // graphic libraries for Windows
 +
using namespace Gdiplus;
 +
 +
unsigned char * returnTimetableImage( long width, long height, long* outSize )
 +
{
 +
// -----------------------------------------------------------------------------------------------------------------------------
 +
// Use GDI to draw our original Bitmap image
 +
 +
Bitmap * outBM = new Bitmap(width, height, PixelFormat32bppARGB );
 +
Graphics * gr = Graphics::FromImage( outBM );
 +
 +
gr->Clear(Gdiplus::Color::Transparent);
 +
 +
SolidBrush sb(Gdiplus::Color::Red);
 +
gr->FillRectangle( &sb, 20,20, 100, 50 );
 +
 +
sb.SetColor(Gdiplus::Color::Green);
 +
gr->FillRectangle( &sb, 220,220, 80, 60 );
 +
 +
Pen pen(Color(Gdiplus::Color::Black), 5);
 +
gr->DrawRectangle( &pen, 30, 30, 120, 70 );
 +
 +
 +
FontFamily fontFamily(L"Verdana");
 +
Font font(&fontFamily, 12, FontStyleRegular, UnitPixel);
 +
PointF pointF(160, 200);
 +
sb.SetColor(Gdiplus::Color::Black);
 +
gr->DrawString(L"Hello", -1, &font, pointF, &sb);
 +
 +
 +
RectF rectF( 180, 250, 100, 100 );
 +
sb.SetColor(Color(127,0,0,255));
 +
gr->FillRectangle( &sb, rectF );
 +
gr->DrawRectangle(&pen, rectF );
 +
 +
sb.SetColor(Color(Gdiplus::Color::Black));
 +
gr->DrawString(L"This is lots of text", -1, &font, rectF, NULL, &sb);
 +
 +
 +
Gdiplus::Rect r;
 +
r.X = 0;
 +
r.Y = 0;
 +
r.Width = width;
 +
r.Height = height;
 +
 +
BitmapData * bitmapData = new BitmapData;
 +
outBM->LockBits( &r, ImageLockModeRead, PixelFormat32bppARGB, bitmapData );  // Lock the bitmapData - must release it after 'CreateBitmapFromMemory'
 +
 +
BYTE* pixels = (BYTE*)bitmapData->Scan0; // This is the Bitmap image raw data
 +
UINT stride = bitmapData->Stride; // This is the bytes per line. We need this for 'CreateBitmapFromMemory' below
 +
 +
 +
// -----------------------------------------------------------------------------------------------------------------------------
 +
HRESULT hr = CoInitialize(NULL);
 +
 +
IWICImagingFactory* pFactory = NULL;
 +
hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*)&pFactory);
 +
 +
//Create the outgoing stream
 +
HGLOBAL hOutGlobal = GlobalAlloc( GMEM_SHARE | GMEM_MOVEABLE, 0 );
 +
IStream* pOutStream = NULL;
 +
hr = CreateStreamOnHGlobal( hOutGlobal, FALSE, &pOutStream );
 +
 +
//Create the encoder.
 +
IWICBitmapEncoder* pEncoder = NULL;
 +
hr = pFactory->CreateEncoder( GUID_ContainerFormatPng, NULL, &pEncoder );
 +
hr = pEncoder->Initialize( pOutStream, WICBitmapEncoderNoCache );
 +
 +
//Get frame to decode
 +
IWICBitmapSource* pFrameDecode = NULL;
 +
hr = pFactory->CreateBitmapFromMemory( width, height, GUID_WICPixelFormat32bppBGRA, stride, height * stride, pixels, (IWICBitmap**)&pFrameDecode );
 +
 +
//Create frame to encode into
 +
IWICBitmapFrameEncode* pFrameEncode = NULL;
 +
IPropertyBag2* pPropertyBag = NULL;
 +
hr = pEncoder->CreateNewFrame( &pFrameEncode, &pPropertyBag );
 +
hr = pFrameEncode->Initialize( pPropertyBag );
 +
 +
// Set the encoder's size, resolution, color palette, pixel format, etc now
 +
WICRect rect = {0, 0, 0, 0};
 +
rect.Width = width;
 +
rect.Height = height;
 +
hr = pFrameEncode->WriteSource( pFrameDecode, &rect );
 +
 +
hr = pFrameEncode->Commit();
 +
hr = pEncoder->Commit();
 +
pFrameEncode->Release();
 +
pFrameDecode->Release();
 +
 +
//Get the bytes from the outStream
 +
ULARGE_INTEGER Size;
 +
LARGE_INTEGER zero;
 +
zero.QuadPart = 0;
 +
 +
pOutStream->Seek( zero, STREAM_SEEK_END, &Size );
 +
ULONG encoded;
 +
ULongLongToULong( Size.QuadPart, &encoded);
 +
UINT imageSize = encoded;
 +
 +
pOutStream->Release();
 +
 +
LPVOID p2 = GlobalLock(hOutGlobal);
 +
void * imagePtr = malloc( encoded );
 +
memcpy( imagePtr, p2, encoded );
 +
 +
pEncoder->Release();
 +
 +
GlobalUnlock( hOutGlobal );
 +
GlobalFree( hOutGlobal );
 +
 +
pFactory->Release();
 +
 +
// Clean up our original Bitmap
 +
outBM->UnlockBits( bitmapData );
 +
delete bitmapData;
 +
delete outBM;
 +
delete gr;
 +
 +
 +
*outSize = imageSize;
 +
    return (unsigned char *)imagePtr;
 +
}
 +
#endif

Latest revision as of 19:13, 20 May 2013

This page is about editing and working with Binary data (Images, sound, etc) passed from FileMaker to your plugin.


Binary Public Functions






Example Image in / out

This example code takes an image as the first parameter - then loops through all 'streams' and then returns only the JPEG or GIF stream (with it's size data) - in effect removing any other data streams. This can be useful to reduce file size - but removing any unnecessary image data if all you want is to display the image in FileMaker

FMX_PROC(fmx::errcode) Do_Graphics_ImageOnly(short /* funcId */, const fmx::ExprEnv& /* environment */, const fmx::DataVect& dataVect, fmx::Data& results )
{
	fmx::errcode			err = -1;
	fmx::QuadCharAutoPtr	bufType;
	fmx::BinaryDataAutoPtr	out;

	void *					buffer;
	long					item, count, size;
	short					w = 0, h = 0;
	bool					haveImage = false;
	
	fmx::uint32 nParams = dataVect.Size();							// get the number of Parameters the user has passed.
	
	fmx::QuadCharAutoPtr	jpeg('J', 'P', 'E', 'G');
	fmx::QuadCharAutoPtr	gif('G', 'I', 'F', 'f');
	uint32 jpegMacType = jpeg->GetMacType();
	uint32 gifMacType = gif->GetMacType();
	
	
	if( nParams == 1 )
	{
		const	fmx::BinaryData&	g = dataVect.AtAsBinaryData( 0 ); // get the container details
		
		count = g.GetCount();
		
		err = g.GetSIZEData(w, h);
		
		if( err == 0)
		{
			for(item = 0; item <= count; item++)
			{
				g.GetType(item, *bufType);
				uint32 bufMacType = bufType->GetMacType();
				
				if( (bufMacType == jpegMacType) || (bufMacType == gifMacType)  )	// is this a JPEG or GIFf stream ?
				{
					size = g.GetSize( item );
					if( size > 0 )
					{
						
						buffer = new void *[ size ];
						if( buffer != NULL )			// make sure the memory was allocated
						{
							err = g.GetData ( item, 0, size, buffer );
							
							if (err == 0)
							{
								err = out->Add ( *bufType, size, buffer );
								haveImage = (err == 0);
							}
							
							free( buffer );  // release the memory we just allocated
						}
					}
				}
			}
		}
	}
	
	if( (haveImage) && (err == 0) )
	{
		err = out->AddSIZEData( w, h );			// all images must have a size specified
		if( err == 0) results.SetBinaryData ( *out );
		
	} else {
		// No image, handle appropriately
	}

	
	return err;
	
}

Example Image Creation

The following example code shows how to create a bitmap image, convert it to PNG and return to FileMaker


FMX_PROC(fmx::errcode) Do_Graphic(short /* funcId */, const fmx::ExprEnv& /* environment */, const fmx::DataVect& dataVect, fmx::Data&  results )
{
	
	fmx::errcode	err = 0;
	bool            haveImage = false;
	fmx::QuadCharAutoPtr	png('P', 'N', 'G', 'f');
	fmx::BinaryDataAutoPtr	outImage;

    
	long pixelsWide = 300;
	long pixelsHigh = 150;
 
	long size = 0;
	unsigned char *	outBuffer = returnGraphicImage(pixelsWide, pixelsHigh, &size);		// Get our image
	if( outBuffer != NULL )
	{
		
		err = outImage->Add ( *png, size, outBuffer );					// Let FM know the image type is PNG
		if (err == 0)
		{
			fmx::TextAutoPtr	temp;
			temp->Assign("Picture.png");
			const fmx::Text&  name	=	*temp;
			err = outImage->AddFNAMData( name );					// so FileMaker has a name for our image if the user tries to save it or external storage is used
			
			err = outImage->AddSIZEData( pixelsWide, pixelsHigh );			// all images must have a size specified
			haveImage = ( err == 0 );
			if( haveImage )	results.SetBinaryData ( *outImage );			// Add the image data
		}
		
		delete [] outBuffer;
	}

	return err;
}

WARNING: No error checking is included in the code below !


The 'returnGraphicImage' function for Mac:

#if defined(FMX_MAC_TARGET)
#include <ApplicationServices/ApplicationServices.h>

unsigned char * returnGraphicImage( long width, long height, long *outSize )
{
	#define BYTES_PER_PIXEL	4

	CFMutableDataRef	imgData = CFDataCreateMutable( kCFAllocatorDefault, 0);
	if( imgData == NULL )	return NULL;
	
	CGImageDestinationRef	destRef = CGImageDestinationCreateWithData(imgData, kUTTypePNG, 1, NULL);
	if( destRef == NULL )	{ CFRelease( imgData );	return NULL; }

	// create an image from the layer
	void	*buffer = malloc(width * height * BYTES_PER_PIXEL);
	if( buffer == NULL )	{ CFRelease( destRef );	CFRelease( imgData );	return NULL; }
	memset(&buffer, 0, sizeof(buffer));


	CGColorSpaceRef	colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
	CGContextRef		context = CGBitmapContextCreate (buffer, width, height, 8, width * BYTES_PER_PIXEL, colorSpace, kCGImageAlphaPremultipliedLast);
	CGColorSpaceRelease( colorSpace );

	if( context == NULL )	{ CFRelease( destRef );	CFRelease( imgData );	free( buffer );	return NULL; }
	

	// Open the image area for drawing
	CGContextSaveGState(context);
	CGRect	rect = CGRectMake(0, 0, width, height);						// RECT representing the area available for drawing to.
	// ---------------------------------------------------------------------------------------------------------------

	CGContextSetRGBStrokeColor(context, 1, 0, 0, 1);					// Draw a 'Red' frame around our image.
	CGContextStrokeRectWithWidth(context, rect, 6);

	CGContextSelectFont(context, "Verdana", 12, kCGEncodingMacRoman);			// Add some text to our image
	CGContextSetAllowsAntialiasing(context, false);
	CGContextSetCharacterSpacing(context, 1.0);
	CGContextSetTextDrawingMode(context, kCGTextFill);
	CGContextShowTextAtPoint(context, 50.0, 50.0, "Hello and Welcome", 17);


	// ---------------------------------------------------------------------------------------------------------------

	CGImageRef	image		= CGBitmapContextCreateImage(context);			// We have finished drawing the image
	CGContextRestoreGState(context);

 	CGImageDestinationAddImage(destRef, image, NULL);					// Convert the image to PNG
	CGImageDestinationFinalize(destRef);
	
	CGContextRelease(context);
	CFRelease(destRef);									// have finished with destRef - our image should now be in 'imgData'
	free(buffer);										// have finished with the image buffer now too

	unsigned char * outBuffer = NULL;
	long size = (long)CFDataGetLength(imgData);
	if( size > 0 )
	{
		outBuffer = new unsigned char [ size ];
		
		if( outBuffer != NULL )		CFDataGetBytes( imgData, CFRangeMake(0, size), outBuffer );
	}
	
	CFRelease(imgData);

	*outSize = size;	// return the size of our created buffer
	return outBuffer;	// and the buffer itself
}
#endif


The 'returnGraphicImage' function for Windows:

#if defined(FMX_WIN_TARGET)
#include <gdiplus.h>
#include "wincodec.h"  // graphic libraries for Windows
using namespace Gdiplus;

unsigned char * returnTimetableImage( long width, long height, long* outSize )
{
	// -----------------------------------------------------------------------------------------------------------------------------
	// Use GDI to draw our original Bitmap image

	Bitmap * outBM = new Bitmap(width, height, PixelFormat32bppARGB );
	Graphics * gr = Graphics::FromImage( outBM );
	
	gr->Clear(Gdiplus::Color::Transparent);

	SolidBrush sb(Gdiplus::Color::Red);
	gr->FillRectangle( &sb, 20,20, 100, 50 );

	sb.SetColor(Gdiplus::Color::Green);
	gr->FillRectangle( &sb, 220,220, 80, 60 );

	Pen pen(Color(Gdiplus::Color::Black), 5);
	gr->DrawRectangle( &pen, 30, 30, 120, 70 );


	FontFamily	fontFamily(L"Verdana");
	Font		font(&fontFamily, 12, FontStyleRegular, UnitPixel);
	PointF		pointF(160, 200);
	sb.SetColor(Gdiplus::Color::Black);
	gr->DrawString(L"Hello", -1, &font, pointF, &sb);


	RectF		rectF( 180, 250, 100, 100 );
	sb.SetColor(Color(127,0,0,255));
	gr->FillRectangle( &sb, rectF );
	gr->DrawRectangle(&pen, rectF );

	sb.SetColor(Color(Gdiplus::Color::Black));
	gr->DrawString(L"This is lots of text", -1, &font, rectF, NULL, &sb);


	Gdiplus::Rect r;
	r.X = 0;
	r.Y = 0;
	r.Width = width;
	r.Height = height;

	BitmapData * bitmapData = new BitmapData;
	outBM->LockBits( &r, ImageLockModeRead, PixelFormat32bppARGB, bitmapData );   		// Lock the bitmapData - must release it after 'CreateBitmapFromMemory'

	BYTE* pixels = (BYTE*)bitmapData->Scan0;						// This is the Bitmap image raw data
	UINT stride = bitmapData->Stride;							// This is the bytes per line. We need this for 'CreateBitmapFromMemory' below


	// -----------------------------------------------------------------------------------------------------------------------------
	HRESULT hr = CoInitialize(NULL);
	
	IWICImagingFactory* pFactory = NULL;
	hr = CoCreateInstance( CLSID_WICImagingFactory, NULL, CLSCTX_INPROC_SERVER, IID_IWICImagingFactory, (LPVOID*)&pFactory);

	//Create the outgoing stream
	HGLOBAL hOutGlobal = GlobalAlloc( GMEM_SHARE | GMEM_MOVEABLE, 0 );
	IStream* pOutStream = NULL;
	hr = CreateStreamOnHGlobal( hOutGlobal, FALSE, &pOutStream );

	//Create the encoder.
	IWICBitmapEncoder* pEncoder = NULL;
	hr = pFactory->CreateEncoder( GUID_ContainerFormatPng, NULL, &pEncoder );
	hr = pEncoder->Initialize( pOutStream, WICBitmapEncoderNoCache );

	//Get frame to decode
	IWICBitmapSource* pFrameDecode = NULL;
	hr = pFactory->CreateBitmapFromMemory( width, height, GUID_WICPixelFormat32bppBGRA, stride, height * stride, pixels, (IWICBitmap**)&pFrameDecode );

	//Create frame to encode into
	IWICBitmapFrameEncode* pFrameEncode = NULL;
	IPropertyBag2* pPropertyBag = NULL;
	hr = pEncoder->CreateNewFrame( &pFrameEncode, &pPropertyBag );
	hr = pFrameEncode->Initialize( pPropertyBag );

	// Set the encoder's size, resolution, color palette, pixel format, etc now
	WICRect rect = {0, 0, 0, 0};
	rect.Width = width;
	rect.Height = height;
	hr = pFrameEncode->WriteSource( pFrameDecode, &rect );

	hr = pFrameEncode->Commit();
	hr = pEncoder->Commit();
	pFrameEncode->Release();
	pFrameDecode->Release();

	//Get the bytes from the outStream
	ULARGE_INTEGER Size;
	LARGE_INTEGER zero;
	zero.QuadPart = 0;

	pOutStream->Seek( zero, STREAM_SEEK_END, &Size );
	ULONG encoded;
	ULongLongToULong( Size.QuadPart, &encoded);
	UINT imageSize = encoded;
		
	pOutStream->Release();

	LPVOID p2 = GlobalLock(hOutGlobal);
	void * imagePtr = malloc( encoded );
	memcpy( imagePtr, p2, encoded );

	pEncoder->Release();
		
	GlobalUnlock( hOutGlobal );
	GlobalFree( hOutGlobal );

	pFactory->Release();

	// Clean up our original Bitmap
	outBM->UnlockBits( bitmapData );
	delete bitmapData;
	delete outBM;
	delete gr;


	*outSize = imageSize;
    return (unsigned char *)imagePtr;
}
#endif