JpegEncoder.java
上传用户:shengda799
上传日期:2007-01-10
资源大小:68k
文件大小:50k
源码类别:

图片显示

开发平台:

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