Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: org/ydp/gfx/JpegEncoder.java


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