Fixes #759: go back to history when closing diff
[redakcja.git] / redakcja / static / filebrowser / uploadify / com / adobe / images / JPGEncoder.as
1 /*\r
2   Copyright (c) 2008, Adobe Systems Incorporated\r
3   All rights reserved.\r
4 \r
5   Redistribution and use in source and binary forms, with or without \r
6   modification, are permitted provided that the following conditions are\r
7   met:\r
8 \r
9   * Redistributions of source code must retain the above copyright notice, \r
10     this list of conditions and the following disclaimer.\r
11   \r
12   * Redistributions in binary form must reproduce the above copyright\r
13     notice, this list of conditions and the following disclaimer in the \r
14     documentation and/or other materials provided with the distribution.\r
15   \r
16   * Neither the name of Adobe Systems Incorporated nor the names of its \r
17     contributors may be used to endorse or promote products derived from \r
18     this software without specific prior written permission.\r
19 \r
20   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS\r
21   IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,\r
22   THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\r
23   PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR \r
24   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\r
25   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\r
26   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\r
27   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF\r
28   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING\r
29   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS\r
30   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
31 */\r
32 package com.adobe.images\r
33 {\r
34         import flash.geom.*;\r
35         import flash.display.*;\r
36         import flash.utils.*;\r
37         \r
38         /**\r
39          * Class that converts BitmapData into a valid JPEG\r
40          */             \r
41         public class JPGEncoder\r
42         {\r
43 \r
44                 // Static table initialization\r
45         \r
46                 private var ZigZag:Array = [\r
47                          0, 1, 5, 6,14,15,27,28,\r
48                          2, 4, 7,13,16,26,29,42,\r
49                          3, 8,12,17,25,30,41,43,\r
50                          9,11,18,24,31,40,44,53,\r
51                         10,19,23,32,39,45,52,54,\r
52                         20,22,33,38,46,51,55,60,\r
53                         21,34,37,47,50,56,59,61,\r
54                         35,36,48,49,57,58,62,63\r
55                 ];\r
56         \r
57                 private var YTable:Array = new Array(64);\r
58                 private var UVTable:Array = new Array(64);\r
59                 private var fdtbl_Y:Array = new Array(64);\r
60                 private var fdtbl_UV:Array = new Array(64);\r
61         \r
62                 private function initQuantTables(sf:int):void\r
63                 {\r
64                         var i:int;\r
65                         var t:Number;\r
66                         var YQT:Array = [\r
67                                 16, 11, 10, 16, 24, 40, 51, 61,\r
68                                 12, 12, 14, 19, 26, 58, 60, 55,\r
69                                 14, 13, 16, 24, 40, 57, 69, 56,\r
70                                 14, 17, 22, 29, 51, 87, 80, 62,\r
71                                 18, 22, 37, 56, 68,109,103, 77,\r
72                                 24, 35, 55, 64, 81,104,113, 92,\r
73                                 49, 64, 78, 87,103,121,120,101,\r
74                                 72, 92, 95, 98,112,100,103, 99\r
75                         ];\r
76                         for (i = 0; i < 64; i++) {\r
77                                 t = Math.floor((YQT[i]*sf+50)/100);\r
78                                 if (t < 1) {\r
79                                         t = 1;\r
80                                 } else if (t > 255) {\r
81                                         t = 255;\r
82                                 }\r
83                                 YTable[ZigZag[i]] = t;\r
84                         }\r
85                         var UVQT:Array = [\r
86                                 17, 18, 24, 47, 99, 99, 99, 99,\r
87                                 18, 21, 26, 66, 99, 99, 99, 99,\r
88                                 24, 26, 56, 99, 99, 99, 99, 99,\r
89                                 47, 66, 99, 99, 99, 99, 99, 99,\r
90                                 99, 99, 99, 99, 99, 99, 99, 99,\r
91                                 99, 99, 99, 99, 99, 99, 99, 99,\r
92                                 99, 99, 99, 99, 99, 99, 99, 99,\r
93                                 99, 99, 99, 99, 99, 99, 99, 99\r
94                         ];\r
95                         for (i = 0; i < 64; i++) {\r
96                                 t = Math.floor((UVQT[i]*sf+50)/100);\r
97                                 if (t < 1) {\r
98                                         t = 1;\r
99                                 } else if (t > 255) {\r
100                                         t = 255;\r
101                                 }\r
102                                 UVTable[ZigZag[i]] = t;\r
103                         }\r
104                         var aasf:Array = [\r
105                                 1.0, 1.387039845, 1.306562965, 1.175875602,\r
106                                 1.0, 0.785694958, 0.541196100, 0.275899379\r
107                         ];\r
108                         i = 0;\r
109                         for (var row:int = 0; row < 8; row++)\r
110                         {\r
111                                 for (var col:int = 0; col < 8; col++)\r
112                                 {\r
113                                         fdtbl_Y[i]  = (1.0 / (YTable [ZigZag[i]] * aasf[row] * aasf[col] * 8.0));\r
114                                         fdtbl_UV[i] = (1.0 / (UVTable[ZigZag[i]] * aasf[row] * aasf[col] * 8.0));\r
115                                         i++;\r
116                                 }\r
117                         }\r
118                 }\r
119         \r
120                 private var YDC_HT:Array;\r
121                 private var UVDC_HT:Array;\r
122                 private var YAC_HT:Array;\r
123                 private var UVAC_HT:Array;\r
124         \r
125                 private function computeHuffmanTbl(nrcodes:Array, std_table:Array):Array\r
126                 {\r
127                         var codevalue:int = 0;\r
128                         var pos_in_table:int = 0;\r
129                         var HT:Array = new Array();\r
130                         for (var k:int=1; k<=16; k++) {\r
131                                 for (var j:int=1; j<=nrcodes[k]; j++) {\r
132                                         HT[std_table[pos_in_table]] = new BitString();\r
133                                         HT[std_table[pos_in_table]].val = codevalue;\r
134                                         HT[std_table[pos_in_table]].len = k;\r
135                                         pos_in_table++;\r
136                                         codevalue++;\r
137                                 }\r
138                                 codevalue*=2;\r
139                         }\r
140                         return HT;\r
141                 }\r
142         \r
143                 private var std_dc_luminance_nrcodes:Array = [0,0,1,5,1,1,1,1,1,1,0,0,0,0,0,0,0];\r
144                 private var std_dc_luminance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11];\r
145                 private var std_ac_luminance_nrcodes:Array = [0,0,2,1,3,3,2,4,3,5,5,4,4,0,0,1,0x7d];\r
146                 private var std_ac_luminance_values:Array = [\r
147                         0x01,0x02,0x03,0x00,0x04,0x11,0x05,0x12,\r
148                         0x21,0x31,0x41,0x06,0x13,0x51,0x61,0x07,\r
149                         0x22,0x71,0x14,0x32,0x81,0x91,0xa1,0x08,\r
150                         0x23,0x42,0xb1,0xc1,0x15,0x52,0xd1,0xf0,\r
151                         0x24,0x33,0x62,0x72,0x82,0x09,0x0a,0x16,\r
152                         0x17,0x18,0x19,0x1a,0x25,0x26,0x27,0x28,\r
153                         0x29,0x2a,0x34,0x35,0x36,0x37,0x38,0x39,\r
154                         0x3a,0x43,0x44,0x45,0x46,0x47,0x48,0x49,\r
155                         0x4a,0x53,0x54,0x55,0x56,0x57,0x58,0x59,\r
156                         0x5a,0x63,0x64,0x65,0x66,0x67,0x68,0x69,\r
157                         0x6a,0x73,0x74,0x75,0x76,0x77,0x78,0x79,\r
158                         0x7a,0x83,0x84,0x85,0x86,0x87,0x88,0x89,\r
159                         0x8a,0x92,0x93,0x94,0x95,0x96,0x97,0x98,\r
160                         0x99,0x9a,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,\r
161                         0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,0xb5,0xb6,\r
162                         0xb7,0xb8,0xb9,0xba,0xc2,0xc3,0xc4,0xc5,\r
163                         0xc6,0xc7,0xc8,0xc9,0xca,0xd2,0xd3,0xd4,\r
164                         0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xe1,0xe2,\r
165                         0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,\r
166                         0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\r
167                         0xf9,0xfa\r
168                 ];\r
169         \r
170                 private var std_dc_chrominance_nrcodes:Array = [0,0,3,1,1,1,1,1,1,1,1,1,0,0,0,0,0];\r
171                 private var std_dc_chrominance_values:Array = [0,1,2,3,4,5,6,7,8,9,10,11];\r
172                 private var std_ac_chrominance_nrcodes:Array = [0,0,2,1,2,4,4,3,4,7,5,4,4,0,1,2,0x77];\r
173                 private var std_ac_chrominance_values:Array = [\r
174                         0x00,0x01,0x02,0x03,0x11,0x04,0x05,0x21,\r
175                         0x31,0x06,0x12,0x41,0x51,0x07,0x61,0x71,\r
176                         0x13,0x22,0x32,0x81,0x08,0x14,0x42,0x91,\r
177                         0xa1,0xb1,0xc1,0x09,0x23,0x33,0x52,0xf0,\r
178                         0x15,0x62,0x72,0xd1,0x0a,0x16,0x24,0x34,\r
179                         0xe1,0x25,0xf1,0x17,0x18,0x19,0x1a,0x26,\r
180                         0x27,0x28,0x29,0x2a,0x35,0x36,0x37,0x38,\r
181                         0x39,0x3a,0x43,0x44,0x45,0x46,0x47,0x48,\r
182                         0x49,0x4a,0x53,0x54,0x55,0x56,0x57,0x58,\r
183                         0x59,0x5a,0x63,0x64,0x65,0x66,0x67,0x68,\r
184                         0x69,0x6a,0x73,0x74,0x75,0x76,0x77,0x78,\r
185                         0x79,0x7a,0x82,0x83,0x84,0x85,0x86,0x87,\r
186                         0x88,0x89,0x8a,0x92,0x93,0x94,0x95,0x96,\r
187                         0x97,0x98,0x99,0x9a,0xa2,0xa3,0xa4,0xa5,\r
188                         0xa6,0xa7,0xa8,0xa9,0xaa,0xb2,0xb3,0xb4,\r
189                         0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xc2,0xc3,\r
190                         0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xd2,\r
191                         0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,\r
192                         0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,\r
193                         0xea,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,\r
194                         0xf9,0xfa\r
195                 ];\r
196         \r
197                 private function initHuffmanTbl():void\r
198                 {\r
199                         YDC_HT = computeHuffmanTbl(std_dc_luminance_nrcodes,std_dc_luminance_values);\r
200                         UVDC_HT = computeHuffmanTbl(std_dc_chrominance_nrcodes,std_dc_chrominance_values);\r
201                         YAC_HT = computeHuffmanTbl(std_ac_luminance_nrcodes,std_ac_luminance_values);\r
202                         UVAC_HT = computeHuffmanTbl(std_ac_chrominance_nrcodes,std_ac_chrominance_values);\r
203                 }\r
204         \r
205                 private var bitcode:Array = new Array(65535);\r
206                 private var category:Array = new Array(65535);\r
207         \r
208                 private function initCategoryNumber():void\r
209                 {\r
210                         var nrlower:int = 1;\r
211                         var nrupper:int = 2;\r
212                         var nr:int;\r
213                         for (var cat:int=1; cat<=15; cat++) {\r
214                                 //Positive numbers\r
215                                 for (nr=nrlower; nr<nrupper; nr++) {\r
216                                         category[32767+nr] = cat;\r
217                                         bitcode[32767+nr] = new BitString();\r
218                                         bitcode[32767+nr].len = cat;\r
219                                         bitcode[32767+nr].val = nr;\r
220                                 }\r
221                                 //Negative numbers\r
222                                 for (nr=-(nrupper-1); nr<=-nrlower; nr++) {\r
223                                         category[32767+nr] = cat;\r
224                                         bitcode[32767+nr] = new BitString();\r
225                                         bitcode[32767+nr].len = cat;\r
226                                         bitcode[32767+nr].val = nrupper-1+nr;\r
227                                 }\r
228                                 nrlower <<= 1;\r
229                                 nrupper <<= 1;\r
230                         }\r
231                 }\r
232         \r
233                 // IO functions\r
234         \r
235                 private var byteout:ByteArray;\r
236                 private var bytenew:int = 0;\r
237                 private var bytepos:int = 7;\r
238         \r
239                 private function writeBits(bs:BitString):void\r
240                 {\r
241                         var value:int = bs.val;\r
242                         var posval:int = bs.len-1;\r
243                         while ( posval >= 0 ) {\r
244                                 if (value & uint(1 << posval) ) {\r
245                                         bytenew |= uint(1 << bytepos);\r
246                                 }\r
247                                 posval--;\r
248                                 bytepos--;\r
249                                 if (bytepos < 0) {\r
250                                         if (bytenew == 0xFF) {\r
251                                                 writeByte(0xFF);\r
252                                                 writeByte(0);\r
253                                         }\r
254                                         else {\r
255                                                 writeByte(bytenew);\r
256                                         }\r
257                                         bytepos=7;\r
258                                         bytenew=0;\r
259                                 }\r
260                         }\r
261                 }\r
262         \r
263                 private function writeByte(value:int):void\r
264                 {\r
265                         byteout.writeByte(value);\r
266                 }\r
267         \r
268                 private function writeWord(value:int):void\r
269                 {\r
270                         writeByte((value>>8)&0xFF);\r
271                         writeByte((value   )&0xFF);\r
272                 }\r
273         \r
274                 // DCT & quantization core\r
275         \r
276                 private function fDCTQuant(data:Array, fdtbl:Array):Array\r
277                 {\r
278                         var tmp0:Number, tmp1:Number, tmp2:Number, tmp3:Number, tmp4:Number, tmp5:Number, tmp6:Number, tmp7:Number;\r
279                         var tmp10:Number, tmp11:Number, tmp12:Number, tmp13:Number;\r
280                         var z1:Number, z2:Number, z3:Number, z4:Number, z5:Number, z11:Number, z13:Number;\r
281                         var i:int;\r
282                         /* Pass 1: process rows. */\r
283                         var dataOff:int=0;\r
284                         for (i=0; i<8; i++) {\r
285                                 tmp0 = data[dataOff+0] + data[dataOff+7];\r
286                                 tmp7 = data[dataOff+0] - data[dataOff+7];\r
287                                 tmp1 = data[dataOff+1] + data[dataOff+6];\r
288                                 tmp6 = data[dataOff+1] - data[dataOff+6];\r
289                                 tmp2 = data[dataOff+2] + data[dataOff+5];\r
290                                 tmp5 = data[dataOff+2] - data[dataOff+5];\r
291                                 tmp3 = data[dataOff+3] + data[dataOff+4];\r
292                                 tmp4 = data[dataOff+3] - data[dataOff+4];\r
293         \r
294                                 /* Even part */\r
295                                 tmp10 = tmp0 + tmp3;    /* phase 2 */\r
296                                 tmp13 = tmp0 - tmp3;\r
297                                 tmp11 = tmp1 + tmp2;\r
298                                 tmp12 = tmp1 - tmp2;\r
299         \r
300                                 data[dataOff+0] = tmp10 + tmp11; /* phase 3 */\r
301                                 data[dataOff+4] = tmp10 - tmp11;\r
302         \r
303                                 z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\r
304                                 data[dataOff+2] = tmp13 + z1; /* phase 5 */\r
305                                 data[dataOff+6] = tmp13 - z1;\r
306         \r
307                                 /* Odd part */\r
308                                 tmp10 = tmp4 + tmp5; /* phase 2 */\r
309                                 tmp11 = tmp5 + tmp6;\r
310                                 tmp12 = tmp6 + tmp7;\r
311         \r
312                                 /* The rotator is modified from fig 4-8 to avoid extra negations. */\r
313                                 z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\r
314                                 z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\r
315                                 z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\r
316                                 z3 = tmp11 * 0.707106781; /* c4 */\r
317         \r
318                                 z11 = tmp7 + z3;        /* phase 5 */\r
319                                 z13 = tmp7 - z3;\r
320         \r
321                                 data[dataOff+5] = z13 + z2;     /* phase 6 */\r
322                                 data[dataOff+3] = z13 - z2;\r
323                                 data[dataOff+1] = z11 + z4;\r
324                                 data[dataOff+7] = z11 - z4;\r
325         \r
326                                 dataOff += 8; /* advance pointer to next row */\r
327                         }\r
328         \r
329                         /* Pass 2: process columns. */\r
330                         dataOff = 0;\r
331                         for (i=0; i<8; i++) {\r
332                                 tmp0 = data[dataOff+ 0] + data[dataOff+56];\r
333                                 tmp7 = data[dataOff+ 0] - data[dataOff+56];\r
334                                 tmp1 = data[dataOff+ 8] + data[dataOff+48];\r
335                                 tmp6 = data[dataOff+ 8] - data[dataOff+48];\r
336                                 tmp2 = data[dataOff+16] + data[dataOff+40];\r
337                                 tmp5 = data[dataOff+16] - data[dataOff+40];\r
338                                 tmp3 = data[dataOff+24] + data[dataOff+32];\r
339                                 tmp4 = data[dataOff+24] - data[dataOff+32];\r
340         \r
341                                 /* Even part */\r
342                                 tmp10 = tmp0 + tmp3;    /* phase 2 */\r
343                                 tmp13 = tmp0 - tmp3;\r
344                                 tmp11 = tmp1 + tmp2;\r
345                                 tmp12 = tmp1 - tmp2;\r
346         \r
347                                 data[dataOff+ 0] = tmp10 + tmp11; /* phase 3 */\r
348                                 data[dataOff+32] = tmp10 - tmp11;\r
349         \r
350                                 z1 = (tmp12 + tmp13) * 0.707106781; /* c4 */\r
351                                 data[dataOff+16] = tmp13 + z1; /* phase 5 */\r
352                                 data[dataOff+48] = tmp13 - z1;\r
353         \r
354                                 /* Odd part */\r
355                                 tmp10 = tmp4 + tmp5; /* phase 2 */\r
356                                 tmp11 = tmp5 + tmp6;\r
357                                 tmp12 = tmp6 + tmp7;\r
358         \r
359                                 /* The rotator is modified from fig 4-8 to avoid extra negations. */\r
360                                 z5 = (tmp10 - tmp12) * 0.382683433; /* c6 */\r
361                                 z2 = 0.541196100 * tmp10 + z5; /* c2-c6 */\r
362                                 z4 = 1.306562965 * tmp12 + z5; /* c2+c6 */\r
363                                 z3 = tmp11 * 0.707106781; /* c4 */\r
364         \r
365                                 z11 = tmp7 + z3;        /* phase 5 */\r
366                                 z13 = tmp7 - z3;\r
367         \r
368                                 data[dataOff+40] = z13 + z2; /* phase 6 */\r
369                                 data[dataOff+24] = z13 - z2;\r
370                                 data[dataOff+ 8] = z11 + z4;\r
371                                 data[dataOff+56] = z11 - z4;\r
372         \r
373                                 dataOff++; /* advance pointer to next column */\r
374                         }\r
375         \r
376                         // Quantize/descale the coefficients\r
377                         for (i=0; i<64; i++) {\r
378                                 // Apply the quantization and scaling factor & Round to nearest integer\r
379                                 data[i] = Math.round((data[i]*fdtbl[i]));\r
380                         }\r
381                         return data;\r
382                 }\r
383         \r
384                 // Chunk writing\r
385         \r
386                 private function writeAPP0():void\r
387                 {\r
388                         writeWord(0xFFE0); // marker\r
389                         writeWord(16); // length\r
390                         writeByte(0x4A); // J\r
391                         writeByte(0x46); // F\r
392                         writeByte(0x49); // I\r
393                         writeByte(0x46); // F\r
394                         writeByte(0); // = "JFIF",'\0'\r
395                         writeByte(1); // versionhi\r
396                         writeByte(1); // versionlo\r
397                         writeByte(0); // xyunits\r
398                         writeWord(1); // xdensity\r
399                         writeWord(1); // ydensity\r
400                         writeByte(0); // thumbnwidth\r
401                         writeByte(0); // thumbnheight\r
402                 }\r
403         \r
404                 private function writeSOF0(width:int, height:int):void\r
405                 {\r
406                         writeWord(0xFFC0); // marker\r
407                         writeWord(17);   // length, truecolor YUV JPG\r
408                         writeByte(8);    // precision\r
409                         writeWord(height);\r
410                         writeWord(width);\r
411                         writeByte(3);    // nrofcomponents\r
412                         writeByte(1);    // IdY\r
413                         writeByte(0x11); // HVY\r
414                         writeByte(0);    // QTY\r
415                         writeByte(2);    // IdU\r
416                         writeByte(0x11); // HVU\r
417                         writeByte(1);    // QTU\r
418                         writeByte(3);    // IdV\r
419                         writeByte(0x11); // HVV\r
420                         writeByte(1);    // QTV\r
421                 }\r
422         \r
423                 private function writeDQT():void\r
424                 {\r
425                         writeWord(0xFFDB); // marker\r
426                         writeWord(132);    // length\r
427                         writeByte(0);\r
428                         var i:int;\r
429                         for (i=0; i<64; i++) {\r
430                                 writeByte(YTable[i]);\r
431                         }\r
432                         writeByte(1);\r
433                         for (i=0; i<64; i++) {\r
434                                 writeByte(UVTable[i]);\r
435                         }\r
436                 }\r
437         \r
438                 private function writeDHT():void\r
439                 {\r
440                         writeWord(0xFFC4); // marker\r
441                         writeWord(0x01A2); // length\r
442                         var i:int;\r
443         \r
444                         writeByte(0); // HTYDCinfo\r
445                         for (i=0; i<16; i++) {\r
446                                 writeByte(std_dc_luminance_nrcodes[i+1]);\r
447                         }\r
448                         for (i=0; i<=11; i++) {\r
449                                 writeByte(std_dc_luminance_values[i]);\r
450                         }\r
451         \r
452                         writeByte(0x10); // HTYACinfo\r
453                         for (i=0; i<16; i++) {\r
454                                 writeByte(std_ac_luminance_nrcodes[i+1]);\r
455                         }\r
456                         for (i=0; i<=161; i++) {\r
457                                 writeByte(std_ac_luminance_values[i]);\r
458                         }\r
459         \r
460                         writeByte(1); // HTUDCinfo\r
461                         for (i=0; i<16; i++) {\r
462                                 writeByte(std_dc_chrominance_nrcodes[i+1]);\r
463                         }\r
464                         for (i=0; i<=11; i++) {\r
465                                 writeByte(std_dc_chrominance_values[i]);\r
466                         }\r
467         \r
468                         writeByte(0x11); // HTUACinfo\r
469                         for (i=0; i<16; i++) {\r
470                                 writeByte(std_ac_chrominance_nrcodes[i+1]);\r
471                         }\r
472                         for (i=0; i<=161; i++) {\r
473                                 writeByte(std_ac_chrominance_values[i]);\r
474                         }\r
475                 }\r
476         \r
477                 private function writeSOS():void\r
478                 {\r
479                         writeWord(0xFFDA); // marker\r
480                         writeWord(12); // length\r
481                         writeByte(3); // nrofcomponents\r
482                         writeByte(1); // IdY\r
483                         writeByte(0); // HTY\r
484                         writeByte(2); // IdU\r
485                         writeByte(0x11); // HTU\r
486                         writeByte(3); // IdV\r
487                         writeByte(0x11); // HTV\r
488                         writeByte(0); // Ss\r
489                         writeByte(0x3f); // Se\r
490                         writeByte(0); // Bf\r
491                 }\r
492         \r
493                 // Core processing\r
494                 private var DU:Array = new Array(64);\r
495         \r
496                 private function processDU(CDU:Array, fdtbl:Array, DC:Number, HTDC:Array, HTAC:Array):Number\r
497                 {\r
498                         var EOB:BitString = HTAC[0x00];\r
499                         var M16zeroes:BitString = HTAC[0xF0];\r
500                         var i:int;\r
501         \r
502                         var DU_DCT:Array = fDCTQuant(CDU, fdtbl);\r
503                         //ZigZag reorder\r
504                         for (i=0;i<64;i++) {\r
505                                 DU[ZigZag[i]]=DU_DCT[i];\r
506                         }\r
507                         var Diff:int = DU[0] - DC; DC = DU[0];\r
508                         //Encode DC\r
509                         if (Diff==0) {\r
510                                 writeBits(HTDC[0]); // Diff might be 0\r
511                         } else {\r
512                                 writeBits(HTDC[category[32767+Diff]]);\r
513                                 writeBits(bitcode[32767+Diff]);\r
514                         }\r
515                         //Encode ACs\r
516                         var end0pos:int = 63;\r
517                         for (; (end0pos>0)&&(DU[end0pos]==0); end0pos--) {\r
518                         };\r
519                         //end0pos = first element in reverse order !=0\r
520                         if ( end0pos == 0) {\r
521                                 writeBits(EOB);\r
522                                 return DC;\r
523                         }\r
524                         i = 1;\r
525                         while ( i <= end0pos ) {\r
526                                 var startpos:int = i;\r
527                                 for (; (DU[i]==0) && (i<=end0pos); i++) {\r
528                                 }\r
529                                 var nrzeroes:int = i-startpos;\r
530                                 if ( nrzeroes >= 16 ) {\r
531                                         for (var nrmarker:int=1; nrmarker <= nrzeroes/16; nrmarker++) {\r
532                                                 writeBits(M16zeroes);\r
533                                         }\r
534                                         nrzeroes = int(nrzeroes&0xF);\r
535                                 }\r
536                                 writeBits(HTAC[nrzeroes*16+category[32767+DU[i]]]);\r
537                                 writeBits(bitcode[32767+DU[i]]);\r
538                                 i++;\r
539                         }\r
540                         if ( end0pos != 63 ) {\r
541                                 writeBits(EOB);\r
542                         }\r
543                         return DC;\r
544                 }\r
545         \r
546                 private var YDU:Array = new Array(64);\r
547                 private var UDU:Array = new Array(64);\r
548                 private var VDU:Array = new Array(64);\r
549         \r
550                 private function RGB2YUV(img:BitmapData, xpos:int, ypos:int):void\r
551                 {\r
552                         var pos:int=0;\r
553                         for (var y:int=0; y<8; y++) {\r
554                                 for (var x:int=0; x<8; x++) {\r
555                                         var P:uint = img.getPixel32(xpos+x,ypos+y);\r
556                                         var R:Number = Number((P>>16)&0xFF);\r
557                                         var G:Number = Number((P>> 8)&0xFF);\r
558                                         var B:Number = Number((P    )&0xFF);\r
559                                         YDU[pos]=((( 0.29900)*R+( 0.58700)*G+( 0.11400)*B))-128;\r
560                                         UDU[pos]=(((-0.16874)*R+(-0.33126)*G+( 0.50000)*B));\r
561                                         VDU[pos]=((( 0.50000)*R+(-0.41869)*G+(-0.08131)*B));\r
562                                         pos++;\r
563                                 }\r
564                         }\r
565                 }\r
566         \r
567                 /**\r
568                  * Constructor for JPEGEncoder class\r
569                  *\r
570                  * @param quality The quality level between 1 and 100 that detrmines the\r
571                  * level of compression used in the generated JPEG\r
572                  * @langversion ActionScript 3.0\r
573                  * @playerversion Flash 9.0\r
574                  * @tiptext\r
575                  */             \r
576                 public function JPGEncoder(quality:Number = 50)\r
577                 {\r
578                         if (quality <= 0) {\r
579                                 quality = 1;\r
580                         }\r
581                         if (quality > 100) {\r
582                                 quality = 100;\r
583                         }\r
584                         var sf:int = 0;\r
585                         if (quality < 50) {\r
586                                 sf = int(5000 / quality);\r
587                         } else {\r
588                                 sf = int(200 - quality*2);\r
589                         }\r
590                         // Create tables\r
591                         initHuffmanTbl();\r
592                         initCategoryNumber();\r
593                         initQuantTables(sf);\r
594                 }\r
595         \r
596                 /**\r
597                  * Created a JPEG image from the specified BitmapData\r
598                  *\r
599                  * @param image The BitmapData that will be converted into the JPEG format.\r
600                  * @return a ByteArray representing the JPEG encoded image data.\r
601                  * @langversion ActionScript 3.0\r
602                  * @playerversion Flash 9.0\r
603                  * @tiptext\r
604                  */     \r
605                 public function encode(image:BitmapData):ByteArray\r
606                 {\r
607                         // Initialize bit writer\r
608                         byteout = new ByteArray();\r
609                         bytenew=0;\r
610                         bytepos=7;\r
611         \r
612                         // Add JPEG headers\r
613                         writeWord(0xFFD8); // SOI\r
614                         writeAPP0();\r
615                         writeDQT();\r
616                         writeSOF0(image.width,image.height);\r
617                         writeDHT();\r
618                         writeSOS();\r
619 \r
620         \r
621                         // Encode 8x8 macroblocks\r
622                         var DCY:Number=0;\r
623                         var DCU:Number=0;\r
624                         var DCV:Number=0;\r
625                         bytenew=0;\r
626                         bytepos=7;\r
627                         for (var ypos:int=0; ypos<image.height; ypos+=8) {\r
628                                 for (var xpos:int=0; xpos<image.width; xpos+=8) {\r
629                                         RGB2YUV(image, xpos, ypos);\r
630                                         DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);\r
631                                         DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);\r
632                                         DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);\r
633                                 }\r
634                         }\r
635         \r
636                         // Do the bit alignment of the EOI marker\r
637                         if ( bytepos >= 0 ) {\r
638                                 var fillbits:BitString = new BitString();\r
639                                 fillbits.len = bytepos+1;\r
640                                 fillbits.val = (1<<(bytepos+1))-1;\r
641                                 writeBits(fillbits);\r
642                         }\r
643         \r
644                         writeWord(0xFFD9); //EOI\r
645                         return byteout;\r
646                 }\r
647         }\r
648 }\r