JAL-1807 Bob's JalviewJS prototype first commit
[jalviewjs.git] / src / javajs / img / JpgEncoder.java
1 // Version 1.0a\r
2 // Copyright (C) 1998, James R. Weeks and BioElectroMech.\r
3 // Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.\r
4 \r
5 // See license.txt for details about the allowed used of this software.\r
6 // This software is based in part on the work of the Independent JPEG Group.\r
7 // See IJGreadme.txt for details about the Independent JPEG Group's license.\r
8 \r
9 // This encoder is inspired by the Java Jpeg encoder by Florian Raemy,\r
10 // studwww.eurecom.fr/~raemy.\r
11 // It borrows a great deal of code and structure from the Independent\r
12 // Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.\r
13 // See license.txt for details \r
14 \r
15 /*\r
16  * JpegEncoder and its associated classes are Copyright (c) 1998, James R. Weeks and BioElectroMech\r
17  * see(Jmol/src/com/obrador/license.txt)\r
18  * \r
19  * javjs.img.JpegEncoder.java was adapted by Bob Hanson\r
20  * \r
21  * for Jmol in the following ways:\r
22  * \r
23  * 1) minor coding efficiencies were made in some for() loops.\r
24  * 2) methods not used by Jmol were commented out\r
25  * 3) method and variable signatures were modified to provide \r
26  *    more appropriate method privacy.\r
27  * 4) additions for Java2Script compatibility \r
28  * \r
29  * Original files are maintained in the Jmol.src.com.obrador package, but\r
30  * these original files are not distributed with Jmol.\r
31  *   \r
32 */\r
33 \r
34 package javajs.img;\r
35 \r
36 import java.io.IOException;\r
37 import java.util.Map;\r
38 \r
39 import javajs.img.ImageEncoder;\r
40 import javajs.util.AU;\r
41 import javajs.util.OC;\r
42 \r
43 /**\r
44  * JpegEncoder - The JPEG main program which performs a jpeg compression of an\r
45  * image.\r
46  * \r
47  *  A system to allow the full Jmol state -- regardless of length -- \r
48  *  to be encoded in a set of APP1 (FFE1) tags.\r
49  *  But we have to be careful about line ends for backward compatibility. \r
50  *  This solution is not 100% effective, because some data lines may in principle be \r
51  *  Very large and may not contain new lines for more than 65500 characters, \r
52  *  But that would be very unusual. Perhaps a huge data set loaded from a \r
53  *  string. Introduced in Jmol 12.1.36. Bob Hanson\r
54  *  \r
55  * See org.com.obrador.license.txt\r
56  * \r
57  */\r
58 \r
59 public class JpgEncoder extends ImageEncoder {\r
60 \r
61   // this string will GENERALLY appear at the end of lines and be escaped \r
62   private static final int CONTINUE_MAX = 65500; // some room to spare here. \r
63   private static final int CONTINUE_MAX_BUFFER = CONTINUE_MAX + 10; // never break up last 10 bytes\r
64 \r
65   private JpegObj jpegObj;\r
66   private Huffman huf;\r
67   private DCT dct;\r
68   protected int defaultQuality = 100;\r
69   private String applicationTag;\r
70 \r
71   public JpgEncoder() {\r
72 \r
73   }\r
74 \r
75   @Override\r
76   protected void setParams(Map<String, Object> params) {\r
77     if (quality <= 0)\r
78       quality = (params.containsKey("qualityJPG") ? ((Integer) params.get("qualityJPG")).intValue() : defaultQuality);\r
79     jpegObj = new JpegObj();\r
80     jpegObj.comment = (String) params.get("comment");\r
81     applicationTag = (String) params.get("jpgAppTag");\r
82   }\r
83 \r
84   @Override\r
85   protected void generate() throws IOException {\r
86     jpegObj.imageWidth = width;\r
87     jpegObj.imageHeight = height;\r
88     dct = new DCT(quality);\r
89     huf = new Huffman(width, height);\r
90     if (jpegObj == null)\r
91       return;\r
92     jpegObj.getYCCArray(pixels);\r
93     String longState = writeHeaders(jpegObj, dct);\r
94     writeCompressedData(jpegObj, dct, huf);\r
95     writeMarker(eoi);\r
96     if (longState != null) {\r
97       byte[] b = longState.getBytes();\r
98       out.write(b, 0, b.length);\r
99     }\r
100   }\r
101 \r
102   private void writeCompressedData(JpegObj jpegObj, DCT dct, Huffman huf) {\r
103     int i, j, r, c, a, b;\r
104     int comp, xpos, ypos, xblockoffset, yblockoffset;\r
105     float inputArray[][];\r
106     float dctArray1[][] = new float[8][8];\r
107     double dctArray2[][] = new double[8][8];\r
108     int dctArray3[] = new int[8 * 8];\r
109 \r
110     /*\r
111      * This method controls the compression of the image.\r
112      * Starting at the upper left of the image, it compresses 8x8 blocks\r
113      * of data until the entire image has been compressed.\r
114      */\r
115 \r
116     int lastDCvalue[] = new int[jpegObj.numberOfComponents];\r
117     //int zeroArray[] = new int[64]; // initialized to hold all zeros\r
118     //int Width = 0, Height = 0;\r
119     //int nothing = 0, not;\r
120     int minBlockWidth, minBlockHeight;\r
121     // This initial setting of MinBlockWidth and MinBlockHeight is done to\r
122     // ensure they start with values larger than will actually be the case.\r
123     minBlockWidth = ((huf.imageWidth % 8 != 0) ? (int) (Math\r
124         .floor(huf.imageWidth / 8.0) + 1) * 8 : huf.imageWidth);\r
125     minBlockHeight = ((huf.imageHeight % 8 != 0) ? (int) (Math\r
126         .floor(huf.imageHeight / 8.0) + 1) * 8 : huf.imageHeight);\r
127     for (comp = 0; comp < jpegObj.numberOfComponents; comp++) {\r
128       minBlockWidth = Math.min(minBlockWidth, jpegObj.blockWidth[comp]);\r
129       minBlockHeight = Math.min(minBlockHeight, jpegObj.blockHeight[comp]);\r
130     }\r
131     xpos = 0;\r
132     for (r = 0; r < minBlockHeight; r++) {\r
133       for (c = 0; c < minBlockWidth; c++) {\r
134         xpos = c * 8;\r
135         ypos = r * 8;\r
136         for (comp = 0; comp < jpegObj.numberOfComponents; comp++) {\r
137           //Width = JpegObj.BlockWidth[comp];\r
138           //Height = JpegObj.BlockHeight[comp];\r
139           inputArray = jpegObj.components[comp];\r
140           int vsampF = jpegObj.vsampFactor[comp];\r
141           int hsampF = jpegObj.hsampFactor[comp];\r
142           int qNumber = jpegObj.qtableNumber[comp];\r
143           int dcNumber = jpegObj.dctableNumber[comp];\r
144           int acNumber = jpegObj.actableNumber[comp];\r
145 \r
146           for (i = 0; i < vsampF; i++) {\r
147             for (j = 0; j < hsampF; j++) {\r
148               xblockoffset = j * 8;\r
149               yblockoffset = i * 8;\r
150               for (a = 0; a < 8; a++) {\r
151                 for (b = 0; b < 8; b++) {\r
152 \r
153                   // I believe this is where the dirty line at the bottom of\r
154                   // the image is coming from.\r
155                   // I need to do a check here to make sure I'm not reading past\r
156                   // image data.\r
157                   // This seems to not be a big issue right now. (04/04/98)\r
158 \r
159                   dctArray1[a][b] = inputArray[ypos + yblockoffset + a][xpos\r
160                       + xblockoffset + b];\r
161                 }\r
162               }\r
163               // The following code commented out because on some images this technique\r
164               // results in poor right and bottom borders.\r
165               // if ((!JpegObj.lastColumnIsDummy[comp] || c < Width - 1) &&\r
166               //       (!JpegObj.lastRowIsDummy[comp] || r < Height - 1)) {\r
167               dctArray2 = DCT.forwardDCT(dctArray1);\r
168               dctArray3 = DCT.quantizeBlock(dctArray2, dct.divisors[qNumber]);\r
169               // }\r
170               // else {\r
171               //   zeroArray[0] = dctArray3[0];\r
172               //   zeroArray[0] = lastDCvalue[comp];\r
173               //   dctArray3 = zeroArray;\r
174               // }\r
175               huf.HuffmanBlockEncoder(out, dctArray3, lastDCvalue[comp],\r
176                   dcNumber, acNumber);\r
177               lastDCvalue[comp] = dctArray3[0];\r
178             }\r
179           }\r
180         }\r
181       }\r
182     }\r
183     huf.flushBuffer(out);\r
184   }\r
185 \r
186   private static byte[] eoi = { (byte) 0xFF, (byte) 0xD9 };\r
187 \r
188   private static byte[] jfif = new byte[] {\r
189   /* JFIF[0] =*/(byte) 0xff,\r
190   /* JFIF[1] =*/(byte) 0xe0,\r
191   /* JFIF[2] =*/0,\r
192   /* JFIF[3] =*/16,\r
193   /* JFIF[4] =*/(byte) 0x4a, //'J'\r
194       /* JFIF[5] =*/(byte) 0x46, //'F'\r
195       /* JFIF[6] =*/(byte) 0x49, //'I'\r
196       /* JFIF[7] =*/(byte) 0x46, //'F'\r
197       /* JFIF[8] =*/0,\r
198       /* JFIF[9] =*/1,\r
199       /* JFIF[10] =*/0,\r
200       /* JFIF[11] =*/0,\r
201       /* JFIF[12] =*/0,\r
202       /* JFIF[13] =*/1,\r
203       /* JFIF[14] =*/0,\r
204       /* JFIF[15] =*/1,\r
205       /* JFIF[16] =*/0,\r
206       /* JFIF[17] =*/0 };\r
207 \r
208   private static byte[] soi = { (byte) 0xFF, (byte) 0xD8 };\r
209 \r
210   private String writeHeaders(JpegObj jpegObj, DCT dct) {\r
211     int i, j, index, offset;\r
212     int tempArray[];\r
213 \r
214     // the SOI marker\r
215     writeMarker(soi);\r
216 \r
217     // The order of the following headers is quite inconsequential.\r
218     // the JFIF header\r
219     writeArray(jfif);\r
220 \r
221     // Comment Header\r
222     String comment = null;\r
223     if (jpegObj.comment.length() > 0)\r
224       writeString(jpegObj.comment, (byte) 0xE1); // App data 1\r
225     writeString(\r
226         "JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech.\n\n",\r
227         (byte) 0xFE);\r
228 \r
229     // The DQT header\r
230     // 0 is the luminance index and 1 is the chrominance index\r
231     byte dqt[] = new byte[134];\r
232     dqt[0] = (byte) 0xFF;\r
233     dqt[1] = (byte) 0xDB;\r
234     dqt[2] = 0;\r
235     dqt[3] = (byte) 132;\r
236     offset = 4;\r
237     for (i = 0; i < 2; i++) {\r
238       dqt[offset++] = (byte) ((0 << 4) + i);\r
239       tempArray = dct.quantum[i];\r
240       for (j = 0; j < 64; j++) {\r
241         dqt[offset++] = (byte) tempArray[Huffman.jpegNaturalOrder[j]];\r
242       }\r
243     }\r
244     writeArray(dqt);\r
245 \r
246     // Start of Frame Header\r
247     byte sof[] = new byte[19];\r
248     sof[0] = (byte) 0xFF;\r
249     sof[1] = (byte) 0xC0;\r
250     sof[2] = 0;\r
251     sof[3] = 17;\r
252     sof[4] = (byte) jpegObj.precision;\r
253     sof[5] = (byte) ((jpegObj.imageHeight >> 8) & 0xFF);\r
254     sof[6] = (byte) ((jpegObj.imageHeight) & 0xFF);\r
255     sof[7] = (byte) ((jpegObj.imageWidth >> 8) & 0xFF);\r
256     sof[8] = (byte) ((jpegObj.imageWidth) & 0xFF);\r
257     sof[9] = (byte) jpegObj.numberOfComponents;\r
258     index = 10;\r
259     for (i = 0; i < sof[9]; i++) {\r
260       sof[index++] = (byte) jpegObj.compID[i];\r
261       sof[index++] = (byte) ((jpegObj.hsampFactor[i] << 4) + jpegObj.vsampFactor[i]);\r
262       sof[index++] = (byte) jpegObj.qtableNumber[i];\r
263     }\r
264     writeArray(sof);\r
265 \r
266     WriteDHTHeader(Huffman.bitsDCluminance, Huffman.valDCluminance);\r
267     WriteDHTHeader(Huffman.bitsACluminance, Huffman.valACluminance);\r
268     WriteDHTHeader(Huffman.bitsDCchrominance, Huffman.valDCchrominance);\r
269     WriteDHTHeader(Huffman.bitsACchrominance, Huffman.valACchrominance);\r
270 \r
271     // Start of Scan Header\r
272     byte sos[] = new byte[14];\r
273     sos[0] = (byte) 0xFF;\r
274     sos[1] = (byte) 0xDA;\r
275     sos[2] = 0;\r
276     sos[3] = 12;\r
277     sos[4] = (byte) jpegObj.numberOfComponents;\r
278     index = 5;\r
279     for (i = 0; i < sos[4]; i++) {\r
280       sos[index++] = (byte) jpegObj.compID[i];\r
281       sos[index++] = (byte) ((jpegObj.dctableNumber[i] << 4) + jpegObj.actableNumber[i]);\r
282     }\r
283     sos[index++] = (byte) jpegObj.ss;\r
284     sos[index++] = (byte) jpegObj.se;\r
285     sos[index++] = (byte) ((jpegObj.ah << 4) + jpegObj.al);\r
286     writeArray(sos);\r
287     return comment;\r
288   }\r
289 \r
290   private void writeString(String s, byte id) {\r
291     int len = s.length();\r
292     int i0 = 0;\r
293     String suffix = applicationTag;\r
294     while (i0 < len) {\r
295       int nBytes = len - i0;\r
296       if (nBytes > CONTINUE_MAX_BUFFER) {\r
297         nBytes = CONTINUE_MAX;\r
298         // but break only at line breaks\r
299         int pt = s.lastIndexOf('\n', i0 + nBytes);\r
300         if (pt > i0 + 1)\r
301           nBytes = pt - i0;\r
302       }\r
303       if (i0 + nBytes == len)\r
304         suffix = "";\r
305       writeTag(nBytes + suffix.length(), id);\r
306       writeArray(s.substring(i0, i0 + nBytes).getBytes());\r
307       if (suffix.length() > 0)\r
308         writeArray(suffix.getBytes());\r
309       i0 += nBytes;\r
310     }\r
311   }\r
312 \r
313   private void writeTag(int length, byte id) {\r
314     length += 2;\r
315     byte com[] = new byte[4];\r
316     com[0] = (byte) 0xFF;\r
317     com[1] = id;\r
318     com[2] = (byte) ((length >> 8) & 0xFF);\r
319     com[3] = (byte) (length & 0xFF);\r
320     writeArray(com);\r
321   }\r
322 \r
323   void WriteDHTHeader(int[] bits, int[] val) {\r
324     // hansonr@stolaf.edu: simplified code.\r
325     byte[] dht;\r
326     int bytes = 0;\r
327     for (int j = 1; j < 17; j++)\r
328       bytes += bits[j];\r
329     dht = new byte[21 + bytes];\r
330     dht[0] = (byte) 0xFF;\r
331     dht[1] = (byte) 0xC4;\r
332     int index = 4;\r
333     for (int j = 0; j < 17; j++)\r
334       dht[index++] = (byte) bits[j];\r
335     for (int j = 0; j < bytes; j++)\r
336       dht[index++] = (byte) val[j];\r
337     dht[2] = (byte) (((index - 2) >> 8) & 0xFF);\r
338     dht[3] = (byte) ((index - 2) & 0xFF);\r
339     writeArray(dht);\r
340   }\r
341 \r
342   void writeMarker(byte[] data) {\r
343     out.write(data, 0, 2);\r
344   }\r
345 \r
346   void writeArray(byte[] data) {\r
347     out.write(data, 0, data.length);\r
348   }\r
349 \r
350 }\r
351 \r
352 // This class incorporates quality scaling as implemented in the JPEG-6a\r
353 // library.\r
354 \r
355 /*\r
356  * DCT - A Java implementation of the Discreet Cosine Transform\r
357  */\r
358 \r
359 class DCT {\r
360 \r
361   /**\r
362    * DCT Block Size - default 8\r
363    */\r
364   private final static int N = 8;\r
365   private final static int NN = N * N;\r
366 \r
367   /**\r
368    * Image Quality (0-100) - default 80 (good image / good compression)\r
369    */\r
370   //public int QUALITY = 80;\r
371 \r
372   int[][] quantum = AU.newInt2(2);\r
373   double[][] divisors = AU.newDouble2(2);\r
374 \r
375   /**\r
376    * Quantitization Matrix for luminace.\r
377    */\r
378   private int quantum_luminance[] = new int[NN];\r
379   private double DivisorsLuminance[] = new double[NN];\r
380 \r
381   /**\r
382    * Quantitization Matrix for chrominance.\r
383    */\r
384   private int quantum_chrominance[] = new int[NN];\r
385   private double DivisorsChrominance[] = new double[NN];\r
386 \r
387   /**\r
388    * Constructs a new DCT object. Initializes the cosine transform matrix these\r
389    * are used when computing the DCT and it's inverse. This also initializes the\r
390    * run length counters and the ZigZag sequence. Note that the image quality\r
391    * can be worse than 25 however the image will be extemely pixelated, usually\r
392    * to a block size of N.\r
393    * \r
394    * @param quality\r
395    *        The quality of the image (0 worst - 100 best)\r
396    * \r
397    */\r
398   DCT(int quality) {\r
399     initMatrix(quality);\r
400   }\r
401 \r
402   /*\r
403    * This method sets up the quantization matrix for luminance and\r
404    * chrominance using the Quality parameter.\r
405    */\r
406   private void initMatrix(int quality) {\r
407     // converting quality setting to that specified in the jpeg_quality_scaling\r
408     // method in the IJG Jpeg-6a C libraries\r
409 \r
410     quality = (quality < 1 ? 1 : quality > 100 ? 100 : quality);\r
411     quality = (quality < 50 ? 5000 / quality : 200 - quality * 2);\r
412 \r
413     // Creating the luminance matrix\r
414 \r
415     quantum_luminance[0] = 16;\r
416     quantum_luminance[1] = 11;\r
417     quantum_luminance[2] = 10;\r
418     quantum_luminance[3] = 16;\r
419     quantum_luminance[4] = 24;\r
420     quantum_luminance[5] = 40;\r
421     quantum_luminance[6] = 51;\r
422     quantum_luminance[7] = 61;\r
423     quantum_luminance[8] = 12;\r
424     quantum_luminance[9] = 12;\r
425     quantum_luminance[10] = 14;\r
426     quantum_luminance[11] = 19;\r
427     quantum_luminance[12] = 26;\r
428     quantum_luminance[13] = 58;\r
429     quantum_luminance[14] = 60;\r
430     quantum_luminance[15] = 55;\r
431     quantum_luminance[16] = 14;\r
432     quantum_luminance[17] = 13;\r
433     quantum_luminance[18] = 16;\r
434     quantum_luminance[19] = 24;\r
435     quantum_luminance[20] = 40;\r
436     quantum_luminance[21] = 57;\r
437     quantum_luminance[22] = 69;\r
438     quantum_luminance[23] = 56;\r
439     quantum_luminance[24] = 14;\r
440     quantum_luminance[25] = 17;\r
441     quantum_luminance[26] = 22;\r
442     quantum_luminance[27] = 29;\r
443     quantum_luminance[28] = 51;\r
444     quantum_luminance[29] = 87;\r
445     quantum_luminance[30] = 80;\r
446     quantum_luminance[31] = 62;\r
447     quantum_luminance[32] = 18;\r
448     quantum_luminance[33] = 22;\r
449     quantum_luminance[34] = 37;\r
450     quantum_luminance[35] = 56;\r
451     quantum_luminance[36] = 68;\r
452     quantum_luminance[37] = 109;\r
453     quantum_luminance[38] = 103;\r
454     quantum_luminance[39] = 77;\r
455     quantum_luminance[40] = 24;\r
456     quantum_luminance[41] = 35;\r
457     quantum_luminance[42] = 55;\r
458     quantum_luminance[43] = 64;\r
459     quantum_luminance[44] = 81;\r
460     quantum_luminance[45] = 104;\r
461     quantum_luminance[46] = 113;\r
462     quantum_luminance[47] = 92;\r
463     quantum_luminance[48] = 49;\r
464     quantum_luminance[49] = 64;\r
465     quantum_luminance[50] = 78;\r
466     quantum_luminance[51] = 87;\r
467     quantum_luminance[52] = 103;\r
468     quantum_luminance[53] = 121;\r
469     quantum_luminance[54] = 120;\r
470     quantum_luminance[55] = 101;\r
471     quantum_luminance[56] = 72;\r
472     quantum_luminance[57] = 92;\r
473     quantum_luminance[58] = 95;\r
474     quantum_luminance[59] = 98;\r
475     quantum_luminance[60] = 112;\r
476     quantum_luminance[61] = 100;\r
477     quantum_luminance[62] = 103;\r
478     quantum_luminance[63] = 99;\r
479 \r
480     AANscale(DivisorsLuminance, quantum_luminance, quality);\r
481 \r
482     // Creating the chrominance matrix\r
483 \r
484     for (int i = 4; i < 64; i++)\r
485       quantum_chrominance[i] = 99;\r
486 \r
487     quantum_chrominance[0] = 17;\r
488     quantum_chrominance[1] = 18;\r
489     quantum_chrominance[2] = 24;\r
490     quantum_chrominance[3] = 47;\r
491 \r
492     quantum_chrominance[8] = 18;\r
493     quantum_chrominance[9] = 21;\r
494     quantum_chrominance[10] = 26;\r
495     quantum_chrominance[11] = 66;\r
496 \r
497     quantum_chrominance[16] = 24;\r
498     quantum_chrominance[17] = 26;\r
499     quantum_chrominance[18] = 56;\r
500 \r
501     quantum_chrominance[24] = 47;\r
502     quantum_chrominance[25] = 66;\r
503 \r
504     AANscale(DivisorsChrominance, quantum_chrominance, quality);\r
505 \r
506     // quantum and Divisors are objects used to hold the appropriate matices\r
507 \r
508     quantum[0] = quantum_luminance;\r
509     quantum[1] = quantum_chrominance;\r
510 \r
511     divisors[0] = DivisorsLuminance;\r
512     divisors[1] = DivisorsChrominance;\r
513 \r
514   }\r
515 \r
516   private final static double[] AANscaleFactor = { 1.0, 1.387039845,\r
517       1.306562965, 1.175875602, 1.0, 0.785694958, 0.541196100, 0.275899379 };\r
518 \r
519   static private void AANscale(double[] divisors, int[] values, int quality) {\r
520 \r
521     for (int j = 0; j < 64; j++) {\r
522       int temp = (values[j] * quality + 50) / 100;\r
523       values[j] = (temp < 1 ? 1 : temp > 255 ? 255 : temp);\r
524     }\r
525 \r
526     for (int i = 0, index = 0; i < 8; i++)\r
527       for (int j = 0; j < 8; j++, index++)\r
528         // The divisors for the LL&M method (the slow integer method used in\r
529         // jpeg 6a library).  This method is currently (04/04/98) incompletely\r
530         // implemented.\r
531         // DivisorsLuminance[index] = ((double) quantum_luminance[index]) << 3;\r
532         // The divisors for the AAN method (the float method used in jpeg 6a library.\r
533         divisors[index] = (0.125 / (values[index] * AANscaleFactor[i] * AANscaleFactor[j]));\r
534   }\r
535 \r
536   /*\r
537    * This method preforms forward DCT on a block of image data using\r
538    * the literal method specified for a 2-D Discrete Cosine Transform.\r
539    * It is included as a curiosity and can give you an idea of the\r
540    * difference in the compression result (the resulting image quality)\r
541    * by comparing its output to the output of the AAN method below.\r
542    * It is ridiculously inefficient.\r
543    */\r
544 \r
545   // For now the final output is unusable.  The associated quantization step\r
546   // needs some tweaking.  If you get this part working, please let me know.\r
547   /*\r
548     public double[][] forwardDCTExtreme(float input[][])\r
549     {\r
550       double output[][] = new double[N][N];\r
551       int v, u, x, y;\r
552       for (v = 0; v < 8; v++) {\r
553         for (u = 0; u < 8; u++) {\r
554           for (x = 0; x < 8; x++) {\r
555             for (y = 0; y < 8; y++) {\r
556               output[v][u] += input[x][y] * \r
557                   Math.cos(((double)(2*x + 1)*(double)u*Math.PI)/16)*\r
558                   Math.cos(((double)(2*y + 1)*(double)v*Math.PI)/16);\r
559             }\r
560           }\r
561           output[v][u] *= (0.25)*((u == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0)*((v == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0);\r
562         }\r
563       }\r
564       return output;\r
565     }\r
566     \r
567   */\r
568   /*\r
569    * This method preforms a DCT on a block of image data using the AAN\r
570    * method as implemented in the IJG Jpeg-6a library.\r
571    */\r
572   static double[][] forwardDCT(float input[][]) {\r
573     double output[][] = new double[N][N];\r
574     double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;\r
575     double tmp10, tmp11, tmp12, tmp13;\r
576     double z1, z2, z3, z4, z5, z11, z13;\r
577     // Subtracts 128 from the input values\r
578     for (int i = 0; i < 8; i++)\r
579       for (int j = 0; j < 8; j++)\r
580         output[i][j] = (input[i][j] - 128.0);\r
581     // input[i][j] -= 128;\r
582 \r
583     for (int i = 0; i < 8; i++) {\r
584       tmp0 = output[i][0] + output[i][7];\r
585       tmp7 = output[i][0] - output[i][7];\r
586       tmp1 = output[i][1] + output[i][6];\r
587       tmp6 = output[i][1] - output[i][6];\r
588       tmp2 = output[i][2] + output[i][5];\r
589       tmp5 = output[i][2] - output[i][5];\r
590       tmp3 = output[i][3] + output[i][4];\r
591       tmp4 = output[i][3] - output[i][4];\r
592 \r
593       tmp10 = tmp0 + tmp3;\r
594       tmp13 = tmp0 - tmp3;\r
595       tmp11 = tmp1 + tmp2;\r
596       tmp12 = tmp1 - tmp2;\r
597 \r
598       output[i][0] = tmp10 + tmp11;\r
599       output[i][4] = tmp10 - tmp11;\r
600 \r
601       z1 = (tmp12 + tmp13) * 0.707106781;\r
602       output[i][2] = tmp13 + z1;\r
603       output[i][6] = tmp13 - z1;\r
604 \r
605       tmp10 = tmp4 + tmp5;\r
606       tmp11 = tmp5 + tmp6;\r
607       tmp12 = tmp6 + tmp7;\r
608 \r
609       z5 = (tmp10 - tmp12) * 0.382683433;\r
610       z2 = 0.541196100 * tmp10 + z5;\r
611       z4 = 1.306562965 * tmp12 + z5;\r
612       z3 = tmp11 * 0.707106781;\r
613 \r
614       z11 = tmp7 + z3;\r
615       z13 = tmp7 - z3;\r
616 \r
617       output[i][5] = z13 + z2;\r
618       output[i][3] = z13 - z2;\r
619       output[i][1] = z11 + z4;\r
620       output[i][7] = z11 - z4;\r
621     }\r
622 \r
623     for (int i = 0; i < 8; i++) {\r
624       tmp0 = output[0][i] + output[7][i];\r
625       tmp7 = output[0][i] - output[7][i];\r
626       tmp1 = output[1][i] + output[6][i];\r
627       tmp6 = output[1][i] - output[6][i];\r
628       tmp2 = output[2][i] + output[5][i];\r
629       tmp5 = output[2][i] - output[5][i];\r
630       tmp3 = output[3][i] + output[4][i];\r
631       tmp4 = output[3][i] - output[4][i];\r
632 \r
633       tmp10 = tmp0 + tmp3;\r
634       tmp13 = tmp0 - tmp3;\r
635       tmp11 = tmp1 + tmp2;\r
636       tmp12 = tmp1 - tmp2;\r
637 \r
638       output[0][i] = tmp10 + tmp11;\r
639       output[4][i] = tmp10 - tmp11;\r
640 \r
641       z1 = (tmp12 + tmp13) * 0.707106781;\r
642       output[2][i] = tmp13 + z1;\r
643       output[6][i] = tmp13 - z1;\r
644 \r
645       tmp10 = tmp4 + tmp5;\r
646       tmp11 = tmp5 + tmp6;\r
647       tmp12 = tmp6 + tmp7;\r
648 \r
649       z5 = (tmp10 - tmp12) * 0.382683433;\r
650       z2 = 0.541196100 * tmp10 + z5;\r
651       z4 = 1.306562965 * tmp12 + z5;\r
652       z3 = tmp11 * 0.707106781;\r
653 \r
654       z11 = tmp7 + z3;\r
655       z13 = tmp7 - z3;\r
656 \r
657       output[5][i] = z13 + z2;\r
658       output[3][i] = z13 - z2;\r
659       output[1][i] = z11 + z4;\r
660       output[7][i] = z11 - z4;\r
661     }\r
662 \r
663     return output;\r
664   }\r
665 \r
666   /*\r
667    * This method quantitizes data and rounds it to the nearest integer.\r
668    */\r
669   static int[] quantizeBlock(double inputData[][], double[] divisorsCode) {\r
670     int outputData[] = new int[NN];\r
671     for (int i = 0, index = 0; i < 8; i++)\r
672       for (int j = 0; j < 8; j++, index++)\r
673         // The second line results in significantly better compression.\r
674         outputData[index] = (int) (Math.round(inputData[i][j]\r
675             * divisorsCode[index]));\r
676     //                        outputData[index] = (int)(((inputData[i][j] * (((double[]) (Divisors[code]))[index])) + 16384.5) -16384);\r
677     return outputData;\r
678   }\r
679 \r
680   /*\r
681    * This is the method for quantizing a block DCT'ed with forwardDCTExtreme\r
682    * This method quantitizes data and rounds it to the nearest integer.\r
683    */\r
684 \r
685   /*\r
686 \r
687     public double[][] forwardDCTExtreme(float input[][])\r
688     {\r
689       double output[][] = new double[N][N];\r
690       int v, u, x, y;\r
691       for (v = 0; v < 8; v++) {\r
692         for (u = 0; u < 8; u++) {\r
693           for (x = 0; x < 8; x++) {\r
694             for (y = 0; y < 8; y++) {\r
695               output[v][u] += input[x][y] * \r
696                   Math.cos(((double)(2*x + 1)*(double)u*Math.PI)/16)*\r
697                   Math.cos(((double)(2*y + 1)*(double)v*Math.PI)/16);\r
698             }\r
699           }\r
700           output[v][u] *= (0.25)*((u == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0)*((v == 0) ? (1.0/Math.sqrt(2)) : (double) 1.0);\r
701         }\r
702       }\r
703       return output;\r
704     }\r
705 \r
706    */\r
707   /*\r
708     public int[] quantizeBlockExtreme(double inputData[][], int code)\r
709     {\r
710       int outputData[] = new int[NN];\r
711       int i, j;\r
712       int index;\r
713       index = 0;\r
714       for (i = 0; i < 8; i++) {\r
715         for (j = 0; j < 8; j++) {\r
716           outputData[index] = (int)(Math.round(inputData[i][j] / (((int[]) (quantum[code]))[index])));\r
717           index++;\r
718         }\r
719       }\r
720       \r
721       return outputData;\r
722     }\r
723   */\r
724 }\r
725 \r
726 // This class was modified by James R. Weeks on 3/27/98.\r
727 // It now incorporates Huffman table derivation as in the C jpeg library\r
728 // from the IJG, Jpeg-6a.\r
729 \r
730 class Huffman {\r
731   private int bufferPutBits, bufferPutBuffer;\r
732   int imageHeight;\r
733   int imageWidth;\r
734   private int dc_matrix0[][];\r
735   private int ac_matrix0[][];\r
736   private int dc_matrix1[][];\r
737   private int ac_matrix1[][];\r
738   private int[][][] dc_matrix;\r
739   private int[][][] ac_matrix;\r
740   //private int code;\r
741   int numOfDCTables;\r
742   int numOfACTables;\r
743   final static int[] bitsDCluminance = { 0x00, 0, 1, 5, 1, 1, 1, 1, 1, 1, 0, 0,\r
744       0, 0, 0, 0, 0 };\r
745   final static int[] valDCluminance = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };\r
746   final static int[] bitsDCchrominance = { 0x01, 0, 3, 1, 1, 1, 1, 1, 1, 1, 1,\r
747       1, 0, 0, 0, 0, 0 };\r
748   final static int[] valDCchrominance = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11 };\r
749   final static int[] bitsACluminance = { 0x10, 0, 2, 1, 3, 3, 2, 4, 3, 5, 5, 4,\r
750       4, 0, 0, 1, 0x7d };\r
751   final static int[] valACluminance = { 0x01, 0x02, 0x03, 0x00, 0x04, 0x11,\r
752       0x05, 0x12, 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07, 0x22, 0x71,\r
753       0x14, 0x32, 0x81, 0x91, 0xa1, 0x08, 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52,\r
754       0xd1, 0xf0, 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16, 0x17, 0x18,\r
755       0x19, 0x1a, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37,\r
756       0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x53,\r
757       0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67,\r
758       0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x83,\r
759       0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,\r
760       0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9,\r
761       0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,\r
762       0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6,\r
763       0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8,\r
764       0xe9, 0xea, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };\r
765   final static int[] bitsACchrominance = { 0x11, 0, 2, 1, 2, 4, 4, 3, 4, 7, 5,\r
766       4, 4, 0, 1, 2, 0x77 };\r
767   final static int[] valACchrominance = { 0x00, 0x01, 0x02, 0x03, 0x11, 0x04,\r
768       0x05, 0x21, 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71, 0x13, 0x22,\r
769       0x32, 0x81, 0x08, 0x14, 0x42, 0x91, 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33,\r
770       0x52, 0xf0, 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34, 0xe1, 0x25,\r
771       0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36,\r
772       0x37, 0x38, 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a,\r
773       0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66,\r
774       0x67, 0x68, 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a,\r
775       0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94,\r
776       0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,\r
777       0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba,\r
778       0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,\r
779       0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,\r
780       0xe8, 0xe9, 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa };\r
781 \r
782   /*\r
783    * jpegNaturalOrder[i] is the natural-order position of the i'th element\r
784    * of zigzag order.\r
785    */\r
786   final static int[] jpegNaturalOrder = { 0, 1, 8, 16, 9, 2, 3, 10, 17, 24, 32,\r
787       25, 18, 11, 4, 5, 12, 19, 26, 33, 40, 48, 41, 34, 27, 20, 13, 6, 7, 14,\r
788       21, 28, 35, 42, 49, 56, 57, 50, 43, 36, 29, 22, 15, 23, 30, 37, 44, 51,\r
789       58, 59, 52, 45, 38, 31, 39, 46, 53, 60, 61, 54, 47, 55, 62, 63, };\r
790 \r
791   Huffman(int width, int height) {\r
792     initHuf();\r
793     imageWidth = width;\r
794     imageHeight = height;\r
795 \r
796   }\r
797 \r
798   /**\r
799    * HuffmanBlockEncoder run length encodes and Huffman encodes the quantized\r
800    * data.\r
801    * \r
802    * @param out\r
803    * @param zigzag\r
804    * @param prec\r
805    * @param dcCode\r
806    * @param acCode\r
807    **/\r
808 \r
809   void HuffmanBlockEncoder(OC out, int zigzag[], int prec,\r
810                            int dcCode, int acCode) {\r
811     int temp, temp2, nbits, k, r, i;\r
812 \r
813     numOfDCTables = 2;\r
814     numOfACTables = 2;\r
815 \r
816     int[][] matrixDC = dc_matrix[dcCode];\r
817     int[][] matrixAC = ac_matrix[acCode];\r
818 \r
819     // The DC portion\r
820 \r
821     temp = temp2 = zigzag[0] - prec;\r
822     if (temp < 0) {\r
823       temp = -temp;\r
824       temp2--;\r
825     }\r
826     nbits = 0;\r
827     while (temp != 0) {\r
828       nbits++;\r
829       temp >>= 1;\r
830     }\r
831     //        if (nbits > 11) nbits = 11;\r
832     bufferIt(out, matrixDC[nbits][0], matrixDC[nbits][1]);\r
833     // The arguments in bufferIt are code and size.\r
834     if (nbits != 0) {\r
835       bufferIt(out, temp2, nbits);\r
836     }\r
837 \r
838     // The AC portion\r
839 \r
840     r = 0;\r
841 \r
842     for (k = 1; k < 64; k++) {\r
843       if ((temp = zigzag[jpegNaturalOrder[k]]) == 0) {\r
844         r++;\r
845       } else {\r
846         while (r > 15) {\r
847           bufferIt(out, matrixAC[0xF0][0], matrixAC[0xF0][1]);\r
848           r -= 16;\r
849         }\r
850         temp2 = temp;\r
851         if (temp < 0) {\r
852           temp = -temp;\r
853           temp2--;\r
854         }\r
855         nbits = 1;\r
856         while ((temp >>= 1) != 0) {\r
857           nbits++;\r
858         }\r
859         i = (r << 4) + nbits;\r
860         bufferIt(out, matrixAC[i][0], matrixAC[i][1]);\r
861         bufferIt(out, temp2, nbits);\r
862 \r
863         r = 0;\r
864       }\r
865     }\r
866 \r
867     if (r > 0) {\r
868       bufferIt(out, matrixAC[0][0], matrixAC[0][1]);\r
869     }\r
870 \r
871   }\r
872 \r
873   // Uses an integer long (32 bits) buffer to store the Huffman encoded bits\r
874   // and sends them to out by the byte.\r
875 \r
876   void bufferIt(OC out, int code, int size) {\r
877     int putBuffer = code;\r
878     int putBits = bufferPutBits;\r
879 \r
880     putBuffer &= (1 << size) - 1;\r
881     putBits += size;\r
882     putBuffer <<= 24 - putBits;\r
883     putBuffer |= bufferPutBuffer;\r
884 \r
885     while (putBits >= 8) {\r
886       int c = ((putBuffer >> 16) & 0xFF);\r
887       out.writeByteAsInt(c);\r
888       if (c == 0xFF) {\r
889         out.writeByteAsInt(0);\r
890       }\r
891       putBuffer <<= 8;\r
892       putBits -= 8;\r
893     }\r
894     bufferPutBuffer = putBuffer;\r
895     bufferPutBits = putBits;\r
896 \r
897   }\r
898 \r
899   void flushBuffer(OC out) {\r
900     int putBuffer = bufferPutBuffer;\r
901     int putBits = bufferPutBits;\r
902     while (putBits >= 8) {\r
903       int c = ((putBuffer >> 16) & 0xFF);\r
904       out.writeByteAsInt(c);\r
905       if (c == 0xFF) {\r
906         out.writeByteAsInt(0);\r
907       }\r
908       putBuffer <<= 8;\r
909       putBits -= 8;\r
910     }\r
911     if (putBits > 0) {\r
912       int c = ((putBuffer >> 16) & 0xFF);\r
913       out.writeByteAsInt(c);\r
914     }\r
915   }\r
916 \r
917   /*\r
918    * Initialisation of the Huffman codes for Luminance and Chrominance.\r
919    * This code results in the same tables created in the IJG Jpeg-6a\r
920    * library.\r
921    */\r
922 \r
923   private void initHuf() {\r
924     dc_matrix0 = new int[12][2];\r
925     dc_matrix1 = new int[12][2];\r
926     ac_matrix0 = new int[255][2];\r
927     ac_matrix1 = new int[255][2];\r
928     dc_matrix = AU.newInt3(2, -1);\r
929     ac_matrix = AU.newInt3(2, -1);\r
930     int p, l, i, lastp, si, code;\r
931     int[] huffsize = new int[257];\r
932     int[] huffcode = new int[257];\r
933 \r
934     /*\r
935      * init of the DC values for the chrominance\r
936      * [][0] is the code   [][1] is the number of bit\r
937      */\r
938 \r
939     p = 0;\r
940     for (l = 1; l <= 16; l++) {\r
941       //      for (i = 1; i <= bitsDCchrominance[l]; i++)\r
942       for (i = bitsDCchrominance[l]; --i >= 0;) {\r
943         huffsize[p++] = l; //that's an "el", not a "one"\r
944       }\r
945     }\r
946     huffsize[p] = 0;\r
947     lastp = p;\r
948 \r
949     code = 0;\r
950     si = huffsize[0];\r
951     p = 0;\r
952     while (huffsize[p] != 0) {\r
953       while (huffsize[p] == si) {\r
954         huffcode[p++] = code;\r
955         code++;\r
956       }\r
957       code <<= 1;\r
958       si++;\r
959     }\r
960 \r
961     for (p = 0; p < lastp; p++) {\r
962       dc_matrix1[valDCchrominance[p]][0] = huffcode[p];\r
963       dc_matrix1[valDCchrominance[p]][1] = huffsize[p];\r
964     }\r
965 \r
966     /*\r
967      * Init of the AC huffman code for the chrominance\r
968      * matrix [][][0] is the code & matrix[][][1] is the number of bit needed\r
969      */\r
970 \r
971     p = 0;\r
972     for (l = 1; l <= 16; l++) {\r
973       for (i = bitsACchrominance[l]; --i >= 0;)\r
974       //      for (i = 1; i <= bitsACchrominance[l]; i++)\r
975       {\r
976         huffsize[p++] = l;\r
977       }\r
978     }\r
979     huffsize[p] = 0;\r
980     lastp = p;\r
981 \r
982     code = 0;\r
983     si = huffsize[0];\r
984     p = 0;\r
985     while (huffsize[p] != 0) {\r
986       while (huffsize[p] == si) {\r
987         huffcode[p++] = code;\r
988         code++;\r
989       }\r
990       code <<= 1;\r
991       si++;\r
992     }\r
993 \r
994     for (p = 0; p < lastp; p++) {\r
995       ac_matrix1[valACchrominance[p]][0] = huffcode[p];\r
996       ac_matrix1[valACchrominance[p]][1] = huffsize[p];\r
997     }\r
998 \r
999     /*\r
1000      * init of the DC values for the luminance\r
1001      * [][0] is the code   [][1] is the number of bit\r
1002      */\r
1003     p = 0;\r
1004     for (l = 1; l <= 16; l++) {\r
1005       //      for (i = 1; i <= bitsDCluminance[l]; i++)\r
1006       for (i = bitsDCluminance[l]; --i >= 0;) {\r
1007         huffsize[p++] = l;\r
1008       }\r
1009     }\r
1010     huffsize[p] = 0;\r
1011     lastp = p;\r
1012 \r
1013     code = 0;\r
1014     si = huffsize[0];\r
1015     p = 0;\r
1016     while (huffsize[p] != 0) {\r
1017       while (huffsize[p] == si) {\r
1018         huffcode[p++] = code;\r
1019         code++;\r
1020       }\r
1021       code <<= 1;\r
1022       si++;\r
1023     }\r
1024 \r
1025     for (p = 0; p < lastp; p++) {\r
1026       dc_matrix0[valDCluminance[p]][0] = huffcode[p];\r
1027       dc_matrix0[valDCluminance[p]][1] = huffsize[p];\r
1028     }\r
1029 \r
1030     /*\r
1031      * Init of the AC huffman code for luminance\r
1032      * matrix [][][0] is the code & matrix[][][1] is the number of bit\r
1033      */\r
1034 \r
1035     p = 0;\r
1036     for (l = 1; l <= 16; l++) {\r
1037       //      for (i = 1; i <= bitsACluminance[l]; i++)\r
1038       for (i = bitsACluminance[l]; --i >= 0;) {\r
1039         huffsize[p++] = l;\r
1040       }\r
1041     }\r
1042     huffsize[p] = 0;\r
1043     lastp = p;\r
1044 \r
1045     code = 0;\r
1046     si = huffsize[0];\r
1047     p = 0;\r
1048     while (huffsize[p] != 0) {\r
1049       while (huffsize[p] == si) {\r
1050         huffcode[p++] = code;\r
1051         code++;\r
1052       }\r
1053       code <<= 1;\r
1054       si++;\r
1055     }\r
1056     for (int q = 0; q < lastp; q++) {\r
1057       ac_matrix0[valACluminance[q]][0] = huffcode[q];\r
1058       ac_matrix0[valACluminance[q]][1] = huffsize[q];\r
1059     }\r
1060 \r
1061     dc_matrix[0] = dc_matrix0;\r
1062     dc_matrix[1] = dc_matrix1;\r
1063     ac_matrix[0] = ac_matrix0;\r
1064     ac_matrix[1] = ac_matrix1;\r
1065   }\r
1066 \r
1067 }\r
1068 \r
1069 /*\r
1070  * JpegInfo - Given an image, sets default information about it and divides\r
1071  * it into its constituant components, downsizing those that need to be.\r
1072  */\r
1073 \r
1074 class JpegObj {\r
1075   String comment;\r
1076   int imageHeight;\r
1077   int imageWidth;\r
1078   int blockWidth[];\r
1079   int blockHeight[];\r
1080 \r
1081   int precision = 8;\r
1082   int numberOfComponents = 3;\r
1083   float[][][] components;\r
1084   int[] compID = { 1, 2, 3 };\r
1085   int[] hsampFactor = { 1, 1, 1 };\r
1086   int[] vsampFactor = { 1, 1, 1 };\r
1087   int[] qtableNumber = { 0, 1, 1 };\r
1088   int[] dctableNumber = { 0, 1, 1 };\r
1089   int[] actableNumber = { 0, 1, 1 };\r
1090   private boolean[] lastColumnIsDummy = { false, false, false };\r
1091   private boolean[] lastRowIsDummy = { false, false, false };\r
1092   int ss = 0;\r
1093   int se = 63;\r
1094   int ah = 0;\r
1095   int al = 0;\r
1096   private int compWidth[];\r
1097   private int compHeight[];\r
1098   private int maxHsampFactor;\r
1099   private int maxVsampFactor;\r
1100 \r
1101   public JpegObj() {\r
1102     components = AU.newFloat3(numberOfComponents, -1);\r
1103     compWidth = new int[numberOfComponents];\r
1104     compHeight = new int[numberOfComponents];\r
1105     blockWidth = new int[numberOfComponents];\r
1106     blockHeight = new int[numberOfComponents];\r
1107   }\r
1108 \r
1109   /*\r
1110    * This method creates and fills three arrays, Y, Cb, and Cr using the\r
1111    * input image.\r
1112    */\r
1113 \r
1114   void getYCCArray(int[] pixels) {\r
1115     // In order to minimize the chance that grabPixels will throw an exception\r
1116     // it may be necessary to grab some pixels every few scanlines and process\r
1117     // those before going for more.  The time expense may be prohibitive.\r
1118     // However, for a situation where memory overhead is a concern, this may be\r
1119     // the only choice.\r
1120     maxHsampFactor = 1;\r
1121     maxVsampFactor = 1;\r
1122     for (int y = 0; y < numberOfComponents; y++) {\r
1123       maxHsampFactor = Math.max(maxHsampFactor, hsampFactor[y]);\r
1124       maxVsampFactor = Math.max(maxVsampFactor, vsampFactor[y]);\r
1125     }\r
1126     for (int y = 0; y < numberOfComponents; y++) {\r
1127       compWidth[y] = (((imageWidth % 8 != 0) ? ((int) Math\r
1128           .ceil(imageWidth / 8.0)) * 8 : imageWidth) / maxHsampFactor)\r
1129           * hsampFactor[y];\r
1130       if (compWidth[y] != ((imageWidth / maxHsampFactor) * hsampFactor[y])) {\r
1131         lastColumnIsDummy[y] = true;\r
1132       }\r
1133       // results in a multiple of 8 for compWidth\r
1134       // this will make the rest of the program fail for the unlikely\r
1135       // event that someone tries to compress an 16 x 16 pixel image\r
1136       // which would of course be worse than pointless\r
1137       blockWidth[y] = (int) Math.ceil(compWidth[y] / 8.0);\r
1138       compHeight[y] = (((imageHeight % 8 != 0) ? ((int) Math\r
1139           .ceil(imageHeight / 8.0)) * 8 : imageHeight) / maxVsampFactor)\r
1140           * vsampFactor[y];\r
1141       if (compHeight[y] != ((imageHeight / maxVsampFactor) * vsampFactor[y])) {\r
1142         lastRowIsDummy[y] = true;\r
1143       }\r
1144       blockHeight[y] = (int) Math.ceil(compHeight[y] / 8.0);\r
1145     }\r
1146     float Y[][] = new float[compHeight[0]][compWidth[0]];\r
1147     float Cr1[][] = new float[compHeight[0]][compWidth[0]];\r
1148     float Cb1[][] = new float[compHeight[0]][compWidth[0]];\r
1149     //float Cb2[][] = new float[compHeight[1]][compWidth[1]];\r
1150     //float Cr2[][] = new float[compHeight[2]][compWidth[2]];\r
1151     for (int pt = 0, y = 0; y < imageHeight; ++y) {\r
1152       for (int x = 0; x < imageWidth; ++x, pt++) {\r
1153         int p = pixels[pt];\r
1154         int r = ((p >> 16) & 0xff);\r
1155         int g = ((p >> 8) & 0xff);\r
1156         int b = (p & 0xff);\r
1157         // The following three lines are a more correct color conversion but\r
1158         // the current conversion technique is sufficient and results in a higher\r
1159         // compression rate.\r
1160         // Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g + 0.114 * (float)b ));\r
1161         // Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 * (float)g + 0.5 * (float)b));\r
1162         // Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g - 0.08131 * (float)b));\r
1163         Y[y][x] = (float) ((0.299 * r + 0.587 * g + 0.114 * b));\r
1164         Cb1[y][x] = 128 + (float) ((-0.16874 * r - 0.33126 * g + 0.5 * b));\r
1165         Cr1[y][x] = 128 + (float) ((0.5 * r - 0.41869 * g - 0.08131 * b));\r
1166       }\r
1167     }\r
1168 \r
1169     // Need a way to set the H and V sample factors before allowing downsampling.\r
1170     // For now (04/04/98) downsampling must be hard coded.\r
1171     // Until a better downsampler is implemented, this will not be done.\r
1172     // Downsampling is currently supported.  The downsampling method here\r
1173     // is a simple box filter.\r
1174 \r
1175     components[0] = Y;\r
1176     //        Cb2 = DownSample(Cb1, 1);\r
1177     components[1] = Cb1;\r
1178     //        Cr2 = DownSample(Cr1, 2);\r
1179     components[2] = Cr1;\r
1180   }\r
1181   /*  \r
1182     float[][] DownSample(float[][] C, int comp)\r
1183     {\r
1184       int inrow, incol;\r
1185       int outrow, outcol;\r
1186       float output[][];\r
1187       int bias;\r
1188       inrow = 0;\r
1189       incol = 0;\r
1190       int cHeight = compHeight[comp];\r
1191       int cWidth = compWidth[comp];\r
1192       output = new float[cHeight][cWidth];\r
1193       \r
1194       for (outrow = 0; outrow < cHeight; outrow++) {\r
1195         bias = 1;\r
1196         for (outcol = 0; outcol < cWidth; outcol++) {\r
1197           output[outrow][outcol] = (C[inrow][incol++] + C[inrow++][incol--] \r
1198                    + C[inrow][incol++] + C[inrow--][incol++] + bias)/(float)4.0;\r
1199           bias ^= 3;\r
1200         }\r
1201         inrow += 2;\r
1202         incol = 0;\r
1203       }\r
1204       return output;\r
1205     }\r
1206   */\r
1207 \r
1208 }\r