Images, Bitmaps, Videos, Sounds: Chapter 8 - Flex 3 Cookbook
Pages: 1, 2, 3, 4
Section 8.15: Read ID3 Data from an MP3 File
Problem
You want to read ID3 data from an MP3 file.
Solution
Use the Event.ID3 method
that the Sound class
will dispatch when the ID3 data has been parsed.
Discussion
The Sound class dispatches an
event when the ID3 data has been parsed from a loaded MP3 file. That
data is then stored as an ID3Info
object, which defines variables to access all the properties written
into the initial bytes of the MP3:
private var sound:Sound;
public function _8_16()
{
sound = new Sound();
sound.addEventListener(Event.ID3, onID3InfoReceived);
sound.load(new URLRequest("../assets/1.mp3"));
}
private function onID3InfoReceived(event:Event):void
{
var id3:ID3Info = event.target.id3;
for (var propName:String in id3)
{
trace(propName + " = " + id3[propName]);
}
}
The information from a song I was listening to while I wrote this recipe appears like this:
TCON = Alternative & Punk TIT2 = The Pink Batman TRCK = 2/9 TPE1 = Dan Deacon TALB = Spiderman Of The Rings TCOM = Dan Deacon
The ID3 info of an MP3 file is simply a grouping of bytes in a certain order that are read and turned into strings or integers. MP3 is the only file format that the Flash Player supports out of the box. Developer Benjamin Dobler of RichApps (www.richapps.de), however, has done some exceptional work with the WAV format. Getting the WAV file to play back in the Flash Player is slightly more tricky. If you're interested, go to Benjamin's site and take a look. If you want to parse the data from a WAV file, it looks like this:
public var bytes:ByteArray;
public var chunkId:String;
public var chunkSize:int;
public var chunkFormat:String;
public var subchunk1Id:String;
public var subchunk1Size;
public var audioFormat;
public var channels;
public var sampleRate;
public var bytesPersecond;
public var blockAlign;
public var bitsPerSample;
public var dataChunkSignature:String;
public var dataChunkLength;
public function read(bytes:ByteArray):void{
this.bytes = bytes;
// Read Header
bytes.endian = "littleEndian";
chunkId = bytes.readMultiByte(4,"utf"); //RIFF
chunkSize = bytes.readUnsignedInt();
chunkFormat = bytes.readMultiByte(4,"utf"); //WAVE
subchunk1Id = bytes.readMultiByte(4,"iso-8859-1"); // 12 Header Signature
subchunk1Size = bytes.readInt(); // 16 4 <fmt length>
audioFormat = bytes.readShort(); // 20 2 <format tag> sample
channels = bytes.readShort(); // 22 2 <channels> 1 = mono, 2 = stereo
sampleRate = bytes.readUnsignedInt();// 24 4 <sample rate>
bytesPersecond = bytes.readUnsignedInt(); //28 4 <bytes/second> Sample-Rate *
Block-Align
blockAlign = bytes.readShort(); // 32 2 <block align> channel * bits/sample / 8
bitsPerSample = bytes.readUnsignedShort(); //34 2 <bits/sample> 8, 16 or 24
dataChunkSignature = bytes.readMultiByte(4,"iso-8859-1"); //RIFF
dataChunkLength = bytes.readInt();
}
If you want to read the header info from an AU file, it would look like this:
public var bytes:ByteArray;
public var magicId;
public var header;
public var datasize;
public var channels;
public var comment;
public var sampleRate;
public var encodingInfo;
public function read(bytes:ByteArray):void{
this.bytes = bytes;
// Read Header
bytes.endian = "bigEndian";
magicId = bytes.readUnsignedInt();
header = bytes.readInt();
datasize = bytes.readUnsignedInt();
encodingInfo = bytes.readUnsignedInt();
sampleRate = bytes.readUnsignedInt();
channels = bytes.readInt();
comment = bytes.readMultiByte(uint(header)-24, "utf");
}
MP3 files may be the easiest format from which to read data, but they are certainly not the only format from which you can read.
Section 8.16: Display a Custom Loader while Loading Images
Problem
You want to display custom animation while an image loads.
Solution
Create a custom graphic and listen for the ProgressEvent.PROGRESS event from the Image object
loading the image. Then draw into the graphic by using the bytesLoaded and bytesTotal properties.
Discussion
There are two approaches to displaying an image when using the
Image component: You can set the
source for the Image class in MXML
or you can pass a URL to load and use the img.load
method:
img.load("http://thefactoryfactory.com/beach.jpg");
Before you load the image, though, you want to attach an event
listener to ensure that each ProgressEvent is handled:
img.addEventListener(ProgressEvent.PROGRESS, progress);
In the progress method, which
is handling the ProgressEvent.PROGRESS event, a UIComponent is redrawn by using the bytesLoaded property of the Image:
<mx:Canvas xmlns:mx="http://www.adobe.com/2006/mxml" creationComplete="loadImage()">
<mx:Script>
<![CDATA[
private var m:Matrix;
private function loadImage():void {
var m:Matrix = new Matrix();
m.createGradientBox(450, 40);
img.addEventListener(ProgressEvent.PROGRESS, progress);
img.load("http://thefactoryfactory.com/beach.jpg");
}
private function progress(event:Event):void{
grid.graphics.clear();
grid.graphics.beginGradientFill("linear", [0x0000ff, 0xffffff],
[1, 1], [0x00, 0xff], m);
grid.graphics.drawRect(0, 0, (img.bytesLoaded / img.bytesTotal) * 300,
40);
grid.graphics.endFill();
}
]]>
</mx:Script>
<mx:Canvas id="grid" height="40" width="300"/>
<mx:Image id="img" y="40"/>
</mx:Canvas>
Section 8.17: Enable Image Upload in Flex
Problem
You want to enable users to upload images via Flex to be stored on a server.
Solution
Create a FileReference object
and attach the appropriate filters so that users can
upload the correct image types only. Then listen for the complete
handler from the object and
send the uploaded image to a server-side script.
Discussion
Image upload in Flex as well as in Flash relies on the use of
the FileReference class. The
FileReference object, when invoked,
creates a window by using the browser's normal upload window and
graphic and sends the image through the Flash Player when the user has
selected a file for upload. Add an event listener to the FileReference object to indicate that the
user has selected a file:
fileRef.addEventListener(Event.SELECT, selectHandler);
Then add a method to upload the file that the user has selected:
private function selectHandler(event:Event):void {
var request:URLRequest = new URLRequest("http://thefactoryfactory.com/
upload2.php");
fileRef.upload(request, "Filedata", true);
}
After the file has been uploaded, send it to a PHP script to save the uploaded image:
package oreilly.cookbook
{
import mx.core.UIComponent;
import flash.net.FileFilter;
import flash.net.FileReference;
import flash.net.URLRequest;
import flash.events.Event;
public class _8_17 extends UIComponent
{
private var fileRef:FileReference;
public function _8_17() {
super();
startUpload();
}
private function startUpload():void {
//set all the file types we're going to allow the user to upload
var imageTypes:FileFilter = new FileFilter("Images (*.jpg, *.jpeg, *.gif,
*.png)", "*.jpg; *.jpeg; *.gif; *.png");
var allTypes:Array = new Array(imageTypes);
fileRef = new FileReference();
fileRef.addEventListener(Event.SELECT, selectHandler);
fileRef.addEventListener(Event.COMPLETE, completeHandler);
//tell the FileRefence object to accept only those image
//types
fileRef.browse(allTypes);
}
private function selectHandler(event:Event):void {
var request:URLRequest = new URLRequest("http://thefactoryfactory.com/
upload2.php");
fileRef.upload(request, "Filedata", true);
}
private function completeHandler(event:Event):void {
trace("uploaded");
}
}
}
Because the file has already been uploaded, you can deal with the data on the server, moving the file to (in this case) a folder called images:
$file_temp = $_FILES['file']['tmp_name'];
$file_name = $_FILES['file']['name'];
$file_path = $_SERVER['DOCUMENT_ROOT']."/images";
//checks for duplicate files
if(!file_exists($file_path."/".$file_name)) {
//complete upload
$filestatus = move_uploaded_file($file_temp,$file_path."/".$file_name);
if(!$filestatus) {
//error in uploading file
}
}
Section 8.18: Compare Two Bitmap Images
Problem
You need to compare two bitmap images and display the differences between them.
Solution
Read the bitmap data from two images and use the compare method to compare the two images.
Set the difference of the two images as the source of a third
image.
Discussion
The compare method of the
BitmapData class returns a BitmapData
object that contains all the pixels that do not match in two specified
images. If the two BitmapData
objects have the same dimensions (width and height), the method
returns a new BitmapData object, in
which each pixel is the difference between the pixels in the two
source objects: If two pixels are equal, the difference pixel is
0x00000000. If two pixels have different RGB values (ignoring the
alpha value), the difference pixel is 0xFFRRGGBB, where RR/GG/BB are
the individual difference values between red, green, and blue
channels. Alpha channel differences are ignored in this case. If only
the alpha channel value is different, the pixel value is 0xZZFFFFFF,
where ZZ is the difference in the alpha value.
<mx:VBox xmlns:mx="http://www.adobe.com/2006/mxml" width="400" height="800">
<mx:Script>
<![CDATA[
import mx.core.BitmapAsset;
private function compare():void {
var bmpd1:BitmapData = new BitmapData(img1.width, img1.height);
var bmpd2:BitmapData = new BitmapData(img2.width, img2.height);
bmpd1.draw(img1)
bmpd2.draw(img2);
var diff:BitmapData = bmpd2.compare(bmpd1) as BitmapData;
var bitmapAsset:BitmapAsset = new BitmapAsset(diff);
img3.source = bitmapAsset;
}
]]>
</mx:Script>
<mx:Image id="img1" source="../assets/mao.jpg" height="200" width="200"/>
<mx:Image id="img2" source="../assets/bigshakey.png" height="200" width="200"/>
<mx:Button click="compare()" label="compare"/>
<mx:Image id="img3"/>
</mx:VBox>
This excerpt is from Flex 3 Cookbook. This highly practical book contains more than 300 proven recipes for developing interactive Rich Internet Applications and Web 2.0 sites. You'll find everything from Flex basics and working with menus and controls, to methods for compiling, deploying, and configuring Flex applications. Each recipe features a discussion of how and why it works, and many of them offer sample code that you can put to use immediately.