JPGEncoder.as 19 KB

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