Permalink
Fetching contributors…
Cannot retrieve contributors at this time
305 lines (239 sloc) 8.87 KB
////////////////////////////////////////////////////////////////////////////////
//
// © 2010 BlooDHounD
//
////////////////////////////////////////////////////////////////////////////////
package by.blooddy.crypto.image {
import flash.display.BitmapData;
import flash.display.PNGEncoderOptions;
import flash.system.ApplicationDomain;
import flash.utils.ByteArray;
import flash.utils.getQualifiedClassName;
import by.blooddy.crypto.CRC32;
import by.blooddy.crypto.process.Process;
/**
* Encodes image data using PNG compression algorithm. This class may use
* different compression techniques provided in <code>PNG8Encoder</code> and
* <code>PNG24Encoder</code>.
*
* @see https://www.w3.org/Graphics/PNG/ W3C
* @see by.blooddy.crypto.image.PNG8Encoder
* @see by.blooddy.crypto.image.PNG24Encoder
* @see by.blooddy.crypto.image.palette.IPalette
* @see by.blooddy.crypto.image.PNGFilter
* @see flash.display.BitmapData#encode
*
* @author BlooDHounD
* @version 2.0
* @playerversion Flash 10.1
* @langversion 3.0
* @created 05.07.2010 17:44:26
*/
public class PNGEncoder extends Process {
//--------------------------------------------------------------------------
//
// Class variables
//
//--------------------------------------------------------------------------
/**
* @private
*/
protected static const _NATIVE:Boolean = ApplicationDomain.currentDomain.hasDefinition( 'flash.display.PNGEncoderOptions' );
/**
* @private
*/
protected static const _TMP:ByteArray = new ByteArray();
//--------------------------------------------------------------------------
//
// Class methods
//
//--------------------------------------------------------------------------
/**
* Creates a PNG-encoded byte sequence from the specified <code>BitmapData</code>.
*
* Used <code>flash.display.BitmapData.encode</code>, if possible.
*
* @param image The <code>BitmapData</code> of the image you wish to encode.
*
* @param filter The encoding algorithm you wish to apply while encoding.
* Use the constants provided in
* <code>by.blooddy.crypto.image.PNGFilter</code> class.
*
* @return The sequence of bytes containing the encoded image.
*
* @see by.blooddy.crypto.image.PNGFilter
* @see flash.display.BitmapData#encode()
*/
public static function encode(image:BitmapData, filter:uint=0):ByteArray {
if ( image == null ) Error.throwError( TypeError, 2007, 'image' );
if ( filter < 0 || filter > 4 ) Error.throwError( ArgumentError, 2008, 'filter' );
if ( _NATIVE ) {
return image.encode( image.rect, new PNGEncoderOptions( filter == PNGFilter.NONE ) );
} else {
var size:uint = image.width * image.height;
if ( size >= 32 && size <= 64 ) return PNG8Encoder.encode( image, filter );
else return PNG24Encoder.encode( image, filter );
}
}
/**
*
*
* @param bytes The <code>ByteArray</code> to be encoded.
* @param width Image width.
* @param height Image height.
*
* @param filter The encoding algorithm you wish to apply while encoding.
* Use the constants provided in
* <code>by.blooddy.crypto.image.PNGFilter</code> class.
*
* @return The sequence of bytes containing the encoded image.
*
* @see by.blooddy.crypto.image.PNGFilter
*/
public static function encodeBytes(bytes:ByteArray, width:uint, height:uint, filter:uint=0):ByteArray {
if ( bytes == null ) Error.throwError( TypeError, 2007, 'bytes' );
if ( filter < 0 || filter > 4 ) Error.throwError( ArgumentError, 2008, 'filter' );
var image:BitmapData = new BitmapData( width, height, false );
var pos:uint = bytes.position;
bytes.position = 0;
image.setPixels( image.rect, bytes );
bytes.position = pos;
return encode( image, filter );
}
//--------------------------------------------------------------------------
//
// Helper methods
//
//--------------------------------------------------------------------------
/**
* @internal
*/
protected static function writeSignature(mem:ByteArray):void {
mem.writeUnsignedInt( 0x89504e47 );
mem.writeUnsignedInt( 0x0D0A1A0A );
}
/**
* @internal
*/
protected static function writeChunk(mem:ByteArray, chunk:ByteArray):void {
mem.writeUnsignedInt( chunk.length - 4 );
mem.writeBytes( chunk, 0 );
mem.writeUnsignedInt( CRC32.hashBytes( chunk ) );
}
/**
* @internal
*/
protected static function writeIHDR(mem:ByteArray, width:uint, height:uint, bits:uint, colors:uint):void {
var chunk:ByteArray = _TMP;
chunk.writeUnsignedInt( 0x49484452 );
chunk.writeUnsignedInt( width ); // width
chunk.writeUnsignedInt( height ); // height
chunk.writeByte( bits ); // Bit depth
chunk.writeByte( colors ); // Colour type
chunk.writeByte( 0x00 ); // Compression method
chunk.writeByte( 0x00 ); // Filter method
chunk.writeByte( 0x00 ); // Interlace method
writeChunk( mem, chunk );
chunk.length = 0;
}
/**
* @internal
*/
protected static function writeIDAT(mem:ByteArray, data:ByteArray):void {
var chunk:ByteArray = _TMP;
data.compress();
chunk.writeUnsignedInt( 0x49444154 );
chunk.writeBytes( data );
writeChunk( mem, chunk );
chunk.length = 0;
}
/**
* @internal
*/
protected static function writeTEXT(mem:ByteArray, keyword:String, text:String):void {
var chunk:ByteArray = _TMP;
chunk.writeUnsignedInt( 0x74455874 );
chunk.writeMultiByte( keyword, 'latin-1' );
chunk.writeByte( 0 );
chunk.writeMultiByte( text, 'latin-1' );
writeChunk( mem, chunk );
chunk.length = 0;
}
/**
* @internal
*/
protected static function writeIEND(mem:ByteArray):void {
var chunk:ByteArray = _TMP;
chunk.writeUnsignedInt( 0x49454E44 );
writeChunk( mem, chunk );
chunk.length = 0;
}
CRYPTO::worker {
//--------------------------------------------------------------------------
//
// Class variables
//
//--------------------------------------------------------------------------
[Embed( source="PNGEncoder.swf", mimeType="application/octet-stream" )]
/**
* @private
*/
private static const WorkerClass:Class;
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Creates a PNGEncoder object.
*/
public function PNGEncoder() {
var c:Class = ( this as Object ).constructor;
if ( c == PNGEncoder || c == PNG24Encoder || c == PNG8Encoder ) {
super( WorkerClass );
} else {
Error.throwError( ArgumentError, 2012, getQualifiedClassName( this ) );
}
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Asynchronously creates a PNG-encoded byte sequence from the specified <code>BitmapData</code>.
*
* Dispatched sequence of bytes in <code>ProcessEvent</code>.
*
* @param image The <code>BitmapData</code> of the image you wish to encode.
*
* @param filter The encoding algorithm you wish to apply while encoding.
* Use the constants provided in
* <code>by.blooddy.crypto.image.PNGFilter</code> class.
*/
public function encode(image:BitmapData, filter:uint=0):void {
if ( image == null ) Error.throwError( TypeError, 2007, 'image' );
if ( filter < 0 || filter > 4 ) Error.throwError( ArgumentError, 2008, 'filter' );
super.call( 'encodeBytes', image.getPixels( image.rect ), image.width, image.height, filter );
}
/**
* Asynchronously creates a PNG-encoded byte sequence from the specified <code>ByteArray</code>.
*
* Dispatched sequence of bytes in <code>ProcessEvent</code>.
*
* @param bytes The <code>ByteArray</code> to be encoded.
* @param width Image width.
* @param height Image height.
*
* @param filter The encoding algorithm you wish to apply while encoding.
* Use the constants provided in
* <code>by.blooddy.crypto.image.PNGFilter</code> class.
*/
public function encodeBytes(bytes:ByteArray, width:uint, height:uint, filter:uint=0):void {
if ( bytes == null ) Error.throwError( TypeError, 2007, 'bytes' );
if ( filter < 0 || filter > 4 ) Error.throwError( ArgumentError, 2008, 'filter' );
super.call( 'encodeBytes', bytes, width, height, filter );
}
}
}
}