Binary Tips

From FM Plugin Wikipedia
Revision as of 01:47, 2 May 2013 by Kent (talk | contribs) (Example Binary Functions)

Jump to: navigation, search

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


Binary Public Functions






Example Binary Functions

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