Showcase and discover digital art at yex

Follow Design Stacks

Subscribe to our free newsletter to get all our latest tutorials and articles delivered directly to your inbox!

Working with Loaded Images

Working with Loaded Images

It is not possible to load an external file (JPEG, GIF, PNG, or Flash movie) directly into an instance of the BitmapData class. Instead, you have to load the external file into a movie clip and wait for it to load before you can take a snapshot of the movie clip that contains the external file:

import flash.display.BitmapData

//create a movie clip to hold the external file
this.createEmptyMovieClip("holder_mc",this.getNextHighestDepth());

/*
Use the MovieClipLoader class so we can be told
when the external file loads or fails to load
*/

loader = new MovieClipLoader()

//Give us status updates by firing events
loader.addListener(this)

//Load the external file into the holding movie clip
loader.loadClip("logo.png",holder_mc)

//this function is called by the 'loader' object
//when the file is loaded and ready to use

function onLoadInit()
{

/*
Create a new bitmap object in memory that is the same size as
the loaded file and fill it with transparent pixels
*/

myBitmap = new BitmapData(holder_mc._width,
holder_mc._height,true,0x00FFFFFF)

//Snapshot the movie clip that contains the external file we loaded
myBitmap.draw(holder_mc)

//we don't need this movie clip anymore, so remove it
holder_mc.removeMovieClip()
}

//this function is called by the 'loader' object
//if the file couldn't be loadd
function onLoadError()
{
/*
The external file failed to load so we don't need
the holding movieclip anymore
*/

holder_mc.removeMovieClip()
}

Applying Filters

A full discussion of filters is beyond the scope of this article. However, often in image processing it is necessary to apply a blur to a bitmap to reduce noise and sharp edges, so I thought it was worth including a little information on how to apply filters to a bitmap. You can apply various filter effects directly to a bitmap using the BitmapData.applyFilter() method. Flash Player supports various filter effects such as Displacement, Blur, Glow, DropShadow, and Bevel. You can apply all of these filters to a rectangular region of a bitmap or the entire bitmap. The following code applies a blur to a bitmap loaded from the Library using the Blur filter:

import flash.filters.BlurFilter
import flash.display.BitmapData

//load a bitmap from the library
myBitmap = BitmapData.loadBitmap("landscape")

//create a blur filter
blur=new BlurFilter(5,5,2)

//apply the blur filter to the loaded bitmap
myBitmap.applyFilter(myBitmap,myBitmap.rectangle,
myBitmap.rectangle.topLeft,blur)

The second parameter of the applyFilter() method enables you to specify a rectangular region to apply the filter. In the above example, I am using the bitmap’s rectangle property, which returns an instance of the flash.geom.Rectangle class that matches the dimensions of the image so that I can apply the filter to the whole bitmap. However, you could change that rectangular region if you wanted to apply the filter only to a certain area of the bitmap by creating an instance of the Rectangle class and passing it to the applyFilter() method as the second parameter:

import flash.filters.BlurFilter 
import flash.display.BitmapData
import flash.geom.Rectangle

//load a bitmap from the library
myBitmap = BitmapData.loadBitmap("landscape")

//create a blur filter
blur=new BlurFilter(5,5,2)

//define the rectangular region to apply the filter to
region=new Rectangle(0,0,50,50)

//apply the blur filter to the loaded bitmap
myBitmap.applyFilter(
myBitmap,region,myBitmap.rectangle.topLeft,blur)

It is worth noting that sometimes, when you apply a filter to the full bitmap, the resulting bitmap is larger than the source bitmap. For example, a DropShadow filter adds pixels around the edges of the bitmap. This makes the generated bitmap larger than the original bitmap to which you applied the filter. Imagine applying a DropShadow filter effect that has a distance of 20 pixels at an angle of 45 degrees to a bitmap that is 100 pixels in width and height. After applying the filter, the resulting image would be 16 pixels larger in width and height. But you wouldn’t know that until after you created the BitmapData object and defined its dimensions. You cannot change the dimensions of a BitmapData object after it has been created.

Thankfully there is a method that enables you to determine the actual size of the resulting image from a filter operation before you apply the filter, so you can size the destination bitmap accordingly:

import flash.filters.DropShadowFilter
import flash.display.BitmapData

//load a bitmap from the library
myBitmap = BitmapData.loadBitmap("logo")

//create a default dropshadow filter
dropShadow = new DropShadowFilter()

