Mercurial > projects > dwt-linux
annotate dwt/internal/image/JPEGFileFormat.d @ 54:8f049b136add
first example working
author | Frank Benoit <benoit@tionex.de> |
---|---|
date | Fri, 11 Jan 2008 14:31:37 +0100 |
parents | fc2b263b8a3f |
children | 8cec8f536af3 |
rev | line source |
---|---|
13 | 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; | |
54 | 127 public static /*const*/ RGB[] RGB16; |
13 | 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; | |
54 | 150 public static void static_this() { |
13 | 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]; | |
25
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
185 System.arraycopy(dataYComp, srcOfs, imageComponents[ID_Y], dstOfs, srcWidth); |
13 | 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; | |
25
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
238 System.arraycopy(imageComponent, srcOfs, imageComponent, dstOfs, componentWidth); |
13 | 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. | |
25
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
711 int[] temp = dataUnit; |
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
712 dataUnit = new int[64]; |
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
713 System.arraycopy(temp, 0, dataUnit, 0, 64); |
13 | 714 } |
715 } | |
716 if (!progressive || (progressive && loader.hasListeners())) { | |
717 dequantize(dataUnit, scanComponent); | |
718 inverseDCT(dataUnit); | |
719 storeData(dataUnit, scanComponent, xmcu, ymcu, hi, ihi, vi, ivi); | |
720 } | |
721 } | |
722 } | |
723 } | |
724 } | |
725 void decodeScan() { | |
726 if (progressive && !scanHeader.verifyProgressiveScan()) { | |
727 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
728 } | |
729 int nComponentsInScan = scanHeader.getNumberOfImageComponents(); | |
730 int mcuRowsInScan = interleavedMcuRows; | |
731 int mcusPerRow = interleavedMcuCols; | |
732 if (nComponentsInScan == 1) { | |
733 // Non-interleaved. | |
734 int scanComponent = 0; | |
735 while (scanHeader.componentParameters[componentIds[scanComponent]] == null) { | |
736 scanComponent++; | |
737 } | |
738 int[] frameComponent = frameComponents[componentIds[scanComponent]]; | |
739 int hi = frameComponent[HI]; | |
740 int vi = frameComponent[VI]; | |
741 int mcuWidth = DCTSIZE * maxH / hi; | |
742 int mcuHeight = DCTSIZE * maxV / vi; | |
743 mcusPerRow = (imageWidth + mcuWidth - 1) / mcuWidth; | |
744 mcuRowsInScan = (imageHeight + mcuHeight - 1) / mcuHeight; | |
745 } | |
746 bool first = scanHeader.isFirstScan(); | |
747 int start = scanHeader.getStartOfSpectralSelection(); | |
748 int end = scanHeader.getEndOfSpectralSelection(); | |
749 int approxBit = scanHeader.getApproxBitPositionLow(); | |
750 restartsToGo = restartInterval; | |
751 nextRestartNumber = 0; | |
752 for (int ymcu = 0; ymcu < mcuRowsInScan; ymcu++) { | |
753 for (int xmcu = 0; xmcu < mcusPerRow; xmcu++) { | |
754 if (restartInterval != 0) { | |
755 if (restartsToGo == 0) processRestartInterval(); | |
756 restartsToGo--; | |
757 } | |
758 decodeMCUAtXAndY(xmcu, ymcu, nComponentsInScan, first, start, end, approxBit); | |
759 } | |
760 } | |
761 } | |
762 int decodeUsingTable(JPEGHuffmanTable huffmanTable) { | |
763 int i = 0; | |
764 int[] maxCodes = huffmanTable.getDhMaxCodes(); | |
765 int[] minCodes = huffmanTable.getDhMinCodes(); | |
766 int[] valPtrs = huffmanTable.getDhValPtrs(); | |
767 int[] huffVals = huffmanTable.getDhValues(); | |
768 int code = nextBit(); | |
769 while (code > maxCodes[i]) { | |
770 code = code * 2 + nextBit(); | |
771 i++; | |
772 } | |
773 int j = valPtrs[i] + code - minCodes[i]; | |
774 return huffVals[j]; | |
775 } | |
776 void emit(int huffCode, int nBits) { | |
777 if (nBits == 0) { | |
778 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
779 } | |
780 int[] power2m1 = [ | |
781 1, 3, 7, 15, 31, 63, 127, 255, 511, 1023, 2047, 4095, 8191, | |
782 16383, 32767, 65535, 131125 | |
783 ]; | |
784 int code = (huffCode & power2m1[nBits - 1]) << (24 - nBits - currentBitCount); | |
785 byte[] codeBuffer = new byte[4]; | |
786 codeBuffer[0] = cast(byte)(code & 0xFF); | |
787 codeBuffer[1] = cast(byte)((code >> 8) & 0xFF); | |
788 codeBuffer[2] = cast(byte)((code >> 16) & 0xFF); | |
789 codeBuffer[3] = cast(byte)((code >> 24) & 0xFF); | |
790 int abs = nBits - (8 - currentBitCount); | |
791 if (abs < 0) abs = -abs; | |
792 if ((abs >> 3) > 0) { | |
793 currentByte += codeBuffer[2]; | |
794 emitByte(cast(byte)currentByte); | |
795 emitByte(codeBuffer[1]); | |
796 currentByte = codeBuffer[0]; | |
797 currentBitCount += nBits - 16; | |
798 } else { | |
799 currentBitCount += nBits; | |
800 if (currentBitCount >= 8) { | |
801 currentByte += codeBuffer[2]; | |
802 emitByte(cast(byte)currentByte); | |
803 currentByte = codeBuffer[1]; | |
804 currentBitCount -= 8; | |
805 } else { | |
806 currentByte += codeBuffer[2]; | |
807 } | |
808 } | |
809 } | |
810 void emitByte(byte byteValue) { | |
811 if (bufferCurrentPosition >= 512) { | |
812 resetOutputBuffer(); | |
813 } | |
814 dataBuffer[bufferCurrentPosition] = byteValue; | |
815 bufferCurrentPosition++; | |
816 if (byteValue == -1) { | |
817 emitByte(cast(byte)0); | |
818 } | |
819 } | |
820 void encodeACCoefficients(int[] dataUnit, int iComp) { | |
821 int[] sParams = scanHeader.componentParameters[iComp]; | |
822 JPEGHuffmanTable acTable = acHuffmanTables[sParams[AC]]; | |
823 int[] ehCodes = acTable.ehCodes; | |
824 byte[] ehSizes = acTable.ehCodeLengths; | |
825 int r = 0; | |
826 int k = 1; | |
827 while (k < 64) { | |
828 k++; | |
829 int acValue = dataUnit[ZigZag8x8[k - 1]]; | |
830 if (acValue == 0) { | |
831 if (k == 64) { | |
832 emit(ehCodes[0], ehSizes[0] & 0xFF); | |
833 } else { | |
834 r++; | |
835 } | |
836 } else { | |
837 while (r > 15) { | |
838 emit(ehCodes[0xF0], ehSizes[0xF0] & 0xFF); | |
839 r -= 16; | |
840 } | |
841 if (acValue < 0) { | |
842 int absACValue = acValue; | |
843 if (absACValue < 0) absACValue = -absACValue; | |
844 int nBits = NBitsTable[absACValue]; | |
845 int rs = r * 16 + nBits; | |
846 emit(ehCodes[rs], ehSizes[rs] & 0xFF); | |
847 emit(0xFFFFFF - absACValue, nBits); | |
848 } else { | |
849 int nBits = NBitsTable[acValue]; | |
850 int rs = r * 16 + nBits; | |
851 emit(ehCodes[rs], ehSizes[rs] & 0xFF); | |
852 emit(acValue, nBits); | |
853 } | |
854 r = 0; | |
855 } | |
856 } | |
857 } | |
858 void encodeDCCoefficients(int[] dataUnit, int iComp) { | |
859 int[] sParams = scanHeader.componentParameters[iComp]; | |
860 JPEGHuffmanTable dcTable = dcHuffmanTables[sParams[DC]]; | |
861 int lastDC = precedingDCs[iComp]; | |
862 int dcValue = dataUnit[0]; | |
863 int diff = dcValue - lastDC; | |
864 precedingDCs[iComp] = dcValue; | |
865 if (diff < 0) { | |
866 int absDiff = 0 - diff; | |
867 int nBits = NBitsTable[absDiff]; | |
868 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]); | |
869 emit(0xFFFFFF - absDiff, nBits); | |
870 } else { | |
871 int nBits = NBitsTable[diff]; | |
872 emit(dcTable.ehCodes[nBits], dcTable.ehCodeLengths[nBits]); | |
873 if (nBits != 0) { | |
874 emit(diff, nBits); | |
875 } | |
876 } | |
877 } | |
878 void encodeMCUAtXAndY(int xmcu, int ymcu) { | |
879 int nComponentsInScan = scanHeader.getNumberOfImageComponents(); | |
880 dataUnit = new int[64]; | |
881 for (int iComp = 0; iComp < nComponentsInScan; iComp++) { | |
882 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
883 int hi = frameComponent[HI]; | |
884 int vi = frameComponent[VI]; | |
885 for (int ivi = 0; ivi < vi; ivi++) { | |
886 for (int ihi = 0; ihi < hi; ihi++) { | |
887 extractData(dataUnit, iComp, xmcu, ymcu, ihi, ivi); | |
888 forwardDCT(dataUnit); | |
889 quantizeData(dataUnit, iComp); | |
890 encodeDCCoefficients(dataUnit, iComp); | |
891 encodeACCoefficients(dataUnit, iComp); | |
892 } | |
893 } | |
894 } | |
895 } | |
896 void encodeScan() { | |
897 for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) { | |
898 for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) { | |
899 encodeMCUAtXAndY(xmcu, ymcu); | |
900 } | |
901 } | |
902 if (currentBitCount != 0) { | |
903 emitByte(cast(byte)currentByte); | |
904 } | |
905 resetOutputBuffer(); | |
906 } | |
907 void expandImageComponents() { | |
908 for (int iComp = 0; iComp < nComponents; iComp++) { | |
909 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
910 int hi = frameComponent[HI]; | |
911 int vi = frameComponent[VI]; | |
912 int upH = maxH / hi; | |
913 int upV = maxV / vi; | |
914 if ((upH * upV) > 1) { | |
915 byte[] component = imageComponents[iComp]; | |
916 int compWidth = frameComponent[CW]; | |
917 int compHeight = frameComponent[CH]; | |
918 int upCompWidth = compWidth * upH; | |
919 int upCompHeight = compHeight * upV; | |
920 ImageData src = new ImageData(compWidth, compHeight, 8, new PaletteData(RGB16), 4, component); | |
921 ImageData dest = src.scaledTo(upCompWidth, upCompHeight); | |
922 imageComponents[iComp] = dest.data; | |
923 } | |
924 } | |
925 } | |
926 int extendBy(int diff, int t) { | |
927 if (diff < ExtendTest[t]) { | |
928 return diff + ExtendOffset[t]; | |
929 } else { | |
930 return diff; | |
931 } | |
932 } | |
933 void extractData(int[] dataUnit, int iComp, int xmcu, int ymcu, int ihi, int ivi) { | |
934 byte[] compImage = imageComponents[iComp]; | |
935 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
936 int hi = frameComponent[HI]; | |
937 int vi = frameComponent[VI]; | |
938 int compWidth = frameComponent[CW]; | |
939 int srcIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE); | |
940 int destIndex = 0; | |
941 for (int i = 0; i < DCTSIZE; i++) { | |
942 for (int col = 0; col < DCTSIZE; col++) { | |
943 dataUnit[destIndex] = (compImage[srcIndex + col] & 0xFF) - 128; | |
944 destIndex++; | |
945 } | |
946 srcIndex += compWidth; | |
947 } | |
948 } | |
949 void forwardDCT(int[] dataUnit) { | |
950 for (int row = 0; row < 8; row++) { | |
951 int rIndex = row * DCTSIZE; | |
952 int tmp0 = dataUnit[rIndex] + dataUnit[rIndex + 7]; | |
953 int tmp7 = dataUnit[rIndex] - dataUnit[rIndex + 7]; | |
954 int tmp1 = dataUnit[rIndex + 1] + dataUnit[rIndex + 6]; | |
955 int tmp6 = dataUnit[rIndex + 1] - dataUnit[rIndex + 6]; | |
956 int tmp2 = dataUnit[rIndex + 2] + dataUnit[rIndex + 5]; | |
957 int tmp5 = dataUnit[rIndex + 2] - dataUnit[rIndex + 5]; | |
958 int tmp3 = dataUnit[rIndex + 3] + dataUnit[rIndex + 4]; | |
959 int tmp4 = dataUnit[rIndex + 3] - dataUnit[rIndex + 4]; | |
960 | |
961 /** | |
962 * Even part per LL&M figure 1 --- note that published figure | |
963 * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'. | |
964 */ | |
965 int tmp10 = tmp0 + tmp3; | |
966 int tmp13 = tmp0 - tmp3; | |
967 int tmp11 = tmp1 + tmp2; | |
968 int tmp12 = tmp1 - tmp2; | |
969 | |
970 dataUnit[rIndex] = (tmp10 + tmp11) * 4; | |
971 dataUnit[rIndex + 4] = (tmp10 - tmp11) * 4; | |
972 | |
973 int z1 = (tmp12 + tmp13) * FIX_0_541196100; | |
974 int n = z1 + (tmp13 * FIX_0_765366865) + 1024; | |
975 dataUnit[rIndex + 2] = n >> 11; | |
976 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 2]--; | |
977 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 1024; | |
978 dataUnit[rIndex + 6] = n >> 11; | |
979 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 6]--; | |
980 | |
981 /** | |
982 * Odd part per figure 8 --- note paper omits factor of sqrt(2). | |
983 * cK represents cos(K*pi/16). | |
984 * i0..i3 in the paper are tmp4..tmp7 here. | |
985 */ | |
986 z1 = tmp4 + tmp7; | |
987 int z2 = tmp5 + tmp6; | |
988 int z3 = tmp4 + tmp6; | |
989 int z4 = tmp5 + tmp7; | |
990 int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3 | |
991 | |
992 tmp4 *= FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7) | |
993 tmp5 *= FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7) | |
994 tmp6 *= FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7) | |
995 tmp7 *= FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7) | |
996 z1 *= 0 - FIX_0_899976223; // sqrt(2) * (c7-c3) | |
997 z2 *= 0 - FIX_2_562915447; // sqrt(2) * (-c1-c3) | |
998 z3 *= 0 - FIX_1_961570560; // sqrt(2) * (-c3-c5) | |
999 z4 *= 0 - FIX_0_390180644; // sqrt(2) * (c5-c3) | |
1000 | |
1001 z3 += z5; | |
1002 z4 += z5; | |
1003 | |
1004 n = tmp4 + z1 + z3 + 1024; | |
1005 dataUnit[rIndex + 7] = n >> 11; | |
1006 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 7]--; | |
1007 n = tmp5 + z2 + z4 + 1024; | |
1008 dataUnit[rIndex + 5] = n >> 11; | |
1009 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 5]--; | |
1010 n = tmp6 + z2 + z3 + 1024; | |
1011 dataUnit[rIndex + 3] = n >> 11; | |
1012 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 3]--; | |
1013 n = tmp7 + z1 + z4 + 1024; | |
1014 dataUnit[rIndex + 1] = n >> 11; | |
1015 if ((n < 0) && ((n & 0x07FF) != 0)) dataUnit[rIndex + 1]--; | |
1016 } | |
1017 | |
1018 /** | |
1019 * Pass 2: process columns. | |
1020 * Note that we must descale the results by a factor of 8 == 2**3, | |
1021 * and also undo the PASS1_BITS scaling. | |
1022 */ | |
1023 for (int col = 0; col < 8; col++) { | |
1024 int c0 = col; | |
1025 int c1 = col + 8; | |
1026 int c2 = col + 16; | |
1027 int c3 = col + 24; | |
1028 int c4 = col + 32; | |
1029 int c5 = col + 40; | |
1030 int c6 = col + 48; | |
1031 int c7 = col + 56; | |
1032 int tmp0 = dataUnit[c0] + dataUnit[c7]; | |
1033 int tmp7 = dataUnit[c0] - dataUnit[c7]; | |
1034 int tmp1 = dataUnit[c1] + dataUnit[c6]; | |
1035 int tmp6 = dataUnit[c1] - dataUnit[c6]; | |
1036 int tmp2 = dataUnit[c2] + dataUnit[c5]; | |
1037 int tmp5 = dataUnit[c2] - dataUnit[c5]; | |
1038 int tmp3 = dataUnit[c3] + dataUnit[c4]; | |
1039 int tmp4 = dataUnit[c3] - dataUnit[c4]; | |
1040 | |
1041 /** | |
1042 * Even part per LL&M figure 1 --- note that published figure | |
1043 * is faulty; rotator 'sqrt(2)*c1' should be 'sqrt(2)*c6'. | |
1044 */ | |
1045 int tmp10 = tmp0 + tmp3; | |
1046 int tmp13 = tmp0 - tmp3; | |
1047 int tmp11 = tmp1 + tmp2; | |
1048 int tmp12 = tmp1 - tmp2; | |
1049 | |
1050 int n = tmp10 + tmp11 + 16; | |
1051 dataUnit[c0] = n >> 5; | |
1052 if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c0]--; | |
1053 n = tmp10 - tmp11 + 16; | |
1054 dataUnit[c4] = n >> 5; | |
1055 if ((n < 0) && ((n & 0x1F) != 0)) dataUnit[c4]--; | |
1056 | |
1057 int z1 = (tmp12 + tmp13) * FIX_0_541196100; | |
1058 n = z1 + (tmp13 * FIX_0_765366865) + 131072; | |
1059 dataUnit[c2] = n >> 18; | |
1060 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c2]--; | |
1061 n = z1 + (tmp12 * (0 - FIX_1_847759065)) + 131072; | |
1062 dataUnit[c6] = n >> 18; | |
1063 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c6]--; | |
1064 | |
1065 /** | |
1066 * Odd part per figure 8 --- note paper omits factor of sqrt(2). | |
1067 * cK represents cos(K*pi/16). | |
1068 * i0..i3 in the paper are tmp4..tmp7 here. | |
1069 */ | |
1070 z1 = tmp4 + tmp7; | |
1071 int z2 = tmp5 + tmp6; | |
1072 int z3 = tmp4 + tmp6; | |
1073 int z4 = tmp5 + tmp7; | |
1074 int z5 = (z3 + z4) * FIX_1_175875602; // sqrt(2) * c3 | |
1075 | |
1076 tmp4 *= FIX_0_298631336; // sqrt(2) * (-c1+c3+c5-c7) | |
1077 tmp5 *= FIX_2_053119869; // sqrt(2) * ( c1+c3-c5+c7) | |
1078 tmp6 *= FIX_3_072711026; // sqrt(2) * ( c1+c3+c5-c7) | |
1079 tmp7 *= FIX_1_501321110; // sqrt(2) * ( c1+c3-c5-c7) | |
1080 z1 *= 0 - FIX_0_899976223; // sqrt(2) * (c7-c3) | |
1081 z2 *= 0 - FIX_2_562915447; // sqrt(2) * (-c1-c3) | |
1082 z3 *= 0 - FIX_1_961570560; // sqrt(2) * (-c3-c5) | |
1083 z4 *= 0 - FIX_0_390180644; // sqrt(2) * (c5-c3) | |
1084 | |
1085 z3 += z5; | |
1086 z4 += z5; | |
1087 | |
1088 n = tmp4 + z1 + z3 + 131072; | |
1089 dataUnit[c7] = n >> 18; | |
1090 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c7]--; | |
1091 n = tmp5 + z2 + z4 + 131072; | |
1092 dataUnit[c5] = n >> 18; | |
1093 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c5]--; | |
1094 n = tmp6 + z2 + z3 + 131072; | |
1095 dataUnit[c3] = n >> 18; | |
1096 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c3]--; | |
1097 n = tmp7 + z1 + z4 + 131072; | |
1098 dataUnit[c1] = n >> 18; | |
1099 if ((n < 0) && ((n & 0x3FFFF) != 0)) dataUnit[c1]--; | |
1100 } | |
1101 } | |
1102 void getAPP0() { | |
1103 JPEGAppn appn = new JPEGAppn(inputStream); | |
1104 if (!appn.verify()) { | |
1105 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1106 } | |
1107 } | |
1108 void getCOM() { | |
1109 new JPEGComment(inputStream); | |
1110 } | |
1111 void getDAC() { | |
1112 new JPEGArithmeticConditioningTable(inputStream); | |
1113 } | |
1114 void getDHT() { | |
1115 JPEGHuffmanTable dht = new JPEGHuffmanTable(inputStream); | |
1116 if (!dht.verify()) { | |
1117 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1118 } | |
1119 if (acHuffmanTables == null) { | |
1120 acHuffmanTables = new JPEGHuffmanTable[4]; | |
1121 } | |
1122 if (dcHuffmanTables == null) { | |
1123 dcHuffmanTables = new JPEGHuffmanTable[4]; | |
1124 } | |
1125 JPEGHuffmanTable[] dhtTables = dht.getAllTables(); | |
1126 for (int i = 0; i < dhtTables.length; i++) { | |
1127 JPEGHuffmanTable dhtTable = dhtTables[i]; | |
1128 if (dhtTable.getTableClass() == 0) { | |
1129 dcHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable; | |
1130 } else { | |
1131 acHuffmanTables[dhtTable.getTableIdentifier()] = dhtTable; | |
1132 } | |
1133 } | |
1134 } | |
1135 void getDNL() { | |
1136 new JPEGRestartInterval(inputStream); | |
1137 } | |
1138 void getDQT() { | |
1139 JPEGQuantizationTable dqt = new JPEGQuantizationTable(inputStream); | |
1140 int[][] currentTables = quantizationTables; | |
1141 if (currentTables == null) { | |
1142 currentTables = new int[][](4); | |
1143 } | |
1144 int[] dqtTablesKeys = dqt.getQuantizationTablesKeys(); | |
1145 int[][] dqtTablesValues = dqt.getQuantizationTablesValues(); | |
1146 for (int i = 0; i < dqtTablesKeys.length; i++) { | |
1147 int index = dqtTablesKeys[i]; | |
1148 currentTables[index] = dqtTablesValues[i]; | |
1149 } | |
1150 quantizationTables = currentTables; | |
1151 } | |
1152 void getDRI() { | |
1153 JPEGRestartInterval dri = new JPEGRestartInterval(inputStream); | |
1154 if (!dri.verify()) { | |
1155 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1156 } | |
1157 restartInterval = dri.getRestartInterval(); | |
1158 } | |
1159 static void initialize() { | |
1160 initializeRGBYCbCrTables(); | |
1161 initializeYCbCrRGBTables(); | |
1162 initializeBitCountTable(); | |
1163 } | |
1164 static void initializeBitCountTable() { | |
1165 int nBits = 1; | |
1166 int power2 = 2; | |
1167 NBitsTable = new int[2048]; | |
1168 NBitsTable[0] = 0; | |
1169 for (int i = 1; i < NBitsTable.length; i++) { | |
1170 if (!(i < power2)) { | |
1171 nBits++; | |
1172 power2 *= 2; | |
1173 } | |
1174 NBitsTable[i] = nBits; | |
1175 } | |
1176 } | |
1177 static void initializeRGBYCbCrTables() { | |
1178 RYTable = new int[256]; | |
1179 GYTable = new int[256]; | |
1180 BYTable = new int[256]; | |
1181 RCbTable = new int[256]; | |
1182 GCbTable = new int[256]; | |
1183 BCbTable = new int[256]; | |
1184 RCrTable = BCbTable; | |
1185 GCrTable = new int[256]; | |
1186 BCrTable = new int[256]; | |
1187 for (int i = 0; i < 256; i++) { | |
1188 RYTable[i] = i * 19595; | |
1189 GYTable[i] = i * 38470; | |
1190 BYTable[i] = i * 7471 + 32768; | |
1191 RCbTable[i] = i * -11059; | |
1192 GCbTable[i] = i * -21709; | |
1193 BCbTable[i] = i * 32768 + 8388608; | |
1194 GCrTable[i] = i * -27439; | |
1195 BCrTable[i] = i * -5329; | |
1196 } | |
1197 } | |
1198 static void initializeYCbCrRGBTables() { | |
1199 CrRTable = new int[256]; | |
1200 CbBTable = new int[256]; | |
1201 CrGTable = new int[256]; | |
1202 CbGTable = new int[256]; | |
1203 for (int i = 0; i < 256; i++) { | |
1204 int x2 = 2 * i - 255; | |
1205 CrRTable[i] = (45941 * x2 + 32768) >> 16; | |
1206 CbBTable[i] = (58065 * x2 + 32768) >> 16; | |
1207 CrGTable[i] = -23401 * x2; | |
1208 CbGTable[i] = -11277 * x2 + 32768; | |
1209 } | |
1210 } | |
1211 void inverseDCT(int[] dataUnit) { | |
1212 for (int row = 0; row < 8; row++) { | |
1213 int rIndex = row * DCTSIZE; | |
1214 /** | |
1215 * Due to quantization, we will usually find that many of the input | |
1216 * coefficients are zero, especially the AC terms. We can exploit this | |
1217 * by short-circuiting the IDCT calculation for any row in which all | |
1218 * the AC terms are zero. In that case each output is equal to the | |
1219 * DC coefficient (with scale factor as needed). | |
1220 * With typical images and quantization tables, half or more of the | |
1221 * row DCT calculations can be simplified this way. | |
1222 */ | |
1223 if (isZeroInRow(dataUnit, rIndex)) { | |
1224 int dcVal = dataUnit[rIndex] << 2; | |
1225 for (int i = rIndex + 7; i >= rIndex; i--) { | |
1226 dataUnit[i] = dcVal; | |
1227 } | |
1228 } else { | |
1229 /** | |
1230 * Even part: reverse the even part of the forward DCT. | |
1231 * The rotator is sqrt(2)*c(-6). | |
1232 */ | |
1233 int z2 = dataUnit[rIndex + 2]; | |
1234 int z3 = dataUnit[rIndex + 6]; | |
1235 int z1 = (z2 + z3) * FIX_0_541196100; | |
1236 int tmp2 = z1 + (z3 * (0 - FIX_1_847759065)); | |
1237 int tmp3 = z1 + (z2 * FIX_0_765366865); | |
1238 int tmp0 = (dataUnit[rIndex] + dataUnit[rIndex + 4]) << 13; | |
1239 int tmp1 = (dataUnit[rIndex] - dataUnit[rIndex + 4]) << 13; | |
1240 int tmp10 = tmp0 + tmp3; | |
1241 int tmp13 = tmp0 - tmp3; | |
1242 int tmp11 = tmp1 + tmp2; | |
1243 int tmp12 = tmp1 - tmp2; | |
1244 /** | |
1245 * Odd part per figure 8; the matrix is unitary and hence its | |
1246 * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. | |
1247 */ | |
1248 tmp0 = dataUnit[rIndex + 7]; | |
1249 tmp1 = dataUnit[rIndex + 5]; | |
1250 tmp2 = dataUnit[rIndex + 3]; | |
1251 tmp3 = dataUnit[rIndex + 1]; | |
1252 z1 = tmp0 + tmp3; | |
1253 z2 = tmp1 + tmp2; | |
1254 z3 = tmp0 + tmp2; | |
1255 int z4 = tmp1 + tmp3; | |
1256 int z5 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */ | |
1257 | |
1258 tmp0 *= FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */ | |
1259 tmp1 *= FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */ | |
1260 tmp2 *= FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */ | |
1261 tmp3 *= FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */ | |
1262 z1 *= 0 - FIX_0_899976223; /* sqrt(2) * (c7-c3) */ | |
1263 z2 *= 0 - FIX_2_562915447; /* sqrt(2) * (-c1-c3) */ | |
1264 z3 *= 0 - FIX_1_961570560; /* sqrt(2) * (-c3-c5) */ | |
1265 z4 *= 0 - FIX_0_390180644; /* sqrt(2) * (c5-c3) */ | |
1266 | |
1267 z3 += z5; | |
1268 z4 += z5; | |
1269 tmp0 += z1 + z3; | |
1270 tmp1 += z2 + z4; | |
1271 tmp2 += z2 + z3; | |
1272 tmp3 += z1 + z4; | |
1273 | |
1274 dataUnit[rIndex] = (tmp10 + tmp3 + 1024) >> 11; | |
1275 dataUnit[rIndex + 7] = (tmp10 - tmp3 + 1024) >> 11; | |
1276 dataUnit[rIndex + 1] = (tmp11 + tmp2 + 1024) >> 11; | |
1277 dataUnit[rIndex + 6] = (tmp11 - tmp2 + 1024) >> 11; | |
1278 dataUnit[rIndex + 2] = (tmp12 + tmp1 + 1024) >> 11; | |
1279 dataUnit[rIndex + 5] = (tmp12 - tmp1 + 1024) >> 11; | |
1280 dataUnit[rIndex + 3] = (tmp13 + tmp0 + 1024) >> 11; | |
1281 dataUnit[rIndex + 4] = (tmp13 - tmp0 + 1024) >> 11; | |
1282 } | |
1283 } | |
1284 /** | |
1285 * Pass 2: process columns. | |
1286 * Note that we must descale the results by a factor of 8 == 2**3, | |
1287 * and also undo the PASS1_BITS scaling. | |
1288 */ | |
1289 for (int col = 0; col < 8; col++) { | |
1290 int c0 = col; | |
1291 int c1 = col + 8; | |
1292 int c2 = col + 16; | |
1293 int c3 = col + 24; | |
1294 int c4 = col + 32; | |
1295 int c5 = col + 40; | |
1296 int c6 = col + 48; | |
1297 int c7 = col + 56; | |
1298 if (isZeroInColumn(dataUnit, col)) { | |
1299 int dcVal = (dataUnit[c0] + 16) >> 5; | |
1300 dataUnit[c0] = dcVal; | |
1301 dataUnit[c1] = dcVal; | |
1302 dataUnit[c2] = dcVal; | |
1303 dataUnit[c3] = dcVal; | |
1304 dataUnit[c4] = dcVal; | |
1305 dataUnit[c5] = dcVal; | |
1306 dataUnit[c6] = dcVal; | |
1307 dataUnit[c7] = dcVal; | |
1308 } else { | |
1309 /** | |
1310 * Even part: reverse the even part of the forward DCT. | |
1311 * The rotator is sqrt(2)*c(-6). | |
1312 */ | |
1313 int z0 = dataUnit[c0]; | |
1314 int z2 = dataUnit[c2]; | |
1315 int z3 = dataUnit[c6]; | |
1316 int z4 = dataUnit[c4]; | |
1317 int z1 = (z2 + z3) * FIX_0_541196100; | |
1318 int tmp2 = z1 + (z3 * (0 - FIX_1_847759065)); | |
1319 int tmp3 = z1 + (z2 * FIX_0_765366865); | |
1320 int tmp0 = (z0 + z4) << 13; | |
1321 int tmp1 = (z0 - z4) << 13; | |
1322 int tmp10 = tmp0 + tmp3; | |
1323 int tmp13 = tmp0 - tmp3; | |
1324 int tmp11 = tmp1 + tmp2; | |
1325 int tmp12 = tmp1 - tmp2; | |
1326 /** | |
1327 * Odd part per figure 8; the matrix is unitary and hence its | |
1328 * transpose is its inverse. i0..i3 are y7,y5,y3,y1 respectively. | |
1329 */ | |
1330 tmp0 = dataUnit[c7]; | |
1331 tmp1 = dataUnit[c5]; | |
1332 tmp2 = dataUnit[c3]; | |
1333 tmp3 = dataUnit[c1]; | |
1334 z1 = tmp0 + tmp3; | |
1335 z2 = tmp1 + tmp2; | |
1336 z3 = tmp0 + tmp2; | |
1337 z4 = tmp1 + tmp3; | |
1338 z0 = (z3 + z4) * FIX_1_175875602; /* sqrt(2) * c3 */ | |
1339 | |
1340 tmp0 *= FIX_0_298631336; /* sqrt(2) * (-c1+c3+c5-c7) */ | |
1341 tmp1 *= FIX_2_053119869; /* sqrt(2) * ( c1+c3-c5+c7) */ | |
1342 tmp2 *= FIX_3_072711026; /* sqrt(2) * ( c1+c3+c5-c7) */ | |
1343 tmp3 *= FIX_1_501321110; /* sqrt(2) * ( c1+c3-c5-c7) */ | |
1344 z1 *= 0 - FIX_0_899976223; /* sqrt(2) * (c7-c3) */ | |
1345 z2 *= 0 - FIX_2_562915447; /* sqrt(2) * (-c1-c3) */ | |
1346 z3 *= 0 - FIX_1_961570560; /* sqrt(2) * (-c3-c5) */ | |
1347 z4 *= 0 - FIX_0_390180644; /* sqrt(2) * (c5-c3) */ | |
1348 | |
1349 z3 += z0; | |
1350 z4 += z0; | |
1351 | |
1352 tmp0 += z1 + z3; | |
1353 tmp1 += z2 + z4; | |
1354 tmp2 += z2 + z3; | |
1355 tmp3 += z1 + z4; | |
1356 | |
1357 /* Final output stage: inputs are tmp10..tmp13, tmp0..tmp3 */ | |
1358 dataUnit[c0] = (tmp10 + tmp3 + 131072) >> 18; | |
1359 dataUnit[c7] = (tmp10 - tmp3 + 131072) >> 18; | |
1360 dataUnit[c1] = (tmp11 + tmp2 + 131072) >> 18; | |
1361 dataUnit[c6] = (tmp11 - tmp2 + 131072) >> 18; | |
1362 dataUnit[c2] = (tmp12 + tmp1 + 131072) >> 18; | |
1363 dataUnit[c5] = (tmp12 - tmp1 + 131072) >> 18; | |
1364 dataUnit[c3] = (tmp13 + tmp0 + 131072) >> 18; | |
1365 dataUnit[c4] = (tmp13 - tmp0 + 131072) >> 18; | |
1366 } | |
1367 } | |
1368 } | |
1369 bool isFileFormat(LEDataInputStream stream) { | |
1370 try { | |
1371 JPEGStartOfImage soi = new JPEGStartOfImage(stream); | |
1372 stream.unread(soi.reference); | |
1373 return soi.verify(); // we no longer check for appN | |
1374 } catch (TracedException e) { | |
1375 return false; | |
1376 } | |
1377 } | |
1378 bool isZeroInColumn(int[] dataUnit, int col) { | |
1379 return dataUnit[col + 8] == 0 && dataUnit[col + 16] == 0 | |
1380 && dataUnit[col + 24] == 0 && dataUnit[col + 32] == 0 | |
1381 && dataUnit[col + 40] == 0 && dataUnit[col + 48] == 0 | |
1382 && dataUnit[col + 56] == 0; | |
1383 } | |
1384 bool isZeroInRow(int[] dataUnit, int rIndex) { | |
1385 return dataUnit[rIndex + 1] == 0 && dataUnit[rIndex + 2] == 0 | |
1386 && dataUnit[rIndex + 3] == 0 && dataUnit[rIndex + 4] == 0 | |
1387 && dataUnit[rIndex + 5] == 0 && dataUnit[rIndex + 6] == 0 | |
1388 && dataUnit[rIndex + 7] == 0; | |
1389 } | |
1390 ImageData[] loadFromByteStream() { | |
1391 //TEMPORARY CODE | |
1392 //PORTING_FIXME | |
1393 if (/+System.getProperty("dwt.internal.image.JPEGFileFormat_3.2") == null+/ true ) { | |
1394 return JPEGDecoder.loadFromByteStream(inputStream, loader); | |
1395 } | |
1396 JPEGStartOfImage soi = new JPEGStartOfImage(inputStream); | |
1397 if (!soi.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1398 restartInterval = 0; | |
1399 | |
1400 /* Process the tables preceding the frame header. */ | |
1401 processTables(); | |
1402 | |
1403 /* Start of Frame. */ | |
1404 frameHeader = new JPEGFrameHeader(inputStream); | |
1405 if (!frameHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1406 imageWidth = frameHeader.getSamplesPerLine(); | |
1407 imageHeight = frameHeader.getNumberOfLines(); | |
1408 maxH = frameHeader.getMaxHFactor(); | |
1409 maxV = frameHeader.getMaxVFactor(); | |
1410 int mcuWidth = maxH * DCTSIZE; | |
1411 int mcuHeight = maxV * DCTSIZE; | |
1412 interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth; | |
1413 interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight; | |
1414 progressive = frameHeader.isProgressive(); | |
1415 samplePrecision = frameHeader.getSamplePrecision(); | |
1416 nComponents = frameHeader.getNumberOfImageComponents(); | |
1417 frameComponents = frameHeader.componentParameters; | |
1418 componentIds = frameHeader.componentIdentifiers; | |
1419 imageComponents = new byte[][](nComponents); | |
1420 if (progressive) { | |
1421 // Progressive jpeg: need to keep all of the data units. | |
1422 dataUnits = new int[][][](nComponents); | |
1423 } else { | |
1424 // Sequential jpeg: only need one data unit. | |
1425 dataUnit = new int[8 * 8]; | |
1426 } | |
1427 for (int i = 0; i < nComponents; i++) { | |
1428 int[] frameComponent = frameComponents[componentIds[i]]; | |
1429 int bufferSize = frameComponent[CW] * frameComponent[CH]; | |
1430 imageComponents[i] = new byte[bufferSize]; | |
1431 if (progressive) { | |
1432 dataUnits[i] = new int[][](bufferSize); | |
1433 } | |
1434 } | |
1435 | |
1436 /* Process the tables preceding the scan header. */ | |
1437 processTables(); | |
1438 | |
1439 /* Start of Scan. */ | |
1440 scanHeader = new JPEGScanHeader(inputStream); | |
1441 if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1442 | |
1443 /* Process scan(s) and further tables until EOI. */ | |
1444 int progressiveScanCount = 0; | |
1445 bool done = false; | |
1446 while(!done) { | |
1447 resetInputBuffer(); | |
1448 precedingDCs = new int[4]; | |
1449 decodeScan(); | |
1450 if (progressive && loader.hasListeners()) { | |
1451 ImageData imageData = createImageData(); | |
1452 loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, false)); | |
1453 progressiveScanCount++; | |
1454 } | |
1455 | |
1456 /* Unread any buffered data before looking for tables again. */ | |
1457 int delta = 512 - bufferCurrentPosition - 1; | |
1458 if (delta > 0) { | |
1459 byte[] unreadBuffer = new byte[delta]; | |
25
fc2b263b8a3f
Merged back the System.arraycopy and use a System class
Frank Benoit <benoit@tionex.de>
parents:
13
diff
changeset
|
1460 System.arraycopy(dataBuffer, bufferCurrentPosition + 1, unreadBuffer, 0, delta); |
13 | 1461 try { |
1462 inputStream.unread(unreadBuffer); | |
1463 } catch (IOException e) { | |
1464 SWT.error(SWT.ERROR_IO, e); | |
1465 } | |
1466 } | |
1467 | |
1468 /* Process the tables preceding the next scan header. */ | |
1469 JPEGSegment jpegSegment = processTables(); | |
1470 if (jpegSegment == null || jpegSegment.getSegmentMarker() == EOI) { | |
1471 done = true; | |
1472 } else { | |
1473 scanHeader = new JPEGScanHeader(inputStream); | |
1474 if (!scanHeader.verify()) SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1475 } | |
1476 } | |
1477 | |
1478 if (progressive) { | |
1479 for (int ymcu = 0; ymcu < interleavedMcuRows; ymcu++) { | |
1480 for (int xmcu = 0; xmcu < interleavedMcuCols; xmcu++) { | |
1481 for (int iComp = 0; iComp < nComponents; iComp++) { | |
1482 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
1483 int hi = frameComponent[HI]; | |
1484 int vi = frameComponent[VI]; | |
1485 int compWidth = frameComponent[CW]; | |
1486 for (int ivi = 0; ivi < vi; ivi++) { | |
1487 for (int ihi = 0; ihi < hi; ihi++) { | |
1488 int index = (ymcu * vi + ivi) * compWidth + xmcu * hi + ihi; | |
1489 dataUnit = dataUnits[iComp][index]; | |
1490 dequantize(dataUnit, iComp); | |
1491 inverseDCT(dataUnit); | |
1492 storeData(dataUnit, iComp, xmcu, ymcu, hi, ihi, vi, ivi); | |
1493 } | |
1494 } | |
1495 } | |
1496 } | |
1497 } | |
1498 dataUnits = null; // release memory | |
1499 } | |
1500 ImageData imageData = createImageData(); | |
1501 if (progressive && loader.hasListeners()) { | |
1502 loader.notifyListeners(new ImageLoaderEvent(loader, imageData, progressiveScanCount, true)); | |
1503 } | |
1504 return [imageData]; | |
1505 } | |
1506 ImageData createImageData() { | |
1507 return ImageData.internal_new( | |
1508 imageWidth, | |
1509 imageHeight, | |
1510 nComponents * samplePrecision, | |
1511 setUpPalette(), | |
1512 nComponents == 1 ? 4 : 1, | |
1513 decodeImageComponents(), | |
1514 0, | |
1515 null, | |
1516 null, | |
1517 -1, | |
1518 -1, | |
1519 SWT.IMAGE_JPEG, | |
1520 0, | |
1521 0, | |
1522 0, | |
1523 0); | |
1524 } | |
1525 int nextBit() { | |
1526 if (currentBitCount != 0) { | |
1527 currentBitCount--; | |
1528 currentByte *= 2; | |
1529 if (currentByte > 255) { | |
1530 currentByte -= 256; | |
1531 return 1; | |
1532 } else { | |
1533 return 0; | |
1534 } | |
1535 } | |
1536 bufferCurrentPosition++; | |
1537 if (bufferCurrentPosition >= 512) { | |
1538 resetInputBuffer(); | |
1539 bufferCurrentPosition = 0; | |
1540 } | |
1541 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1542 currentBitCount = 8; | |
1543 byte nextByte; | |
1544 if (bufferCurrentPosition == 511) { | |
1545 resetInputBuffer(); | |
1546 currentBitCount = 8; | |
1547 nextByte = dataBuffer[0]; | |
1548 } else { | |
1549 nextByte = dataBuffer[bufferCurrentPosition + 1]; | |
1550 } | |
1551 if (currentByte == 0xFF) { | |
1552 if (nextByte == 0) { | |
1553 bufferCurrentPosition ++; | |
1554 currentBitCount--; | |
1555 currentByte *= 2; | |
1556 if (currentByte > 255) { | |
1557 currentByte -= 256; | |
1558 return 1; | |
1559 } else { | |
1560 return 0; | |
1561 } | |
1562 } else { | |
1563 if ((nextByte & 0xFF) + 0xFF00 == DNL) { | |
1564 getDNL(); | |
1565 return 0; | |
1566 } else { | |
1567 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1568 return 0; | |
1569 } | |
1570 } | |
1571 } else { | |
1572 currentBitCount--; | |
1573 currentByte *= 2; | |
1574 if (currentByte > 255) { | |
1575 currentByte -= 256; | |
1576 return 1; | |
1577 } else { | |
1578 return 0; | |
1579 } | |
1580 } | |
1581 } | |
1582 void processRestartInterval() { | |
1583 do { | |
1584 bufferCurrentPosition++; | |
1585 if (bufferCurrentPosition > 511) { | |
1586 resetInputBuffer(); | |
1587 bufferCurrentPosition = 0; | |
1588 } | |
1589 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1590 } while (currentByte != 0xFF); | |
1591 while (currentByte == 0xFF) { | |
1592 bufferCurrentPosition++; | |
1593 if (bufferCurrentPosition > 511) { | |
1594 resetInputBuffer(); | |
1595 bufferCurrentPosition = 0; | |
1596 } | |
1597 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1598 } | |
1599 if (currentByte != ((RST0 + nextRestartNumber) & 0xFF)) { | |
1600 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1601 } | |
1602 bufferCurrentPosition++; | |
1603 if (bufferCurrentPosition > 511) { | |
1604 resetInputBuffer(); | |
1605 bufferCurrentPosition = 0; | |
1606 } | |
1607 currentByte = dataBuffer[bufferCurrentPosition] & 0xFF; | |
1608 currentBitCount = 8; | |
1609 restartsToGo = restartInterval; | |
1610 nextRestartNumber = (nextRestartNumber + 1) & 0x7; | |
1611 precedingDCs = new int[4]; | |
1612 eobrun = 0; | |
1613 } | |
1614 /* Process all markers until a frame header, scan header, or EOI is found. */ | |
1615 JPEGSegment processTables() { | |
1616 while (true) { | |
1617 JPEGSegment jpegSegment = seekUnspecifiedMarker(inputStream); | |
1618 if (jpegSegment == null) return null; | |
1619 JPEGFrameHeader sof = new JPEGFrameHeader(jpegSegment.reference); | |
1620 if (sof.verify()) { | |
1621 return jpegSegment; | |
1622 } | |
1623 int marker = jpegSegment.getSegmentMarker(); | |
1624 switch (marker) { | |
1625 case SOI: // there should only be one SOI per file | |
1626 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1627 case EOI: | |
1628 case SOS: | |
1629 return jpegSegment; | |
1630 case DQT: | |
1631 getDQT(); | |
1632 break; | |
1633 case DHT: | |
1634 getDHT(); | |
1635 break; | |
1636 case DAC: | |
1637 getDAC(); | |
1638 break; | |
1639 case DRI: | |
1640 getDRI(); | |
1641 break; | |
1642 case APP0: | |
1643 getAPP0(); | |
1644 break; | |
1645 case COM: | |
1646 getCOM(); | |
1647 break; | |
1648 default: | |
1649 skipSegmentFrom(inputStream); | |
1650 | |
1651 } | |
1652 } | |
1653 } | |
1654 void quantizeData(int[] dataUnit, int iComp) { | |
1655 int[] qTable = quantizationTables[frameComponents[componentIds[iComp]][TQI]]; | |
1656 for (int i = 0; i < dataUnit.length; i++) { | |
1657 int zzIndex = ZigZag8x8[i]; | |
1658 int data = dataUnit[zzIndex]; | |
1659 int absData = data < 0 ? 0 - data : data; | |
1660 int qValue = qTable[i]; | |
1661 int q2 = qValue >> 1; | |
1662 absData += q2; | |
1663 if (absData < qValue) { | |
1664 dataUnit[zzIndex] = 0; | |
1665 } else { | |
1666 absData /= qValue; | |
1667 if (data >= 0) { | |
1668 dataUnit[zzIndex] = absData; | |
1669 } else { | |
1670 dataUnit[zzIndex] = 0 - absData; | |
1671 } | |
1672 } | |
1673 } | |
1674 } | |
1675 int receive(int nBits) { | |
1676 int v = 0; | |
1677 for (int i = 0; i < nBits; i++) { | |
1678 v = v * 2 + nextBit(); | |
1679 } | |
1680 return v; | |
1681 } | |
1682 void resetInputBuffer() { | |
1683 if (dataBuffer == null) { | |
1684 dataBuffer = new byte[512]; | |
1685 } | |
1686 try { | |
1687 inputStream.read(dataBuffer); | |
1688 } catch (IOException e) { | |
1689 SWT.error(SWT.ERROR_IO, e); | |
1690 } | |
1691 currentBitCount = 0; | |
1692 bufferCurrentPosition = -1; | |
1693 } | |
1694 void resetOutputBuffer() { | |
1695 if (dataBuffer == null) { | |
1696 dataBuffer = new byte[512]; | |
1697 } else { | |
1698 try { | |
1699 outputStream.write(dataBuffer, 0, bufferCurrentPosition); | |
1700 } catch (IOException e) { | |
1701 SWT.error(SWT.ERROR_IO, e); | |
1702 } | |
1703 } | |
1704 bufferCurrentPosition = 0; | |
1705 } | |
1706 static JPEGSegment seekUnspecifiedMarker(LEDataInputStream byteStream) { | |
1707 byte[] byteArray = new byte[2]; | |
1708 try { | |
1709 while (true) { | |
1710 if (byteStream.read(byteArray, 0, 1) != 1) return null; | |
1711 if (byteArray[0] == cast(byte) 0xFF) { | |
1712 if (byteStream.read(byteArray, 1, 1) != 1) return null; | |
1713 if (byteArray[1] != cast(byte) 0xFF && byteArray[1] != 0) { | |
1714 byteStream.unread(byteArray); | |
1715 return new JPEGSegment(byteArray); | |
1716 } | |
1717 } | |
1718 } | |
1719 } catch (IOException e) { | |
1720 SWT.error(SWT.ERROR_IO, e); | |
1721 } | |
1722 return null; | |
1723 } | |
1724 PaletteData setUpPalette() { | |
1725 if (nComponents == 1) { | |
1726 RGB[] entries = new RGB[256]; | |
1727 for (int i = 0; i < 256; i++) { | |
1728 entries[i] = new RGB(i, i, i); | |
1729 } | |
1730 return new PaletteData(entries); | |
1731 } | |
1732 return new PaletteData(0xFF, 0xFF00, 0xFF0000); | |
1733 } | |
1734 static void skipSegmentFrom(LEDataInputStream byteStream) { | |
1735 try { | |
1736 byte[] byteArray = new byte[4]; | |
1737 JPEGSegment jpegSegment = new JPEGSegment(byteArray); | |
1738 | |
1739 if (byteStream.read(byteArray) != byteArray.length) { | |
1740 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1741 } | |
1742 if (!(byteArray[0] == -1 && byteArray[1] != 0 && byteArray[1] != -1)) { | |
1743 SWT.error(SWT.ERROR_INVALID_IMAGE); | |
1744 } | |
1745 int delta = jpegSegment.getSegmentLength() - 2; | |
1746 byteStream.skip(delta); | |
1747 } catch (TracedException e) { | |
1748 SWT.error(SWT.ERROR_IO, e); | |
1749 } | |
1750 } | |
1751 void storeData(int[] dataUnit, int iComp, int xmcu, int ymcu, int hi, int ihi, int vi, int ivi) { | |
1752 byte[] compImage = imageComponents[iComp]; | |
1753 int[] frameComponent = frameComponents[componentIds[iComp]]; | |
1754 int compWidth = frameComponent[CW]; | |
1755 int destIndex = ((ymcu * vi + ivi) * compWidth * DCTSIZE) + ((xmcu * hi + ihi) * DCTSIZE); | |
1756 int srcIndex = 0; | |
1757 for (int i = 0; i < DCTSIZE; i++) { | |
1758 for (int col = 0; col < DCTSIZE; col++) { | |
1759 int x = dataUnit[srcIndex] + 128; | |
1760 if (x < 0) { | |
1761 x = 0; | |
1762 } else { | |
1763 if (x > 255) x = 255; | |
1764 } | |
1765 compImage[destIndex + col] = cast(byte)x; | |
1766 srcIndex++; | |
1767 } | |
1768 destIndex += compWidth; | |
1769 } | |
1770 } | |
1771 void unloadIntoByteStream(ImageLoader loader) { | |
1772 ImageData image = loader.data[0]; | |
1773 if (!(new JPEGStartOfImage()).writeToStream(outputStream)) { | |
1774 SWT.error(SWT.ERROR_IO); | |
1775 } | |
1776 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]); | |
1777 if (!appn.writeToStream(outputStream)) { | |
1778 SWT.error(SWT.ERROR_IO); | |
1779 } | |
1780 quantizationTables = new int[][](4); | |
1781 JPEGQuantizationTable chromDQT = JPEGQuantizationTable.defaultChrominanceTable(); | |
1782 chromDQT.scaleBy(encoderQFactor); | |
1783 int[] jpegDQTKeys = chromDQT.getQuantizationTablesKeys(); | |
1784 int[][] jpegDQTValues = chromDQT.getQuantizationTablesValues(); | |
1785 for (int i = 0; i < jpegDQTKeys.length; i++) { | |
1786 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i]; | |
1787 } | |
1788 JPEGQuantizationTable lumDQT = JPEGQuantizationTable.defaultLuminanceTable(); | |
1789 lumDQT.scaleBy(encoderQFactor); | |
1790 jpegDQTKeys = lumDQT.getQuantizationTablesKeys(); | |
1791 jpegDQTValues = lumDQT.getQuantizationTablesValues(); | |
1792 for (int i = 0; i < jpegDQTKeys.length; i++) { | |
1793 quantizationTables[jpegDQTKeys[i]] = jpegDQTValues[i]; | |
1794 } | |
1795 if (!lumDQT.writeToStream(outputStream)) { | |
1796 SWT.error(SWT.ERROR_IO); | |
1797 } | |
1798 if (!chromDQT.writeToStream(outputStream)) { | |
1799 SWT.error(SWT.ERROR_IO); | |
1800 } | |
1801 int frameLength, scanLength, precision; | |
1802 int[][] frameParams, scanParams; | |
1803 if (image.depth == 1) { | |
1804 frameLength = 11; | |
1805 frameParams = new int[][](1); | |
1806 frameParams[0] = [1, 1, 1, 0, 0]; | |
1807 scanParams = new int[][](1); | |
1808 scanParams[0] = [0, 0]; | |
1809 scanLength = 8; | |
1810 nComponents = 1; | |
1811 precision = 1; | |
1812 } else { | |
1813 frameLength = 17; | |
1814 frameParams = new int[][](3); | |
1815 frameParams[0] = [0, 2, 2, 0, 0]; | |
1816 frameParams[1] = [1, 1, 1, 0, 0]; | |
1817 frameParams[2] = [1, 1, 1, 0, 0]; | |
1818 scanParams = new int[][](3); | |
1819 scanParams[0] = [0, 0]; | |
1820 scanParams[1] = [1, 1]; | |
1821 scanParams[2] = [1, 1]; | |
1822 scanLength = 12; | |
1823 nComponents = 3; | |
1824 precision = 8; | |
1825 } | |
1826 imageWidth = image.width; | |
1827 imageHeight = image.height; | |
1828 frameHeader = new JPEGFrameHeader(new byte[19]); | |
1829 frameHeader.setSegmentMarker(SOF0); | |
1830 frameHeader.setSegmentLength(frameLength); | |
1831 frameHeader.setSamplePrecision(precision); | |
1832 frameHeader.setSamplesPerLine(imageWidth); | |
1833 frameHeader.setNumberOfLines(imageHeight); | |
1834 frameHeader.setNumberOfImageComponents(nComponents); | |
1835 frameHeader.componentParameters = frameParams; | |
1836 frameHeader.componentIdentifiers = [0, 1, 2]; | |
1837 frameHeader.initializeContents(); | |
1838 if (!frameHeader.writeToStream(outputStream)) { | |
1839 SWT.error(SWT.ERROR_IO); | |
1840 } | |
1841 frameComponents = frameParams; | |
1842 componentIds = frameHeader.componentIdentifiers; | |
1843 maxH = frameHeader.getMaxHFactor(); | |
1844 maxV = frameHeader.getMaxVFactor(); | |
1845 int mcuWidth = maxH * DCTSIZE; | |
1846 int mcuHeight = maxV * DCTSIZE; | |
1847 interleavedMcuCols = (imageWidth + mcuWidth - 1) / mcuWidth; | |
1848 interleavedMcuRows = (imageHeight + mcuHeight - 1) / mcuHeight; | |
1849 acHuffmanTables = new JPEGHuffmanTable[4]; | |
1850 dcHuffmanTables = new JPEGHuffmanTable[4]; | |
1851 JPEGHuffmanTable[] dhtTables = [ | |
1852 JPEGHuffmanTable.getDefaultDCLuminanceTable(), | |
1853 JPEGHuffmanTable.getDefaultDCChrominanceTable(), | |
1854 JPEGHuffmanTable.getDefaultACLuminanceTable(), | |
1855 JPEGHuffmanTable.getDefaultACChrominanceTable() | |
1856 ]; | |
1857 for (int i = 0; i < dhtTables.length; i++) { | |
1858 JPEGHuffmanTable dhtTable = dhtTables[i]; | |
1859 if (!dhtTable.writeToStream(outputStream)) { | |
1860 SWT.error(SWT.ERROR_IO); | |
1861 } | |
1862 JPEGHuffmanTable[] allTables = dhtTable.getAllTables(); | |
1863 for (int j = 0; j < allTables.length; j++) { | |
1864 JPEGHuffmanTable huffmanTable = allTables[j]; | |
1865 if (huffmanTable.getTableClass() == 0) { | |
1866 dcHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable; | |
1867 } else { | |
1868 acHuffmanTables[huffmanTable.getTableIdentifier()] = huffmanTable; | |
1869 } | |
1870 } | |
1871 } | |
1872 precedingDCs = new int[4]; | |
1873 scanHeader = new JPEGScanHeader(new byte[14]); | |
1874 scanHeader.setSegmentMarker(SOS); | |
1875 scanHeader.setSegmentLength(scanLength); | |
1876 scanHeader.setNumberOfImageComponents(nComponents); | |
1877 scanHeader.setStartOfSpectralSelection(0); | |
1878 scanHeader.setEndOfSpectralSelection(63); | |
1879 scanHeader.componentParameters = scanParams; | |
1880 scanHeader.initializeContents(); | |
1881 if (!scanHeader.writeToStream(outputStream)) { | |
1882 SWT.error(SWT.ERROR_IO); | |
1883 } | |
1884 convertImageToYCbCr(image); | |
1885 resetOutputBuffer(); | |
1886 currentByte = 0; | |
1887 currentBitCount = 0; | |
1888 encodeScan(); | |
1889 if (!(new JPEGEndOfImage()).writeToStream(outputStream)) { | |
1890 SWT.error(SWT.ERROR_IO); | |
1891 } | |
1892 } | |
1893 } |