Performs a jpeg compression of an image : JPEG « 2D Graphics GUI « Java

Home
Java
1.2D Graphics GUI
2.2D Graphics GUI1
3.3D
4.Advanced Graphics
5.Ant
6.Apache Common
7.Chart
8.Class
9.Collections Data Structure
10.Data Type
11.Database SQL JDBC
12.Design Pattern
13.Development Class
14.EJB3
15.Email
16.Event
17.File Input Output
18.Game
19.Generics
20.GWT
21.Hibernate
22.I18N
23.J2EE
24.J2ME
25.JDK 6
26.JNDI LDAP
27.JPA
28.JSP
29.JSTL
30.Language Basics
31.Network Protocol
32.PDF RTF
33.Reflection
34.Regular Expressions
35.Scripting
36.Security
37.Servlets
38.Spring
39.Swing Components
40.Swing JFC
41.SWT JFace Eclipse
42.Threads
43.Tiny Application
44.Velocity
45.Web Services SOA
46.XML
Java Tutorial
Java Source Code / Java Documentation
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
SCJP
Java » 2D Graphics GUI » JPEGScreenshots 
Performs a jpeg compression of an image
   
// Copyright (C) 1998, James R. Weeks and BioElectroMech.
// Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.

// This software is based in part on the work of the Independent JPEG Group.
// See license.txt for details about the allowed used of this software.
// See IJGreadme.txt for details about the Independent JPEG Group's license.

import java.awt.AWTException;
import java.awt.Frame;
import java.awt.Image;
import java.awt.MediaTracker;
import java.awt.Toolkit;
import java.awt.image.PixelGrabber;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Vector;

public class Jpeg {
  /** ************ Main Method *************** */
  /*****************************************************************************
   * Jpeg("Imagefile", Quality, "OutFileName") According to JAVA virtual
   * machine, the files which can be read are jpeg, tiff and gif files
   ****************************************************************************/

  public static void StandardUsage() {
    System.out.println("JpegEncoder for Java(tm) Version 0.9");
    System.out.println("");
    System.out
        .println("Program usage: java Jpeg \"InputImage\".\"ext\" Quality [\"OutputFile\"[.jpg]]");
    System.out.println("");
    System.out
        .println("Where \"InputImage\" is the name of an existing image in the current directory.");
    System.out
        .println("  (\"InputImage may specify a directory, too.) \"ext\" must be .tif, .gif,");
    System.out.println("  or .jpg.");
    System.out
        .println("Quality is an integer (0 to 100) that specifies how similar the compressed");
    System.out
        .println("  image is to \"InputImage.\"  100 is almost exactly like \"InputImage\" and 0 is");
    System.out.println("  most dissimilar.  In most cases, 70 - 80 gives very good results.");
    System.out
        .println("\"OutputFile\" is an optional argument.  If \"OutputFile\" isn't specified, then");
    System.out
        .println("  the input file name is adopted.  This program will NOT write over an existing");
    System.out
        .println("  file.  If a directory is specified for the input image, then \"OutputFile\"");
    System.out
        .println("  will be written in that directory.  The extension \".jpg\" may automatically be");
    System.out.println("  added.");
    System.out.println("");
    System.out
        .println("Copyright 1998 BioElectroMech and James R. Weeks.  Portions copyright IJG and");
    System.out.println("  Florian Raemy, LCAV.  See license.txt for details.");
    System.out.println("Visit BioElectroMech at www.obrador.com.  Email James@obrador.com.");
    System.exit(0);
  }

