website promotion banner
eturnkeys
Your Ad Here
Flash & Swish  Home Flash & Swish Flash Tutorials Export JPEG with Flash/PHP
rss

Export JPEG with Flash/PHP

Author: Alessandro Crugnola More by this author


1. Description

With the introduction of flash 8 "flash.display.BitmapData" class thousands of new application can now be made using Flash..

In this tutorial we will focus our attention to the BitmapData.gePixel() method in order to transform a portion of flash movie into a JPEG (created with PHP/GD)

BitmapData has different ways to get pixel color informations:

  • getPixel(x:Number, y:Number) : Number

    Returns an integer representing an RGB pixel value from a BitmapData object at a specific point (x, y).

  • getPixel32(x:Number, y:Number) : Number

    Returns an ARGB color value that contains alpha channel data as well as RGB data.

  • getColorBoundsRect(mask:Number, color:Number, [findColor:Boolean]) : Rectangle

    Determines a rectangular region that fully encloses all pixels of a given color within the bitmap image.

What we will use in this tutorial is getPixel().

Here a basic example on how it can work:

import flash.display.*

var bmp:BitmapData = new BitmapData(this._width, this._height, false)
bmp.draw(this);

this.onMouseMove = function(){
var pColor:Number = bmp.getPixel(_xmouse, _ymouse)
var hexColor:String = pColor.toString(16).toUpperCase()
while(hexColor.length < 6){
hexColor = "0" + hexColor
}
var r = Number("0x" + hexColor.substr(0,2))
var g = Number("0x" + hexColor.substr(2,2))
var b = Number("0x" + hexColor.substr(4,2))
testo.text = "0x" + hexColor + ", {r:" + r + ", g:" + g + ", b:" + b + "}" }

Remember to import the flash.display.BitmapData class.

Create a new bitmapdata instance and assign to it the same dimensions as the current Stage.

Then using draw() we're making an exact copy of the _root movieclip into the bitmapdata object.

Using:

bmp.getPixel( _xmouse, _ymouse).toString(16).toUpperCase()

we will have the hexadecimal color value of the pixel at those coordinates.

2. Advanced Example

Ok, we can make a copy of everything in a flash movie using this method.. and so we can also send all the pixel color values to an external application in order to recreate a JPEG of the copied movieclip. The bigger problem is that for a movie of 550x400 whe should collect 220000 colors values, and converting the value into an hexadecimal string this means that the final string to send will be 1320000 chars long. This means a lot of data!

Another problem is that we can't collect all the pixel color values in a single for loop, otherwise the flash player will dead suddenly!

I made this example ( 500x210 ), with a .flv video included.

You can also draw some lines above the .swf using mouse

As you can see in the previous example, once "print" button is pressed a loader window appears counting the percent progress.

This is because i used a setInterval function to copy all the pixels. This won't stress your cpu so much..

Here the class i use:

import flash.display.BitmapData;
import flash.geom.Rectangle;
import flash.geom.ColorTransform;
import flash.geom.Matrix;

/**
* Little and simple print flash screen class
*/
class it.sephiroth.PrintScreen {

public var addListener:Function
public var broadcastMessage:Function

private var id: Number;
public var record:LoadVars;

function PrintScreen(){
AsBroadcaster.initialize( this );
}

public function print(mc:MovieClip, x:Number, y:Number, w:Number, h:Number){
broadcastMessage("onStart", mc);
if(x == undefined) x = 0;
if(y == undefined) y = 0;
if(w == undefined) w = mc._width;
if(h == undefined) h = mc._height;
var bmp:BitmapData = new BitmapData(w, h, false);
record = new LoadVars();
record.width = w
record.height = h
record.cols = 0
record.rows = 0
var matrix = new Matrix();
matrix.translate(-x, -y)
bmp.draw(mc, matrix, new ColorTransform(), 1, new Rectangle(0, 0, w, h));
id = setInterval(copysource, 5, this, mc, bmp);
}

private function copysource(scope, movie, bit){
var pixel:Number
var str_pixel:String
scope.record["px" + scope.record.rows] = new Array();
for(var a = 0; a < bit.width; a++){
pixel = bit.getPixel(a, scope.record.rows)
str_pixel = pixel.toString(16)
if(pixel == 0xFFFFFF) str_pixel = ""; // don't send blank pixel
scope.record["px" + scope.record.rows].push(str_pixel)
}
scope.broadcastMessage("onProgress", movie, scope.record.rows, bit.height) // send back the progress status
scope.record.rows += 1
if(scope.record.rows >= bit.height){
clearInterval(scope.id)
scope.broadcastMessage("onComplete", movie, scope.record) // completed!
bit.dispose();
}
}
}

The ASBroadcaster class will be useful because i will use the addListener() method in order to receive events (onStart, onComplete and onProgress).