//find out the size of the bitmap after the filter is applied
filteredSize=myBitmap.generateFilterRect(
myBitmap.rectangle,dropShadow)

//if the topleft corner is negative,
//then you need to increase the width and height
w=(filteredSize.x<0) ?
filteredSize.width-filteredSize.x : filteredSize.width
h=(filteredSize.y<0) ?
filteredSize.height-filteredSize.y : filteredSize.height

//if the loaded bitmap is transparent,
//then fill the bitmap with transparent pixels otherwise white pixels
fillColor=(myBitmap.transparent) ? 0x00FFFFFF : 0xFFFFFFFF

//create a new bitmap to store the filtered result
filteredBitmap = new BitmapData(w,h,myBitmap.transparent,fillColor)

//apply the filter to the loaded bitmap
filteredBitmap.applyFilter(myBitmap,myBitmap.rectangle,
myBitmap.rectangle.topLeft,dropShadow)

Getting the Color of a Pixel

You can find out the color value of any given pixel inside a bitmap. The BitmapData.getPixel() method returns the RGB color of the pixel at the specified x/y coordinate as a base-10 number:

import flash.display.BitmapData
myBitmap = new BitmapData(100,100,false,0xFFCC00)
pixelColor=myBitmap.getPixel(50,50)

To get a hexadecimal representation of the returned color value which is base-10 you have to convert the number to a base-16 string using the toString() method and by setting the optional radix parameter to 16:

trace("0x"+pixelColor.toString(16)) 
//outputs : 0xffcc00

However, you should note that if you use the getPixel() method on a bitmap that contains alpha channel data (BitmapData.transparent == true), then the returned value will be pre-multiplied with the alpha channel. This means that the color of the pixel will be multiplied by the intensity of the alpha channel for that pixel and you will get unexpected results.

The BitmapData.getPixel32() method returns the ARGB color of the pixel at the specified x/y co-ordinate as a base-10 number. This method also returns the alpha channel data of the pixel unlike getPixel():

import flash.display.BitmapData
myBitmap = new BitmapData(100,100,true,0x11FFCC00)
pixelColor=myBitmap.getPixel32(50,50)
trace("0x"+pixelColor.toString(16))
//outputs : 0x11ffd200

Setting the Color of a Pixel

To set the color of a pixel, you can use the BitmapData.setPixel() method. This method changes the color of the pixel at the specified x/y coordinates to the specified color. The color that you specify should be a 24-bit hexadecimal number such as 0xFFCC00 (yellow) as the alpha channel bits are ignored:

myBitmap = BitmapData.load("photo")
//shift 100 pixels around
for(i=0;i<100;++i)
{
//generate two random x/y co-ordinates
rx1=Math.floor(Math.random()*myBitmap.width)
rx2=Math.floor(Math.random()*myBitmap.width)
ry1=Math.floor(Math.random()*myBitmap.height)
ry2=Math.floor(Math.random()*myBitmap.height)
//set a random pixels color to be the color
//of another random pixel
myBitmap.setPixel(rx1,ry1,myBitmap.getPixel(rx2,ry2))
}

You should only use this method if the bitmap doesn’t contain alpha transparency (BitmapData.transparent) otherwise you should use the BitmapData.setPixel32() method. The setPixel32() method enables you to specify a 32-bit hexadecimal number that contains alpha channel data:

myBitmap.setPixel32(50,50,0xFFFFCC00) 
//make the pixel at x:50, y:50 opaque yellow

Setting the Color of a Group of Pixels

You can fill a rectangular group of pixels with a specified color using the fillRect() method. This method often becomes useful to reset the state of a bitmap back to its original state, because you can fill the whole bitmap with one color, effectively erasing its contents.

The first parameter of this method is the rectangular area that you want to fill. This should be an instance of the flash.geom.Rectangle class. The second parameter is the color to which you want to change the pixels in that rectangular area.

To specify a rectangular area, first import the fully qualified path to the Rectangle class; find the Rectangle class in the flash.geom package:

Import flash.geom.Rectangle 

Then, create an instance of it using this code:

myRect=new Rectangle(0,0,100,100) 

The first two parameters are the x/y coordinates of the top left-hand corner of the rectangle. The last two parameters specify the dimensions of the rectangle (width and height).

You can then fill that area with a specific color:

myBitmap.fillRect(myRect,0xFFFF0000) 
//make all the pixels in the specified area red

Note that every instance of the BitmapData class has a property that returns the size and position of the bitmap object. The bitmap object will always be positioned at 0,0, so it is really only useful to find out the dimensions in a format that is required by most of the methods available in the BitmapData class. The property is called BitmapData.rectangle and it returns an instance of the Rectangle class.

