Mercurial > projects > dwt-linux
comparison dwt/internal/image/JPEGFileFormat.d @ 13:3d9bbe0a83a0
FileFormats
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Sun, 06 Jan 2008 22:54:14 +0100 |
parents | |
children | fc2b263b8a3f |
comparison
equal
deleted
inserted
replaced
12:0c78fa47d476 | 13:3d9bbe0a83a0 |
---|---|
1 /******************************************************************************* | |
2 * Copyright (c) 2000, 2006 IBM Corporation and others. | |
3 * All rights reserved. This source file is made available under the terms contained in the README file | |
4 * accompanying this program. The README file should be located in the about_files directory of the | |
5 * plug-in that contains this source file. | |
6 * | |
7 * Contributors: | |
8 * IBM Corporation - initial API and implementation | |
9 *******************************************************************************/ | |
10 module dwt.internal.image.JPEGFileFormat; | |
11 | |
12 import dwt.SWT; | |
13 import dwt.internal.image.JPEGFrameHeader; | |
14 import dwt.internal.image.JPEGScanHeader; | |
15 import dwt.internal.image.JPEGHuffmanTable; | |
16 import dwt.internal.image.JPEGAppn; | |
17 import dwt.internal.image.JPEGSegment; | |
18 import dwt.internal.image.FileFormat; | |
19 import dwt.internal.image.JPEGComment; | |
20 import dwt.internal.image.JPEGArithmeticConditioningTable; | |
21 import dwt.internal.image.JPEGRestartInterval; | |
22 import dwt.internal.image.JPEGQuantizationTable; | |
23 import dwt.internal.image.JPEGStartOfImage; | |
24 import dwt.internal.image.JPEGDecoder; | |
25 import dwt.internal.image.JPEGEndOfImage; | |
26 | |
27 import dwt.graphics.RGB; | |
28 import dwt.graphics.PaletteData; | |
29 | |
30 import tango.core.Exception; | |
31 | |
32 final class JPEGFileFormat : FileFormat { | |
33 int restartInterval; | |
34 JPEGFrameHeader frameHeader; | |
35 int imageWidth, imageHeight; | |
36 int interleavedMcuCols, interleavedMcuRows; | |
37 int maxV, maxH; | |
38 bool progressive; | |
39 int samplePrecision; | |
40 int nComponents; | |
41 int[][] frameComponents; | |
42 int[] componentIds; | |
43 byte[][] imageComponents; | |
44 int[] dataUnit; | |
45 int[][][] dataUnits; | |
46 int[] precedingDCs; | |
47 JPEGScanHeader scanHeader; | |
48 byte[] dataBuffer; | |
49 int currentBitCount; | |
50 int bufferCurrentPosition; | |
51 int restartsToGo; | |
52 int nextRestartNumber; | |
53 JPEGHuffmanTable[] acHuffmanTables; | |
54 JPEGHuffmanTable[] dcHuffmanTables; | |
55 int[][] quantizationTables; | |
56 int currentByte; | |
57 int encoderQFactor = 75; | |
58 int eobrun = 0; | |
59 /* JPEGConstants */ | |
60 public static const int DCTSIZE = 8; | |
61 public static const int DCTSIZESQR = 64; | |
62 /* JPEGFixedPointConstants */ | |
63 public static const int FIX_0_899976223 = 7373; | |
64 public static const int FIX_1_961570560 = 16069; | |
65 public static const int FIX_2_053119869 = 16819; | |
66 public static const int FIX_0_298631336 = 2446; | |
67 public static const int FIX_1_847759065 = 15137; | |
68 public static const int FIX_1_175875602 = 9633; | |
69 public static const int FIX_3_072711026 = 25172; | |
70 public static const int FIX_0_765366865 = 6270; | |
71 public static const int FIX_2_562915447 = 20995; | |
72 public static const int FIX_0_541196100 = 4433; | |
73 public static const int FIX_0_390180644 = 3196; | |
74 public static const int FIX_1_501321110 = 12299; | |
75 /* JPEGMarkerCodes */ | |
76 public static const int APP0 = 0xFFE0; | |
77 public static const int APP15 = 0xFFEF; | |
78 public static const int COM = 0xFFFE; | |
79 public static const int DAC = 0xFFCC; | |
80 public static const int DHP = 0xFFDE; | |
81 public static const int DHT = 0xFFC4; | |
82 public static const int DNL = 0xFFDC; | |
83 public static const int DRI = 0xFFDD; | |
84 public static const int DQT = 0xFFDB; | |
85 public static const int EOI = 0xFFD9; | |
86 public static const int EXP = 0xFFDF; | |
87 public static const int JPG = 0xFFC8; | |
88 public static const int JPG0 = 0xFFF0; | |
89 public static const int JPG13 = 0xFFFD; | |
90 public static const int RST0 = 0xFFD0; | |
91 public static const int RST1 = 0xFFD1; | |
92 public static const int RST2 = 0xFFD2; | |
93 public static const int RST3 = 0xFFD3; | |
94 public static const int RST4 = 0xFFD4; | |
95 public static const int RST5 = 0xFFD5; | |
96 public static const int RST6 = 0xFFD6; | |
97 public static const int RST7 = 0xFFD7; | |
98 public static const int SOF0 = 0xFFC0; | |
99 public static const int SOF1 = 0xFFC1; | |
100 public static const int SOF2 = 0xFFC2; | |
101 public static const int SOF3 = 0xFFC3; | |
102 public static const int SOF5 = 0xFFC5; | |
103 public static const int SOF6 = 0xFFC6; | |
104 public static const int SOF7 = 0xFFC7; | |
105 public static const int SOF9 = 0xFFC9; | |
106 public static const int SOF10 = 0xFFCA; | |
107 public static const int SOF11 = 0xFFCB; | |
108 public static const int SOF13 = 0xFFCD; | |
109 public static const int SOF14 = 0xFFCE; | |
110 public static const int SOF15 = 0xFFCF; | |
111 public static const int SOI = 0xFFD8; | |
112 public static const int SOS = 0xFFDA; | |
113 public static const int TEM = 0xFF01; | |
114 /* JPEGFrameComponentParameterConstants */ | |
115 public static const int TQI = 0; | |
116 public static const int HI = 1; | |
117 public static const int VI = 2; | |
118 public static const int CW = 3; | |
119 public static const int CH = 4; | |
120 /* JPEGScanComponentParameterConstants */ | |
121 public static const int DC = 0; | |
122 public static const int AC = 1; | |
123 /* JFIF Component Constants */ | |
124 public static const int ID_Y = 1 - 1; | |
125 public static const int ID_CB = 2 - 1; | |
126 public static const int ID_CR = 3 - 1; | |
127 public static const RGB[] RGB16; | |
128 public static const int[] ExtendTest = [ | |
129 0, 1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, | |
130 4096, 8192, 16384, 32768, 65536, 131072, 262144 | |
131 ]; | |
132 public static const int[] ExtendOffset = [ | |
133 0, -1, -3, -7, -15, -31, -63, -127, -255, -511, -1023, -2047, | |
134 -4095, -8191, -16383, -32767, -65535, -131071, -262143 | |
135 ]; | |
136 public static const int[] ZigZag8x8 = [ | |
137 0, 1, 8, 16, 9, 2, 3, 10, | |
138 17, 24, 32, 25, 18, 11, 4, 5, | |
139 12, 19, 26, 33, 40, 48, 41, 34, | |
140 27, 20, 13, 6, 7, 14, 21, 28, | |
141 35, 42, 49, 56, 57, 50, 43, 36, | |
142 29, 22, 15, 23, 30, 37, 44, 51, | |
143 58, 59, 52, 45, 38, 31, 39, 46, | |
144 53, 60, 61, 54, 47, 55, 62, 63 | |
145 ]; | |
146 | |
147 public static int[] CrRTable, CbBTable, CrGTable, CbGTable; | |
148 public static int[] RYTable, GYTable, BYTable, | |
149 RCbTable, GCbTable, BCbTable, RCrTable, GCrTable, BCrTable, NBitsTable; | |
150 static this(){ | |
151 initialize(); | |
152 RGB16 = [ | |
153 new RGB(0,0,0), | |
154 new RGB(0x80,0,0), | |
155 new RGB(0,0x80,0), | |
156 new RGB(0x80,0x80,0), | |
157 new RGB(0,0,0x80), | |
158 new RGB(0x80,0,0x80), | |
159 new RGB(0,0x80,0x80), | |
160 new RGB(0xC0,0xC0,0xC0), | |
161 new RGB(0x80,0x80,0x80), | |
162 new RGB(0xFF,0,0), | |
163 new RGB(0,0xFF,0), | |
164 new RGB(0xFF,0xFF,0), | |
165 new RGB(0,0,0xFF), | |
166 new RGB(0xFF,0,0xFF), | |
167 new RGB(0,0xFF,0xFF), | |
168 new RGB(0xFF,0xFF,0xFF) | |
169 ]; | |
170 } | |
171 void compress(ImageData image, byte[] dataYComp, byte[] dataCbComp, byte[] dataCrComp) { | |
172 int srcWidth = image.width; | |
173 int srcHeight = image.height; | |
174 int vhFactor = maxV * maxH; | |
175 int[] frameComponent; | |
176 imageComponents = new byte[][](nComponents); | |
177 for (int i = 0; i < nComponents; i++) { | |
178 frameComponent = frameComponents[componentIds[i]]; | |
179 imageComponents[i] = new byte[frameComponent[CW] * frameComponent[CH]]; | |
180 } | |
181 frameComponent = frameComponents[componentIds[ID_Y]]; | |
182 for (int yPos = 0; yPos < srcHeight; yPos++) { | |
183 int srcOfs = yPos * srcWidth; | |
184 int dstOfs = yPos * frameComponent[CW]; | |
185 imageComponents[ID_Y][ dstOfs .. dstOfs+srcWidth] = dataYComp[ srcOfs .. srcOfs+srcWidth ]; | |
186 } | |
187 frameComponent = frameComponents[componentIds[ID_CB]]; | |
188 for (int yPos = 0; yPos < srcHeight / maxV; yPos++) { | |
189 int destRowIndex = yPos * frameComponent[CW]; | |
190 for (int xPos = 0; xPos < srcWidth / maxH; xPos++) { | |
191 int sum = 0; | |
192 for (int iv = 0; iv < maxV; iv++) { | |
193 int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH); | |
194 for (int ih = 0; ih < maxH; ih++) { | |
195 sum += dataCbComp[srcIndex + ih] & 0xFF; | |
196 } | |
197 } | |
198 imageComponents[ID_CB][destRowIndex + xPos] = cast(byte)(sum / vhFactor); | |
199 } | |
200 } | |
201 frameComponent = frameComponents[componentIds[ID_CR]]; | |
202 for (int yPos = 0; yPos < srcHeight / maxV; yPos++) { | |
203 int destRowIndex = yPos * frameComponent[CW]; | |
204 for (int xPos = 0; xPos < srcWidth / maxH; xPos++) { | |
205 int sum = 0; | |
206 for (int iv = 0; iv < maxV; iv++) { | |
207 int srcIndex = (yPos * maxV + iv) * srcWidth + (xPos * maxH); | |
208 for (int ih = 0; ih < maxH; ih++) { | |
209 sum += dataCrComp[srcIndex + ih] & 0xFF; | |
210 } | |
211 } | |
212 imageComponents[ID_CR][destRowIndex + xPos] = cast(byte)(sum / vhFactor); | |
213 } | |
214 } | |
215 for (int iComp = 0; iComp < nComponents; iComp++) { | |
216 byte[] imageComponent = imageComponents[iComp]; | |
217 frameComponent = frameComponents[componentIds[iComp]]; | |
218 int hFactor = frameComponent[HI]; | |
219 int vFactor = frameComponent[VI]; | |
220 int componentWidth = frameComponent[CW]; | |
221 int componentHeight = frameComponent[CH]; | |
222 int compressedWidth = srcWidth / (maxH / hFactor); | |
223 int compressedHeight = srcHeight / (maxV / vFactor); | |
224 if (compressedWidth < componentWidth) { | |
225 int delta = componentWidth - compressedWidth; | |
226 for (int yPos = 0; yPos < compressedHeight; yPos++) { | |
227 int dstOfs = ((yPos + 1) * componentWidth - delta); | |
228 int dataValue = imageComponent[dstOfs - 1] & 0xFF; | |
229 for (int i = 0; i < delta; i++) { | |
230 imageComponent[dstOfs + i] = cast(byte)dataValue; | |
231 } | |
232 } | |
233 } | |
234 if (compressedHeight < componentHeight) { | |
235 int srcOfs = (compressedHeight - 1) * componentWidth; | |
236 for (int yPos = compressedHeight; yPos <= componentHeight; yPos++) { | |
237 int dstOfs = (yPos - 1) * componentWidth; | |
238 imageComponent[dstOfs .. dstOfs+componentWidth] = imageComponent[srcOfs .. srcOfs+componentWidth]; | |
239 } | |
240 } | |
241 } | |
242 } | |
243 void convert4BitRGBToYCbCr(ImageData image) { | |
244 RGB[] rgbs = image.getRGBs(); | |
245 int paletteSize = rgbs.length; | |
246 byte[] yComp = new byte[paletteSize]; | |
247 byte[] cbComp = new byte[paletteSize]; | |
248 byte[] crComp = new byte[paletteSize]; | |
249 int srcWidth = image.width; | |
250 int srcHeight = image.height; | |
251 for (int i = 0; i < paletteSize; i++) { | |
252 RGB color = rgbs[i]; | |
253 int r = color.red; | |
254 int g = color.green; | |
255 int b = color.blue; | |
256 int n = RYTable[r] + GYTable[g] + BYTable[b]; | |
257 yComp[i] = cast(byte)(n >> 16); | |
258 if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--; | |
259 n = RCbTable[r] + GCbTable[g] + BCbTable[b]; | |
260 cbComp[i] = cast(byte)(n >> 16); | |
261 if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--; | |
262 n = RCrTable[r] + GCrTable[g] + BCrTable[b]; | |
263 crComp[i] = cast(byte)(n >> 16); | |
264 if ((n < 0) && ((n & 0xFFFF) != 0)) crComp[i]--; | |
265 } | |
266 int bSize = srcWidth * srcHeight; | |
267 byte[] dataYComp = new byte[bSize]; | |
268 byte[] dataCbComp = new byte[bSize]; | |
269 byte[] dataCrComp = new byte[bSize]; | |
270 byte[] origData = image.data; | |
271 int bytesPerLine = image.bytesPerLine; | |
272 int maxScanlineByte = srcWidth >> 1; | |
273 for (int yPos = 0; yPos < srcHeight; yPos++) { | |
274 for (int xPos = 0; xPos < maxScanlineByte; xPos++) { | |
275 int srcIndex = yPos * bytesPerLine + xPos; | |
276 int dstIndex = yPos * srcWidth + (xPos * 2); | |
277 int value2 = origData[srcIndex] & 0xFF; | |
278 int value1 = value2 >> 4; | |
279 value2 &= 0x0F; | |
280 dataYComp[dstIndex] = yComp[value1]; | |
281 dataCbComp[dstIndex] = cbComp[value1]; | |
282 dataCrComp[dstIndex] = crComp[value1]; | |
283 dataYComp[dstIndex + 1] = yComp[value2]; | |
284 dataCbComp[dstIndex + 1] = cbComp[value2]; | |
285 dataCrComp[dstIndex + 1] = crComp[value2]; | |
286 } | |
287 } | |
288 compress(image, dataYComp, dataCbComp, dataCrComp); | |
289 } | |
290 void convert8BitRGBToYCbCr(ImageData image) { | |
291 RGB[] rgbs = image.getRGBs(); | |
292 int paletteSize = rgbs.length; | |
293 byte[] yComp = new byte[paletteSize]; | |
294 byte[] cbComp = new byte[paletteSize]; | |
295 byte[] crComp = new byte[paletteSize]; | |
296 int srcWidth = image.width; | |
297 int srcHeight = image.height; | |
298 for (int i = 0; i < paletteSize; i++) { | |
299 RGB color = rgbs[i]; | |
300 int r = color.red; | |
301 int g = color.green; | |
302 int b = color.blue; | |
303 int n = RYTable[r] + GYTable[g] + BYTable[b]; | |
304 yComp[i] = cast(byte)(n >> 16); | |
305 if ((n < 0) && ((n & 0xFFFF) != 0)) yComp[i]--; | |
306 n = RCbTable[r] + GCbTable[g] + BCbTable[b]; | |
307 cbComp[i] = cast(byte)(n >> 16); | |
308 if ((n < 0) && ((n & 0xFFFF) != 0)) cbComp[i]--; | |
309 n = RCrTable[r] + GCrTable[g] + BCrTable[b]; | |
310 crComp[i] = cast(byte)(n >> 16); | |
311 if ((n < 0) && ((n & 0xFFFF) != 0)) crComp[i]--; | |
312 } | |
313 int dstWidth = image.width; | |
314 int dstHeight = srcHeight; | |
315 int stride = ((srcWidth + 3) >> 2) << 2; | |
316 int bSize = dstWidth * dstHeight; | |
317 byte[] dataYComp = new byte[bSize]; | |
318 byte[] dataCbComp = new byte[bSize]; | |
319 byte[] dataCrComp = new byte[bSize]; | |
320 byte[] origData = image.data; | |
321 for (int yPos = 0; yPos < srcHeight; yPos++) { | |
322 int srcRowIndex = yPos * stride; | |
323 int dstRowIndex = yPos * dstWidth; | |
324 for (int xPos = 0; xPos < srcWidth; xPos++) { | |
325 int value = origData[srcRowIndex + xPos] & 0xFF; | |
326 int dstIndex = dstRowIndex + xPos; | |
327 dataYComp[dstIndex] = yComp[value]; | |
328 dataCbComp[dstIndex] = cbComp[value]; | |
329 dataCrComp[dstIndex] = crComp[value]; | |
330 } | |
331 } | |
332 compress(image, dataYComp, dataCbComp, dataCrComp); | |
333 } | |
334 byte[] convertCMYKToRGB() { | |
335 /* Unsupported CMYK format. Answer an empty byte array. */ | |
336 return new byte[0]; | |
337 } | |
338 void convertImageToYCbCr(ImageData image) { | |
339 switch (image.depth) { | |
340 case 4: | |
341 convert4BitRGBToYCbCr(image); | |
342 return; | |
343 case 8: | |
344 convert8BitRGBToYCbCr(image); | |
345 return; | |
346 case 16: | |
347 case 24: | |
348 case 32: | |
349 convertMultiRGBToYCbCr(image); | |
350 return; | |
351 default: | |
352 SWT.error(SWT.ERROR_UNSUPPORTED_DEPTH); | |
353 } | |
354 return; | |
355 } | |
356 void convertMultiRGBToYCbCr(ImageData image) { | |
357 int srcWidth = image.width; | |
358 int srcHeight = image.height; | |
359 int bSize = srcWidth * srcHeight; | |
360 byte[] dataYComp = new byte[bSize]; | |
361 byte[] dataCbComp = new byte[bSize]; | |
362 byte[] dataCrComp = new byte[bSize]; | |
363 PaletteData palette = image.palette; | |
364 int[] buffer = new int[srcWidth]; | |
365 if (palette.isDirect) { | |
366 int redMask = palette.redMask; | |
367 int greenMask = palette.greenMask; | |
368 int blueMask = palette.blueMask; | |
369 int redShift = palette.redShift; | |
370 int greenShift = palette.greenShift; | |
371 int blueShift = palette.blueShift; | |
372 for (int yPos = 0; yPos < srcHeight; yPos++) { | |
373 image.getPixels(0, yPos, srcWidth, buffer, 0); | |
374 int dstRowIndex = yPos * srcWidth; | |
375 for (int xPos = 0; xPos < srcWidth; xPos++) { | |
376 int pixel = buffer[xPos]; | |
377 int dstDataIndex = dstRowIndex + xPos; | |
378 int r = pixel & redMask; | |
379 r = (redShift < 0) ? r >>> -redShift : r << redShift; | |
380 int g = pixel & greenMask; | |
381 g = (greenShift < 0) ? g >>> -greenShift : g << greenShift; | |
382 int b = pixel & blueMask; | |
383 b = (blueShift < 0) ? b >>> -blueShift : b << blueShift; | |
384 dataYComp[dstDataIndex] = cast(byte)((RYTable[r] + GYTable[g] + BYTable[b]) >> 16); | |
385 dataCbComp[dstDataIndex] = cast(byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) >> 16); | |
386 dataCrComp[dstDataIndex] = cast(byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) >> 16); | |
387 } | |
388 } | |
389 } else { | |
390 for (int yPos = 0; yPos < srcHeight; yPos++) { | |
391 image.getPixels(0, yPos, srcWidth, buffer, 0); | |
392 int dstRowIndex = yPos * srcWidth; | |
393 for (int xPos = 0; xPos < srcWidth; xPos++) { | |
394 int pixel = buffer[xPos]; | |
395 int dstDataIndex = dstRowIndex + xPos; | |
396 RGB rgb = palette.getRGB(pixel); | |
397 int r = rgb.red; | |
398 int g = rgb.green; | |
399 int b = rgb.blue; | |
400 dataYComp[dstDataIndex] = cast(byte)((RYTable[r] + GYTable[g] + BYTable[b]) >> 16); | |
401 dataCbComp[dstDataIndex] = cast(byte)((RCbTable[r] + GCbTable[g] + BCbTable[b]) >> 16); | |
402 dataCrComp[dstDataIndex] = cast(byte)((RCrTable[r] + GCrTable[g] + BCrTable[b]) >> 16); | |
403 } | |
404 } | |
405 } | |
406 compress(image, dataYComp, dataCbComp, dataCrComp); | |
407 } | |
408 byte[] convertYToRGB() { | |
409 int compWidth = frameComponents[componentIds[ID_Y]][CW]; | |
410 int bytesPerLine = (((imageWidth * 8 + 7) / 8) + 3) / 4 * 4; | |
411 byte[] data = new byte[bytesPerLine * imageHeight]; | |
412 byte[] yComp = imageComponents[ID_Y]; | |
413 int destIndex = 0; | |
414 for (int i = 0; i < imageHeight; i++) { | |
415 int srcIndex = i * compWidth; | |
416 for (int j = 0; j < bytesPerLine; j++) { | |
417 int y = yComp[srcIndex] & 0xFF; | |
418 if (y < 0) { | |
419 y = 0; | |
420 } else { | |
421 if (y > 255) y = 255; | |
422 } | |
423 if (j >= imageWidth) { | |
424 y = 0; | |
425 } | |
426 data[destIndex] = cast(byte)y; | |
427 srcIndex++; | |
428 destIndex++; | |
429 } | |
430 } | |
431 return data; | |
432 } | |
433 byte[] convertYCbCrToRGB() { | |
434 /** | |
435 * Convert existing image components into an RGB format. | |
436 * YCbCr is defined per CCIR 601-1, except that Cb and Cr are | |
437 * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. | |
438 * The conversion equations to be implemented are therefore | |
439 * R = Y + 1.40200 * Cr | |
440 * G = Y - 0.34414 * Cb - 0.71414 * Cr | |
441 * B = Y + 1.77200 * Cb | |
442 * where Cb and Cr represent the incoming values less MAXJSAMPLE/2. | |
443 * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) | |
444 * | |
445 * To avoid floating-point arithmetic, we represent the fractional constants | |
446 * as integers scaled up by 2^16 (about 4 digits precision); we have to divide | |
447 * the products by 2^16, with appropriate rounding, to get the correct answer. | |
448 * Notice that Y, being an integral input, does not contribute any fraction | |
449 * so it need not participate in the rounding. | |
450 * | |
451 * For even more speed, we avoid doing any multiplications in the inner loop | |
452 * by precalculating the constants times Cb and Cr for all possible values. | |
453 * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); | |
454 * for 12-bit samples it is still acceptable. It's not very reasonable for | |
455 * 16-bit samples, but if you want lossless storage you shouldn't be changing | |
456 * colorspace anyway. | |
457 * The Cr=>R and Cb=>B values can be rounded to integers in advance; the | |
458 * values for the G calculation are left scaled up, since we must add them | |
459 * together before rounding. | |
460 */ | |
461 int bSize = imageWidth * imageHeight * nComponents; | |
462 byte[] rgbData = new byte[bSize]; | |
463 int destIndex = 0; | |
464 expandImageComponents(); | |
465 byte[] yComp = imageComponents[ID_Y]; | |
466 byte[] cbComp = imageComponents[ID_CB]; | |
467 byte[] crComp = imageComponents[ID_CR]; | |
468 int compWidth = frameComponents[componentIds[ID_Y]][CW]; | |
469 for (int v = 0; v < imageHeight; v++) { | |
470 int srcIndex = v * compWidth; | |
471 for (int i = 0; i < imageWidth; i++) { | |
472 int y = yComp[srcIndex] & 0xFF; | |
473 int cb = cbComp[srcIndex] & 0xFF; | |
474 int cr = crComp[srcIndex] & 0xFF; | |
475 int r = y + CrRTable[cr]; | |
476 int g = y + ((CbGTable[cb] + CrGTable[cr]) >> 16); | |
477 int b = y + CbBTable[cb]; | |
478 if (r < 0) { | |
479 r = 0; | |
480 } else { | |
481 if (r > 255) r = 255; | |
482 } | |
483 if (g < 0) { | |
484 g = 0; | |
485 } else { | |
486 if (g > 255) g = 255; | |
487 } | |
488 if (b < 0) { | |
489 b = 0; | |
490 } else { | |
491 if (b > 255) b = 255; | |
492 } | |
493 rgbData[destIndex] = cast(byte)b; | |
494 rgbData[destIndex + 1] = cast(byte)g; | |
495 rgbData[destIndex + 2] = cast(byte)r; | |
496 destIndex += 3; | |
497 srcIndex++; | |
498 } | |
499 } | |
500 return rgbData; | |
501 } | |
502 void decodeACCoefficients(int[] dataUnit, int iComp) { | |
503 int[] sParams = scanHeader.componentParameters[componentIds[iComp]]; | |
504 JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]]; | |
505 int k = 1; | |
506 while (k < 64) { | |
507 int rs = decodeUsingTable(acTable); | |
508 int r = rs >> 4; | |
509 int s = rs & 0xF; | |
510 if (s == 0) { | |
511 if (r == 15) { | |
512 k += 16; | |
513 } else { | |
514 break; | |
515 } | |
516 } else { | |
517 k += r; | |
518 int bits = receive(s); | |
519 dataUnit[ZigZag8x8[k]] = extendBy(bits, s); | |
520 k++; | |
521 } | |
522 } | |
523 } | |
524 void decodeACFirstCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) { | |
525 if (eobrun > 0) { | |
526 eobrun--; | |
527 return; | |
528 } | |
529 int[] sParams = scanHeader.componentParameters[componentIds[iComp]]; | |
530 JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]]; | |
531 int k = start; | |
532 while (k <= end) { | |
533 int rs = decodeUsingTable(acTable); | |
534 int r = rs >> 4; | |
535 int s = rs & 0xF; | |
536 if (s == 0) { | |
537 if (r == 15) { | |
538 k += 16; | |
539 } else { | |
540 eobrun = (1 << r) + receive(r) - 1; | |
541 break; | |
542 } | |
543 } else { | |
544 k += r; | |
545 int bits = receive(s); | |
546 dataUnit[ZigZag8x8[k]] = extendBy(bits, s) << approxBit; | |
547 k++; | |
548 } | |
549 } | |
550 } | |
551 void decodeACRefineCoefficients(int[] dataUnit, int iComp, int start, int end, int approxBit) { | |
552 int[] sParams = scanHeader.componentParameters[componentIds[iComp]]; | |
553 JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]]; | |
554 int k = start; | |
555 while (k <= end) { | |
556 if (eobrun > 0) { | |
557 while (k <= end) { | |
558 int zzIndex = ZigZag8x8[k]; | |
559 if (dataUnit[zzIndex] != 0) { | |
560 dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit); | |
561 } | |
562 k++; | |
563 } | |
564 eobrun--; | |
565 } else { | |
566 int rs = decodeUsingTable(acTable); | |
567 int r = rs >> 4; | |
568 int s = rs & 0xF; | |
569 if (s == 0) { | |
570 if (r == 15) { | |
571 int zeros = 0; | |
572 while (zeros < 16 && k <= end) { | |
573 int zzIndex = ZigZag8x8[k]; | |
574 if (dataUnit[zzIndex] != 0) { | |
575 dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit); | |
576 } else { | |
577 zeros++; | |
578 } | |
579 k++; | |
580 } | |
581 } else { | |
582 eobrun = (1 << r) + receive(r); | |
583 } | |
584 } else { | |
585 int bit = receive(s); | |
586 int zeros = 0; | |
587 int zzIndex = ZigZag8x8[k]; | |
588 while ((zeros < r || dataUnit[zzIndex] != 0) && k <= end) { | |
589 if (dataUnit[zzIndex] != 0) { | |
590 dataUnit[zzIndex] = refineAC(dataUnit[zzIndex], approxBit); | |
591 } else { | |
592 zeros++; | |
593 } | |
594 k++; | |
595 zzIndex = ZigZag8x8[k]; | |
596 } | |
597 if (bit != 0) { | |
598 dataUnit[zzIndex] = 1 << approxBit; | |
599 } else { | |
600 dataUnit[zzIndex] = -1 << approxBit; | |
601 } | |
602 k++; | |
603 } | |
604 } | |
605 } | |
606 } | |
607 int refineAC(int ac, int approxBit) { | |
608 if (ac > 0) { | |
609 int bit = nextBit(); | |
610 if (bit != 0) { | |
611 ac += 1 << approxBit; | |
612 } | |
613 } else if (ac < 0) { | |
614 int bit = nextBit(); | |
615 if (bit != 0) { | |
616 ac += -1 << approxBit; | |
617 } | |
618 } | |
619 return ac; | |
620 } | |
621 void decodeDCCoefficient(int[] dataUnit, int iComp, bool first, int approxBit) { | |
622 int[] sParams = scanHeader.componentParameters[componentIds[iComp]]; | |
623 JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]]; | |
624 int lastDC = 0; | |
625 if (progressive && !first) { | |
626 int bit = nextBit(); | |
627 lastDC = dataUnit[0] + (bit << approxBit); | |
628 } else { | |
629 lastDC = precedingDCs[iComp]; | |
630 int nBits = decodeUsingTable(dcTable); | |
631 if (nBits != 0) { | |
632 int bits = receive(nBits); | |
633 int diff = extendBy(bits, nBits); | |
634 lastDC += diff; | |
635 precedingDCs[iComp] = lastDC; | |
636 } | |
637 if (progressive) { | |
638 lastDC = lastDC << approxBit; | |
639 } | |
640 } | |
641 dataUnit[0] = lastDC; | |
642 } | |
643 void dequantize(int[] dataUnit, int iComp) { | |
644 int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]]; | |
645 for (int i = 0; i < dataUnit.length; i++) { | |
646 int zzIndex = ZigZag8x8[i]; | |
647 dataUnit[zzIndex] = dataUnit[zzIndex] * qTable[i]; | |
648 } | |
649 } | |
650 byte[] decodeImageComponents() { | |
651 if (nComponents == 3) { // compIds 1, 2, 3 | |
652 return convertYCbCrToRGB(); | |
653 } | |
654 // if (nComponents == 3) { // compIds 1, 4, 5 | |
655 // Unsupported CMYK format. | |
656 // return convertYIQToRGB(); | |
657 // } | |
658 if (nComponents == 4) { | |
659 return convertCMYKToRGB(); | |
660 } | |
661 return convertYToRGB(); | |
662 } | |
663 void decodeMCUAtXAndY(int xmcu, int ymcu, int nComponentsInScan, bool first, int start, int end, int approxBit) { | |
664 for (int iComp = 0; iComp < nComponentsInScan; iComp++) { | |
665 int scanComponent = iComp; | |
666 while (scanHeader.componentParameters[componentIds[scanComponent]] == null) { | |
667 scanComponent++; | |
668 } | |
669 int[] frameComponent = frameComponents[componentIds[scanComponent]]; | |
670 int hi = frameComponent[HI]; | |
671 int vi = frameComponent[VI]; | |
672 if (nComponentsInScan == 1) { | |
673 hi = 1; | |
674 vi = 1; | |
675 } | |
676 int compWidth = frameComponent[CW]; | |
677 for (int ivi = 0; ivi < vi; ivi++) { | |
678 for (int ihi = 0; ihi < hi; ihi++) { | |
679 if (progressive) { | |
680 // Progressive: First scan - create a new data unit. | |
681 // Subsequent scans - refine the existing data unit. | |
682 int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi; | |
683 dataUnit = dataUnits[scanComponent][index]; | |
684 if (dataUnit == null) { | |
685 dataUnit = new int[64]; | |
686 dataUnits[scanComponent][index] = dataUnit; | |
687 } | |
688 } else { | |
689 // Sequential: Clear and reuse the data unit buffer. | |
690 for (int i = 0; i < dataUnit.length; i++) { | |
691 dataUnit[i] = 0; | |
692 } | |
693 } | |
694 if (!progressive || scanHeader.isDCProgressiveScan()) { | |
695 decodeDCCoefficient(dataUnit, scanComponent, first, approxBit); | |
696 } | |
697 if (!progressive) { | |
698 decodeACCoefficients(dataUnit, scanComponent); | |
699 } else { | |
700 if (scanHeader.isACProgressiveScan()) { | |
701 if (first) { | |
702 decodeACFirstCoefficients(dataUnit, scanComponent, start, end, approxBit); | |
703 } else { | |
704 decodeACRefineCoefficients(dataUnit, scanComponent, start, end, approxBit); | |
705 } | |
706 } | |
707 if (loader.hasListeners()) { | |
708 // Dequantization, IDCT, up-sampling and color conversion | |
709 // are done on a copy of the coefficient data in order to | |
710 // display the image incrementally. | |
711 dataUnit.length = 64; | |
712 } | |
713 } | |
714 if (!progressive || (progressive && loader.hasListeners())) { | |
715 dequantize(dataUnit, scanComponent); | |
716 inverseDCT(dataUnit); | |
717 storeData(dataUnit, scanComponent, xmcu, ymcu, hi, ihi, vi, ivi); | |
718 } | |
719 } | |
720 } | |
721 } | |
722 } | |
723 void decodeScan() { | |
724 if (progressive && !scanHeader.verifyProgressiveScan()) { | |
725 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
726 } | |
727 int nComponentsInScan = scanHeader.getNumberOfImageComponents(); | |
728 int mcuRowsInScan = interleavedMcuRows; | |
729 int mcusPerRow = interleavedMcuCols; | |
730 if (nComponentsInScan == 1) { | |
731 // Non-interleaved. | |
732 int scanComponent = 0; | |
733 while (scanHeader.componentParameters[componentIds[scanComponent]] == null) { | |
734 scanComponent++; | |
735 } | |
736 int[] frameComponent = frameComponents[componentIds[scanComponent]]; | |
737 int hi = frameComponent[HI]; | |
738 int vi = frameComponent[VI]; | |
739 int mcuWidth = DCTSIZE * maxH / hi; | |
740 int mcuHeight = DCTSIZE * maxV / vi; | |
741 mcusPerRow = (imageWidth + mcuWidth - 1) / mcuWidth; | |
742 mcuRowsInScan = (imageHeight + mcuHeight - 1) / mcuHeight; | |
743 } | |
744 bool first = scanHeader.isFirstScan(); | |
745 int start = scanHeader.getStartOfSpectralSelection(); | |
746 int end = scanHeader.getEndOfSpectralSelection(); | |
747 int approxBit = scanHeader.getApproxBitPositionLow(); | |
748 restartsToGo = restartInterval; | |
749 nextRestartNumber = 0; | |
750 for (int ymcu = 0; ymcu < mcuRowsInScan; ymcu++) { | |
751 for (int xmcu = 0; xmcu < mcusPerRow; xmcu++) { | |
752 if (restartInterval != 0) { | |
753 if (restartsToGo == 0) processRestartInterval(); | |
754 restartsToGo--; | |
755 } | |
756 decodeMCUAtXAndY(xmcu, ymcu, nComponentsInScan, first, start, end, approxBit); | |
757 } | |
758 } | |
759 } | |
760 int decodeUsingTable(JPEGHuffmanTable huffmanTable) { | |
761 int i = 0; | |
762 int[] maxCodes = huffmanTable.getDhMaxCodes(); | |
763 int[] minCodes = huffmanTable.getDhMinCodes(); | |
764 int[] valPtrs = huffmanTable.getDhValPtrs(); | |
765 int[] huffVals = huffmanTable.getDhValues(); | |
766 int code = nextBit(); | |
767 while (code > maxCodes[i]) { | |
768 code = code * 2 + nextBit(); | |
769 i++; | |
770 } | |
771 int j = valPtrs[i] + code - minCodes[i]; | |
772 return huffVals[j]; | |
773 } | |
774 void emit(int huffCode, int nBits) { | |
775 if (nBits == 0) { | |
776 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
777 } | |
778 int[] power2m1 = [ | |
779 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, | |
780 16383, 32767, 65535, 131125 | |
781 ]; | |
782 int code = (huffCode & power2m1[nBits - 1]) << (24 - nBits - currentBitCount); | |
783 byte[] codeBuffer = new byte[4]; | |
784 codeBuffer[0] = cast(byte)(code & 0xFF); | |
785 codeBuffer[1] = cast(byte)((code >> 8) & 0xFF); | |
786 codeBuffer[2] = cast(byte)((code >> 16) & 0xFF); | |
787 codeBuffer[3] = cast(byte)((code >> 24) & 0xFF); | |
788 int abs = nBits - (8 - currentBitCount); | |
789 if (abs < 0) abs = -abs; | |
790 if ((abs >> 3) > 0) { | |
791 currentByte += codeBuffer[2]; | |
792 emitByte(cast(byte)currentByte); | |
793 emitByte(codeBuffer[1]); | |
794 currentByte = codeBuffer[0]; | |
795 currentBitCount += nBits - 16; | |
796 } else { | |
797 currentBitCount += nBits; | |
798 if (currentBitCount >= 8) { | |
799 currentByte += codeBuffer[2]; | |
800 emitByte(cast(byte)currentByte); | |
801 currentByte = codeBuffer[1]; | |
802 currentBitCount -= 8; | |
803 } else { | |
804 currentByte += codeBuffer[2]; | |
805 } | |
806 } | |
807 } | |
808 void emitByte(byte byteValue) { | |
809 if (bufferCurrentPosition >= 512) { | |
810 resetOutputBuffer(); | |
811 } | |
812 dataBuffer[bufferCurrentPosition] = byteValue; | |
813 bufferCurrentPosition++; | |
814 if (byteValue == -1) { | |
815 emitByte(cast(byte)0); | |
816 } | |
817 } | |
818 void encodeACCoefficients(int[] dataUnit, int iComp) { | |
819 int[] sParams = scanHeader.componentParameters[iComp]; | |
820 JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]]; | |
821 int[] ehCodes = acTable.ehCodes; | |
822 byte[] ehSizes = acTable.ehCodeLengths; | |
823 int r = 0; | |
824 int k = 1; | |
825 while (k < 64) { | |
826 k++; | |
827 int acValue = dataUnit[ZigZag8x8[k - 1]]; | |
828 if (acValue == 0) { | |
829 if (k == 64) { | |
830 emit(ehCodes[0], ehSizes[0] & 0xFF); | |
831 } else { | |
832 r++; | |
833 } | |
834 } else { | |
835 while (r > 15) { | |
836 emit(ehCodes[0xF0], ehSizes[0xF0] & 0xFF); | |
837 r -= 16; | |
838 } | |
839 if (acValue < 0) { | |
840 int absACValue = acValue; | |
841 if (absACValue < 0) absACValue = -absACValue; | |
842 int nBits = NBitsTable[absACValue]; | |
843 int rs = r * 16 + nBits; | |
844 emit(ehCodes[rs], ehSizes[rs] & 0xFF); | |
845 emit(0xFFFFFF - absACValue, nBits); | |
846 } else { | |
847 int nBits = NBitsTable[acValue]; | |
848 int rs = r * 16 + nBits; | |
849 emit(ehCodes[rs], ehSizes[rs] & 0xFF); | |
850 emit(acValue, nBits); | |
851 } | |
852 r = 0; | |
853 } | |
854 } | |
855 } | |
856 void encodeDCCoefficients(int[] dataUnit, int iComp) { | |
857 int[] sParams = scanHeader.componentParameters[iComp]; | |
858 JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]]; | |
859 int lastDC = precedingDCs[iComp]; | |
860 int dcValue = dataUnit[0]; | |
861 int diff = dcValue - lastDC; | |
862 precedingDCs[iComp] = dcValue; | |
863 if (diff < 0) { | |
864 int absDiff = 0 - diff; | |
865 int nBits = NBitsTable[absDiff]; | |
866 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]); | |
867 emit(0xFFFFFF - absDiff, nBits); | |
868 } else { | |
869 int nBits = NBitsTable[diff]; | |
870 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]); | |
871 if (nBits != 0) { | |
872 emit(diff, nBits); | |
873 } | |
874 } | |
875 } | |
876 void encodeMCUAtXAndY(int xmcu, int ymcu) { | |
877 int nComponentsInScan = scanHeader.getNumberOfImageComponents(); | |
878 dataUnit = new int[64]; | |
879 for (int iComp = 0; iComp < nComponentsInScan; iComp++) { | |
880 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
881 int hi = frameComponent[HI]; | |
882 int vi = frameComponent[VI]; | |
883 for (int ivi = 0; ivi < vi; ivi++) { | |
884 for (int ihi = 0; ihi < hi; ihi++) { | |
885 extractData(dataUnit, iComp, xmcu, ymcu, ihi, ivi); | |
886 forwardDCT(dataUnit); | |
887 quantizeData(dataUnit, iComp); | |
888 encodeDCCoefficients(dataUnit, iComp); | |
889 encodeACCoefficients(dataUnit, iComp); | |
890 } | |
891 } | |
892 } | |
893 } | |
894 void encodeScan() { | |
895 for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) { | |
896 for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) { | |
897 encodeMCUAtXAndY(xmcu, ymcu); | |
898 } | |
899 } | |
900 if (currentBitCount != 0) { | |
901 emitByte(cast(byte)currentByte); | |
902 } | |
903 resetOutputBuffer(); | |
904 } | |
905 void expandImageComponents() { | |
906 for (int iComp = 0; iComp < nComponents; iComp++) { | |
907 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
908 int hi = frameComponent[HI]; | |
909 int vi = frameComponent[VI]; | |
910 int upH = maxH / hi; | |
911 int upV = maxV / vi; | |
912 if ((upH * upV) > 1) { | |
913 byte[] component = imageComponents[iComp]; | |
914 int compWidth = frameComponent[CW]; | |
915 int compHeight = frameComponent[CH]; | |
916 int upCompWidth = compWidth * upH; | |
917 int upCompHeight = compHeight * upV; | |
918 ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(RGB16), 4, component); | |
919 ImageData dest = src.scaledTo(upCompWidth, upCompHeight); | |
920 imageComponents[iComp] = dest.data; | |
921 } | |
922 } | |
923 } | |
924 int extendBy(int diff, int t) { | |
925 if (diff < ExtendTest[t]) { | |
926 return diff + ExtendOffset[t]; | |
927 } else { | |
928 return diff; | |
929 } | |
930 } | |
931 void extractData(int[] dataUnit, int iComp, int xmcu, int ymcu, int ihi, int ivi) { | |
932 byte[] compImage = imageComponents[iComp]; | |
933 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
934 int hi = frameComponent[HI]; | |
935 int vi = frameComponent[VI]; | |
936 int compWidth = frameComponent[CW]; | |
937 int srcIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE); | |
938 int destIndex = 0; | |
939 for (int i = 0; i < DCTSIZE; i++) { | |
940 for (int col = 0; col < DCTSIZE; col++) { | |
941 dataUnit[destIndex] = (compImage[srcIndex + col] & 0xFF) - 128; | |
942 destIndex++; | |
943 } | |
944 srcIndex += compWidth; | |
945 } | |
946 } | |
947 void forwardDCT(int[] dataUnit) { | |
948 for (int row = 0; row < 8; row++) { | |
949 int rIndex = row * DCTSIZE; | |
950 int tmp0 = dataUnit[rIndex] + dataUnit[rIndex + 7]; | |
951 int tmp7 = dataUnit[rIndex] - dataUnit[rIndex + 7]; | |
952 int tmp1 = dataUnit[rIndex + 1] + dataUnit[rIndex + 6]; | |
953 int tmp6 = dataUnit[rIndex + 1] - dataUnit[rIndex + 6]; | |
954 int tmp2 = dataUnit[rIndex + 2] + dataUnit[rIndex + 5]; | |
955 int tmp5 = dataUnit[rIndex + 2] - dataUnit[rIndex + 5]; | |
956 int tmp3 = dataUnit[rIndex + 3] + dataUnit[rIndex + 4]; | |
957 int tmp4 = dataUnit[rIndex + 3] - dataUnit[rIndex + 4]; | |
958 | |
959 /** | |
960 * Even part per LL&M figure 1 --- note that published figure | |
961 * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'. | |
962 */ | |
963 int tmp10 = tmp0 + tmp3; | |
964 int tmp13 = tmp0 - tmp3; | |
965 int tmp11 = tmp1 + tmp2; | |
966 int tmp12 = tmp1 - tmp2; | |
967 | |
968 dataUnit[rIndex] = (tmp10 + tmp11) * 4; | |
969 dataUnit[rIndex + 4] = (tmp10 - tmp11) * 4; | |
970 | |
971 int z1 = (tmp12 + tmp13) * FIX_0_541196100; | |
972 int n = z1 + (tmp13 * FIX_0_765366865) + 1024; | |
973 dataUnit[rIndex + 2] = n >> 11; | |
974 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 2]--; | |
975 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 1024; | |
976 dataUnit[rIndex + 6] = n >> 11; | |
977 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 6]--; | |
978 | |
979 /** | |
980 * Odd part per figure 8 --- note paper omits factor of sqrt(2). | |
981 * cK represents cos(K*pi/16). | |
982 * i0..i3 in the paper are tmp4..tmp7 here. | |
983 */ | |
984 z1 = tmp4 + tmp7; | |
985 int z2 = tmp5 + tmp6; | |
986 int z3 = tmp4 + tmp6; | |
987 int z4 = tmp5 + tmp7; | |
988 int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3 | |
989 | |
990 tmp4 *= FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7) | |
991 tmp5 *= FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7) | |
992 tmp6 *= FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7) | |
993 tmp7 *= FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7) | |
994 z1 *= 0 - FIX_0_899976223; // sqrt(2) * (c7-c3) | |
995 z2 *= 0 - FIX_2_562915447; // sqrt(2) * (-c1-c3) | |
996 z3 *= 0 - FIX_1_961570560; // sqrt(2) * (-c3-c5) | |
997 z4 *= 0 - FIX_0_390180644; // sqrt(2) * (c5-c3) | |
998 | |
999 z3 += z5; | |
1000 z4 += z5; | |
1001 | |
1002 n = tmp4 + z1 + z3 + 1024; | |
1003 dataUnit[rIndex + 7] = n >> 11; | |
1004 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 7]--; | |
1005 n = tmp5 + z2 + z4 + 1024; | |
1006 dataUnit[rIndex + 5] = n >> 11; | |
1007 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 5]--; | |
1008 n = tmp6 + z2 + z3 + 1024; | |
1009 dataUnit[rIndex + 3] = n >> 11; | |
1010 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 3]--; | |
1011 n = tmp7 + z1 + z4 + 1024; | |
1012 dataUnit[rIndex + 1] = n >> 11; | |
1013 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 1]--; | |
1014 } | |
1015 | |
1016 /** | |
1017 * Pass 2: process columns. | |
1018 * Note that we must descale the results by a factor of 8 == 2**3, | |
1019 * and also undo the PASS1_BITS scaling. | |
1020 */ | |
1021 for (int col = 0; col < 8; col++) { | |
1022 int c0 = col; | |
1023 int c1 = col + 8; | |
1024 int c2 = col + 16; | |
1025 int c3 = col + 24; | |
1026 int c4 = col + 32; | |
1027 int c5 = col + 40; | |
1028 int c6 = col + 48; | |
1029 int c7 = col + 56; | |
1030 int tmp0 = dataUnit[c0] + dataUnit[c7]; | |
1031 int tmp7 = dataUnit[c0] - dataUnit[c7]; | |
1032 int tmp1 = dataUnit[c1] + dataUnit[c6]; | |
1033 int tmp6 = dataUnit[c1] - dataUnit[c6]; | |
1034 int tmp2 = dataUnit[c2] + dataUnit[c5]; | |
1035 int tmp5 = dataUnit[c2] - dataUnit[c5]; | |
1036 int tmp3 = dataUnit[c3] + dataUnit[c4]; | |
1037 int tmp4 = dataUnit[c3] - dataUnit[c4]; | |
1038 | |
1039 /** | |
1040 * Even part per LL&M figure 1 --- note that published figure | |
1041 * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'. | |
1042 */ | |
1043 int tmp10 = tmp0 + tmp3; | |
1044 int tmp13 = tmp0 - tmp3; | |
1045 int tmp11 = tmp1 + tmp2; | |
1046 int tmp12 = tmp1 - tmp2; | |
1047 | |
1048 int n = tmp10 + tmp11 + 16; | |
1049 dataUnit[c0] = n >> 5; | |
1050 if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c0]--; | |
1051 n = tmp10 - tmp11 + 16; | |
1052 dataUnit[c4] = n >> 5; | |
1053 if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c4]--; | |
1054 | |
1055 int z1 = (tmp12 + tmp13) * FIX_0_541196100; | |
1056 n = z1 + (tmp13 * FIX_0_765366865) + 131072; | |
1057 dataUnit[c2] = n >> 18; | |
1058 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c2]--; | |
1059 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 131072; | |
1060 dataUnit[c6] = n >> 18; | |
1061 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c6]--; | |
1062 | |
1063 /** | |
1064 * Odd part per figure 8 --- note paper omits factor of sqrt(2). | |
1065 * cK represents cos(K*pi/16). | |
1066 * i0..i3 in the paper are tmp4..tmp7 here. | |
1067 */ | |
1068 z1 = tmp4 + tmp7; | |
1069 int z2 = tmp5 + tmp6; | |
1070 int z3 = tmp4 + tmp6; | |
1071 int z4 = tmp5 + tmp7; | |
1072 int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3 | |
1073 | |
1074 tmp4 *= FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7) | |
1075 tmp5 *= FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7) | |
1076 tmp6 *= FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7) | |
1077 tmp7 *= FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7) | |
1078 z1 *= 0 - FIX_0_899976223; // sqrt(2) * (c7-c3) | |
1079 z2 *= 0 - FIX_2_562915447; // sqrt(2) * (-c1-c3) | |
1080 z3 *= 0 - FIX_1_961570560; // sqrt(2) * (-c3-c5) | |
1081 z4 *= 0 - FIX_0_390180644; // sqrt(2) * (c5-c3) | |
1082 | |
1083 z3 += z5; | |
1084 z4 += z5; | |
1085 | |
1086 n = tmp4 + z1 + z3 + 131072; | |
1087 dataUnit[c7] = n >> 18; | |
1088 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c7]--; | |
1089 n = tmp5 + z2 + z4 + 131072; | |
1090 dataUnit[c5] = n >> 18; | |
1091 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c5]--; | |
1092 n = tmp6 + z2 + z3 + 131072; | |
1093 dataUnit[c3] = n >> 18; | |
1094 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c3]--; | |
1095 n = tmp7 + z1 + z4 + 131072; | |
1096 dataUnit[c1] = n >> 18; | |
1097 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c1]--; | |
1098 } | |
1099 } | |
1100 void getAPP0() { | |
1101 JPEGAppn appn = new JPEGAppn(inputStream); | |
1102 if (!appn.verify()) { | |
1103 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1104 } | |
1105 } | |
1106 void getCOM() { | |
1107 new JPEGComment(inputStream); | |
1108 } | |
1109 void getDAC() { | |
1110 new JPEGArithmeticConditioningTable(inputStream); | |
1111 } | |
1112 void getDHT() { | |
1113 JPEGHuffmanTable dht = new JPEGHuffmanTable(inputStream); | |
1114 if (!dht.verify()) { | |
1115 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1116 } | |
1117 if (acHuffmanTables == null) { | |
1118 acHuffmanTables = new JPEGHuffmanTable[4]; | |
1119 } | |
1120 if (dcHuffmanTables == null) { | |
1121 dcHuffmanTables = new JPEGHuffmanTable[4]; | |
1122 } | |
1123 JPEGHuffmanTable[] dhtTables = dht.getAllTables(); | |
1124 for (int i = 0; i < dhtTables.length; i++) { | |
1125 JPEGHuffmanTable dhtTable = dhtTables[i]; | |
1126 if (dhtTable.getTableClass() == 0) { | |
1127 dcHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable; | |
1128 } else { | |
1129 acHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable; | |
1130 } | |
1131 } | |
1132 } | |
1133 void getDNL() { | |
1134 new JPEGRestartInterval(inputStream); | |
1135 } | |
1136 void getDQT() { | |
1137 JPEGQuantizationTable dqt = new JPEGQuantizationTable(inputStream); | |
1138 int[][] currentTables = quantizationTables; | |
1139 if (currentTables == null) { | |
1140 currentTables = new int[][](4); | |
1141 } | |
1142 int[] dqtTablesKeys = dqt.getQuantizationTablesKeys(); | |
1143 int[][] dqtTablesValues = dqt.getQuantizationTablesValues(); | |
1144 for (int i = 0; i < dqtTablesKeys.length; i++) { | |
1145 int index = dqtTablesKeys[i]; | |
1146 currentTables[index] = dqtTablesValues[i]; | |
1147 } | |
1148 quantizationTables = currentTables; | |
1149 } | |
1150 void getDRI() { | |
1151 JPEGRestartInterval dri = new JPEGRestartInterval(inputStream); | |
1152 if (!dri.verify()) { | |
1153 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1154 } | |
1155 restartInterval = dri.getRestartInterval(); | |
1156 } | |
1157 static void initialize() { | |
1158 initializeRGBYCbCrTables(); | |
1159 initializeYCbCrRGBTables(); | |
1160 initializeBitCountTable(); | |
1161 } | |
1162 static void initializeBitCountTable() { | |
1163 int nBits = 1; | |
1164 int power2 = 2; | |
1165 NBitsTable = new int[2048]; | |
1166 NBitsTable[0] = 0; | |
1167 for (int i = 1; i < NBitsTable.length; i++) { | |
1168 if (!(i < power2)) { | |
1169 nBits++; | |
1170 power2 *= 2; | |
1171 } | |
1172 NBitsTable[i] = nBits; | |
1173 } | |
1174 } | |
1175 static void initializeRGBYCbCrTables() { | |
1176 RYTable = new int[256]; | |
1177 GYTable = new int[256]; | |
1178 BYTable = new int[256]; | |
1179 RCbTable = new int[256]; | |
1180 GCbTable = new int[256]; | |
1181 BCbTable = new int[256]; | |
1182 RCrTable = BCbTable; | |
1183 GCrTable = new int[256]; | |
1184 BCrTable = new int[256]; | |
1185 for (int i = 0; i < 256; i++) { | |
1186 RYTable[i] = i * 19595; | |
1187 GYTable[i] = i * 38470; | |
1188 BYTable[i] = i * 7471 + 32768; | |
1189 RCbTable[i] = i * -11059; | |
1190 GCbTable[i] = i * -21709; | |
1191 BCbTable[i] = i * 32768 + 8388608; | |
1192 GCrTable[i] = i * -27439; | |
1193 BCrTable[i] = i * -5329; | |
1194 } | |
1195 } | |
1196 static void initializeYCbCrRGBTables() { | |
1197 CrRTable = new int[256]; | |
1198 CbBTable = new int[256]; | |
1199 CrGTable = new int[256]; | |
1200 CbGTable = new int[256]; | |
1201 for (int i = 0; i < 256; i++) { | |
1202 int x2 = 2 * i - 255; | |
1203 CrRTable[i] = (45941 * x2 + 32768) >> 16; | |
1204 CbBTable[i] = (58065 * x2 + 32768) >> 16; | |
1205 CrGTable[i] = -23401 * x2; | |
1206 CbGTable[i] = -11277 * x2 + 32768; | |
1207 } | |
1208 } | |
1209 void inverseDCT(int[] dataUnit) { | |
1210 for (int row = 0; row < 8; row++) { | |
1211 int rIndex = row * DCTSIZE; | |
1212 /** | |
1213 * Due to quantization, we will usually find that many of the input | |
1214 * coefficients are zero, especially the AC terms. We can exploit this | |
1215 * by short-circuiting the IDCT calculation for any row in which all | |
1216 * the AC terms are zero. In that case each output is equal to the | |
1217 * DC coefficient (with scale factor as needed). | |
1218 * With typical images and quantization tables, half or more of the | |
1219 * row DCT calculations can be simplified this way. | |
1220 */ | |
1221 if (isZeroInRow(dataUnit, rIndex)) { | |
1222 int dcVal = dataUnit[rIndex] << 2; | |
1223 for (int i = rIndex + 7; i >= rIndex; i--) { | |
1224 dataUnit[i] = dcVal; | |
1225 } | |
1226 } else { | |
1227 /** | |
1228 * Even part: reverse the even part of the forward DCT. | |
1229 * The rotator is sqrt(2)*c(-6). | |
1230 */ | |
1231 int z2 = dataUnit[rIndex + 2]; | |
1232 int z3 = dataUnit[rIndex + 6]; | |
1233 int z1 = (z2 + z3) * FIX_0_541196100; | |
1234 int tmp2 = z1 + (z3 * (0 - FIX_1_847759065)); | |
1235 int tmp3 = z1 + (z2 * FIX_0_765366865); | |
1236 int tmp0 = (dataUnit[rIndex] + dataUnit[rIndex + 4]) << 13; | |
1237 int tmp1 = (dataUnit[rIndex] - dataUnit[rIndex + 4]) << 13; | |
1238 int tmp10 = tmp0 + tmp3; | |
1239 int tmp13 = tmp0 - tmp3; | |
1240 int tmp11 = tmp1 + tmp2; | |
1241 int tmp12 = tmp1 - tmp2; | |
1242 /** | |
1243 * Odd part per figure 8; the matrix is unitary and hence its | |
1244 * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. | |
1245 */ | |
1246 tmp0 = dataUnit[rIndex + 7]; | |
1247 tmp1 = dataUnit[rIndex + 5]; | |
1248 tmp2 = dataUnit[rIndex + 3]; | |
1249 tmp3 = dataUnit[rIndex + 1]; | |
1250 z1 = tmp0 + tmp3; | |
1251 z2 = tmp1 + tmp2; | |
1252 z3 = tmp0 + tmp2; | |
1253 int z4 = tmp1 + tmp3; | |
1254 int z5 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */ | |
1255 | |
1256 tmp0 *= FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */ | |
1257 tmp1 *= FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */ | |
1258 tmp2 *= FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */ | |
1259 tmp3 *= FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */ | |
1260 z1 *= 0 - FIX_0_899976223; /* sqrt(2) * (c7-c3) */ | |
1261 z2 *= 0 - FIX_2_562915447; /* sqrt(2) * (-c1-c3) */ | |
1262 z3 *= 0 - FIX_1_961570560; /* sqrt(2) * (-c3-c5) */ | |
1263 z4 *= 0 - FIX_0_390180644; /* sqrt(2) * (c5-c3) */ | |
1264 | |
1265 z3 += z5; | |
1266 z4 += z5; | |
1267 tmp0 += z1 + z3; | |
1268 tmp1 += z2 + z4; | |
1269 tmp2 += z2 + z3; | |
1270 tmp3 += z1 + z4; | |
1271 | |
1272 dataUnit[rIndex] = (tmp10 + tmp3 + 1024) >> 11; | |
1273 dataUnit[rIndex + 7] = (tmp10 - tmp3 + 1024) >> 11; | |
1274 dataUnit[rIndex + 1] = (tmp11 + tmp2 + 1024) >> 11; | |
1275 dataUnit[rIndex + 6] = (tmp11 - tmp2 + 1024) >> 11; | |
1276 dataUnit[rIndex + 2] = (tmp12 + tmp1 + 1024) >> 11; | |
1277 dataUnit[rIndex + 5] = (tmp12 - tmp1 + 1024) >> 11; | |
1278 dataUnit[rIndex + 3] = (tmp13 + tmp0 + 1024) >> 11; | |
1279 dataUnit[rIndex + 4] = (tmp13 - tmp0 + 1024) >> 11; | |
1280 } | |
1281 } | |
1282 /** | |
1283 * Pass 2: process columns. | |
1284 * Note that we must descale the results by a factor of 8 == 2**3, | |
1285 * and also undo the PASS1_BITS scaling. | |
1286 */ | |
1287 for (int col = 0; col < 8; col++) { | |
1288 int c0 = col; | |
1289 int c1 = col + 8; | |
1290 int c2 = col + 16; | |
1291 int c3 = col + 24; | |
1292 int c4 = col + 32; | |
1293 int c5 = col + 40; | |
1294 int c6 = col + 48; | |
1295 int c7 = col + 56; | |
1296 if (isZeroInColumn(dataUnit, col)) { | |
1297 int dcVal = (dataUnit[c0] + 16) >> 5; | |
1298 dataUnit[c0] = dcVal; | |
1299 dataUnit[c1] = dcVal; | |
1300 dataUnit[c2] = dcVal; | |
1301 dataUnit[c3] = dcVal; | |
1302 dataUnit[c4] = dcVal; | |
1303 dataUnit[c5] = dcVal; | |
1304 dataUnit[c6] = dcVal; | |
1305 dataUnit[c7] = dcVal; | |
1306 } else { | |
1307 /** | |
1308 * Even part: reverse the even part of the forward DCT. | |
1309 * The rotator is sqrt(2)*c(-6). | |
1310 */ | |
1311 int z0 = dataUnit[c0]; | |
1312 int z2 = dataUnit[c2]; | |
1313 int z3 = dataUnit[c6]; | |
1314 int z4 = dataUnit[c4]; | |
1315 int z1 = (z2 + z3) * FIX_0_541196100; | |
1316 int tmp2 = z1 + (z3 * (0 - FIX_1_847759065)); | |
1317 int tmp3 = z1 + (z2 * FIX_0_765366865); | |
1318 int tmp0 = (z0 + z4) << 13; | |
1319 int tmp1 = (z0 - z4) << 13; | |
1320 int tmp10 = tmp0 + tmp3; | |
1321 int tmp13 = tmp0 - tmp3; | |
1322 int tmp11 = tmp1 + tmp2; | |
1323 int tmp12 = tmp1 - tmp2; | |
1324 /** | |
1325 * Odd part per figure 8; the matrix is unitary and hence its | |
1326 * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. | |
1327 */ | |
1328 tmp0 = dataUnit[c7]; | |
1329 tmp1 = dataUnit[c5]; | |
1330 tmp2 = dataUnit[c3]; | |
1331 tmp3 = dataUnit[c1]; | |
1332 z1 = tmp0 + tmp3; | |
1333 z2 = tmp1 + tmp2; | |
1334 z3 = tmp0 + tmp2; | |
1335 z4 = tmp1 + tmp3; | |
1336 z0 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */ | |
1337 | |
1338 tmp0 *= FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */ | |
1339 tmp1 *= FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */ | |
1340 tmp2 *= FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */ | |
1341 tmp3 *= FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */ | |
1342 z1 *= 0 - FIX_0_899976223; /* sqrt(2) * (c7-c3) */ | |
1343 z2 *= 0 - FIX_2_562915447; /* sqrt(2) * (-c1-c3) */ | |
1344 z3 *= 0 - FIX_1_961570560; /* sqrt(2) * (-c3-c5) */ | |
1345 z4 *= 0 - FIX_0_390180644; /* sqrt(2) * (c5-c3) */ | |
1346 | |
1347 z3 += z0; | |
1348 z4 += z0; | |
1349 | |
1350 tmp0 += z1 + z3; | |
1351 tmp1 += z2 + z4; | |
1352 tmp2 += z2 + z3; | |
1353 tmp3 += z1 + z4; | |
1354 | |
1355 /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ | |
1356 dataUnit[c0] = (tmp10 + tmp3 + 131072) >> 18; | |
1357 dataUnit[c7] = (tmp10 - tmp3 + 131072) >> 18; | |
1358 dataUnit[c1] = (tmp11 + tmp2 + 131072) >> 18; | |
1359 dataUnit[c6] = (tmp11 - tmp2 + 131072) >> 18; | |
1360 dataUnit[c2] = (tmp12 + tmp1 + 131072) >> 18; | |
1361 dataUnit[c5] = (tmp12 - tmp1 + 131072) >> 18; | |
1362 dataUnit[c3] = (tmp13 + tmp0 + 131072) >> 18; | |
1363 dataUnit[c4] = (tmp13 - tmp0 + 131072) >> 18; | |
1364 } | |
1365 } | |
1366 } | |
1367 bool isFileFormat(LEDataInputStream stream) { | |
1368 try { | |
1369 JPEGStartOfImage soi = new JPEGStartOfImage(stream); | |
1370 stream.unread(soi.reference); | |
1371 return soi.verify(); // we no longer check for appN | |
1372 } catch (TracedException e) { | |
1373 return false; | |
1374 } | |
1375 } | |
1376 bool isZeroInColumn(int[] dataUnit, int col) { | |
1377 return dataUnit[col + 8] == 0 && dataUnit[col + 16] == 0 | |
1378 && dataUnit[col + 24] == 0 && dataUnit[col + 32] == 0 | |
1379 && dataUnit[col + 40] == 0 && dataUnit[col + 48] == 0 | |
1380 && dataUnit[col + 56] == 0; | |
1381 } | |
1382 bool isZeroInRow(int[] dataUnit, int rIndex) { | |
1383 return dataUnit[rIndex + 1] == 0 && dataUnit[rIndex + 2] == 0 | |
1384 && dataUnit[rIndex + 3] == 0 && dataUnit[rIndex + 4] == 0 | |
1385 && dataUnit[rIndex + 5] == 0 && dataUnit[rIndex + 6] == 0 | |
1386 && dataUnit[rIndex + 7] == 0; | |
1387 } | |
1388 ImageData[] loadFromByteStream() { | |
1389 //TEMPORARY CODE | |
1390 //PORTING_FIXME | |
1391 if (/+System.getProperty("dwt.internal.image.JPEGFileFormat_3.2") == null+/ true ) { | |
1392 return JPEGDecoder.loadFromByteStream(inputStream, loader); | |
1393 } | |
1394 JPEGStartOfImage soi = new JPEGStartOfImage(inputStream); | |
1395 if (!soi.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1396 restartInterval = 0; | |
1397 | |
1398 /* Process the tables preceding the frame header. */ | |
1399 processTables(); | |
1400 | |
1401 /* Start of Frame. */ | |
1402 frameHeader = new JPEGFrameHeader(inputStream); | |
1403 if (!frameHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1404 imageWidth = frameHeader.getSamplesPerLine(); | |
1405 imageHeight = frameHeader.getNumberOfLines(); | |
1406 maxH = frameHeader.getMaxHFactor(); | |
1407 maxV = frameHeader.getMaxVFactor(); | |
1408 int mcuWidth = maxH * DCTSIZE; | |
1409 int mcuHeight = maxV * DCTSIZE; | |
1410 interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth; | |
1411 interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight; | |
1412 progressive = frameHeader.isProgressive(); | |
1413 samplePrecision = frameHeader.getSamplePrecision(); | |
1414 nComponents = frameHeader.getNumberOfImageComponents(); | |
1415 frameComponents = frameHeader.componentParameters; | |
1416 componentIds = frameHeader.componentIdentifiers; | |
1417 imageComponents = new byte[][](nComponents); | |
1418 if (progressive) { | |
1419 // Progressive jpeg: need to keep all of the data units. | |
1420 dataUnits = new int[][][](nComponents); | |
1421 } else { | |
1422 // Sequential jpeg: only need one data unit. | |
1423 dataUnit = new int[8 * 8]; | |
1424 } | |
1425 for (int i = 0; i < nComponents; i++) { | |
1426 int[] frameComponent = frameComponents[componentIds[i]]; | |
1427 int bufferSize = frameComponent[CW] * frameComponent[CH]; | |
1428 imageComponents[i] = new byte[bufferSize]; | |
1429 if (progressive) { | |
1430 dataUnits[i] = new int[][](bufferSize); | |
1431 } | |
1432 } | |
1433 | |
1434 /* Process the tables preceding the scan header. */ | |
1435 processTables(); | |
1436 | |
1437 /* Start of Scan. */ | |
1438 scanHeader = new JPEGScanHeader(inputStream); | |
1439 if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1440 | |
1441 /* Process scan(s) and further tables until EOI. */ | |
1442 int progressiveScanCount = 0; | |
1443 bool done = false; | |
1444 while(!done) { | |
1445 resetInputBuffer(); | |
1446 precedingDCs = new int[4]; | |
1447 decodeScan(); | |
1448 if (progressive && loader.hasListeners()) { | |
1449 ImageData imageData = createImageData(); | |
1450 loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, false)); | |
1451 progressiveScanCount++; | |
1452 } | |
1453 | |
1454 /* Unread any buffered data before looking for tables again. */ | |
1455 int delta = 512 - bufferCurrentPosition - 1; | |
1456 if (delta > 0) { | |
1457 byte[] unreadBuffer = new byte[delta]; | |
1458 unreadBuffer[ 0 .. delta ] = dataBuffer[ bufferCurrentPosition+1 .. bufferCurrentPosition+1+delta ]; | |
1459 try { | |
1460 inputStream.unread(unreadBuffer); | |
1461 } catch (IOException e) { | |
1462 SWT.error(SWT.ERROR_IO, e); | |
1463 } | |
1464 } | |
1465 | |
1466 /* Process the tables preceding the next scan header. */ | |
1467 JPEGSegment jpegSegment = processTables(); | |
1468 if (jpegSegment == null || jpegSegment.getSegmentMarker() == EOI) { | |
1469 done = true; | |
1470 } else { | |
1471 scanHeader = new JPEGScanHeader(inputStream); | |
1472 if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1473 } | |
1474 } | |
1475 | |
1476 if (progressive) { | |
1477 for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) { | |
1478 for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) { | |
1479 for (int iComp = 0; iComp < nComponents; iComp++) { | |
1480 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
1481 int hi = frameComponent[HI]; | |
1482 int vi = frameComponent[VI]; | |
1483 int compWidth = frameComponent[CW]; | |
1484 for (int ivi = 0; ivi < vi; ivi++) { | |
1485 for (int ihi = 0; ihi < hi; ihi++) { | |
1486 int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi; | |
1487 dataUnit = dataUnits[iComp][index]; | |
1488 dequantize(dataUnit, iComp); | |
1489 inverseDCT(dataUnit); | |
1490 storeData(dataUnit, iComp, xmcu, ymcu, hi, ihi, vi, ivi); | |
1491 } | |
1492 } | |
1493 } | |
1494 } | |
1495 } | |
1496 dataUnits = null; // release memory | |
1497 } | |
1498 ImageData imageData = createImageData(); | |
1499 if (progressive && loader.hasListeners()) { | |
1500 loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, true)); | |
1501 } | |
1502 return [imageData]; | |
1503 } | |
1504 ImageData createImageData() { | |
1505 return ImageData.internal_new( | |
1506 imageWidth, | |
1507 imageHeight, | |
1508 nComponents * samplePrecision, | |
1509 setUpPalette(), | |
1510 nComponents == 1 ? 4 : 1, | |
1511 decodeImageComponents(), | |
1512 0, | |
1513 null, | |
1514 null, | |
1515 -1, | |
1516 -1, | |
1517 SWT.IMAGE_JPEG, | |
1518 0, | |
1519 0, | |
1520 0, | |
1521 0); | |
1522 } | |
1523 int nextBit() { | |
1524 if (currentBitCount != 0) { | |
1525 currentBitCount--; | |
1526 currentByte *= 2; | |
1527 if (currentByte > 255) { | |
1528 currentByte -= 256; | |
1529 return 1; | |
1530 } else { | |
1531 return 0; | |
1532 } | |
1533 } | |
1534 bufferCurrentPosition++; | |
1535 if (bufferCurrentPosition >= 512) { | |
1536 resetInputBuffer(); | |
1537 bufferCurrentPosition = 0; | |
1538 } | |
1539 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1540 currentBitCount = 8; | |
1541 byte nextByte; | |
1542 if (bufferCurrentPosition == 511) { | |
1543 resetInputBuffer(); | |
1544 currentBitCount = 8; | |
1545 nextByte = dataBuffer[0]; | |
1546 } else { | |
1547 nextByte = dataBuffer[bufferCurrentPosition + 1]; | |
1548 } | |
1549 if (currentByte == 0xFF) { | |
1550 if (nextByte == 0) { | |
1551 bufferCurrentPosition ++; | |
1552 currentBitCount--; | |
1553 currentByte *= 2; | |
1554 if (currentByte > 255) { | |
1555 currentByte -= 256; | |
1556 return 1; | |
1557 } else { | |
1558 return 0; | |
1559 } | |
1560 } else { | |
1561 if ((nextByte & 0xFF) + 0xFF00 == DNL) { | |
1562 getDNL(); | |
1563 return 0; | |
1564 } else { | |
1565 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1566 return 0; | |
1567 } | |
1568 } | |
1569 } else { | |
1570 currentBitCount--; | |
1571 currentByte *= 2; | |
1572 if (currentByte > 255) { | |
1573 currentByte -= 256; | |
1574 return 1; | |
1575 } else { | |
1576 return 0; | |
1577 } | |
1578 } | |
1579 } | |
1580 void processRestartInterval() { | |
1581 do { | |
1582 bufferCurrentPosition++; | |
1583 if (bufferCurrentPosition > 511) { | |
1584 resetInputBuffer(); | |
1585 bufferCurrentPosition = 0; | |
1586 } | |
1587 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1588 } while (currentByte != 0xFF); | |
1589 while (currentByte == 0xFF) { | |
1590 bufferCurrentPosition++; | |
1591 if (bufferCurrentPosition > 511) { | |
1592 resetInputBuffer(); | |
1593 bufferCurrentPosition = 0; | |
1594 } | |
1595 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1596 } | |
1597 if (currentByte != ((RST0 + nextRestartNumber) & 0xFF)) { | |
1598 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1599 } | |
1600 bufferCurrentPosition++; | |
1601 if (bufferCurrentPosition > 511) { | |
1602 resetInputBuffer(); | |
1603 bufferCurrentPosition = 0; | |
1604 } | |
1605 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1606 currentBitCount = 8; | |
1607 restartsToGo = restartInterval; | |
1608 nextRestartNumber = (nextRestartNumber + 1) & 0x7; | |
1609 precedingDCs = new int[4]; | |
1610 eobrun = 0; | |
1611 } | |
1612 /* Process all markers until a frame header, scan header, or EOI is found. */ | |
1613 JPEGSegment processTables() { | |
1614 while (true) { | |
1615 JPEGSegment jpegSegment = seekUnspecifiedMarker(inputStream); | |
1616 if (jpegSegment == null) return null; | |
1617 JPEGFrameHeader sof = new JPEGFrameHeader(jpegSegment.reference); | |
1618 if (sof.verify()) { | |
1619 return jpegSegment; | |
1620 } | |
1621 int marker = jpegSegment.getSegmentMarker(); | |
1622 switch (marker) { | |
1623 case SOI: // there should only be one SOI per file | |
1624 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1625 case EOI: | |
1626 case SOS: | |
1627 return jpegSegment; | |
1628 case DQT: | |
1629 getDQT(); | |
1630 break; | |
1631 case DHT: | |
1632 getDHT(); | |
1633 break; | |
1634 case DAC: | |
1635 getDAC(); | |
1636 break; | |
1637 case DRI: | |
1638 getDRI(); | |
1639 break; | |
1640 case APP0: | |
1641 getAPP0(); | |
1642 break; | |
1643 case COM: | |
1644 getCOM(); | |
1645 break; | |
1646 default: | |
1647 skipSegmentFrom(inputStream); | |
1648 | |
1649 } | |
1650 } | |
1651 } | |
1652 void quantizeData(int[] dataUnit, int iComp) { | |
1653 int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]]; | |
1654 for (int i = 0; i < dataUnit.length; i++) { | |
1655 int zzIndex = ZigZag8x8[i]; | |
1656 int data = dataUnit[zzIndex]; | |
1657 int absData = data < 0 ? 0 - data : data; | |
1658 int qValue = qTable[i]; | |
1659 int q2 = qValue >> 1; | |
1660 absData += q2; | |
1661 if (absData < qValue) { | |
1662 dataUnit[zzIndex] = 0; | |
1663 } else { | |
1664 absData /= qValue; | |
1665 if (data >= 0) { | |
1666 dataUnit[zzIndex] = absData; | |
1667 } else { | |
1668 dataUnit[zzIndex] = 0 - absData; | |
1669 } | |
1670 } | |
1671 } | |
1672 } | |
1673 int receive(int nBits) { | |
1674 int v = 0; | |
1675 for (int i = 0; i < nBits; i++) { | |
1676 v = v * 2 + nextBit(); | |
1677 } | |
1678 return v; | |
1679 } | |
1680 void resetInputBuffer() { | |
1681 if (dataBuffer == null) { | |
1682 dataBuffer = new byte[512]; | |
1683 } | |
1684 try { | |
1685 inputStream.read(dataBuffer); | |
1686 } catch (IOException e) { | |
1687 SWT.error(SWT.ERROR_IO, e); | |
1688 } | |
1689 currentBitCount = 0; | |
1690 bufferCurrentPosition = -1; | |
1691 } | |
1692 void resetOutputBuffer() { | |
1693 if (dataBuffer == null) { | |
1694 dataBuffer = new byte[512]; | |
1695 } else { | |
1696 try { | |
1697 outputStream.write(dataBuffer, 0, bufferCurrentPosition); | |
1698 } catch (IOException e) { | |
1699 SWT.error(SWT.ERROR_IO, e); | |
1700 } | |
1701 } | |
1702 bufferCurrentPosition = 0; | |
1703 } | |
1704 static JPEGSegment seekUnspecifiedMarker(LEDataInputStream byteStream) { | |
1705 byte[] byteArray = new byte[2]; | |
1706 try { | |
1707 while (true) { | |
1708 if (byteStream.read(byteArray, 0, 1) != 1) return null; | |
1709 if (byteArray[0] == cast(byte) 0xFF) { | |
1710 if (byteStream.read(byteArray, 1, 1) != 1) return null; | |
1711 if (byteArray[1] != cast(byte) 0xFF && byteArray[1] != 0) { | |
1712 byteStream.unread(byteArray); | |
1713 return new JPEGSegment(byteArray); | |
1714 } | |
1715 } | |
1716 } | |
1717 } catch (IOException e) { | |
1718 SWT.error(SWT.ERROR_IO, e); | |
1719 } | |
1720 return null; | |
1721 } | |
1722 PaletteData setUpPalette() { | |
1723 if (nComponents == 1) { | |
1724 RGB[] entries = new RGB[256]; | |
1725 for (int i = 0; i < 256; i++) { | |
1726 entries[i] = new RGB(i, i, i); | |
1727 } | |
1728 return new PaletteData(entries); | |
1729 } | |
1730 return new PaletteData(0xFF, 0xFF00, 0xFF0000); | |
1731 } | |
1732 static void skipSegmentFrom(LEDataInputStream byteStream) { | |
1733 try { | |
1734 byte[] byteArray = new byte[4]; | |
1735 JPEGSegment jpegSegment = new JPEGSegment(byteArray); | |
1736 | |
1737 if (byteStream.read(byteArray) != byteArray.length) { | |
1738 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1739 } | |
1740 if (!(byteArray[0] == -1 && byteArray[1] != 0 && byteArray[1] != -1)) { | |
1741 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1742 } | |
1743 int delta = jpegSegment.getSegmentLength() - 2; | |
1744 byteStream.skip(delta); | |
1745 } catch (TracedException e) { | |
1746 SWT.error(SWT.ERROR_IO, e); | |
1747 } | |
1748 } | |
1749 void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, int vi, int ivi) { | |
1750 byte[] compImage = imageComponents[iComp]; | |
1751 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
1752 int compWidth = frameComponent[CW]; | |
1753 int destIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE); | |
1754 int srcIndex = 0; | |
1755 for (int i = 0; i < DCTSIZE; i++) { | |
1756 for (int col = 0; col < DCTSIZE; col++) { | |
1757 int x = dataUnit[srcIndex] + 128; | |
1758 if (x < 0) { | |
1759 x = 0; | |
1760 } else { | |
1761 if (x > 255) x = 255; | |
1762 } | |
1763 compImage[destIndex + col] = cast(byte)x; | |
1764 srcIndex++; | |
1765 } | |
1766 destIndex += compWidth; | |
1767 } | |
1768 } | |
1769 void unloadIntoByteStream(ImageLoader loader) { | |
1770 ImageData image = loader.data[0]; | |
1771 if (!(new JPEGStartOfImage()).writeToStream(outputStream)) { | |
1772 SWT.error(SWT.ERROR_IO); | |
1773 } | |
1774 JPEGAppn appn = new JPEGAppn([cast(byte)0xFF, cast(byte)0xE0, 0, 0x10, 0x4A, 0x46, 0x49, 0x46, 0, 1, 1, 0, 0, 1, 0, 1, 0, 0]); | |
1775 if (!appn.writeToStream(outputStream)) { | |
1776 SWT.error(SWT.ERROR_IO); | |
1777 } | |
1778 quantizationTables = new int[][](4); | |
1779 JPEGQuantizationTable chromDQT = JPEGQuantizationTable.defaultChrominanceTable(); | |
1780 chromDQT.scaleBy(encoderQFactor); | |
1781 int[] jpegDQTKeys = chromDQT.getQuantizationTablesKeys(); | |
1782 int[][] jpegDQTValues = chromDQT.getQuantizationTablesValues(); | |
1783 for (int i = 0; i < jpegDQTKeys.length; i++) { | |
1784 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i]; | |
1785 } | |
1786 JPEGQuantizationTable lumDQT = JPEGQuantizationTable.defaultLuminanceTable(); | |
1787 lumDQT.scaleBy(encoderQFactor); | |
1788 jpegDQTKeys = lumDQT.getQuantizationTablesKeys(); | |
1789 jpegDQTValues = lumDQT.getQuantizationTablesValues(); | |
1790 for (int i = 0; i < jpegDQTKeys.length; i++) { | |
1791 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i]; | |
1792 } | |
1793 if (!lumDQT.writeToStream(outputStream)) { | |
1794 SWT.error(SWT.ERROR_IO); | |
1795 } | |
1796 if (!chromDQT.writeToStream(outputStream)) { | |
1797 SWT.error(SWT.ERROR_IO); | |
1798 } | |
1799 int frameLength, scanLength, precision; | |
1800 int[][] frameParams, scanParams; | |
1801 if (image.depth == 1) { | |
1802 frameLength = 11; | |
1803 frameParams = new int[][](1); | |
1804 frameParams[0] = [1, 1, 1, 0, 0]; | |
1805 scanParams = new int[][](1); | |
1806 scanParams[0] = [0, 0]; | |
1807 scanLength = 8; | |
1808 nComponents = 1; | |
1809 precision = 1; | |
1810 } else { | |
1811 frameLength = 17; | |
1812 frameParams = new int[][](3); | |
1813 frameParams[0] = [0, 2, 2, 0, 0]; | |
1814 frameParams[1] = [1, 1, 1, 0, 0]; | |
1815 frameParams[2] = [1, 1, 1, 0, 0]; | |
1816 scanParams = new int[][](3); | |
1817 scanParams[0] = [0, 0]; | |
1818 scanParams[1] = [1, 1]; | |
1819 scanParams[2] = [1, 1]; | |
1820 scanLength = 12; | |
1821 nComponents = 3; | |
1822 precision = 8; | |
1823 } | |
1824 imageWidth = image.width; | |
1825 imageHeight = image.height; | |
1826 frameHeader = new JPEGFrameHeader(new byte[19]); | |
1827 frameHeader.setSegmentMarker(SOF0); | |
1828 frameHeader.setSegmentLength(frameLength); | |
1829 frameHeader.setSamplePrecision(precision); | |
1830 frameHeader.setSamplesPerLine(imageWidth); | |
1831 frameHeader.setNumberOfLines(imageHeight); | |
1832 frameHeader.setNumberOfImageComponents(nComponents); | |
1833 frameHeader.componentParameters = frameParams; | |
1834 frameHeader.componentIdentifiers = [0, 1, 2]; | |
1835 frameHeader.initializeContents(); | |
1836 if (!frameHeader.writeToStream(outputStream)) { | |
1837 SWT.error(SWT.ERROR_IO); | |
1838 } | |
1839 frameComponents = frameParams; | |
1840 componentIds = frameHeader.componentIdentifiers; | |
1841 maxH = frameHeader.getMaxHFactor(); | |
1842 maxV = frameHeader.getMaxVFactor(); | |
1843 int mcuWidth = maxH * DCTSIZE; | |
1844 int mcuHeight = maxV * DCTSIZE; | |
1845 interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth; | |
1846 interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight; | |
1847 acHuffmanTables = new JPEGHuffmanTable[4]; | |
1848 dcHuffmanTables = new JPEGHuffmanTable[4]; | |
1849 JPEGHuffmanTable[] dhtTables = [ | |
1850 JPEGHuffmanTable.getDefaultDCLuminanceTable(), | |
1851 JPEGHuffmanTable.getDefaultDCChrominanceTable(), | |
1852 JPEGHuffmanTable.getDefaultACLuminanceTable(), | |
1853 JPEGHuffmanTable.getDefaultACChrominanceTable() | |
1854 ]; | |
1855 for (int i = 0; i < dhtTables.length; i++) { | |
1856 JPEGHuffmanTable dhtTable = dhtTables[i]; | |
1857 if (!dhtTable.writeToStream(outputStream)) { | |
1858 SWT.error(SWT.ERROR_IO); | |
1859 } | |
1860 JPEGHuffmanTable[] allTables = dhtTable.getAllTables(); | |
1861 for (int j = 0; j < allTables.length; j++) { | |
1862 JPEGHuffmanTable huffmanTable = allTables[j]; | |
1863 if (huffmanTable.getTableClass() == 0) { | |
1864 dcHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable; | |
1865 } else { | |
1866 acHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable; | |
1867 } | |
1868 } | |
1869 } | |
1870 precedingDCs = new int[4]; | |
1871 scanHeader = new JPEGScanHeader(new byte[14]); | |
1872 scanHeader.setSegmentMarker(SOS); | |
1873 scanHeader.setSegmentLength(scanLength); | |
1874 scanHeader.setNumberOfImageComponents(nComponents); | |
1875 scanHeader.setStartOfSpectralSelection(0); | |
1876 scanHeader.setEndOfSpectralSelection(63); | |
1877 scanHeader.componentParameters = scanParams; | |
1878 scanHeader.initializeContents(); | |
1879 if (!scanHeader.writeToStream(outputStream)) { | |
1880 SWT.error(SWT.ERROR_IO); | |
1881 } | |
1882 convertImageToYCbCr(image); | |
1883 resetOutputBuffer(); | |
1884 currentByte = 0; | |
1885 currentBitCount = 0; | |
1886 encodeScan(); | |
1887 if (!(new JPEGEndOfImage()).writeToStream(outputStream)) { | |
1888 SWT.error(SWT.ERROR_IO); | |
1889 } | |
1890 } | |
1891 } |