import {BitmapImage2D} from "../image/BitmapImage2D";
import {ImageCube} from "../image/ImageCube";
import {BlendMode} from "../image/BlendMode";
import {ColorTransform} from "../geom/ColorTransform";
import {Matrix} from "../geom/Matrix";
import {Rectangle} from "../geom/Rectangle";
import {Point} from "../geom/Point";
import {ByteArray} from "../utils/ByteArray";
import {ColorUtils} from "../utils/ColorUtils";
import {BitmapImageUtils} from "../utils/BitmapImageUtils";
/**
* The BitmapImage2D export class lets you work with the data(pixels) of a Bitmap
* object. You can use the methods of the BitmapImage2D export class to create
* arbitrarily sized transparent or opaque bitmap images and manipulate them
* in various ways at runtime. You can also access the BitmapImage2D for a bitmap
* image that you load with the flash.Assets or
* flash.display.Loader classes.
*
*
This export class lets you separate bitmap rendering operations from the * internal display updating routines of flash. By manipulating a * BitmapImage2D object directly, you can create complex images without incurring * the per-frame overhead of constantly redrawing the content from vector * data.
* *The methods of the BitmapImage2D export class support effects that are not * available through the filters available to non-bitmap display objects.
* *A BitmapImage2D object contains an array of pixel data. This data can * represent either a fully opaque bitmap or a transparent bitmap that * contains alpha channel data. Either type of BitmapImage2D object is stored as * a buffer of 32-bit integers. Each 32-bit integer determines the properties * of a single pixel in the bitmap.
* *Each 32-bit integer is a combination of four 8-bit channel values(from * 0 to 255) that describe the alpha transparency and the red, green, and blue * (ARGB) values of the pixel.(For ARGB values, the most significant byte * represents the alpha channel value, followed by red, green, and blue.)
* *The four channels(alpha, red, green, and blue) are represented as
* numbers when you use them with the BitmapImage2D.copyChannel()
* method or the DisplacementMapFilter.componentX and
* DisplacementMapFilter.componentY properties, and these numbers
* are represented by the following constants in the BitmapImage2DChannel
* class:
BitmapImage2DChannel.ALPHABitmapImage2DChannel.REDBitmapImage2DChannel.GREENBitmapImage2DChannel.BLUEYou can attach BitmapImage2D objects to a Bitmap object by using the
* bitmapData property of the Bitmap object.
You can use a BitmapImage2D object to fill a Graphics object by using the
* Graphics.beginBitmapFill() method.
You can also use a BitmapImage2D object to perform batch tile rendering
* using the flash.display.Tilesheet class.
In Flash Player 10, the maximum size for a BitmapImage2D object * is 8,191 pixels in width or height, and the total number of pixels cannot * exceed 16,777,215 pixels.(So, if a BitmapImage2D object is 8,191 pixels wide, * it can only be 2,048 pixels high.) In Flash Player 9 and earlier, the limitation * is 2,880 pixels in height and 2,880 in width.
*/ export class BitmapImageCube extends ImageCube { public static assetType:string = "[image BitmapImageCube]"; public static posX:number = 0; public static negX:number = 1; public static posY:number = 2; public static negY:number = 3; public static posZ:number = 4; public static negZ:number = 5; private _imageCanvas:Arraytrue for the transparent parameter of the
* constructor. Then, after you create a BitmapImage2D object, you can check
* whether it supports per-pixel transparency by determining if the value of
* the transparent property is true.
*/
public get transparent():boolean
{
return this._transparent;
}
public set transparent(value:boolean)
{
this._transparent = value;
}
/**
* Creates a BitmapImage2D object with a specified width and height. If you
* specify a value for the fillColor parameter, every pixel in
* the bitmap is set to that color.
*
* By default, the bitmap is created as transparent, unless you pass
* the value false for the transparent parameter. After you
* create an opaque bitmap, you cannot change it to a transparent bitmap.
* Every pixel in an opaque bitmap uses only 24 bits of color channel
* information. If you define the bitmap as transparent, every pixel uses 32
* bits of color channel information, including an alpha transparency
* channel.
true
* (transparent). To create a fully transparent bitmap,
* set the value of the transparent
* parameter to true and the value of the
* fillColor parameter to 0x00000000(or to
* 0). Setting the transparent property to
* false can result in minor improvements
* in rendering performance.
* @param fillColor A 32-bit ARGB color value that you use to fill the
* bitmap image area. The default value is
* 0xFFFFFFFF(solid white).
*/
constructor(size:number, transparent:boolean = true, fillColor:number = null)
{
super(size);
this._transparent = transparent;
for (var i:number = 0; i < 6; i++) {
this._imageCanvas[i] = ColorTransform object. If the rectangle matches the
* boundaries of the bitmap image, this method transforms the color values of
* the entire image.
*
* @param rect A Rectangle object that defines the area of the
* image in which the ColorTransform object is applied.
* @param colorTransform A ColorTransform object that describes the color
* transformation values to apply.
*/
public colorTransform(side:number, rect:Rectangle, colorTransform:ColorTransform):void
{
if (!this._locked)
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
var data:Uint8ClampedArray = this._imageData[side].data;
var i:number, j:number, index:number;
for (i = 0; i < rect.width; ++i) {
for (j = 0; j < rect.height; ++j) {
index = (i + rect.x + (j + rect.y)*this._size)*4;
data[index] = data[index]*colorTransform.redMultiplier + colorTransform.redOffset;
data[index + 1] = data[index + 1]*colorTransform.greenMultiplier + colorTransform.greenOffset;
data[index + 2] = data[index + 2]*colorTransform.blueMultiplier + colorTransform.blueOffset;
data[index + 3] = data[index + 3]*colorTransform.alphaMultiplier + colorTransform.alphaOffset;
}
}
if (!this._locked) {
this._context[side].putImageData(this._imageData[side], 0, 0);
this._imageData[side] = null;
}
this.invalidate();
}
/**
* Transfers data from one channel of another BitmapImage2D object or the
* current BitmapImage2D object into a channel of the current BitmapImage2D object.
* All of the data in the other channels in the destination BitmapImage2D object
* are preserved.
*
* The source channel value and destination channel value can be one of * following values:
* *BitmapImage2DChannel.REDBitmapImage2DChannel.GREENBitmapImage2DChannel.BLUEBitmapImage2DChannel.ALPHABitmapImage2DChannel.RED,
* BitmapImage2DChannel.BLUE,
* BitmapImage2DChannel.GREEN,
* BitmapImage2DChannel.ALPHA).
* @param destChannel The destination channel. Use a value from the
* BitmapImage2DChannel class
* (BitmapImage2DChannel.RED,
* BitmapImage2DChannel.BLUE,
* BitmapImage2DChannel.GREEN,
* BitmapImage2DChannel.ALPHA).
* @throws TypeError The sourceBitmapImage2D, sourceRect or destPoint are null.
*/
public copyChannel(side:number, sourceBitmap:BitmapImage2D, sourceRect:Rectangle, destPoint:Point, sourceChannel:number, destChannel:number):void
{
var imageData:ImageData = sourceBitmap.getImageData();
if (!this._locked)
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
var sourceData:Uint8ClampedArray = sourceBitmap.getImageData().data;
var destData:Uint8ClampedArray = this._imageData[side].data;
var sourceOffset:number = Math.round(Math.log(sourceChannel)/Math.log(2));
var destOffset:number = Math.round(Math.log(destChannel)/Math.log(2));
var i:number, j:number, sourceIndex:number, destIndex:number;
for (i = 0; i < sourceRect.width; ++i) {
for (j = 0; j < sourceRect.height; ++j) {
sourceIndex = (i + sourceRect.x + (j + sourceRect.y)*sourceBitmap.width)*4;
destIndex = (i + destPoint.x + (j + destPoint.y)*this._size)*4;
destData[destIndex + destOffset] = sourceData[sourceIndex + sourceOffset];
}
}
if (!this._locked) {
this._context[side].putImageData(this._imageData[side], 0, 0);
this._imageData[side] = null;
}
this.invalidate();
}
/**
* Provides a fast routine to perform pixel manipulation between images with
* no stretching, rotation, or color effects. This method copies a
* rectangular area of a source image to a rectangular area of the same size
* at the destination point of the destination BitmapImage2D object.
*
* If you include the alphaBitmap and alphaPoint
* parameters, you can use a secondary image as an alpha source for the
* source image. If the source image has alpha data, both sets of alpha data
* are used to composite pixels from the source image to the destination
* image. The alphaPoint parameter is the point in the alpha
* image that corresponds to the upper-left corner of the source rectangle.
* Any pixels outside the intersection of the source image and alpha image
* are not copied to the destination image.
The mergeAlpha property controls whether or not the alpha
* channel is used when a transparent image is copied onto another
* transparent image. To copy pixels with the alpha channel data, set the
* mergeAlpha property to true. By default, the
* mergeAlpha property is false.
sourceRect parameter.
* @param mergeAlpha To use the alpha channel, set the value to
* true. To copy pixels with no alpha
* channel, set the value to false.
* @throws TypeError The sourceBitmapImage2D, sourceRect, destPoint are null.
*/
public copyPixels(side:number, source:BitmapImage2D, sourceRect:Rectangle, destRect:Rectangle);
public copyPixels(side:number, source:HTMLImageElement, sourceRect:Rectangle, destRect:Rectangle);
public copyPixels(side:number, source:any, sourceRect:Rectangle, destRect:Rectangle):void
{
if (source instanceof BitmapImage2D)
source = source.getCanvas();
if (this._locked) {
// If canvas is locked:
//
// 1) copy image data back to canvas
// 2) draw object
// 3) read _imageData back out
this._context[side].putImageData(this._imageData[side], 0, 0); // at coords 0,0
BitmapImageUtils._copyPixels(this._context[side], source, sourceRect, destRect);
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
} else {
BitmapImageUtils._copyPixels(this._context[side], source, sourceRect, destRect);
}
this.invalidate();
}
/**
* Frees memory that is used to store the BitmapImage2D object.
*
* When the dispose() method is called on an image, the width
* and height of the image are set to 0. All subsequent calls to methods or
* properties of this BitmapImage2D instance fail, and an exception is thrown.
*
BitmapImage2D.dispose() releases the memory occupied by the
* actual bitmap data, immediately(a bitmap can consume up to 64 MB of
* memory). After using BitmapImage2D.dispose(), the BitmapImage2D
* object is no longer usable and an exception may be thrown if
* you call functions on the BitmapImage2D object. However,
* BitmapImage2D.dispose() does not garbage collect the BitmapImage2D
* object(approximately 128 bytes); the memory occupied by the actual
* BitmapImage2D object is released at the time the BitmapImage2D object is
* collected by the garbage collector.
source display object onto the bitmap image, using
* the NME software renderer. You can specify matrix,
* colorTransform, blendMode, and a destination
* clipRect parameter to control how the rendering performs.
* Optionally, you can specify whether the bitmap should be smoothed when
* scaled(this works only if the source object is a BitmapImage2D object).
*
* The source display object does not use any of its applied
* transformations for this call. It is treated as it exists in the library
* or file, with no matrix transform, no color transform, and no blend mode.
* To draw a display object(such as a movie clip) by using its own transform
* properties, you can copy its transform property object to the
* transform property of the Bitmap object that uses the
* BitmapImage2D object.
new Matrix() constructor, or
* pass a null value.
* @param colorTransform A ColorTransform object that you use to adjust the
* color values of the bitmap. If no object is
* supplied, the bitmap image's colors are not
* transformed. If you must pass this parameter but you
* do not want to transform the image, set this
* parameter to a ColorTransform object created with
* the default new ColorTransform()
* constructor.
* @param blendMode A string value, from the flash.display.BlendMode
* class, specifying the blend mode to be applied to
* the resulting bitmap.
* @param clipRect A Rectangle object that defines the area of the
* source object to draw. If you do not supply this
* value, no clipping occurs and the entire source
* object is drawn.
* @param smoothing A Boolean value that determines whether a BitmapImage2D
* object is smoothed when scaled or rotated, due to a
* scaling or rotation in the matrix
* parameter. The smoothing parameter only
* applies if the source parameter is a
* BitmapImage2D object. With smoothing set
* to false, the rotated or scaled
* BitmapImage2D image can appear pixelated or jagged. For
* example, the following two images use the same
* BitmapImage2D object for the source
* parameter, but the smoothing parameter
* is set to true on the left and
* false on the right:
*
* Drawing a bitmap with smoothing set
* to true takes longer than doing so with
* smoothing set to
* false.
source parameter is not a
* BitmapImage2D or DisplayObject object.
* @throws ArgumentError The source is null or not a valid IBitmapDrawable
* object.
* @throws SecurityError The source object and(in the case of a
* Sprite or MovieClip object) all of its child objects
* do not come from the same domain as the caller, or
* are not in a content that is accessible to the
* caller by having called the
* Security.allowDomain() method. This
* restriction does not apply to AIR content in the
* application security sandbox.
*/
public draw(side:number, source:BitmapImage2D, matrix?:Matrix, colorTransform?:ColorTransform, blendMode?:BlendMode, clipRect?:Rectangle, smoothing?:boolean);
public draw(side:number, source:HTMLElement, matrix?:Matrix, colorTransform?:ColorTransform, blendMode?:BlendMode, clipRect?:Rectangle, smoothing?:boolean);
public draw(side:number, source:any, matrix?:Matrix, colorTransform?:ColorTransform, blendMode?:BlendMode, clipRect?:Rectangle, smoothing?:boolean):void
{
if (source instanceof BitmapImage2D)
source = source.getCanvas();
if (this._locked) {
// If canvas is locked:
//
// 1) copy image data back to canvas
// 2) draw object
// 3) read _imageData back out
this._context[side].putImageData(this._imageData[side], 0, 0); // at coords 0,0
BitmapImageUtils._draw(this._context[side], source, matrix, colorTransform, blendMode, clipRect, smoothing);
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
} else {
BitmapImageUtils._draw(this._context[side], source, matrix, colorTransform, blendMode, clipRect, smoothing);
}
this.invalidate();
}
/**
* Fills a rectangular area of pixels with a specified ARGB color.
*
* @param rect The rectangular area to fill.
* @param color The ARGB color value that fills the area. ARGB colors are
* often specified in hexadecimal format; for example,
* 0xFF336699.
* @throws TypeError The rect is null.
*/
public fillRect(side:number, rect:Rectangle, color:number):void
{
if (this._locked) {
// If canvas is locked:
//
// 1) copy image data back to canvas
// 2) apply fill
// 3) read _imageData back out
if (this._imageData[side])
this._context[side].putImageData(this._imageData[side], 0, 0); // at coords 0,0
BitmapImageUtils._fillRect(this._context[side], rect, color, this._transparent);
if (this._imageData[side])
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
} else {
BitmapImageUtils._fillRect(this._context[side], rect, color, this._transparent);
}
this.invalidate();
}
/**
* Returns an integer that represents an RGB pixel value from a BitmapImage2D
* object at a specific point(x, y). The
* getPixel() method returns an unmultiplied pixel value. No
* alpha information is returned.
*
* All pixels in a BitmapImage2D object are stored as premultiplied color * values. A premultiplied image pixel has the red, green, and blue color * channel values already multiplied by the alpha data. For example, if the * alpha value is 0, the values for the RGB channels are also 0, independent * of their unmultiplied values. This loss of data can cause some problems * when you perform operations. All BitmapImage2D methods take and return * unmultiplied values. The internal pixel representation is converted from * premultiplied to unmultiplied before it is returned as a value. During a * set operation, the pixel value is premultiplied before the raw image pixel * is set.
* * @param x The x position of the pixel. * @param y The y position of the pixel. * @return A number that represents an RGB pixel value. If the(x, * y) coordinates are outside the bounds of the image, the * method returns 0. */ public getPixel(side:number, x:number, y:number):number { var r:number; var g:number; var b:number; var a:number; if (!this._locked) { var pixelData:ImageData = this._context[side].getImageData(x, y, 1, 1); r = pixelData.data[0]; g = pixelData.data[1]; b = pixelData.data[2]; a = pixelData.data[3]; } else { var index:number = (x + y*this._size)*4; r = this._imageData[side].data[index + 0]; g = this._imageData[side].data[index + 1]; b = this._imageData[side].data[index + 2]; a = this._imageData[side].data[index + 3]; } //returns black if fully transparent if (!a) return 0x0; return (r << 16) | (g << 8) | b; } /** * Returns an ARGB color value that contains alpha channel data and RGB data. * This method is similar to thegetPixel() method, which
* returns an RGB color without alpha channel data.
*
* All pixels in a BitmapImage2D object are stored as premultiplied color * values. A premultiplied image pixel has the red, green, and blue color * channel values already multiplied by the alpha data. For example, if the * alpha value is 0, the values for the RGB channels are also 0, independent * of their unmultiplied values. This loss of data can cause some problems * when you perform operations. All BitmapImage2D methods take and return * unmultiplied values. The internal pixel representation is converted from * premultiplied to unmultiplied before it is returned as a value. During a * set operation, the pixel value is premultiplied before the raw image pixel * is set.
* * @param x The x position of the pixel. * @param y The y position of the pixel. * @return A number representing an ARGB pixel value. If the(x, * y) coordinates are outside the bounds of the image, 0 is * returned. */ public getPixel32(side:number, x, y):number { var r:number; var g:number; var b:number; var a:number; if (!this._locked) { var pixelData:ImageData = this._context[side].getImageData(x, y, 1, 1); r = pixelData.data[0]; g = pixelData.data[1]; b = pixelData.data[2]; a = pixelData.data[3]; } else { var index:number = (x + y*this._size)*4; r = this._imageData[side].data[index + 0]; g = this._imageData[side].data[index + 1]; b = this._imageData[side].data[index + 2]; a = this._imageData[side].data[index + 3]; } return (a << 24) | (r << 16) | (g << 8) | b; } /** * Locks an image so that any objects that reference the BitmapImage2D object, * such as Bitmap objects, are not updated when this BitmapImage2D object * changes. To improve performance, use this method along with the *unlock() method before and after numerous calls to the
* setPixel() or setPixel32() method.
*
*/
public lock():void
{
if (this._locked)
return;
this._locked = true;
for (var i:number = 0; i < 6; i++)
this._imageData[i] = this._context[i].getImageData(0, 0, this._size, this._size);
}
/**
* Converts an Array into a rectangular region of pixel data. For each pixel,
* an Array element is read and written into the BitmapImage2D pixel. The data
* in the Array is expected to be 32-bit ARGB pixel values.
*
* @param rect Specifies the rectangular region of the BitmapImage2D
* object.
* @param inputArray An Array that consists of 32-bit unmultiplied pixel
* values to be used in the rectangular region.
* @throws RangeError The vector array is not large enough to read all the
* pixel data.
*/
public setArray(side:number, rect:Rectangle, inputArray:ArrayNote: To increase performance, when you use the
* setPixel() or setPixel32() method repeatedly,
* call the lock() method before you call the
* setPixel() or setPixel32() method, and then call
* the unlock() method when you have made all pixel changes.
* This process prevents objects that reference this BitmapImage2D instance from
* updating until you finish making the pixel changes.
setPixel()
* method; the main difference is that the setPixel32() method
* takes an ARGB color value that contains alpha channel information.
*
* All pixels in a BitmapImage2D object are stored as premultiplied color * values. A premultiplied image pixel has the red, green, and blue color * channel values already multiplied by the alpha data. For example, if the * alpha value is 0, the values for the RGB channels are also 0, independent * of their unmultiplied values. This loss of data can cause some problems * when you perform operations. All BitmapImage2D methods take and return * unmultiplied values. The internal pixel representation is converted from * premultiplied to unmultiplied before it is returned as a value. During a * set operation, the pixel value is premultiplied before the raw image pixel * is set.
* *Note: To increase performance, when you use the
* setPixel() or setPixel32() method repeatedly,
* call the lock() method before you call the
* setPixel() or setPixel32() method, and then call
* the unlock() method when you have made all pixel changes.
* This process prevents objects that reference this BitmapImage2D instance from
* updating until you finish making the pixel changes.
ByteArray.readUnsignedInt() method is called and
* the return value is written into the pixel. If the byte array ends before
* the full rectangle is written, the function returns. The data in the byte
* array is expected to be 32-bit ARGB pixel values. No seeking is performed
* on the byte array before or after the pixels are read.
*
* @param rect Specifies the rectangular region of the BitmapImage2D
* object.
* @param inputByteArray A ByteArray object that consists of 32-bit
* unmultiplied pixel values to be used in the
* rectangular region.
* @throws EOFError The inputByteArray object does not include
* enough data to fill the area of the rect
* rectangle. The method fills as many pixels as possible
* before throwing the exception.
* @throws TypeError The rect or inputByteArray are null.
*/
public setPixels(side:number, rect:Rectangle, inputByteArray:ByteArray):void
{
if (!this._locked)
this._imageData[side] = this._context[side].getImageData(0, 0, this._size, this._size);
inputByteArray.position = 0;
var i:number, j:number, index:number;
for (i = 0; i < rect.width; ++i) {
for (j = 0; j < rect.height; ++j) {
index = (i + rect.x + (j + rect.y)*this._size)*4;
this._imageData[side].data[index + 0] = inputByteArray.readUnsignedInt();
this._imageData[side].data[index + 1] = inputByteArray.readUnsignedInt();
this._imageData[side].data[index + 2] = inputByteArray.readUnsignedInt();
this._imageData[side].data[index + 3] = inputByteArray.readUnsignedInt();
}
}
if (!this._locked) {
this._context[side].putImageData(this._imageData[side], 0, 0);
this._imageData[side] = null;
}
this.invalidate();
}
/**
* Unlocks an image so that any objects that reference the BitmapImage2D object,
* such as Bitmap objects, are updated when this BitmapImage2D object changes.
* To improve performance, use this method along with the lock()
* method before and after numerous calls to the setPixel() or
* setPixel32() method.
*
* @param changeRect The area of the BitmapImage2D object that has changed. If
* you do not specify a value for this parameter, the
* entire area of the BitmapImage2D object is considered
* changed.
*/
public unlock():void
{
if (!this._locked)
return;
this._locked = false;
for (var i:number = 0; i < 6; i++) {
this._context[i].putImageData(this._imageData[i], 0, 0); // at coords 0,0
this._imageData[i] = null;
}
}
/**
*
* @returns {ImageData}
*/
public getImageData(side:number):ImageData
{
if (!this._locked)
return this._context[side].getImageData(0, 0, this._size, this._size);
return this._imageData[side];
}
/**
*
* @returns {HTMLCanvasElement}
*/
public getCanvas(side:number):HTMLCanvasElement
{
return this._imageCanvas[side];
}
/**
*
* @param width
* @param height
* @private
*/
public _setSize(size:number):void
{
super._setSize(size);
for (var i:number = 0; i < 6; i++) {
if (this._locked)
this._context[i].putImageData(this._imageData[i], 0, 0);
this._imageCanvas[i].width = size;
this._imageCanvas[i].height = size;
if (this._locked)
this._imageData[i] = this._context[i].getImageData(0, 0, this._size, this._size);
}
}
}