Microphone data sampling - actionscript-3

Im having a issue with converting microphone data sampling to 16-bit PCM signed integer.
The app i have is in Adobe AIR with actionScript 3, but i have the service demo code which used Web Audio API and there it states:
/**
* Creates a Blob type: 'audio/l16' with the
* chunk coming from the microphone.
*/
var exportDataBuffer = function(buffer, bufferSize) {
var pcmEncodedBuffer = null,
dataView = null,
index = 0,
volume = 0x7FFF; //range from 0 to 0x7FFF to control the volume
pcmEncodedBuffer = new ArrayBuffer(bufferSize * 2);
dataView = new DataView(pcmEncodedBuffer);
/* Explanation for the math: The raw values captured from the Web Audio API are
* in 32-bit Floating Point, between -1 and 1 (per the specification).
* The values for 16-bit PCM range between -32768 and +32767 (16-bit signed integer).
* Multiply to control the volume of the output. We store in little endian.
*/
for (var i = 0; i < buffer.length; i++) {
dataView.setInt16(index, buffer[i] * volume, true);
index += 2;
}
// l16 is the MIME type for 16-bit PCM
return new Blob([dataView], { type: 'audio/l16' });
};
I need a way to convert my samples in the same way.
This is what i have but it doesn't seem to be working:
function micSampleDataHandler(event:SampleDataEvent):void
{
while(event.data.bytesAvailable)
{
var sample:Number = event.data.readFloat();
var integer:int;
sample = sample * 32768 ;
if( sample > 32767 ) sample = 32767;
if( sample < -32768 ) sample = -32768;
integer = int(sample) ;
soundBytes.writeInt(integer);
}
}
Any advice would help me a bunch, thanks
EDIT:
This is the WaveEncoder function i have. Can this be used to encode the samples into desired format :
public function encode( samples:ByteArray, channels:int=2, bits:int=16, rate:int=44100 ):ByteArray
{
var data:ByteArray = create( samples );
_bytes.length = 0;
_bytes.endian = Endian.LITTLE_ENDIAN;
_bytes.writeUTFBytes( WaveEncoder.RIFF );
_bytes.writeInt( uint( data.length + 44 ) );
_bytes.writeUTFBytes( WaveEncoder.WAVE );
_bytes.writeUTFBytes( WaveEncoder.FMT );
_bytes.writeInt( uint( 16 ) );
_bytes.writeShort( uint( 1 ) );
_bytes.writeShort( channels );
_bytes.writeInt( rate );
_bytes.writeInt( uint( rate * channels * ( bits >> 3 ) ) );
_bytes.writeShort( uint( channels * ( bits >> 3 ) ) );
_bytes.writeShort( bits );
_bytes.writeUTFBytes( WaveEncoder.DATA );
_bytes.writeInt( data.length );
_bytes.writeBytes( data );
_bytes.position = 0;
return _bytes;
}
EDIT2:
Problem seems to be in : dataview.setInt16(byteOffset, value [, littleEndian])
How do i do the byteOffset in as3?

Got it. writeInt() writes 32 bits, and you need to write only 16. Use writeShort() instead.
soundBytes.writeShort(integer);

Related

Autokey Encryption

