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