Project

General

Profile

Statistics
| Branch: | Revision:

colonymech / docs / www / colonyscout / internal / includes / uploadify / com / adobe / images / JPGEncoder.as @ f59acf11

History | View | Annotate | Download (18 KB)

1
/*
2
  Copyright (c) 2008, Adobe Systems Incorporated
3
  All rights reserved.
4

    
5
  Redistribution and use in source and binary forms, with or without 
6
  modification, are permitted provided that the following conditions are
7
  met:
8

    
9
  * Redistributions of source code must retain the above copyright notice, 
10
    this list of conditions and the following disclaimer.
11
  
12
  * Redistributions in binary form must reproduce the above copyright
13
    notice, this list of conditions and the following disclaimer in the 
14
    documentation and/or other materials provided with the distribution.
15
  
16
  * Neither the name of Adobe Systems Incorporated nor the names of its 
17
    contributors may be used to endorse or promote products derived from 
18
    this software without specific prior written permission.
19

    
20
  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
21
  IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22
  THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23
  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 
24
  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25
  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26
  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27
  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28
  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29
  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30
  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31
*/
32
package com.adobe.images
33
{
34
	import flash.geom.*;
35
	import flash.display.*;
36
	import flash.utils.*;
37
	
38
	/**
39
	 * Class that converts BitmapData into a valid JPEG
40
	 */		
41
	public class JPGEncoder
42
	{
43

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

    
620
	
621
			// Encode 8x8 macroblocks
622
			var DCY:Number=0;
623
			var DCU:Number=0;
624
			var DCV:Number=0;
625
			bytenew=0;
626
			bytepos=7;
627
			for (var ypos:int=0; ypos<image.height; ypos+=8) {
628
				for (var xpos:int=0; xpos<image.width; xpos+=8) {
629
					RGB2YUV(image, xpos, ypos);
630
					DCY = processDU(YDU, fdtbl_Y, DCY, YDC_HT, YAC_HT);
631
					DCU = processDU(UDU, fdtbl_UV, DCU, UVDC_HT, UVAC_HT);
632
					DCV = processDU(VDU, fdtbl_UV, DCV, UVDC_HT, UVAC_HT);
633
				}
634
			}
635
	
636
			// Do the bit alignment of the EOI marker
637
			if ( bytepos >= 0 ) {
638
				var fillbits:BitString = new BitString();
639
				fillbits.len = bytepos+1;
640
				fillbits.val = (1<<(bytepos+1))-1;
641
				writeBits(fillbits);
642
			}
643
	
644
			writeWord(0xFFD9); //EOI
645
			return byteout;
646
		}
647
	}
648
}