Difference between revisions of "Binary Tips"

From FM Plugin Wikipedia
Jump to: navigation, search
(Example Binary Functions)
(Example Binary Functions)
Line 81: Line 81:
  
  
 
 
The 'returnGraphicImage' function for Windows:
 
 
#if defined(FMX_WIN_TARGET)
 
unsigned char * returnGraphicImage( long width, long height, long *outSize )
 
{
 
  long size = 0;
 
unsigned char outBuffer = NULL;
 
 
// This is a work in progress !
 
 
  *outSize = size; // return the size of our created buffer
 
  return outBuffer; // and the buffer itself
 
}
 
#endif
 
  
  
Line 165: Line 149:
 
  *outSize = size; // return the size of our created buffer
 
  *outSize = size; // return the size of our created buffer
 
  return outBuffer; // and the buffer itself
 
  return outBuffer; // and the buffer itself
 +
}
 +
#endif
 +
 +
 +
 +
The 'returnGraphicImage' function for Windows:
 +
 +
#if defined(FMX_WIN_TARGET)
 +
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
 
  #endif

Revision as of 01:28, 2 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 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;
}



The 'returnGraphicImage' function for Mac:

#if defined(FMX_MAC_TARGET)
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)
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