I am working on a project to write to and read from a TP Link / Kaza power strip or smart plug.
The data that is sent is encrypted json that has been "autokey encrypted".
So far I have been able to convert a typescript encrypt function and it works well. I get the expected result. However, I need to add a "header" to my encrypted data. That data is 3 null bytes followed by a byte that is a measure of the length of the encrypted bytes.
The typescript example has this bit of code to "encrypt with headers", however, I've hit a bit of a wall trying to convert it to something usable. Can someone nudge me along the path ?
First are the two typescript functions: (borrowed from https://github.com/plasticrake/tplink-smarthome-crypto/blob/master/src/index.ts)
/**
* Encrypts input where each byte is XOR'd with the previous encrypted byte.
*
* #param input - Data to encrypt
* #param firstKey - Value to XOR first byte of input
* #returns encrypted buffer
*/
export function encrypt(input: Buffer | string, firstKey = 0xab): Buffer {
const buf = Buffer.from(input);
let key = firstKey;
for (let i = 0; i < buf.length; i += 1) {
// eslint-disable-next-line no-bitwise
buf[i] ^= key;
key = buf[i];
}
return buf;
}
/**
* Encrypts input that has a 4 byte big-endian length header;
* each byte is XOR'd with the previous encrypted byte.
*
* #param input - Data to encrypt
* #param firstKey - Value to XOR first byte of input
* #returns encrypted buffer with header
*/
export function encryptWithHeader(
input: Buffer | string,
firstKey = 0xab
): Buffer {
const msgBuf = encrypt(input, firstKey);
const outBuf = Buffer.alloc(msgBuf.length + 4);
outBuf.writeUInt32BE(msgBuf.length, 0);
msgBuf.copy(outBuf, 4);
return outBuf;
}
Second is what I have so far.
// This part works well and produces the expected results
String encrypt(String input)
{
int16_t firstKey = 0xab;
String buf;
int key;
int i;
buf = input;
key = firstKey;
i = 0;
for (;i < buf.length();(i = i + 1))
{
buf[i] ^= key;
key = buf[i];
}
return buf;
}
// This does not function yet, as I'm pretty lost..
// This was orginally converted from typescript with https://andrei-markeev.github.io/ts2c/
// I started work on converting this, but ran into errors I don't know how to solve.
String encryptWithHeader(String input){
String msgBuf;
String outBuf;
int16_t firstKey = 0xab;
char * null = NULL;
msgBuf = encrypt(input);
outBuf = msgBuf.length() +1;
//this is where I got lost...
assert(null != NULL);
null[0] = '\0';
strncat(null, outBuf, msgBuf.length());
str_int16_t_cat(null, 4);
outBuf = msgBuf + 4
return outBuf;
}
Finally, the data:
//this is the unencrypted json
String offMsg = "{\"system\":{\"set_relay_state\":{\"state\":0}}}";
//current encrypt function produces:
d0f281f88bff9af7d5ef94b6c5a0d48bf99cf091e8b7c4b0d1a5c0e2d8a381f286e793f6d4eedea3dea3
//the working "withheaders" should produce:
00002ad0f281f88bff9af7d5ef94b6c5a0d48bf99cf091e8b7c4b0d1a5c0e2d8a381f286e793f6d4eedea3dea3
Admittedly my C/C++ ability is very limited and I can spell typescript, that's about all. I have a very extensive history with PHP. As useful as that is. So, I understand the basics of data structures and whatnot, but I'm venturing off into areas I've never been in. Any help would be greatly appreciated.
It looks like the encryption is fairly simple: write the current character XORed with the key to the buffer and make that newly written character the new key. It also looks like the "withHeaders" version adds the length of the encrypted string as a 4 byte integer to the start of the buffer. I think it might be easier to allocate a character array and pass that array to a function that writes the result to that buffer. For example:
void encryptWithHeader(byte buffer[], int bufferLength, byte key, String message) {
int i;
uint32_t messageLength = message.length();
Serial.println(message);
Serial.println(message.length());
// check that we won't overrun the buffer
if ( messageLength + 5 < bufferLength) {
buffer[0] = messageLength >> 24 & 0xFF;
buffer[1] = messageLength >> 16 & 0xFF;
buffer[2] = messageLength >> 8 & 0xFF;
buffer[3] = messageLength & 0xFF;
for (i = 0; i < messageLength; i++) {
buffer[i + 4] = message[i] ^ key;
key = buffer[i + 4];
}
}
else { // we would have overrun the buffer
Serial.println("not enough room in buffer for message");
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(9600);
}
void loop() {
byte theBuffer[64];
int i;
String offMsg = "{\"system\":{\"set_relay_state\":{\"state\":0}}}";
encryptWithHeader(theBuffer, 64, 0xab, offMsg);
// now print it out to check
for (i = 0; i < offMsg.length() + 4; i++) {
if (theBuffer[i] < 0x10) // adds an extra zero if a byte prints as on1y 1 char
Serial.print("0");
Serial.print(theBuffer[i], HEX);
}
while (true)
;
}
If you want to send the character buffer to a remote device you can send it out one byte at a time:
for (i = 0; i < offMsg.length() + 4; i++)
Serial.write(theBuffer[i]);

Trouble creating a spectrogram

I know it was asked a thousand times before, but I still can't find a solution.
Searching SO, I indeed found the algorithm for it, but lacking the mathematical knowledge required to truly understand it, I am helplessly lost!
To start with the beginning, my goal is to compute an entire spectrogram and save it to an image in order to use it for a visualizer.
I tried using Sound.computeSpectrum, but this requires to play the sound and wait for it to end, I want to compute the spectrogram in a way shorter time than that will require to listen all the song. And I have 2 hours long mp3s.
What I am doing now is to read the bytes from a Sound object, the separate into two Vectors(.); Then using a timer, at each 100 ms I call a function (step1) where I have the implementation of the algorithm, as follows:
for each vector (each for a channel) I apply the hann function to the elements;
for each vector I nullify the imaginary part (I have a secondary vector for that)
for each vector I apply FFT
for each vector I find the magnitude for the first N / 2 elements
for each vector I convert squared magnitude to dB scale
end.
But I get only negative values, and only 30 percent of the results might be useful (in the way that the rest are identical)
I will post the code for only one channel to get rid off the "for each vector" part.
private var N:Number = 512;
private function step1() : void
{
var xReLeft:Vector.<Number> = new Vector.<Number>(N);
var xImLeft:Vector.<Number> = new Vector.<Number>(N);
var leftA:Vector.<Number> = new Vector.<Number>(N);
// getting sample range
leftA = this.channels.left.slice(step * N, step * (N) + (N));
if (leftA.length < N)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
else if (leftA.length == 0)
{
stepper.removeEventListener(TimerEvent.TIMER, getFreq100ms);
return;
}
var i:int;
// hann window function init
m_win = new Vector.<Number>(N);
for ( var i:int = 0; i < N; i++ )
m_win[i] = (4.0 / N) * 0.5 * (1 - Math.cos(2 * Math.PI * i / N));
// applying hann window function
for ( i = 0; i < N; i++ )
{
xReLeft[i] = m_win[i]*leftA[i];
//xReRight[i] = m_win[i]*rightA[i];
}
// nullify the imaginary part
for ( i = 0; i < N; i++ )
{
xImLeft[i] = 0.0;
//xImRight[i] = 0.0;
}
var magnitutel:Vector.<Number> = new Vector.<Number>(N);
fftl.run( xReLeft, xImLeft );
current = xReLeft;
currf = xImLeft;
for ( i = 0; i < N / 2; i++ )
{
var re:Number = xReLeft[i];
var im:Number = xImLeft[i];
magnitutel[i] = Math.sqrt(re * re + im * im);
}
const SCALE:Number = 20 / Math.LN10;
var l:uint = this.total.length;
for ( i = 0; i < N / 2; i++ )
{
magnitutel[i] = SCALE * Math.log( magnitutel[i] + Number.MIN_VALUE );
}
var bufferl:Vector.<Number> = new Vector.<Number>();
for (i = 0; i < N / 2 ; i++)
{
bufferl[i] = magnitutel[i];
}
var complete:Vector.<Vector.<Number>> = new Vector.<Vector.<Number>>();
complete[0] = bufferl;
this.total[step] = complete;
this.step++;
}
This function is executed in the event dispatched by the timer (stepper).
Obviously I do something wrong, as I said I have only negative values and further more values range between 1 and 7000 (at least).
I want to thank you in advance for any help.
With respect,
Paul
Negative dB values are OK. Just add a constant (representing your volume control) until the number of points you want to color become positive. The remaining values that stay negative are usually just displayed or colored as black in a spectrogram. No matter how negative (as they might just be the FFT's numerical noise, which can be a huge negative dB number or even NaN or -Inf for log(0)).

Rotate bitmap data in AS3 180deg for export

I have a bitmap in AS3 flash and I am sending it over to javascript using a base64 encoded jpg string.
All that works great. I need to send the img over scaled down, and rotated 180deg. The scaling works, but not the rotation. The rotation never takes. I know Im am obviously doing it wrong, but don't know the right way.
So basically I just need to rotate the image 180deg so when it is sent to javascript it is upside down.
Here is my transform code
var scaleFactor:int = 5;
var tempBitmap:BitmapData = new BitmapData(img.width/scaleFactor, img.height/scaleFactor);
var drawMatrix:Matrix = new Matrix(1/scaleFactor, 0, 0, 1 /scaleFactor );
drawMatrix.rotate(Math.PI); //180deg
tempBitmap.draw(img, drawMatrix);
I think you need to translate your object after rotation otherwise it gets clipped so you don't see it, I did an example with a bitmap in a MovieClip just on the stage using CS5.
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.MovieClip;
var scaleFactor:int = 1;
var tempBitmap:BitmapData = new BitmapData(img.width, img.height);
var rotationMatrix:Matrix = new Matrix();
rotationMatrix.rotate(Math.PI);
rotationMatrix.translate(img.width, img.height);
tempBitmap.draw(box_mc, rotationMatrix);
var output:Bitmap = new Bitmap(tempBitmap);
addChild(output);
I didn't mess with the scaling, you can do that yourself I guess. The one I put on the stage is on the right, the bitmapData drawn one is top left of stage, and correctly inverted.
UPDATE
Also have a look at fl.motion.MatrixTransformer as per 32bitkid comment below!
/** flips individual blocks within a bitmap. Specifically used for doing sprite sheets. But I am sure you could find another use if you wanted.
* #param inBM
* #param spritePixelWidth
* #param spritePixelHeight
* #param inTransformType :An enum from TransFiveConstants. Example: TransFiveConstants.VERTICAL_FLIP
* #return a bitmap data object where all the sprites within the sprite sheet bitmap have been rotated or transformed **/
public static function makeTransformedCopyOfSpriteSheet(inSpriteSheet:BitmapData, spritePixelWidth:int, spritePixelHeight:int, inTransformType:int):BitmapData
{
//Do error check to make sure we evenly fit into the bitmap we are doing transforms on.
CONFIG::debug{
if ( (inSpriteSheet.width % spritePixelWidth ) != 0) { throw new Error("input error: width does not go in evenly! Fix it."); }
if ( (inSpriteSheet.height % spritePixelHeight) != 0) { throw new Error("input error: height does not go in evenly! Fix it."); }
}//CONFIG_debug
//Calculate width and height in sprites of the inSpriteSheet.
var widthInSprites :int = inSpriteSheet.width / spritePixelWidth ;
var heightInSprites:int = inSpriteSheet.height / spritePixelHeight;
/** Bitmap that takes rectangle chunks out of inSpriteSheet, one at a time. **/
var inBM:BitmapData = new BitmapData(spritePixelWidth, spritePixelHeight, true, 0x00);
//Inlined copy of code in makeTransformedCopy
////////////////////////////////////////////////////////////////////
var flipWidthHeight:Boolean = false;
if (inTransformType == TransFiveConstants.ROTATE_NEG_90 ||
inTransformType == TransFiveConstants.ROTATE_POS_90 )
{
flipWidthHeight = true;
}
var outWID:int = (flipWidthHeight ? inBM.height : inBM.width );
var outHGT:int = (flipWidthHeight ? inBM.width : inBM.height);
////////////////////////////////////////////////////////////////////
/** Bitmap that is a [rotated||transformed] version of inputBitmap: **/
var outBM:BitmapData = new BitmapData(outWID, outHGT, true, 0x00);
var outputSpriteSheetWidth :int = outBM.width * widthInSprites;
var outputSpriteSheetHeight:int = outBM.height * heightInSprites;
/** The output of this function **/
var outputSpriteSheet :BitmapData = new BitmapData(outputSpriteSheetWidth, outputSpriteSheetHeight, true, 0x00);
//scan through the sheet with a rectangle and make all the transformed copies you need.
//Every time you make a transformed chunk/copy, move it from the inSpriteSheet to the outputSpriteSheet
/** Places the [rotated||transformed] chunk in correct spot on outputSpriteSheet **/
var finalDestination:Point = new Point();
var cookieCutter:Rectangle = new Rectangle();
cookieCutter.width = spritePixelWidth ;
cookieCutter.height = spritePixelHeight;
for (var xx:int = 0; xx < widthInSprites ; ++xx){
for (var yy:int = 0; yy < heightInSprites; ++yy){
cookieCutter.x = xx * spritePixelWidth;
cookieCutter.y = yy * spritePixelHeight;
//Cut chunk out of main sprite sheet:
inBM.copyPixels(inSpriteSheet, cookieCutter, ZZ, null, null, true);
//Transform the chunk you cut out of the main sprite sheet:
makeTransformedCopy(inBM, inTransformType, outBM);
//Paste the transformed copy into the output sheet:
finalDestination.x = xx * outBM.width; //if outBM is rotated, this width will NOT BE SAME AS spritePixelWidth
finalDestination.y = yy * outBM.height;
outputSpriteSheet.copyPixels(outBM, outBM.rect, finalDestination, null, null, true);
}}//next [xx, yy]
return outputSpriteSheet;
}//makeTransformedCopyOfSpriteSheet
/** Flips/Mirrors and Rotates using a 1D index scan remap. "transformUsingScanRemap"
*
* Meaning, I put data into a 1D array, then change my assumptions on the "scan order" ( left-right, then top-bottom is default convention),
* I can effectively rotate or transform the pixel input.
*
* All we have to do is pack the bitmap into a 1D array. (scanning left-right, top-to-bottom)
* And then convert it BACK to the 2D array using a different formula assuming the data is packed via a different scan order.
*
* EXAMPLE:
* If we change our assumption to assume it is left-right, then BOTTOM-to-top, and make a formula for mapping 1D indexes
* to 2D values based on that scan order assumption, we achieve a vertical flip.
*
* #param inBM :Bitmap we are making a transformed copy of.
* #param inTransformType :The enum for the type of [transform||rotation] to use. For values check TransFiveConstants.as
* #param outputBitmap :Supply this to OVERWRITE an existing bitmap instead of create a NEW bitmap for output.
* #return a transformed or rotated bitmap **/
public static function makeTransformedCopy(inBM:BitmapData, inTransformType:int, outputBitmap:BitmapData = null):BitmapData
{
//If the bitmap is being ROTATED, we will have to flip the output width and height.
var flipWidthHeight:Boolean = false;
if (inTransformType == TransFiveConstants.ROTATE_NEG_90 ||
inTransformType == TransFiveConstants.ROTATE_POS_90 )
{
flipWidthHeight = true;
}
var outWID:int = (flipWidthHeight ? inBM.height : inBM.width );
var outHGT:int = (flipWidthHeight ? inBM.width : inBM.height);
//You can supply a reference to the OUTPUT of this function if you are doing some type of batch processing
//And want to avoid repetitively constructing new intermediary bitmaps:
if (outputBitmap == null)
{
var outputBitmap:BitmapData = new BitmapData(outWID, outHGT, true, 0x00);
}
else
{
if (outputBitmap.width != outWID) { ICU.error("Bad output bitmap supplied. Size is wrong."); }
if (outputBitmap.height != outHGT) { ICU.error("Bad output bitmap supplied. Size is wrong."); }
}
/** Max x index when remapping 1D values. **/
var maxXXX:int = outWID - 1;
/** Max y index when remapping 1D values. **/
var YYYmax:int = outHGT - 1;
/** Number of full columns, using 1D scan order for this orientation. **/
var fullColumns:int = 0;
/** Number of full rows, using 1D scan order for orientation specified. **/
var fullRows:int = 0;
/**What is left over after we have calculated the rows or collumns we have. **/
var remainder:int = 0;
var curPix:uint;
var index:int = ( -1);
var trans:IntPoint = new IntPoint();
inBM.lock();
outputBitmap.lock();
for (var yy:int = 0; yy < inBM.height; yy++) {
for (var xx:int = 0; xx < inBM.width ; xx++) {
++index;
//using 1D index position, remap that to correct 2D position.
//To do different transforms and rotations, simply change your assumptions on how we
//map from 1D to 2D.
//Standard 1D to 2D assumes scan lines go left-right, then top-bottom. Row by row.
//2D to 1D formula for standard:
//1D = (Y * width) + X.
//how many full widths you can get out of 1D == Y. Remainder == X.
//2D.Y = (1D/width);
//2D.X = 1D - (2D.Y * width);
if (inTransformType == TransFiveConstants.NO_TRANSFORM)
{ //[1][2] Assumed scan order (AKA 1D to 2D Mapping)
fullRows = (index / outWID); //[3][4] used to get full
remainder = index - (fullRows * outWID); //[5][6] rows and remainder.
trans.iy = fullRows;
trans.ix = remainder;
}else
if (inTransformType == TransFiveConstants.VERTICAL_FLIP)
{ //[5][6] Assumed scan order (AKA 1D to 2D Mapping)
fullRows = (index / outWID); //[3][4] used to get full
remainder = index - (fullRows * outWID); //[1][2] rows and remainder.
trans.iy = YYYmax - fullRows;
trans.ix = remainder;
}else
if (inTransformType == TransFiveConstants.ROTATE_NEG_90)
{ //[2][4][6] Assumed scan order (AKA 1D to 2D Mapping)
fullColumns = (index / outHGT); //[1][3][5] used to get full rows and remainder.
remainder = index - (fullColumns * outHGT);
trans.ix = fullColumns;
trans.iy = YYYmax - remainder;
}else
if (inTransformType == TransFiveConstants.ROTATE_POS_90)
{ //[5][3][1] Assumed scan order (AKA 1D to 2D Mapping)
fullColumns = (index / outHGT); //[6][4][2] used to get full rows and remainder.
remainder = index - (fullColumns * outHGT);
trans.ix = maxXXX - fullColumns;
trans.iy = remainder;
}else
if (inTransformType == TransFiveConstants.FLOOR_MIRROR)
{ //[2][1] Assumed scan order (AKA 1D to 2D Mapping)
fullRows = (index / outWID); //[4][3] used to get full
remainder = index - (fullRows * outWID); //[6][5] rows and remainder.
trans.iy = fullRows;
trans.ix = maxXXX - remainder;
}
else
{
throw new Error("Transform type not recognized");
}
//Copy and paste the pixel now that we know where to put it:
curPix = inBM.getPixel32(xx, yy);
outputBitmap.setPixel32(trans.ix, trans.iy, curPix);
}}//next [xx, yy]
inBM.unlock();
outputBitmap.unlock();
return outputBitmap;
}//transformUsingScanRemap

Best way to save data from flash

I have an AS3 document with roughly 200 individual elements I'm trying to save to the database. I just need to saved information about their physical properties on the stage.
There are many ways to do this, but what is the recommended approach?
The backend is PHP/MySQL and it's not a two-way exchange. Save it, done.
apart from the server side, a good way to store / assign position/rotation/scale is to use the DisplayObjects' transformation matrices:
shape.transform.matrix
sprite.transform.matrix
it is rather compact ; need to store 6 Numbers per object.
rounding the scale/rotation values down to 5 decimals ( 0.12345 instead of 0.123456789123456 ) and the translation to 1 decimal ( 0.1 instead of 0.123456 ) works pretty well to spare some Ko.
for example this method:
private function storeMatrix( displayObject:DisplayObject, decimals:int = 5 ):String
{
var str:String = '';
var m:Matrix = displayObject.transform.matrix;
str += m.a.toFixed( decimals ) + ':';
str += m.b.toFixed( decimals ) + ':';
str += m.c.toFixed( decimals ) + ':';
str += m.d.toFixed( decimals ) + ':';
str += m.tx.toFixed( 1 ) + ':';
str += m.ty.toFixed( 1 );
return str;
}
will return something like:
-0.95119:-0.30550:0.30550:-0.95119:110.0:110.0
and this method sets the position/rotation/scale from the string:
private function assignMatrix( str:String, _do:DisplayObject ):void
{
var values:Array = str.split( ':' );
var m:Matrix = new Matrix();
m.a = values[ 0 ];
m.b = values[ 1 ];
m.c = values[ 2 ];
m.d = values[ 3 ];
m.tx = values[ 4 ];
m.ty = values[ 5 ];
_do.transform.matrix = m;
}
once you've collected all the object's matrices, you can serialize them with AMF and store to database. last time I did that, I used FZIP to compress the data even further ( 500Ko->20Ko). I don't think it'll help in your case, just wanted to point it out :)
NB: if needed, you can also store the transform.ColorTransform properties of an object in the very same way.
I would check out flash remoting/AMFPHP: http://amfphp.sourceforge.net/
It's pretty straightforwad, and really easy to implement.
Hope this helps.

Actionscript convert background to Transparent

The purpose of the function is to covert the background to transparent and then return the bitmapdata, but it seems it do not work. The code is following:
private function transparentConverter( source:BitmapData, threshold:Number = 0.1 ):BitmapData
{
var bitmapData:BitmapData = new BitmapData( source.width, source.height, true, 0x00000000 );
bitmapData.lock();
var color:uint = source.getPixel( 0, 0 );
var x:uint, y:uint;
for ( y = 0; y < source.height; y++ )
{
for ( x = 0; x < source.width; x++ )
{
var c1:uint = source.getPixel( x, y );
var c2:uint = color;
var rx:uint = Math.abs((( c1 & 0xff0000 ) >> 16 ) - (( c2 & 0xff0000 ) >> 16 ));
var gx:uint = Math.abs((( c1 & 0xff00) >> 8 ) - (( c2 & 0xff00 ) >> 8 ));
var bx:uint = Math.abs(( c1 & 0xff ) - ( c2 & 0xff ));
var dist:uint = Math.sqrt( rx*rx + gx*gx + bx*bx );
if ( dist <= threshold )
{
bitmapData.setPixel32( x, y, 0x00000000 );
}else
{
bitmapData.setPixel32( x, y, c1 );
}
}
}
bitmapData.unlock();
return bitmapData;
}
Please advice.
Can you try this :
// This bitmapData should be defined for real, wherever you get that from ...
var source:BitmapData;
if(source == null)
trace("The source cannot be empty");
// Here you get the transformed BitmapData
var destination:bitmapData = transparentConverter( source );
// You apply it to a Bitmap in order to visualize it
var viewBitmap:Bitmap = new Bitmap(destination);
// You add the Bitmap to the stage so you can see it
addChild(viewBitmap);
Theo, thanks for your effort. I think the problem is the functions takes too long to run. After I try your script, a warning messages come out. It said the program takes more than 15 seconds to run and told me to stop running.
I think the function should be OK, but, maybe, not quite practical.
Theo, thank for your time and advice again.
I think the question can be closed.
Theo, the function seems can run, but take some time, however no bitmapdata return.
I receive the bitmpadata by the following code:
bitmapData = transparentConverter( bitmapData );
var bitmap:Bitmap = new Bitmap( bitmapData );
image1.source = bitmap;
The image do not appear.
And also, I can trace( c1 ), and I get a long list of data.
Thanks for your response.