Blog

Exporting BitmapData in hexa for file saving using swf2exe soft ( like mdm Zinc )

This class will help you to have a string in hexadecimal format to save it in a file. It creates the header of the file, the header of the bitmap and the data. This class require the Hexa class. Be sure you have it when compiling.

This class do its job, but I have to admit as soon as you are processing big bitmap, it’s slow… very slow. This is due because of the string operation I’m doing to format it to a conform Hexa string.

So check it and give feedbacks if you find any way to improve it or if you have any request.

[as]
/*
* Class written by Xavier MARTIN (xxlm or zeflasher)
* http://dev.webbymx.net
* http://www.webbymx.net
* If you are using this class, I will be glad to receive a picture of you front of your city hall ( or wherever outside )
* To do so please visit http://dev.webbymx.net and go in the about page to get my details…
* Licence: http://creativecommons.org/licenses/by-nc-sa/2.0/fr/deed.en
*/

import flash.display.BitmapData;
import net.webbymx.files.Hexa;

class net.webbymx.files.binary.BitmapDataExporter {
/* ****************************************************************************
* PRIVATE VARIABLES
**************************************************************************** */
private var _bmp : BitmapData;
private var _nWidth : Number;
private var _nHeight : Number;

private var _nRemainder : Number;
private var _nCurrentStep : Number;
private var _nStepLength : Number;
private var _nTotalSteps : Number;
private var _mcEnterFrame : MovieClip;

/* ****************************************************************************
* PUBLIC VARIABLES
**************************************************************************** */
public var onProgress : Function;
public var onExportDone : Function;

/* ****************************************************************************
* CONSTRUCTOR
**************************************************************************** */
function BitmapDataExporter( b : BitmapData ) {
_init( b );
}

private function _init( b : BitmapData ) : Void {
_bmp = b;
_nWidth = _bmp.width;
_nHeight = _bmp.height;
_nCurrentStep = 0;
_nRemainder = _nWidth % 4;
_nTotalSteps = Math.ceil( _nWidth * _nHeight / 900 );
_nStepLength = Math.ceil( _nWidth * _nHeight / _nTotalSteps / 2 ) * 2;
}

/* ****************************************************************************
* PRIVATE FUNCTIONS
**************************************************************************** */

/**
* Return a string of hexa for the file header
* @param Void
* @return
*/
private function _fileHeader( Void ) : Void {
var bin : String = “”;

/*
* bfType1 : Byte ; (* “B” *)
* bfType2 : Byte ; (* “M” *)
* bfSize : LongInt ; (* Size of File. Zero is acceptable *)
* bfReserved1 : Word ; (* Zero *)
* bfReserved2 : Word ; (* Zero *)
* bfOffBits : LongInt ; (* Offset to beginning of BitMap *)
*/

// writing the file type ( B and M == 42 and 4D )
bin = “424D”;

// writing size ( longInt )
bin += “00000000″;

// writing reserved, reserved ( word )
bin += “00000000″;

// writing Offset to beginning of BitMap ( longInt )
bin += “36000000″;

onProgress( bin );
}

private function _bitmapHeader( Void ) : Void {
var bin : String = “”;

var wh : String = Hexa.getDWord( _nWidth.toString( 16 ) )
var hh : String = Hexa.getDWord( _nHeight.toString( 16 ) )

/*
* biSize : LongInt ; (* Number of Bytes in Structure *)
* biWidth : LongInt ; (* Width of BitMap in Pixels *)
* biHeight : LongInt ; (* Height of BitMap in Pixels *)
* biPlanes : Word ; (* Planes in target device = 1 *)
* biBitCount : Word ; (* Bits per Pixel 1, 4, 8, or 24 *)
* biCompression : LongInt ; (* BI_RGB = 0, BI_RLE8, BI_RLE4 *)
* biSizeImage : LongInt ; (* Size of Image Part (often ignored) *)
* biXPelsPerMeter : LongInt ; (* Always Zero *)
* biYPelsPerMeter : LongInt ; (* Always Zero *)
* biClrUsed : LongInt ; (* Number of Colors used in Palette *)
* biClrImportant : LongInt ; (* Number of Colors that are Important *)
*/

// writing Number of Bytes in Structure ( longInt )
bin = “28000000″;

// writing width & height
bin += wh + hh;

// writing planes
bin += “0100″;

// writing bitcounts
bin += “1800″;

// writing compression
bin += “00000000″;

// writing Size Image
bin += “00000000″;

// writing biXPelsPerMeter
bin += “00000000″;

// writing biYPelsPerMeter
bin += “00000000″;

// writing biClrUsed
bin += “00000000″;

// writing biClrImportant
bin += “00000000″;

onProgress( bin );
}

private function _buildData( Void ) : Void {
// local access of the function -> speed improvement
var getString : Function = Hexa.getString;

// string where the hexa is saved
var row : String = “”;

// The extracted pixel
var pix1 : Number;
var pix2 : Number;
var pix3 : Number;

// The max value to consider in the local for loop
var maxPix : Number = Math.min( ( _nCurrentStep + 1 ) * _nStepLength, _nWidth * _nHeight);

// writing data
for( var i : Number = _nCurrentStep * _nStepLength; i < maxPix; i += 2 ) {

// The pixel to examine
pix1 = _bmp.getPixel( i % _nWidth, ( _nHeight - 1 ) - Math.floor( i / _nWidth ) );
pix2 = _bmp.getPixel( (i + 1) % _nWidth, ( _nHeight - 1 ) - Math.floor( (i + 1) / _nWidth ) );

if( i % _nWidth == 0 && i !=0 ) for ( var r : Number = 0; r < _nRemainder; ++r ) row = row + "00";
row += getString( pix1.toString( 16 ), 6 );
if( ( i + 1 ) % _nWidth == 0 && ( i + 1 ) >= _nWidth ) for ( var r : Number = 0; r < _nRemainder; ++r ) row += "00";
row += getString( pix2.toString( 16 ), 6 );

}

onProgress( row, ( _nCurrentStep / _nTotalSteps * 100 ) );

}

/* ****************************************************************************
* PUBLIC STATIC FUNCTIONS
**************************************************************************** */
/**
* Return the string of hexa to be written in a file or sent
* @param b
* @param p
*/
public function export( Void ) : Void {

// reference to the instance
var owner : BitmapDataExporter = this;

// get the file header
_fileHeader();

// get the bitmap header
_bitmapHeader();

// create the mc holding the enter frame ( the player will not freeze )
_mcEnterFrame = _root.createEmptyMovieClip( "mc_BitmapDataExporter", 98765 )

// build the data onEnterFrame ( do not freeze the player )
_mcEnterFrame.onEnterFrame = function () {
// get the data
if ( owner._nCurrentStep <= owner._nTotalSteps ) {
owner._buildData();
owner._nCurrentStep++;
} else {
owner.onExportDone();
this.removeMovieClip()
}
}
}
}
[/as]

[Download id not defined]

Here is a little example

[as]
var bmp : BitmapData = new BitmapData( 100, 100, false, 0xFF0000 );
var bmpExport : BitmapDataExporter = new BitmapDataExporter( bmp );

mdm.FileSystem.BinaryFile.setData( "" );
mdm.FileSystem.BinaryFile.writeData( mdm.Application.path + "test.bmp" );

bmpExport.onProgress = function ( b : String, percent : Number ) : Void {
mdm.FileSystem.BinaryFile.setData( b );
mdm.FileSystem.BinaryFile.appendData( mdm.Application.path + "test.bmp" );
trace( "percent done: " + percent.toString() );
}

bmpExport.onExportDone = function ( Void ) : Void {
trace( "export done" );
}

bmpExport.export();
[/as]

Hope it will help some of you...

Take care.