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.

buy button