The main method is "print", which accepts there params:

  1. mc: the movieclip to copy
  2. x: x origin of the copy
  3. y: y origin of the copy
  4. w: width
  5. h: height

Then the setInterval will copy all the pixel in one single row in the BitmapData object, every 5 ms seconds.

Every array of colors (in each row) will be stored in a new array within a LoadVar object. In this way i will have 210 variables to post with the LoadVars object.

Please note that 0xFFFFFF pixels won't be added in the arrays, this beacuse the image i will create in PHP will have a blank background color, and for this reason blank pixels wont be created every time...

3. The .fla source

Now let's take a look at the flash file will use this "PrintScreen" class:

import it.sephiroth.mloaderWindow
import it.sephiroth.PrintScreen


var loader:mloaderWindow = this.createClassObject(mloaderWindow, "loader", 10, {_x:-1000, _y:-1000})
loader.setStyle("borderColor", 0x006699)

// listener which receives the broadcast message
// from the PrintScreen class
var listener:Object = new Object();

// copy in progress...
listener.onProgress = function(target:MovieClip, loaded:Number, total:Number){
var perc = Math.round((loaded/total)*100)
loader.label = "computing... " + perc + "%"
loader.value = perc
}
// copy is complete, send the result LoadVars to PHP
listener.onComplete = function(target:MovieClip, load_var:LoadVars){
loader.label = "sending to php..."
load_var.send("pixels.php", "_blank", "POST")
loader.close()
}

/**
* Print Button has been clicked
*/
function print_me(){
video_mc.pause() // first pause the playing video
pn = new PrintScreen(); // initialize the PrintScreen class
pn.addListener( listener ); // assign a listener
pn.print(_root, 0, 0, 500, 210) // copy the _root
loader.label = "computing... 0%" loader.open(true, true, true); // open a loader
}

There's nothing particular to say here..

Once the "print" button is clicked call the print_me() function.

Stop the playing video, in order to copy the current video frame.

Initialize the PrintScreen class and assign a listener which will receive all the broadcaster messages.

I used pn.print(_root, 0,0, 500, 210) in order to print all the contents in _root.

Once the process is completed send the LoadVars object, which is returned by the onComplete function, to PHP using the POST method ( the posted Content-length is: 563024 )

4. Generate the image in PHP

Here the code of the "pixels.php" page

<?php

error_reporting(0);
/**
 * Get the width and height of the destination image
 * from the POST variables and convert them into
 * integer values
 */
$w = (int)$_POST['width'];
$h = (int)$_POST['height'];

// create the image with desired width and height

$img = imagecreatetruecolor($w, $h);

// now fill the image with blank color
// do you remember i wont pass the 0xFFFFFF pixels 
// from flash?
imagefill($img, 0, 0, 0xFFFFFF);

$rows = 0;
$cols = 0;

// now process every POST variable which
// contains a pixel color
for($rows = 0; $rows < $h; $rows++){
    // convert the string into an array of n elements
    $c_row = explode(",", $_POST['px' . $rows]);
    for($cols = 0; $cols < $w; $cols++){
        // get the single pixel color value
        $value = $c_row[$cols];
        // if value is not empty (empty values are the blank pixels)
        if($value != ""){
            // get the hexadecimal string (must be 6 chars length)
            // so add the missing chars if needed
            $hex = $value;
            while(strlen($hex) < 6){
                $hex = "0" . $hex;
            }
            // convert value from HEX to RGB
            $r = hexdec(substr($hex, 0, 2));
            $g = hexdec(substr($hex, 2, 2));
            $b = hexdec(substr($hex, 4, 2));
            // allocate the new color
            // N.B. teorically if a color was already allocated 
            // we dont need to allocate another time
            // but this is only an example
            $test = imagecolorallocate($img, $r, $g, $b);
            // and paste that color into the image
            // at the correct position
            imagesetpixel($img, $cols, $rows, $test);
        }
    }
}

// print out the correct header to the browser
header("Content-type:image/jpeg");
// display the image
imagejpeg($img, "", 90);
?>

That's all.

This is only a demonstration, because this method require a lot of memory to be used from PHP in order to generate the image (ImageMagik should be a better solution in this case indeed), and also because the POST headers are very very big!

You can use for example the Live HTTP headers FireFox extension to see exactly what we're passing to the pixels.php page.

In the same way you can read pixels informations from a BitmapData many other things can be done, for example parsing an image and find streets

6. Download file source

Download files used in this tutorial here.



Author's URL: www.sephiroth.it

Rate this Material: Bad 1 2 3 4 5 Excellent
print this page tell a friend subscribe to newsletter subscribe to rss

Add comments to "Export JPEG with Flash/PHP"