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