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 }