//fill the whole bitmap with green pixels
myBitmap.fillRect(myBitmap.rectangle,0xFF00FF00);

Changing Ranges of Color

It is a cumbersome and intensive task for you to loop through every pixel in an image to change it to another color. However, if you find yourself in a position where you need to change the color of all pixels that are within a certain range of colors or all pixels that are a particular color, then there is no need to loop through each pixel. Using the BitmapData.threshold() method, you can isolate and replace the color of pixels that are in a particular color range and perform other logical operations on pixels. For example, to make all the red pixels in an image transparent, you can use the following code:

import flash.display.BitmapData
import flash.geom.Rectangle

//create a new 100 * 100 bitmap and fill it with red pixels
myBitmap = new BitmapData(100,100,true,0xFFFF0000)

//define a rectangular region which is equivalent
//to a 20 * 20 square in the center of the bitmap
centeredRectangle=new Rectangle(40,40,20,20)

//fill a rectangular area in the center
//of the bitmap with black pixels
myBitmap.fillRect(centeredRectangle,0xFF000000)

//change all the pixels in the bitmap
//that are red to transparent
redPixelCount=myBitmap.threshold(
myBitmap,myBitmap.rectangle,myBitmap.rectangle.topLeft,
"==",0xFFFF0000,0x00FFFFFF)

The BitmapData.threshold() method returns the number of pixels that were affected by the operation:

trace(redPixelCount) 

You can change the operation of the threshold method by passing one of these strings for the operation parameter, which is the fourth parameter:

>
==
!=
<
<=
>=

This enables you to do things like changing all the pixels in the image that are not a particular color using != for the operation parameter, for example:

myBitmap.threshold(myBitmap,myBitmap.rectangle,
myBitmap.rectangle.topLeft,"!=",0xFFFF0000,0x00FFFFFF)

Copying Pixels

Copying pixels is a regular routine used in image processing. You can copy pixels from one bitmap to another using the BitmapData.copyPixels() method. This method copies a rectangular region from a specified area of the source bitmap to a specified location in the destination bitmap. This enables you to create things like jigsaws and such. Even cooler than that, you can also use a secondary image containing alpha channel data to act as a mask for the copying. This enables you to copy regions of a bitmap that are not rectangular.

The following example copies a rectangular region of pixels from one bitmap to another:

import flash.display.BitmapData
import flash.geom.Rectangle

//attach a bitmap from the library
myBitmap = BitmapData.loadBitmap("logo")

//define the area to copy from the source bitmap
area=new Rectangle(10,10,50,50)

//create a new bitmap to hold the pixels that are copied
bitmapSlot=new BitmapData(50,50)

//copy the pixels from the specified region of the loaded bitmap
//into the top left hand corner
bitmapSlot.copyPixels(myBitmap,area,bitmapSlot.rectangle.topLeft)

This example copies a circular region of pixels from one bitmap to another, using the bitmap that contains a circle and transparent pixels around it as the alpha mask:

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

//attach a bitmap from the library
myBitmap = BitmapData.loadBitmap('logo')

//draw a circle inside a movie clip
this.createEmptyMovieClip('mask_mc',1)
mask_mc.lineStyle(75,0x00FF00)
//this creates a circle that has a diameter of 75
mask_mc.lineTo(0,1)
//create a bitmap to hold the alpha mask
maskBitmap = new BitmapData(100,100,true,0x00FFFFFF)
//create a transformation matrix
m=new Matrix()
//displace the position of the movie clip
//when it is drawn into the bitmap
m.translate(50,50)
//draw the circle into the bitmap
maskBitmap.draw(mask_mc,m)
//remove the movie clip that contains the circle,
//we don't need it anymore
mask_mc.removeMovieClip()
//create a bitmap to hold the pixels copied
//from the bitmap loaded from the library
//fill it with transparent pixels
circleBitmap=new BitmapData(100,100,true,0x00FFFFFF)
//copy the pixels from the bitmap loaded from the library
//using the bitmap containing the circle as an alpha mask
circleBitmap.copyPixels(myBitmap,myBitmap.rectangle,
circleBitmap.rectangle.topLeft,maskBitmap,
maskBitmap.rectangle.topLeft)
//display the bitmap
this.attachBitmap(circleBitmap,1)
//get rid of the mask bitmap we don't need it anymore
maskBitmap.dispose()

Comments