  public static void main(String args[]) {
    Image image = null;
    FileOutputStream dataOut = null;
    File file, outFile;
    JpegEncoder jpg;
    String string = "";
    int i, Quality = 80;
    // Check to see if the input file name has one of the extensions:
    // .tif, .gif, .jpg
    // If not, print the standard use info.
    if (args.length < 2)
      StandardUsage();
    if (!args[0].endsWith(".jpg"&& !args[0].endsWith(".tif"&& !args[0].endsWith(".gif"))
      StandardUsage();
    // First check to see if there is an OutputFile argument. If there isn't
    // then name the file "InputFile".jpg
    // Second check to see if the .jpg extension is on the OutputFile argument.
    // If there isn't one, add it.
    // Need to check for the existence of the output file. If it exists already,
    // rename the file with a # after the file name, then the .jpg extension.
    if (args.length < 3) {
      string = args[0].substring(0, args[0].lastIndexOf(".")) ".jpg";
    else {
      string = args[2];
      if (string.endsWith(".tif"|| string.endsWith(".gif"))
        string = string.substring(0, string.lastIndexOf("."));
      if (!string.endsWith(".jpg"))
        string = string.concat(".jpg");
    }
    outFile = new File(string);
    i = 1;
    while (outFile.exists()) {
      outFile = new File(string.substring(0, string.lastIndexOf(".")) (i++".jpg");
      if (i > 100)
        System.exit(0);
    }
    file = new File(args[0]);
    if (file.exists()) {
      try {
        dataOut = new FileOutputStream(outFile);
      catch (IOException e) {
      }
      try {
        Quality = Integer.parseInt(args[1]);
      catch (NumberFormatException e) {
        StandardUsage();
      }
      image = Toolkit.getDefaultToolkit().getImage(args[0]);
      jpg = new JpegEncoder(image, Quality, dataOut);
      jpg.Compress();
      try {
        dataOut.close();
      catch (IOException e) {
      }
    else {
      System.out.println("I couldn't find " + args[0". Is it in another directory?");
    }
    System.exit(0);
  }
}

// Version 1.0a
// Copyright (C) 1998, James R. Weeks and BioElectroMech.
// Visit BioElectroMech at www.obrador.com. Email James@obrador.com.

// See license.txt for details about the allowed used of this software.
// This software is based in part on the work of the Independent JPEG Group.
// See IJGreadme.txt for details about the Independent JPEG Group's license.

// This encoder is inspired by the Java Jpeg encoder by Florian Raemy,
// studwww.eurecom.fr/~raemy.
// It borrows a great deal of code and structure from the Independent
// Jpeg Group's Jpeg 6a library, Copyright Thomas G. Lane.
// See license.txt for details.

/*
 * JpegEncoder - The JPEG main program which performs a jpeg compression of an
 * image.
 */
class JpegEncoder extends Frame {
  Thread runner;

  BufferedOutputStream outStream;

  Image image;

  JpegInfo JpegObj;

  Huffman Huf;

  DCT dct;

  int imageHeight, imageWidth;

  int Quality;

  int code;

  public static int[] jpegNaturalOrder = 018169231017243225181145,
      1219263340484134272013671421283542495657504336,
      2922152330374451585952453831394653606154475562,
      63};

  public JpegEncoder(Image image, int quality, OutputStream out) {
    MediaTracker tracker = new MediaTracker(this);
    tracker.addImage(image, 0);
    try {
      tracker.waitForID(0);
    catch (InterruptedException e) {
      // Got to do something?
    }
    /*
     * Quality of the image. 0 to 100 and from bad image quality, high
     * compression to good image quality low compression
     */
    Quality = quality;

    /*
     * Getting picture information It takes the Width, Height and RGB scans of
     * the image.
     */
    JpegObj = new JpegInfo(image);

    imageHeight = JpegObj.imageHeight;
    imageWidth = JpegObj.imageWidth;
    outStream = new BufferedOutputStream(out);
    dct = new DCT(Quality);
    Huf = new Huffman(imageWidth, imageHeight);
  }

  public void setQuality(int quality) {
    dct = new DCT(quality);
  }

  public int getQuality() {
    return Quality;
  }

  public void Compress() {
    WriteHeaders(outStream);
    WriteCompressedData(outStream);
    WriteEOI(outStream);
    try {
      outStream.flush();
    catch (IOException e) {
      System.out.println("IO Error: " + e.getMessage());
    }
  }

  public void WriteCompressedData(BufferedOutputStream outStream) {
    int i, j, r, c, a, b;
    int comp, xpos, ypos, xblockoffset, yblockoffset;
    float inputArray[][];
    float dctArray1[][] new float[8][8];
    double dctArray2[][] new double[8][8];
    int dctArray3[] new int[8];

    /*
     * This method controls the compression of the image. Starting at the upper
     * left of the image, it compresses 8x8 blocks of data until the entire
     * image has been compressed.
     */

    int lastDCvalue[] new int[JpegObj.NumberOfComponents];
    // int zeroArray[] = new int[64]; // initialized to hold all zeros
    // int Width = 0, Height = 0;
    // int nothing = 0, not;
    int MinBlockWidth, MinBlockHeight;
    // This initial setting of MinBlockWidth and MinBlockHeight is done to
    // ensure they start with values larger than will actually be the case.
    MinBlockWidth = ((imageWidth % != 0(int) (Math.floor(imageWidth / 8.018
        : imageWidth);
    MinBlockHeight = ((imageHeight % != 0(int) (Math.floor(imageHeight / 8.018
        : imageHeight);
    for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {
      MinBlockWidth = Math.min(MinBlockWidth, JpegObj.BlockWidth[comp]);
      MinBlockHeight = Math.min(MinBlockHeight, JpegObj.BlockHeight[comp]);
    }
    xpos = 0;
    for (r = 0; r < MinBlockHeight; r++) {
      for (c = 0; c < MinBlockWidth; c++) {
        xpos = c * 8;
        ypos = r * 8;
        for (comp = 0; comp < JpegObj.NumberOfComponents; comp++) {
          // Width = JpegObj.BlockWidth[comp];
          // Height = JpegObj.BlockHeight[comp];
          inputArray = (float[][]) JpegObj.Components[comp];

          for (i = 0; i < JpegObj.VsampFactor[comp]; i++) {
            for (j = 0; j < JpegObj.HsampFactor[comp]; j++) {
              xblockoffset = j * 8;
              yblockoffset = i * 8;
              for (a = 0; a < 8; a++) {
                for (b = 0; b < 8; b++) {

                  // I believe this is where the dirty line at the bottom of
                  // the image is coming from.
                  // I need to do a check here to make sure I'm not reading past
                  // image data.
                  // This seems to not be a big issue right now. (04/04/98)

                  dctArray1[a][b= inputArray[ypos + yblockoffset + a][xpos + xblockoffset + b];
                }
              }
              // The following code commented out because on some images this
              // technique
              // results in poor right and bottom borders.
              // if ((!JpegObj.lastColumnIsDummy[comp] || c < Width - 1) &&
              // (!JpegObj.lastRowIsDummy[comp] || r < Height - 1)) {
              dctArray2 = dct.forwardDCT(dctArray1);
              dctArray3 = dct.quantizeBlock(dctArray2, JpegObj.QtableNumber[comp]);
              // }
              // else {
              // zeroArray[0] = dctArray3[0];
              // zeroArray[0] = lastDCvalue[comp];
              // dctArray3 = zeroArray;
              // }
              Huf.HuffmanBlockEncoder(outStream, dctArray3, lastDCvalue[comp],
                  JpegObj.DCtableNumber[comp], JpegObj.ACtableNumber[comp]);
              lastDCvalue[comp= dctArray3[0];
            }
          }
        }
      }
    }
    Huf.flushBuffer(outStream);
  }

  public void WriteEOI(BufferedOutputStream out) {
    byte[] EOI = { (byte0xFF(byte0xD9 };
    WriteMarker(EOI, out);
  }

  public void WriteHeaders(BufferedOutputStream out) {
    int i, j, index, offset, length;
    int tempArray[];

    // the SOI marker
    byte[] SOI = { (byte0xFF(byte0xD8 };
    WriteMarker(SOI, out);

    // The order of the following headers is quiet inconsequential.
    // the JFIF header
    byte JFIF[] new byte[18];
    JFIF[0(byte0xff;
    JFIF[1(byte0xe0;
    JFIF[2(byte0x00;
    JFIF[3(byte0x10;
    JFIF[4(byte0x4a;
    JFIF[5(byte0x46;
    JFIF[6(byte0x49;
    JFIF[7(byte0x46;
    JFIF[8(byte0x00;
    JFIF[9(byte0x01;
    JFIF[10(byte0x00;
    JFIF[11(byte0x00;
    JFIF[12(byte0x00;
    JFIF[13(byte0x01;
    JFIF[14(byte0x00;
    JFIF[15(byte0x01;
    JFIF[16(byte0x00;
    JFIF[17(byte0x00;
    WriteArray(JFIF, out);

    // Comment Header
    String comment = "";
    comment = JpegObj.getComment();
    length = comment.length();
    byte COM[] new byte[length + 4];
    COM[0(byte0xFF;
    COM[1(byte0xFE;
    COM[2(byte) ((length >> 80xFF);
    COM[3(byte) (length & 0xFF);
    java.lang.System.arraycopy(JpegObj.Comment.getBytes()0, COM, 4, JpegObj.Comment.length());
    WriteArray(COM, out);

    // The DQT header
    // 0 is the luminance index and 1 is the chrominance index
    byte DQT[] new byte[134];
    DQT[0(byte0xFF;
    DQT[1(byte0xDB;
    DQT[2(byte0x00;
    DQT[3(byte0x84;
    offset = 4;
    for (i = 0; i < 2; i++) {
      DQT[offset++(byte) ((<< 4+ i);
      tempArray = (int[]) dct.quantum[i];
      for (j = 0; j < 64; j++) {
        DQT[offset++(bytetempArray[jpegNaturalOrder[j]];
      }
    }
    WriteArray(DQT, out);

    // Start of Frame Header
    byte SOF[] new byte[19];
    SOF[0(byte0xFF;
    SOF[1(byte0xC0;
    SOF[2(byte0x00;
    SOF[3(byte17;
    SOF[4(byteJpegObj.Precision;
    SOF[5(byte) ((JpegObj.imageHeight >> 80xFF);
    SOF[6(byte) ((JpegObj.imageHeight0xFF);
    SOF[7(byte) ((JpegObj.imageWidth >> 80xFF);
    SOF[8(byte) ((JpegObj.imageWidth0xFF);
    SOF[9(byteJpegObj.NumberOfComponents;
    index = 10;
    for (i = 0; i < SOF[9]; i++) {
      SOF[index++(byteJpegObj.CompID[i];
      SOF[index++(byte) ((JpegObj.HsampFactor[i<< 4+ JpegObj.VsampFactor[i]);
      SOF[index++(byteJpegObj.QtableNumber[i];
    }
    WriteArray(SOF, out);

    // The DHT Header
    byte DHT1[], DHT2[], DHT3[], DHT4[];
    int bytes, temp, oldindex, intermediateindex;
    length = 2;
    index = 4;
    oldindex = 4;
    DHT1 = new byte[17];
    DHT4 = new byte[4];
    DHT4[0(byte0xFF;
    DHT4[1(byte0xC4;
    for (i = 0; i < 4; i++) {
      bytes = 0;
      DHT1[index++ - oldindex(byte) ((int[]) Huf.bits.elementAt(i))[0];
      for (j = 1; j < 17; j++) {
        temp = ((int[]) Huf.bits.elementAt(i))[j];
        DHT1[index++ - oldindex(bytetemp;
        bytes += temp;
      }
      intermediateindex = index;
      DHT2 = new byte[bytes];
      for (j = 0; j < bytes; j++) {
        DHT2[index++ - intermediateindex(byte) ((int[]) Huf.val.elementAt(i))[j];
      }
      DHT3 = new byte[index];
      java.lang.System.arraycopy(DHT4, 0, DHT3, 0, oldindex);
      java.lang.System.arraycopy(DHT1, 0, DHT3, oldindex, 17);
      java.lang.System.arraycopy(DHT2, 0, DHT3, oldindex + 17, bytes);
      DHT4 = DHT3;
      oldindex = index;
    }
    DHT4[2(byte) (((index - 2>> 80xFF);
    DHT4[3(byte) ((index - 20xFF);
    WriteArray(DHT4, out);

    // Start of Scan Header
    byte SOS[] new byte[14];
    SOS[0(byte0xFF;
    SOS[1(byte0xDA;
    SOS[2(byte0x00;
    SOS[3(byte12;
    SOS[4(byteJpegObj.NumberOfComponents;
    index = 5;
    for (i = 0; i < SOS[4]; i++) {
      SOS[index++(byteJpegObj.CompID[i];
      SOS[index++(byte) ((JpegObj.DCtableNumber[i<< 4+ JpegObj.ACtableNumber[i]);
    }
    SOS[index++(byteJpegObj.Ss;
    SOS[index++(byteJpegObj.Se;
    SOS[index++(byte) ((JpegObj.Ah << 4+ JpegObj.Al);
    WriteArray(SOS, out);

  }

  void WriteMarker(byte[] data, BufferedOutputStream out) {
    try {
      out.write(data, 02);
    catch (IOException e) {
      System.out.println("IO Error: " + e.getMessage());
    }
  }

  void WriteArray(byte[] data, BufferedOutputStream out) {
    int length;
    try {
      length = ((data[20xFF<< 8(data[30xFF2;
      out.write(data, 0, length);
    catch (IOException e) {
      System.out.println("IO Error: " + e.getMessage());
    }
  }
}

// This class incorporates quality scaling as implemented in the JPEG-6a
// library.

/*
 * DCT - A Java implementation of the Discreet Cosine Transform
 */

class DCT {
  /**
   * DCT Block Size - default 8
   */
  public int N = 8;

  /**
   * Image Quality (0-100) - default 80 (good image / good compression)
   */
  public int QUALITY = 80;

  public Object quantum[] new Object[2];

  public Object Divisors[] new Object[2];

  /**
   * Quantitization Matrix for luminace.
   */
  public int quantum_luminance[] new int[N * N];

  public double DivisorsLuminance[] new double[N * N];

  /**
   * Quantitization Matrix for chrominance.
   */
  public int quantum_chrominance[] new int[N * N];

  public double DivisorsChrominance[] new double[N * N];

  /**
   * Constructs a new DCT object. Initializes the cosine transform matrix these
   * are used when computing the DCT and it's inverse. This also initializes the
   * run length counters and the ZigZag sequence. Note that the image quality
   * can be worse than 25 however the image will be extemely pixelated, usually
   * to a block size of N.
   
   @param QUALITY
   *          The quality of the image (0 worst - 100 best)
   
   */
  public DCT(int QUALITY) {
    initMatrix(QUALITY);
  }

  /*
   * This method sets up the quantization matrix for luminance and chrominance
   * using the Quality parameter.
   */
  private void initMatrix(int quality) {
    double[] AANscaleFactor = 1.01.3870398451.3065629651.1758756021.00.785694958,
        0.5411961000.275899379 };
    int i;
    int j;
    int index;
    int Quality;
    int temp;

    // converting quality setting to that specified in the jpeg_quality_scaling
    // method in the IJG Jpeg-6a C libraries

    Quality = quality;
    if (Quality <= 0)
      Quality = 1;
    if (Quality > 100)
      Quality = 100;
    if (Quality < 50)
      Quality = 5000 / Quality;
    else
      Quality = 200 - Quality * 2;

    // Creating the luminance matrix

    quantum_luminance[016;
    quantum_luminance[111;
    quantum_luminance[210;
    quantum_luminance[316;
    quantum_luminance[424;
    quantum_luminance[540;
    quantum_luminance[651;
    quantum_luminance[761;
    quantum_luminance[812;
    quantum_luminance[912;
    quantum_luminance[1014;
    quantum_luminance[1119;
    quantum_luminance[1226;
    quantum_luminance[1358;
    quantum_luminance[1460;
    quantum_luminance[1555;
    quantum_luminance[1614;
    quantum_luminance[1713;
    quantum_luminance[1816;
    quantum_luminance[1924;
    quantum_luminance[2040;
    quantum_luminance[2157;
    quantum_luminance[2269;
    quantum_luminance[2356;
    quantum_luminance[2414;
    quantum_luminance[2517;
    quantum_luminance[2622;
    quantum_luminance[2729;
    quantum_luminance[2851;
    quantum_luminance[2987;
    quantum_luminance[3080;
    quantum_luminance[3162;
    quantum_luminance[3218;
    quantum_luminance[3322;
    quantum_luminance[3437;
    quantum_luminance[3556;
    quantum_luminance[3668;
    quantum_luminance[37109;
    quantum_luminance[38103;
    quantum_luminance[3977;
    quantum_luminance[4024;
    quantum_luminance[4135;
    quantum_luminance[4255;
    quantum_luminance[4364;
    quantum_luminance[4481;
    quantum_luminance[45104;
    quantum_luminance[46113;
    quantum_luminance[4792;
    quantum_luminance[4849;
    quantum_luminance[4964;
    quantum_luminance[5078;
    quantum_luminance[5187;
    quantum_luminance[52103;
    quantum_luminance[53121;
    quantum_luminance[54120;
    quantum_luminance[55101;
    quantum_luminance[5672;
    quantum_luminance[5792;
    quantum_luminance[5895;
    quantum_luminance[5998;
    quantum_luminance[60112;
    quantum_luminance[61100;
    quantum_luminance[62103;
    quantum_luminance[6399;

    for (j = 0; j < 64; j++) {
      temp = (quantum_luminance[j* Quality + 50100;
      if (temp <= 0)
        temp = 1;
      if (temp > 255)
        temp = 255;
      quantum_luminance[j= temp;
    }
    index = 0;
    for (i = 0; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        // The divisors for the LL&M method (the slow integer method used in
        // jpeg 6a library). This method is currently (04/04/98) incompletely
        // implemented.
        // DivisorsLuminance[index] = ((double) quantum_luminance[index]) << 3;
        // The divisors for the AAN method (the float method used in jpeg 6a
        // library.
        DivisorsLuminance[index(1.0 (quantum_luminance[index* AANscaleFactor[i]
            * AANscaleFactor[j8.0));
        index++;
      }
    }

    // Creating the chrominance matrix

    quantum_chrominance[017;
    quantum_chrominance[118;
    quantum_chrominance[224;
    quantum_chrominance[347;
    quantum_chrominance[499;
    quantum_chrominance[599;
    quantum_chrominance[699;
    quantum_chrominance[799;
    quantum_chrominance[818;
    quantum_chrominance[921;
    quantum_chrominance[1026;
    quantum_chrominance[1166;
    quantum_chrominance[1299;
    quantum_chrominance[1399;
    quantum_chrominance[1499;
    quantum_chrominance[1599;
    quantum_chrominance[1624;
    quantum_chrominance[1726;
    quantum_chrominance[1856;
    quantum_chrominance[1999;
    quantum_chrominance[2099;
    quantum_chrominance[2199;
    quantum_chrominance[2299;
    quantum_chrominance[2399;
    quantum_chrominance[2447;
    quantum_chrominance[2566;
    quantum_chrominance[2699;
    quantum_chrominance[2799;
    quantum_chrominance[2899;
    quantum_chrominance[2999;
    quantum_chrominance[3099;
    quantum_chrominance[3199;
    quantum_chrominance[3299;
    quantum_chrominance[3399;
    quantum_chrominance[3499;
    quantum_chrominance[3599;
    quantum_chrominance[3699;
    quantum_chrominance[3799;
    quantum_chrominance[3899;
    quantum_chrominance[3999;
    quantum_chrominance[4099;
    quantum_chrominance[4199;
    quantum_chrominance[4299;
    quantum_chrominance[4399;
    quantum_chrominance[4499;
    quantum_chrominance[4599;
    quantum_chrominance[4699;
    quantum_chrominance[4799;
    quantum_chrominance[4899;
    quantum_chrominance[4999;
    quantum_chrominance[5099;
    quantum_chrominance[5199;
    quantum_chrominance[5299;
    quantum_chrominance[5399;
    quantum_chrominance[5499;
    quantum_chrominance[5599;
    quantum_chrominance[5699;
    quantum_chrominance[5799;
    quantum_chrominance[5899;
    quantum_chrominance[5999;
    quantum_chrominance[6099;
    quantum_chrominance[6199;
    quantum_chrominance[6299;
    quantum_chrominance[6399;

    for (j = 0; j < 64; j++) {
      temp = (quantum_chrominance[j* Quality + 50100;
      if (temp <= 0)
        temp = 1;
      if (temp >= 255)
        temp = 255;
      quantum_chrominance[j= temp;
    }
    index = 0;
    for (i = 0; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        // The divisors for the LL&M method (the slow integer method used in
        // jpeg 6a library). This method is currently (04/04/98) incompletely
        // implemented.
        // DivisorsChrominance[index] = ((double) quantum_chrominance[index]) <<
        // 3;
        // The divisors for the AAN method (the float method used in jpeg 6a
        // library.
        DivisorsChrominance[index1.0 (quantum_chrominance[index* AANscaleFactor[i]
            * AANscaleFactor[j8.0);
        index++;
      }
    }

    // quantum and Divisors are objects used to hold the appropriate matices

    quantum[0= quantum_luminance;
    Divisors[0= DivisorsLuminance;
    quantum[1= quantum_chrominance;
    Divisors[1= DivisorsChrominance;

  }

  /*
   * This method preforms forward DCT on a block of image data using the literal
   * method specified for a 2-D Discrete Cosine Transform. It is included as a
   * curiosity and can give you an idea of the difference in the compression
   * result (the resulting image quality) by comparing its output to the output
   * of the AAN method below. It is ridiculously inefficient.
   */

  // For now the final output is unusable. The associated quantization step
  // needs some tweaking. If you get this part working, please let me know.
  public double[][] forwardDCTExtreme(float input[][]) {
    double output[][] new double[N][N];
    int v, u, x, y;
    for (v = 0; v < 8; v++) {
      for (u = 0; u < 8; u++) {
        for (x = 0; x < 8; x++) {
          for (y = 0; y < 8; y++) {
            output[v][u+= input[x][y]
                * Math.cos(((double) (* x + 1(doubleu * Math.PI16)
                * Math.cos(((double) (* y + 1(doublev * Math.PI16);
          }
        }
        output[v][u*= (0.25((u == 0(1.0 / Math.sqrt(2)) (double1.0)
            ((v == 0(1.0 / Math.sqrt(2)) (double1.0);
      }
    }
    return output;
  }

  /*
   * This method preforms a DCT on a block of image data using the AAN method as
   * implemented in the IJG Jpeg-6a library.
   */
  public double[][] forwardDCT(float input[][]) {
    double output[][] new double[N][N];
    double tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
    double tmp10, tmp11, tmp12, tmp13;
    double z1, z2, z3, z4, z5, z11, z13;
    int i;
    int j;

    // Subtracts 128 from the input values
    for (i = 0; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        output[i][j(input[i][j128.0);
        // input[i][j] -= 128;

      }
    }

    for (i = 0; i < 8; i++) {
      tmp0 = output[i][0+ output[i][7];
      tmp7 = output[i][0- output[i][7];
      tmp1 = output[i][1+ output[i][6];
      tmp6 = output[i][1- output[i][6];
      tmp2 = output[i][2+ output[i][5];
      tmp5 = output[i][2- output[i][5];
      tmp3 = output[i][3+ output[i][4];
      tmp4 = output[i][3- output[i][4];

      tmp10 = tmp0 + tmp3;
      tmp13 = tmp0 - tmp3;
      tmp11 = tmp1 + tmp2;
      tmp12 = tmp1 - tmp2;

      output[i][0= tmp10 + tmp11;
      output[i][4= tmp10 - tmp11;

      z1 = (tmp12 + tmp130.707106781;
      output[i][2= tmp13 + z1;
      output[i][6= tmp13 - z1;

      tmp10 = tmp4 + tmp5;
      tmp11 = tmp5 + tmp6;
      tmp12 = tmp6 + tmp7;

      z5 = (tmp10 - tmp120.382683433;
      z2 = 0.541196100 * tmp10 + z5;
      z4 = 1.306562965 * tmp12 + z5;
      z3 = tmp11 * 0.707106781;

      z11 = tmp7 + z3;
      z13 = tmp7 - z3;

      output[i][5= z13 + z2;
      output[i][3= z13 - z2;
      output[i][1= z11 + z4;
      output[i][7= z11 - z4;
    }

    for (i = 0; i < 8; i++) {
      tmp0 = output[0][i+ output[7][i];
      tmp7 = output[0][i- output[7][i];
      tmp1 = output[1][i+ output[6][i];
      tmp6 = output[1][i- output[6][i];
      tmp2 = output[2][i+ output[5][i];
      tmp5 = output[2][i- output[5][i];
      tmp3 = output[3][i+ output[4][i];
      tmp4 = output[3][i- output[4][i];

      tmp10 = tmp0 + tmp3;
      tmp13 = tmp0 - tmp3;
      tmp11 = tmp1 + tmp2;
      tmp12 = tmp1 - tmp2;

      output[0][i= tmp10 + tmp11;
      output[4][i= tmp10 - tmp11;

      z1 = (tmp12 + tmp130.707106781;
      output[2][i= tmp13 + z1;
      output[6][i= tmp13 - z1;

      tmp10 = tmp4 + tmp5;
      tmp11 = tmp5 + tmp6;
      tmp12 = tmp6 + tmp7;

      z5 = (tmp10 - tmp120.382683433;
      z2 = 0.541196100 * tmp10 + z5;
      z4 = 1.306562965 * tmp12 + z5;
      z3 = tmp11 * 0.707106781;

      z11 = tmp7 + z3;
      z13 = tmp7 - z3;

      output[5][i= z13 + z2;
      output[3][i= z13 - z2;
      output[1][i= z11 + z4;
      output[7][i= z11 - z4;
    }

    return output;
  }

  /*
   * This method quantitizes data and rounds it to the nearest integer.
   */
  public int[] quantizeBlock(double inputData[][]int code) {
    int outputData[] new int[N * N];
    int i, j;
    int index;
    index = 0;
    for (i = 0; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        // The second line results in significantly better compression.
        outputData[index(int) (Math.round(inputData[i][j]
            (((double[]) (Divisors[code]))[index])));
        // outputData[index] = (int)(((inputData[i][j] * (((double[])
        // (Divisors[code]))[index])) + 16384.5) -16384);
        index++;
      }
    }

    return outputData;
  }

  /*
   * This is the method for quantizing a block DCT'ed with forwardDCTExtreme
   * This method quantitizes data and rounds it to the nearest integer.
   */
  public int[] quantizeBlockExtreme(double inputData[][]int code) {
    int outputData[] new int[N * N];
    int i, j;
    int index;
    index = 0;
    for (i = 0; i < 8; i++) {
      for (j = 0; j < 8; j++) {
        outputData[index(int) (Math.round(inputData[i][j(((int[]) (quantum[code]))[index])));
        index++;
      }
    }

    return outputData;
  }
}

// This class was modified by James R. Weeks on 3/27/98.
// It now incorporates Huffman table derivation as in the C jpeg library
// from the IJG, Jpeg-6a.

class Huffman {
  int bufferPutBits, bufferPutBuffer;

  public int ImageHeight;

  public int ImageWidth;

  public int DC_matrix0[][];

  public int AC_matrix0[][];

  public int DC_matrix1[][];

  public int AC_matrix1[][];

  public Object DC_matrix[];

  public Object AC_matrix[];

  public int code;

  public int NumOfDCTables;

  public int NumOfACTables;

  public int[] bitsDCluminance = 0x00015111111000000};

  public int[] valDCluminance = 01234567891011 };

  public int[] bitsDCchrominance = 0x01031111111110000};

  public int[] valDCchrominance = 01234567891011 };

  public int[] bitsACluminance = 0x100213324355440010x7d };

  public int[] valACluminance = 0x010x020x030x000x040x110x050x120x210x310x41,
      0x060x130x510x610x070x220x710x140x320x810x910xa10x080x230x42,
      0xb10xc10x150x520xd10xf00x240x330x620x720x820x090x0a0x160x17,
      0x180x190x1a0x250x260x270x280x290x2a0x340x350x360x370x380x39,
      0x3a0x430x440x450x460x470x480x490x4a0x530x540x550x560x570x58,
      0x590x5a0x630x640x650x660x670x680x690x6a0x730x740x750x760x77,
      0x780x790x7a0x830x840x850x860x870x880x890x8a0x920x930x940x95,
      0x960x970x980x990x9a0xa20xa30xa40xa50xa60xa70xa80xa90xaa0xb2,
      0xb30xb40xb50xb60xb70xb80xb90xba0xc20xc30xc40xc50xc60xc70xc8,
      0xc90xca0xd20xd30xd40xd50xd60xd70xd80xd90xda0xe10xe20xe30xe4,
      0xe50xe60xe70xe80xe90xea0xf10xf20xf30xf40xf50xf60xf70xf80xf9,
      0xfa };

  public int[] bitsACchrominance = 0x110212443475440120x77 };

  public int[] valACchrominance = 0x000x010x020x030x110x040x050x210x310x06,
      0x120x410x510x070x610x710x130x220x320x810x080x140x420x910xa1,
      0xb10xc10x090x230x330x520xf00x150x620x720xd10x0a0x160x240x34,
      0xe10x250xf10x170x180x190x1a0x260x270x280x290x2a0x350x360x37,
      0x380x390x3a0x430x440x450x460x470x480x490x4a0x530x540x550x56,
      0x570x580x590x5a0x630x640x650x660x670x680x690x6a0x730x740x75,
      0x760x770x780x790x7a0x820x830x840x850x860x870x880x890x8a0x92,
      0x930x940x950x960x970x980x990x9a0xa20xa30xa40xa50xa60xa70xa8,
      0xa90xaa0xb20xb30xb40xb50xb60xb70xb80xb90xba0xc20xc30xc40xc5,
      0xc60xc70xc80xc90xca0xd20xd30xd40xd50xd60xd70xd80xd90xda0xe2,
      0xe30xe40xe50xe60xe70xe80xe90xea0xf20xf30xf40xf50xf60xf70xf8,
      0xf90xfa };

  public Vector bits;

  public Vector val;

  /*
   * jpegNaturalOrder[i] is the natural-order position of the i'th element of
   * zigzag order.
   */
  public static int[] jpegNaturalOrder = 018169231017243225181145,
      1219263340484134272013671421283542495657504336,
      2922152330374451585952453831394653606154475562,
      63};

  /*
   * The Huffman class constructor
   */
  public Huffman(int Width, int Height) {

    bits = new Vector();
    bits.addElement(bitsDCluminance);
    bits.addElement(bitsACluminance);
    bits.addElement(bitsDCchrominance);
    bits.addElement(bitsACchrominance);
    val = new Vector();
    val.addElement(valDCluminance);
    val.addElement(valACluminance);
    val.addElement(valDCchrominance);
    val.addElement(valACchrominance);
    initHuf();
    ImageWidth = Width;
    ImageHeight = Height;

  }

  /**
   * HuffmanBlockEncoder run length encodes and Huffman encodes the quantized
   * data.
   
   @param outStream
   @param zigzag
   @param prec
   @param DCcode
   @param ACcode
   */

  public void HuffmanBlockEncoder(BufferedOutputStream outStream, int zigzag[]int prec,
      int DCcode, int ACcode) {
    int temp, temp2, nbits, k, r, i;

    NumOfDCTables = 2;
    NumOfACTables = 2;

    // The DC portion

    temp = temp2 = zigzag[0- prec;
    if (temp < 0) {
      temp = -temp;
      temp2--;
    }
    nbits = 0;
    while (temp != 0) {
      nbits++;
      temp >>= 1;
    }
    // if (nbits > 11) nbits = 11;
    bufferIt(outStream, ((int[][]) DC_matrix[DCcode])[nbits][0],
        ((int[][]) DC_matrix[DCcode])[nbits][1]);
    // The arguments in bufferIt are code and size.
    if (nbits != 0) {
      bufferIt(outStream, temp2, nbits);
    }

    // The AC portion

    r = 0;

    for (k = 1; k < 64; k++) {
      if ((temp = zigzag[jpegNaturalOrder[k]]) == 0) {
        r++;
      else {
        while (r > 15) {
          bufferIt(outStream, ((int[][]) AC_matrix[ACcode])[0xF0][0],
              ((int[][]) AC_matrix[ACcode])[0xF0][1]);
          r -= 16;
        }
        temp2 = temp;
        if (temp < 0) {
          temp = -temp;
          temp2--;
        }
        nbits = 1;
        while ((temp >>= 1!= 0) {
          nbits++;
        }
        i = (r << 4+ nbits;
        bufferIt(outStream, ((int[][]) AC_matrix[ACcode])[i][0],
            ((int[][]) AC_matrix[ACcode])[i][1]);
        bufferIt(outStream, temp2, nbits);

        r = 0;
      }
    }

    if (r > 0) {
      bufferIt(outStream, ((int[][]) AC_matrix[ACcode])[0][0]((int[][]) AC_matrix[ACcode])[0][1]);
    }

  }

  // Uses an integer long (32 bits) buffer to store the Huffman encoded bits
  // and sends them to outStream by the byte.

  void bufferIt(BufferedOutputStream outStream, int code, int size) {
    int PutBuffer = code;
    int PutBits = bufferPutBits;

    PutBuffer &= (<< size1;
    PutBits += size;
    PutBuffer <<= 24 - PutBits;
    PutBuffer |= bufferPutBuffer;

    while (PutBits >= 8) {
      int c = ((PutBuffer >> 160xFF);
      try {
        outStream.write(c);
      catch (IOException e) {
        System.out.println("IO Error: " + e.getMessage());
      }
      if (c == 0xFF) {
        try {
          outStream.write(0);
        catch (IOException e) {
          System.out.println("IO Error: " + e.getMessage());
        }
      }
      PutBuffer <<= 8;
      PutBits -= 8;
    }
    bufferPutBuffer = PutBuffer;
    bufferPutBits = PutBits;

  }

  void flushBuffer(BufferedOutputStream outStream) {
    int PutBuffer = bufferPutBuffer;
    int PutBits = bufferPutBits;
    while (PutBits >= 8) {
      int c = ((PutBuffer >> 160xFF);
      try {
        outStream.write(c);
      catch (IOException e) {
        System.out.println("IO Error: " + e.getMessage());
      }
      if (c == 0xFF) {
        try {
          outStream.write(0);
        catch (IOException e) {
          System.out.println("IO Error: " + e.getMessage());
        }
      }
      PutBuffer <<= 8;
      PutBits -= 8;
    }
    if (PutBits > 0) {
      int c = ((PutBuffer >> 160xFF);
      try {
        outStream.write(c);
      catch (IOException e) {
        System.out.println("IO Error: " + e.getMessage());
      }
    }
  }

  /*
   * Initialisation of the Huffman codes for Luminance and Chrominance. This
   * code results in the same tables created in the IJG Jpeg-6a library.
   */

  public void initHuf() {
    DC_matrix0 = new int[12][2];
    DC_matrix1 = new int[12][2];
    AC_matrix0 = new int[255][2];
    AC_matrix1 = new int[255][2];
    DC_matrix = new Object[2];
    AC_matrix = new Object[2];
    int p, l, i, lastp, si, code;
    int[] huffsize = new int[257];
    int[] huffcode = new int[257];

    /*
     * init of the DC values for the chrominance [][0] is the code [][1] is the
     * number of bit
     */

    p = 0;
    for (l = 1; l <= 16; l++) {
      for (i = 1; i <= bitsDCchrominance[l]; i++) {
        huffsize[p++= l;
      }
    }
    huffsize[p0;
    lastp = p;

    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p!= 0) {
      while (huffsize[p== si) {
        huffcode[p++= code;
        code++;
      }
      code <<= 1;
      si++;
    }

    for (p = 0; p < lastp; p++) {
      DC_matrix1[valDCchrominance[p]][0= huffcode[p];
      DC_matrix1[valDCchrominance[p]][1= huffsize[p];
    }

    /*
     * Init of the AC hufmann code for the chrominance matrix [][][0] is the
     * code & matrix[][][1] is the number of bit needed
     */

    p = 0;
    for (l = 1; l <= 16; l++) {
      for (i = 1; i <= bitsACchrominance[l]; i++) {
        huffsize[p++= l;
      }
    }
    huffsize[p0;
    lastp = p;

    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p!= 0) {
      while (huffsize[p== si) {
        huffcode[p++= code;
        code++;
      }
      code <<= 1;
      si++;
    }

    for (p = 0; p < lastp; p++) {
      AC_matrix1[valACchrominance[p]][0= huffcode[p];
      AC_matrix1[valACchrominance[p]][1= huffsize[p];
    }

    /*
     * init of the DC values for the luminance [][0] is the code [][1] is the
     * number of bit
     */
    p = 0;
    for (l = 1; l <= 16; l++) {
      for (i = 1; i <= bitsDCluminance[l]; i++) {
        huffsize[p++= l;
      }
    }
    huffsize[p0;
    lastp = p;

    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p!= 0) {
      while (huffsize[p== si) {
        huffcode[p++= code;
        code++;
      }
      code <<= 1;
      si++;
    }

    for (p = 0; p < lastp; p++) {
      DC_matrix0[valDCluminance[p]][0= huffcode[p];
      DC_matrix0[valDCluminance[p]][1= huffsize[p];
    }

    /*
     * Init of the AC hufmann code for luminance matrix [][][0] is the code &
     * matrix[][][1] is the number of bit
     */

    p = 0;
    for (l = 1; l <= 16; l++) {
      for (i = 1; i <= bitsACluminance[l]; i++) {
        huffsize[p++= l;
      }
    }
    huffsize[p0;
    lastp = p;

    code = 0;
    si = huffsize[0];
    p = 0;
    while (huffsize[p!= 0) {
      while (huffsize[p== si) {
        huffcode[p++= code;
        code++;
      }
      code <<= 1;
      si++;
    }
    for (int q = 0; q < lastp; q++) {
      AC_matrix0[valACluminance[q]][0= huffcode[q];
      AC_matrix0[valACluminance[q]][1= huffsize[q];
    }

    DC_matrix[0= DC_matrix0;
    DC_matrix[1= DC_matrix1;
    AC_matrix[0= AC_matrix0;
    AC_matrix[1= AC_matrix1;
  }

}

/*
 * JpegInfo - Given an image, sets default information about it and divides it
 * into its constituant components, downsizing those that need to be.
 */

class JpegInfo {
  String Comment;

  public Image imageobj;

  public int imageHeight;

  public int imageWidth;

  public int BlockWidth[];

  public int BlockHeight[];

  // the following are set as the default
  public int Precision = 8;

  public int NumberOfComponents = 3;

  public Object Components[];

  public int[] CompID = 12};

  public int[] HsampFactor = 11};

  public int[] VsampFactor = 11};

  public int[] QtableNumber = 01};

  public int[] DCtableNumber = 01};

  public int[] ACtableNumber = 01};

  public boolean[] lastColumnIsDummy = false, false, false };

  public boolean[] lastRowIsDummy = false, false, false };

  public int Ss = 0;

  public int Se = 63;

  public int Ah = 0;

  public int Al = 0;

  public int compWidth[], compHeight[];

  public int MaxHsampFactor;

  public int MaxVsampFactor;

  public JpegInfo(Image image) {
    Components = new Object[NumberOfComponents];
    compWidth = new int[NumberOfComponents];
    compHeight = new int[NumberOfComponents];
    BlockWidth = new int[NumberOfComponents];
    BlockHeight = new int[NumberOfComponents];
    imageobj = image;
    imageWidth = image.getWidth(null);
    imageHeight = image.getHeight(null);
    Comment = "JPEG Encoder Copyright 1998, James R. Weeks and BioElectroMech.  ";
    getYCCArray();
  }

  public void setComment(String comment) {
    Comment.concat(comment);
  }

  public String getComment() {
    return Comment;
  }

  /*
   * This method creates and fills three arrays, Y, Cb, and Cr using the input
   * image.
   */

  private void getYCCArray() {
    int values[] new int[imageWidth * imageHeight];
    int r, g, b, y, x;
    // In order to minimize the chance that grabPixels will throw an exception
    // it may be necessary to grab some pixels every few scanlines and process
    // those before going for more. The time expense may be prohibitive.
    // However, for a situation where memory overhead is a concern, this may be
    // the only choice.
    PixelGrabber grabber = new PixelGrabber(imageobj.getSource()00, imageWidth, imageHeight,
        values, 0, imageWidth);
    MaxHsampFactor = 1;
    MaxVsampFactor = 1;
    for (y = 0; y < NumberOfComponents; y++) {
      MaxHsampFactor = Math.max(MaxHsampFactor, HsampFactor[y]);
      MaxVsampFactor = Math.max(MaxVsampFactor, VsampFactor[y]);
    }
    for (y = 0; y < NumberOfComponents; y++) {
      compWidth[y(((imageWidth % != 0((intMath.ceil(imageWidth / 8.0)) : imageWidth/ MaxHsampFactor)
          * HsampFactor[y];
      if (compWidth[y!= ((imageWidth / MaxHsampFactor* HsampFactor[y])) {
        lastColumnIsDummy[ytrue;
      }
      // results in a multiple of 8 for compWidth
      // this will make the rest of the program fail for the unlikely
      // event that someone tries to compress an 16 x 16 pixel image
      // which would of course be worse than pointless
      BlockWidth[y(intMath.ceil(compWidth[y8.0);
      compHeight[y(((imageHeight % != 0((intMath.ceil(imageHeight / 8.0)) 8
          : imageHeight/ MaxVsampFactor)
          * VsampFactor[y];
      if (compHeight[y!= ((imageHeight / MaxVsampFactor* VsampFactor[y])) {
        lastRowIsDummy[ytrue;
      }
      BlockHeight[y(intMath.ceil(compHeight[y8.0);
    }
    try {
      if (grabber.grabPixels() != true) {
        try {
          throw new AWTException("Grabber returned false: " + grabber.status());
        catch (Exception e) {
        }
      }
    catch (InterruptedException e) {
    }
    float Y[][] new float[compHeight[0]][compWidth[0]];
    float Cr1[][] new float[compHeight[0]][compWidth[0]];
    float Cb1[][] new float[compHeight[0]][compWidth[0]];
    // float Cb2[][] = new float[compHeight[1]][compWidth[1]];
    // float Cr2[][] = new float[compHeight[2]][compWidth[2]];
    int index = 0;
    for (y = 0; y < imageHeight; ++y) {
      for (x = 0; x < imageWidth; ++x) {
        r = ((values[index>> 160xff);
        g = ((values[index>> 80xff);
        b = (values[index0xff);

        // The following three lines are a more correct color conversion but
        // the current conversion technique is sufficient and results in a
        // higher
        // compression rate.
        // Y[y][x] = 16 + (float)(0.8588*(0.299 * (float)r + 0.587 * (float)g +
        // 0.114 * (float)b ));
        // Cb1[y][x] = 128 + (float)(0.8784*(-0.16874 * (float)r - 0.33126 *
        // (float)g + 0.5 * (float)b));
        // Cr1[y][x] = 128 + (float)(0.8784*(0.5 * (float)r - 0.41869 * (float)g
        // - 0.08131 * (float)b));
        Y[y][x(float) ((0.299 * r + 0.587 * g + 0.114 * b));
        Cb1[y][x128 (float) ((-0.16874 * r - 0.33126 * g + 0.5 * b));
        Cr1[y][x128 (float) ((0.5 * r - 0.41869 * g - 0.08131 * b));
        index++;
      }
    }

    // Need a way to set the H and V sample factors before allowing
    // downsampling.
    // For now (04/04/98) downsampling must be hard coded.
    // Until a better downsampler is implemented, this will not be done.
    // Downsampling is currently supported. The downsampling method here
    // is a simple box filter.

    Components[0= Y;
    // Cb2 = DownSample(Cb1, 1);
    Components[1= Cb1;
    // Cr2 = DownSample(Cr1, 2);
    Components[2= Cr1;
  }

  float[][] DownSample(float[][] C, int comp) {
    int inrow, incol;
    int outrow, outcol;
    float output[][];
    int bias;
    inrow = 0;
    incol = 0;
    output = new float[compHeight[comp]][compWidth[comp]];
    for (outrow = 0; outrow < compHeight[comp]; outrow++) {
      bias = 1;
      for (outcol = 0; outcol < compWidth[comp]; outcol++) {
        output[outrow][outcol(C[inrow][incol+++ C[inrow++][incol--+ C[inrow][incol++]
            + C[inrow--][incol+++ bias)
            (float4.0;
        bias ^= 3;
      }
      inrow += 2;
      incol = 0;
    }
    return output;
  }
}

   
    
    
  
Related examples in the same category
1.Encoding an image to a JPEG file
2.Rescale JPG
3.Get Jpeg Properties
4.Takes a list of JPEG image files and convert them into a QuickTime movie.
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.