////////////////////////////////////////////////////////////////////////////////
//
// Licensed to the Apache Software Foundation (ASF) under one or more
// contributor license agreements. See the NOTICE file distributed with
// this work for additional information regarding copyright ownership.
// The ASF licenses this file to You under the Apache License, Version 2.0
// (the "License"); you may not use this file except in compliance with
// the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////////
package mx.graphics.codec
{
import flash.display.BitmapData;
import flash.utils.ByteArray;
/**
* The JPEGEncoder class converts raw bitmap images into encoded
* images using Joint Photographic Experts Group (JPEG) compression.
*
* For information about the JPEG algorithm, see the document
* http://www.opennet.ru/docs/formats/jpeg.txt by Cristi Cuturicu.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public class JPEGEncoder implements IImageEncoder
{
include "../../core/Version.as";
//--------------------------------------------------------------------------
//
// Class constants
//
//--------------------------------------------------------------------------
/**
* @private
*/
private static const CONTENT_TYPE:String = "image/jpeg";
//--------------------------------------------------------------------------
//
// Constructor
//
//--------------------------------------------------------------------------
/**
* Constructor.
*
* @param quality A value between 0.0 and 100.0.
* The smaller the quality
value,
* the smaller the file size of the resultant image.
* The value does not affect the encoding speed.
*. Note that even though this value is a number between 0.0 and 100.0,
* it does not represent a percentage.
* The default value is 50.0.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function JPEGEncoder(quality:Number = 50.0)
{
super();
if (quality <= 0.0)
quality = 1.0;
if (quality > 100.0)
quality = 100.0;
var sf:int = 0;
if (quality < 50.0)
sf = int(5000 / quality);
else
sf = int(200 - quality * 2);
// Create tables
initHuffmanTbl();
initCategoryNumber();
initQuantTables(sf);
}
//--------------------------------------------------------------------------
//
// Constants
//
//--------------------------------------------------------------------------
/**
* @private
*/
private const std_dc_luminance_nrcodes:Array =
[ 0, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0 ];
/**
* @private
*/
private const std_dc_luminance_values:Array =
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
/**
* @private
*/
private const std_dc_chrominance_nrcodes:Array =
[ 0, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 ];
/**
* @private
*/
private const std_dc_chrominance_values:Array =
[ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 ];
/**
* @private
*/
private const std_ac_luminance_nrcodes:Array =
[ 0, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4, 4, 0, 0, 1, 0x7D ];
/**
* @private
*/
private const std_ac_luminance_values:Array =
[
0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xA1, 0x08,
0x23, 0x42, 0xB1, 0xC1, 0x15, 0x52, 0xD1, 0xF0,
0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0A, 0x16,
0x17, 0x18, 0x19, 0x1A, 0x25, 0x26, 0x27, 0x28,
0x29, 0x2A, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
0x7A, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
0x8A, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7,
0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6,
0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3, 0xC4, 0xC5,
0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2, 0xD3, 0xD4,
0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xE1, 0xE2,
0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
0xF9, 0xFA
];
/**
* @private
*/
private const std_ac_chrominance_nrcodes:Array =
[ 0, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5, 4, 4, 0, 1, 2, 0x77 ];
/**
* @private
*/
private const std_ac_chrominance_values:Array =
[
0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
0xA1, 0xB1, 0xC1, 0x09, 0x23, 0x33, 0x52, 0xF0,
0x15, 0x62, 0x72, 0xD1, 0x0A, 0x16, 0x24, 0x34,
0xE1, 0x25, 0xF1, 0x17, 0x18, 0x19, 0x1A, 0x26,
0x27, 0x28, 0x29, 0x2A, 0x35, 0x36, 0x37, 0x38,
0x39, 0x3A, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
0x49, 0x4A, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
0x59, 0x5A, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
0x69, 0x6A, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
0x79, 0x7A, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
0x88, 0x89, 0x8A, 0x92, 0x93, 0x94, 0x95, 0x96,
0x97, 0x98, 0x99, 0x9A, 0xA2, 0xA3, 0xA4, 0xA5,
0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xB2, 0xB3, 0xB4,
0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xC2, 0xC3,
0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xD2,
0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA,
0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9,
0xEA, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,
0xF9, 0xFA
];
/**
* @private
*/
private const ZigZag:Array =
[
0, 1, 5, 6, 14, 15, 27, 28,
2, 4, 7, 13, 16, 26, 29, 42,
3, 8, 12, 17, 25, 30, 41, 43,
9, 11, 18, 24, 31, 40, 44, 53,
10, 19, 23, 32, 39, 45, 52, 54,
20, 22, 33, 38, 46, 51, 55, 60,
21, 34, 37, 47, 50, 56, 59, 61,
35, 36, 48, 49, 57, 58, 62, 63
];
//--------------------------------------------------------------------------
//
// Variables
//
//--------------------------------------------------------------------------
/**
* @private
* Initialized by initHuffmanTbl() in constructor.
*/
private var YDC_HT:Array;
/**
* @private
* Initialized by initHuffmanTbl() in constructor.
*/
private var UVDC_HT:Array;
/**
* @private
* Initialized by initHuffmanTbl() in constructor.
*/
private var YAC_HT:Array;
/**
* @private
* Initialized by initHuffmanTbl() in constructor.
*/
private var UVAC_HT:Array;
/**
* @private
* Initialized by initCategoryNumber() in constructor.
*/
private var category:Array = new Array(65535);
/**
* @private
* Initialized by initCategoryNumber() in constructor.
*/
private var bitcode:Array = new Array(65535);
/**
* @private
* Initialized by initQuantTables() in constructor.
*/
private var YTable:Array = new Array(64);
/**
* @private
* Initialized by initQuantTables() in constructor.
*/
private var UVTable:Array = new Array(64);
/**
* @private
* Initialized by initQuantTables() in constructor.
*/
private var fdtbl_Y:Array = new Array(64);
/**
* @private
* Initialized by initQuantTables() in constructor.
*/
private var fdtbl_UV:Array = new Array(64);
/**
* @private
* The output ByteArray containing the encoded image data.
*/
private var byteout:ByteArray;
/**
* @private
*/
private var bytenew:int = 0;
/**
* @private
*/
private var bytepos:int = 7;
/**
* @private
*/
private var DU:Array = new Array(64);
/**
* @private
*/
private var YDU:Array = new Array(64);
/**
* @private
*/
private var UDU:Array = new Array(64);
/**
* @private
*/
private var VDU:Array = new Array(64);
//--------------------------------------------------------------------------
//
// Properties
//
//--------------------------------------------------------------------------
//----------------------------------
// contentType
//----------------------------------
/**
* The MIME type for the JPEG encoded image.
* The value is "image/jpeg"
.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function get contentType():String
{
return CONTENT_TYPE;
}
//--------------------------------------------------------------------------
//
// Methods
//
//--------------------------------------------------------------------------
/**
* Converts the pixels of BitmapData object
* to a JPEG-encoded ByteArray object.
*
* @param bitmapData The input BitmapData object.
*
* @return Returns a ByteArray object containing JPEG-encoded image data.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function encode(bitmapData:BitmapData):ByteArray
{
return internalEncode(bitmapData, bitmapData.width, bitmapData.height,
bitmapData.transparent);
}
/**
* Converts a ByteArray object containing raw pixels
* in 32-bit ARGB (Alpha, Red, Green, Blue) format
* to a new JPEG-encoded ByteArray object.
* The original ByteArray is left unchanged.
* Transparency is not supported; however you still must represent
* each pixel as four bytes in ARGB format.
*
* @param byteArray The input ByteArray object containing raw pixels.
* This ByteArray should contain
* 4 * width * height
bytes.
* Each pixel is represented by 4 bytes, in the order ARGB.
* The first four bytes represent the top-left pixel of the image.
* The next four bytes represent the pixel to its right, etc.
* Each row follows the previous one without any padding.
*
* @param width The width of the input image, in pixels.
*
* @param height The height of the input image, in pixels.
*
* @param transparent If false
,
* alpha channel information is ignored.
*
* @return Returns a ByteArray object containing JPEG-encoded image data.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function encodeByteArray(byteArray:ByteArray, width:int, height:int,
transparent:Boolean = true):ByteArray
{
return internalEncode(byteArray, width, height, transparent);
}
//--------------------------------------------------------------------------
//
// Methods: Initialization
//
//--------------------------------------------------------------------------
/**
* @private
* Initializes the Huffman tables YDC_HT, UVDC_HT, YAC_HT, and UVAC_HT.
*/
private function initHuffmanTbl():void
{
YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,
std_dc_luminance_values);
UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,
std_dc_chrominance_values);
YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,
std_ac_luminance_values);
UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,
std_ac_chrominance_values);
}
/**
* @private
*/
private function computeHuffmanTbl(nrcodes:Array, std_table:Array):Array
{
var codevalue:int = 0;
var pos_in_table:int = 0;
var HT:Array = [];
for (var k:int = 1; k <= 16; k++)
{
for (var j:int = 1; j <= nrcodes[k]; j++)
{
HT[std_table[pos_in_table]] = new BitString();
HT[std_table[pos_in_table]].val = codevalue;
HT[std_table[pos_in_table]].len = k;
pos_in_table++;
codevalue++;
}
codevalue *= 2;
}
return HT;
}
/**
* @private
* Initializes the category and bitcode arrays.
*/
private function initCategoryNumber():void
{
var nr:int;
var nrlower:int = 1;
var nrupper:int = 2;
for (var cat:int = 1; cat <= 15; cat++)
{
// Positive numbers
for (nr = nrlower; nr < nrupper; nr++)
{
category[32767 + nr] = cat;
bitcode[32767 + nr] = new BitString();
bitcode[32767 + nr].len = cat;
bitcode[32767 + nr].val = nr;
}
// Negative numbers
for (nr = -(nrupper - 1); nr <= -nrlower; nr++)
{
category[32767 + nr] = cat;
bitcode[32767 + nr] = new BitString();
bitcode[32767 + nr].len = cat;
bitcode[32767 + nr].val = nrupper - 1 + nr;
}
nrlower <<= 1;
nrupper <<= 1;
}
}
/**
* @private
* Initializes YTable, UVTable, fdtbl_Y, and fdtbl_UV.
*/
private function initQuantTables(sf:int):void
{
var i:int = 0;
var t:Number;
var YQT:Array =
[
16, 11, 10, 16, 24, 40, 51, 61,
12, 12, 14, 19, 26, 58, 60, 55,
14, 13, 16, 24, 40, 57, 69, 56,
14, 17, 22, 29, 51, 87, 80, 62,
18, 22, 37, 56, 68, 109, 103, 77,
24, 35, 55, 64, 81, 104, 113, 92,
49, 64, 78, 87, 103, 121, 120, 101,
72, 92, 95, 98, 112, 100, 103, 99
];
for (i = 0; i < 64; i++)
{
t = Math.floor((YQT[i] * sf + 50)/100);
if (t < 1)
t = 1;
else if (t > 255)
t = 255;
YTable[ZigZag[i]] = t;
}
var UVQT:Array =
[
17, 18, 24, 47, 99, 99, 99, 99,
18, 21, 26, 66, 99, 99, 99, 99,
24, 26, 56, 99, 99, 99, 99, 99,
47, 66, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99,
99, 99, 99, 99, 99, 99, 99, 99
];
for (i = 0; i < 64; i++)
{
t = Math.floor((UVQT[i] * sf + 50) / 100);
if (t < 1)
t = 1;
else if (t > 255)
t = 255;
UVTable[ZigZag[i]] = t;
}
var aasf:Array =
[
1.0, 1.387039845, 1.306562965, 1.175875602,
1.0, 0.785694958, 0.541196100, 0.275899379
];
i = 0;
for (var row:int = 0; row < 8; row++)
{
for (var col:int = 0; col < 8; col++)
{
fdtbl_Y[i] =
(1.0 / (YTable [ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
fdtbl_UV[i] =
(1.0 / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0));
i++;
}
}
}
//--------------------------------------------------------------------------
//
// Methods: Core processing
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function internalEncode(source:Object, width:int, height:int,
transparent:Boolean = true):ByteArray
{
// The source is either a BitmapData or a ByteArray.
var sourceBitmapData:BitmapData = source as BitmapData;
var sourceByteArray:ByteArray = source as ByteArray;
// Initialize bit writer
byteout = new ByteArray();
bytenew = 0;
bytepos = 7;
// Add JPEG headers
writeWord(0xFFD8); // SOI
writeAPP0();
writeDQT();
writeSOF0(width, height);
writeDHT();
writeSOS();
// Encode 8x8 macroblocks
var DCY:Number = 0;
var DCU:Number = 0;
var DCV:Number = 0;
bytenew = 0;
bytepos = 7;
for (var ypos:int = 0; ypos < height; ypos += 8)
{
for (var xpos:int = 0; xpos < width; xpos += 8)
{
RGB2YUV(sourceBitmapData, sourceByteArray, xpos, ypos, width, height);
DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
}
}
// Do the bit alignment of the EOI marker
if (bytepos >= 0)
{
var fillbits:BitString = new BitString();
fillbits.len = bytepos + 1;
fillbits.val = (1 << (bytepos + 1)) - 1;
writeBits(fillbits);
}
// Add EOI
writeWord(0xFFD9);
return byteout;
}
/**
* @private
*/
private function RGB2YUV(sourceBitmapData:BitmapData,
sourceByteArray:ByteArray,
xpos:int, ypos:int,
width:int, height:int):void
{
var k:int = 0; // index into 64-element block arrays
for (var j:int = 0; j < 8; j++)
{
var y:int = ypos + j;
if (y >= height)
y = height - 1;
for (var i:int = 0; i < 8; i++)
{
var x:int = xpos + i;
if (x >= width)
x = width - 1;
var pixel:uint;
if (sourceBitmapData)
{
pixel = sourceBitmapData.getPixel32(x, y);
}
else
{
sourceByteArray.position = 4 * (y * width + x);
pixel = sourceByteArray.readUnsignedInt();
}
var r:Number = Number((pixel >> 16) & 0xFF);
var g:Number = Number((pixel >> 8) & 0xFF);
var b:Number = Number(pixel & 0xFF);
YDU[k] = 0.29900 * r + 0.58700 * g + 0.11400 * b - 128.0;
UDU[k] = -0.16874 * r - 0.33126 * g + 0.50000 * b;
VDU[k] = 0.50000 * r - 0.41869 * g - 0.08131 * b;
k++;
}
}
}
/**
* @private
*/
private function processDU(CDU:Array, fdtbl:Array, DC:Number,
HTDC:Array, HTAC:Array):Number
{
var EOB:BitString = HTAC[0x00];
var M16zeroes:BitString = HTAC[0xF0];
var i:int;
var DU_DCT:Array = fDCTQuant(CDU, fdtbl);
// ZigZag reorder
for (i = 0; i < 64; i++)
{
DU[ZigZag[i]] = DU_DCT[i];
}
var Diff:int = DU[0] - DC;
DC = DU[0];
// Encode DC
if (Diff == 0)
{
writeBits(HTDC[0]); // Diff might be 0
}
else
{
writeBits(HTDC[category[32767 + Diff]]);
writeBits(bitcode[32767 + Diff]);
}
// Encode ACs
var end0pos:int = 63;
for (; (end0pos > 0) && (DU[end0pos] == 0); end0pos--)
{
};
// end0pos = first element in reverse order != 0
if (end0pos == 0)
{
writeBits(EOB);
return DC;
}
i = 1;
while (i <= end0pos)
{
var startpos:int = i;
for (; (DU[i] == 0) && (i <= end0pos); i++)
{
}
var nrzeroes:int = i - startpos;
if (nrzeroes >= 16)
{
for (var nrmarker:int = 1; nrmarker <= nrzeroes / 16; nrmarker++)
{
writeBits(M16zeroes);
}
nrzeroes = int(nrzeroes & 0xF);
}
writeBits(HTAC[nrzeroes * 16 + category[32767 + DU[i]]]);
writeBits(bitcode[32767 + DU[i]]);
i++;
}
if (end0pos != 63)
writeBits(EOB);
return DC;
}
/**
* @private
*/
private function fDCTQuant(data:Array, fdtbl:Array):Array
{
// Pass 1: process rows.
var dataOff:int = 0;
var i:int;
for (i = 0; i < 8; i++)
{
var tmp0:Number = data[dataOff + 0] + data[dataOff + 7];
var tmp7:Number = data[dataOff + 0] - data[dataOff + 7];
var tmp1:Number = data[dataOff + 1] + data[dataOff + 6];
var tmp6:Number = data[dataOff + 1] - data[dataOff + 6];
var tmp2:Number = data[dataOff + 2] + data[dataOff + 5];
var tmp5:Number = data[dataOff + 2] - data[dataOff + 5];
var tmp3:Number = data[dataOff + 3] + data[dataOff + 4];
var tmp4:Number = data[dataOff + 3] - data[dataOff + 4];
// Even part
var tmp10:Number = tmp0 + tmp3; // phase 2
var tmp13:Number = tmp0 - tmp3;
var tmp11:Number = tmp1 + tmp2;
var tmp12:Number = tmp1 - tmp2;
data[dataOff + 0] = tmp10 + tmp11; // phase 3
data[dataOff + 4] = tmp10 - tmp11;
var z1:Number = (tmp12 + tmp13) * 0.707106781; // c4
data[dataOff + 2] = tmp13 + z1; // phase 5
data[dataOff + 6] = tmp13 - z1;
// Odd part
tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations.
var z5:Number = (tmp10 - tmp12) * 0.382683433; // c6
var z2:Number = 0.541196100 * tmp10 + z5; // c2 - c6
var z4:Number = 1.306562965 * tmp12 + z5; // c2 + c6
var z3:Number = tmp11 * 0.707106781; // c4
var z11:Number = tmp7 + z3; // phase 5
var z13:Number = tmp7 - z3;
data[dataOff + 5] = z13 + z2; // phase 6
data[dataOff + 3] = z13 - z2;
data[dataOff + 1] = z11 + z4;
data[dataOff + 7] = z11 - z4;
dataOff += 8; // advance pointer to next row
}
// Pass 2: process columns.
dataOff = 0;
for (i = 0; i < 8; i++)
{
tmp0 = data[dataOff + 0] + data[dataOff + 56];
tmp7 = data[dataOff + 0] - data[dataOff + 56];
tmp1 = data[dataOff + 8] + data[dataOff + 48];
tmp6 = data[dataOff + 8] - data[dataOff + 48];
tmp2 = data[dataOff + 16] + data[dataOff + 40];
tmp5 = data[dataOff + 16] - data[dataOff + 40];
tmp3 = data[dataOff + 24] + data[dataOff + 32];
tmp4 = data[dataOff + 24] - data[dataOff + 32];
// Even par
tmp10 = tmp0 + tmp3; // phase 2
tmp13 = tmp0 - tmp3;
tmp11 = tmp1 + tmp2;
tmp12 = tmp1 - tmp2;
data[dataOff + 0] = tmp10 + tmp11; // phase 3
data[dataOff + 32] = tmp10 - tmp11;
z1 = (tmp12 + tmp13) * 0.707106781; // c4
data[dataOff + 16] = tmp13 + z1; // phase 5
data[dataOff + 48] = tmp13 - z1;
// Odd part
tmp10 = tmp4 + tmp5; // phase 2
tmp11 = tmp5 + tmp6;
tmp12 = tmp6 + tmp7;
// The rotator is modified from fig 4-8 to avoid extra negations.
z5 = (tmp10 - tmp12) * 0.382683433; // c6
z2 = 0.541196100 * tmp10 + z5; // c2 - c6
z4 = 1.306562965 * tmp12 + z5; // c2 + c6
z3 = tmp11 * 0.707106781; // c4
z11 = tmp7 + z3; // phase 5 */
z13 = tmp7 - z3;
data[dataOff + 40] = z13 + z2; // phase 6
data[dataOff + 24] = z13 - z2;
data[dataOff + 8] = z11 + z4;
data[dataOff + 56] = z11 - z4;
dataOff++; // advance pointer to next column
}
// Quantize/descale the coefficients
for (i = 0; i < 64; i++)
{
// Apply the quantization and scaling factor
// and round to nearest integer
data[i] = Math.round((data[i] * fdtbl[i]));
}
return data;
}
//--------------------------------------------------------------------------
//
// Methods: Output
//
//--------------------------------------------------------------------------
/**
* @private
*/
private function writeBits(bs:BitString):void
{
var value:int = bs.val;
var posval:int = bs.len - 1;
while (posval >= 0)
{
if (value & uint(1 << posval) )
{
bytenew |= uint(1 << bytepos);
}
posval--;
bytepos--;
if (bytepos < 0)
{
if (bytenew == 0xFF)
{
writeByte(0xFF);
writeByte(0);
}
else
{
writeByte(bytenew);
}
bytepos = 7;
bytenew = 0;
}
}
}
/**
* @private
*/
private function writeByte(value:int):void
{
byteout.writeByte(value);
}
/**
* @private
*/
private function writeWord(value:int):void
{
writeByte((value >> 8) & 0xFF);
writeByte(value & 0xFF);
}
/**
* @private
*/
private function writeAPP0():void
{
writeWord(0xFFE0); // marker
writeWord(16); // length
writeByte(0x4A); // J
writeByte(0x46); // F
writeByte(0x49); // I
writeByte(0x46); // F
writeByte(0); // = "JFIF",'\0'
writeByte(1); // versionhi
writeByte(1); // versionlo
writeByte(0); // xyunits
writeWord(1); // xdensity
writeWord(1); // ydensity
writeByte(0); // thumbnwidth
writeByte(0); // thumbnheight
}
/**
* @private
*/
private function writeDQT():void
{
writeWord(0xFFDB); // marker
writeWord(132); // length
writeByte(0);
var i:int;
for (i = 0; i < 64; i++)
{
writeByte(YTable[i]);
}
writeByte(1);
for (i = 0; i < 64; i++)
{
writeByte(UVTable[i]);
}
}
/**
* @private
*/
private function writeSOF0(width:int, height:int):void
{
writeWord(0xFFC0); // marker
writeWord(17); // length, truecolor YUV JPG
writeByte(8); // precision
writeWord(height);
writeWord(width);
writeByte(3); // nrofcomponents
writeByte(1); // IdY
writeByte(0x11); // HVY
writeByte(0); // QTY
writeByte(2); // IdU
writeByte(0x11); // HVU
writeByte(1); // QTU
writeByte(3); // IdV
writeByte(0x11); // HVV
writeByte(1); // QTV
}
/**
* @private
*/
private function writeDHT():void
{
var i:int;
writeWord(0xFFC4); // marker
writeWord(0x01A2); // length
writeByte(0); // HTYDCinfo
for (i = 0; i < 16; i++)
{
writeByte(std_dc_luminance_nrcodes[i + 1]);
}
for (i = 0; i <= 11; i++)
{
writeByte(std_dc_luminance_values[i]);
}
writeByte(0x10); // HTYACinfo
for (i = 0; i < 16; i++)
{
writeByte(std_ac_luminance_nrcodes[i + 1]);
}
for (i = 0; i <= 161; i++)
{
writeByte(std_ac_luminance_values[i]);
}
writeByte(1); // HTUDCinfo
for (i = 0; i < 16; i++)
{
writeByte(std_dc_chrominance_nrcodes[i + 1]);
}
for (i = 0; i <= 11; i++)
{
writeByte(std_dc_chrominance_values[i]);
}
writeByte(0x11); // HTUACinfo
for (i = 0; i < 16; i++)
{
writeByte(std_ac_chrominance_nrcodes[i + 1]);
}
for (i = 0; i <= 161; i++)
{
writeByte(std_ac_chrominance_values[i]);
}
}
/**
* @private
*/
private function writeSOS():void
{
writeWord(0xFFDA); // marker
writeWord(12); // length
writeByte(3); // nrofcomponents
writeByte(1); // IdY
writeByte(0); // HTY
writeByte(2); // IdU
writeByte(0x11); // HTU
writeByte(3); // IdV
writeByte(0x11); // HTV
writeByte(0); // Ss
writeByte(0x3f); // Se
writeByte(0); // Bf
}
}
}
class BitString
{
/**
* Constructor.
*
* @langversion 3.0
* @playerversion Flash 9
* @playerversion AIR 1.1
* @productversion Flex 3
*/
public function BitString()
{
super();
}
/**
* @private
*/
public var len:int = 0;
/**
* @private
*/
public var val:int = 0;
}