/flowplayer/trunk/lib/corelib/src/com/adobe/images/JPGEncoder.as

http://flowplayer-core.googlecode.com/ · ActionScript · 651 lines · 511 code · 59 blank · 81 comment · 56 complexity · 17d60068a631d2172b5d2d099fed9abb MD5 · raw file

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