Java/2D Graphics GUI/Image Filter

Материал из Java эксперт
Версия от 09:54, 1 июня 2010; Admin (обсуждение | вклад) (1 версия)
(разн.) ← Предыдущая | Текущая версия (разн.) | Следующая → (разн.)
Перейти к: навигация, поиск

Copy Raster

<source lang="java"> /*

* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
* 
*      http://www.apache.org/licenses/LICENSE-2.0
* 
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

/* $Id: GraphicsUtil.java 603243 2007-12-11 13:49:04Z jeremias $ */

import java.awt.Point; import java.awt.Rectangle; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; import java.awt.image.ruponentSampleModel; import java.awt.image.DataBuffer; import java.awt.image.DataBufferByte; import java.awt.image.DataBufferInt; import java.awt.image.DataBufferShort; import java.awt.image.DataBufferUShort; import java.awt.image.DirectColorModel; import java.awt.image.Raster; import java.awt.image.RenderedImage; import java.awt.image.SampleModel; import java.awt.image.SinglePixelPackedSampleModel; import java.awt.image.WritableRaster; /**

* Set of utility methods for Graphics.
* These generally bypass broken methods in Java2D or provide tweaked
* implementations.
*
* @author 
* @version $Id: GraphicsUtil.java 603243 2007-12-11 13:49:04Z jeremias $
*/

public class GraphicsUtil {

   public static AffineTransform IDENTITY = new AffineTransform();
   /**
    * Standard prebuilt Linear_sRGB color model with no alpha */
   public static final ColorModel Linear_sRGB =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_LINEAR_RGB), 24,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0x0, false,
                            DataBuffer.TYPE_INT);
   /**
    * Standard prebuilt Linear_sRGB color model with premultiplied alpha.
    */
   public static final ColorModel Linear_sRGB_Pre =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_LINEAR_RGB), 32,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0xFF000000, true,
                            DataBuffer.TYPE_INT);
   /**
    * Standard prebuilt Linear_sRGB color model with unpremultiplied alpha.
    */
   public static final ColorModel Linear_sRGB_Unpre =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_LINEAR_RGB), 32,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0xFF000000, false,
                            DataBuffer.TYPE_INT);
   /**
    * Standard prebuilt sRGB color model with no alpha.
    */
   public static final ColorModel sRGB =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_sRGB), 24,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0x0, false,
                            DataBuffer.TYPE_INT);
   /**
    * Standard prebuilt sRGB color model with premultiplied alpha.
    */
   public static final ColorModel sRGB_Pre =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_sRGB), 32,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0xFF000000, true,
                            DataBuffer.TYPE_INT);
   /**
    * Standard prebuilt sRGB color model with unpremultiplied alpha.
    */
   public static final ColorModel sRGB_Unpre =
       new DirectColorModel(ColorSpace.getInstance
                            (ColorSpace.CS_sRGB), 32,
                            0x00FF0000, 0x0000FF00,
                            0x000000FF, 0xFF000000, false,
                            DataBuffer.TYPE_INT);
   /**
    * Method that returns either Linear_sRGB_Pre or Linear_sRGB_UnPre
    * based on premult flag.
    * @param premult True if the ColorModel should have premultiplied alpha.
    * @return        a ColorMdoel with Linear sRGB colorSpace and
    *                the alpha channel set in accordance with
    *                premult
    */
   public static ColorModel makeLinear_sRGBCM(boolean premult) {
        return premult ? Linear_sRGB_Pre : Linear_sRGB_Unpre;
   }
   /**
    * Constructs a BufferedImage with a linear sRGB colorModel, and alpha.
    * @param width   The desired width of the BufferedImage
    * @param height  The desired height of the BufferedImage
    * @param premult The desired state of alpha premultiplied
    * @return        The requested BufferedImage.
    */
   public static BufferedImage makeLinearBufferedImage(int width,
                                                       int height,
                                                       boolean premult) {
       ColorModel cm = makeLinear_sRGBCM(premult);
       WritableRaster wr = cm.createCompatibleWritableRaster(width, height);
       return new BufferedImage(cm, wr, premult, null);
   }
   /**
    * Creates a new raster that has a copy of the data in
    * ras.  This is highly optimized for speed.  There is
    * no provision for changing any aspect of the SampleModel.
    *
    * This method should be used when you need to change the contents
    * of a Raster that you do not "own" (ie the result of a
    * getData call).
    * @param ras The Raster to copy.
    * @return    A writable copy of ras
    */
   public static WritableRaster copyRaster(Raster ras) {
       return copyRaster(ras, ras.getMinX(), ras.getMinY());
   }
   /**
    * Creates a new raster that has a copy of the data in
    * ras.  This is highly optimized for speed.  There is
    * no provision for changing any aspect of the SampleModel.
    * However you can specify a new location for the returned raster.
    *
    * This method should be used when you need to change the contents
    * of a Raster that you do not "own" (ie the result of a
    * getData call).
    *
    * @param ras The Raster to copy.
    *
    * @param minX The x location for the upper left corner of the
    *             returned WritableRaster.
    *
    * @param minY The y location for the upper left corner of the
    *             returned WritableRaster.
    *
    * @return    A writable copy of ras
    */
   public static WritableRaster copyRaster(Raster ras, int minX, int minY) {
       WritableRaster ret = Raster.createWritableRaster
           (ras.getSampleModel(),
            new Point(0,0));
       ret = ret.createWritableChild
           (ras.getMinX()-ras.getSampleModelTranslateX(),
            ras.getMinY()-ras.getSampleModelTranslateY(),
            ras.getWidth(), ras.getHeight(),
            minX, minY, null);
       // Use System.arraycopy to copy the data between the two...
       DataBuffer srcDB = ras.getDataBuffer();
       DataBuffer retDB = ret.getDataBuffer();
       if (srcDB.getDataType() != retDB.getDataType()) {
           throw new IllegalArgumentException
               ("New DataBuffer doesn"t match original");
       }
       int len   = srcDB.getSize();
       int banks = srcDB.getNumBanks();
       int [] offsets = srcDB.getOffsets();
       for (int b=0; b< banks; b++) {
           switch (srcDB.getDataType()) {
           case DataBuffer.TYPE_BYTE: {
               DataBufferByte srcDBT = (DataBufferByte)srcDB;
               DataBufferByte retDBT = (DataBufferByte)retDB;
               System.arraycopy(srcDBT.getData(b), offsets[b],
                                retDBT.getData(b), offsets[b], len);
               break;
           }
           case DataBuffer.TYPE_INT: {
               DataBufferInt srcDBT = (DataBufferInt)srcDB;
               DataBufferInt retDBT = (DataBufferInt)retDB;
               System.arraycopy(srcDBT.getData(b), offsets[b],
                                retDBT.getData(b), offsets[b], len);
               break;
           }
           case DataBuffer.TYPE_SHORT: {
               DataBufferShort srcDBT = (DataBufferShort)srcDB;
               DataBufferShort retDBT = (DataBufferShort)retDB;
               System.arraycopy(srcDBT.getData(b), offsets[b],
                                retDBT.getData(b), offsets[b], len);
               break;
           }
           case DataBuffer.TYPE_USHORT: {
               DataBufferUShort srcDBT = (DataBufferUShort)srcDB;
               DataBufferUShort retDBT = (DataBufferUShort)retDB;
               System.arraycopy(srcDBT.getData(b), offsets[b],
                                retDBT.getData(b), offsets[b], len);
               break;
           }
           }
       }
       return ret;
   }
   /**
    * Coerces ras to be writable.  The returned Raster continues to
    * reference the DataBuffer from ras, so modifications to the returned
* WritableRaster will be seen in ras.

* * This method should only be used if you need a WritableRaster due to * an interface (such as to construct a BufferedImage), but have no * intention of modifying the contents of the returned Raster. If * you have any doubt about other users of the data in ras, * use copyRaster (above). * @param ras The raster to make writable. * @return A Writable version of ras (shares DataBuffer with * ras). */ public static WritableRaster makeRasterWritable(Raster ras) { return makeRasterWritable(ras, ras.getMinX(), ras.getMinY()); } /** * Coerces ras to be writable. The returned Raster continues to * reference the DataBuffer from ras, so modifications to the returned * WritableRaster will be seen in ras.<p> * * You can specify a new location for the returned WritableRaster, this * is especially useful for constructing BufferedImages which require * the Raster to be at (0,0). * * This method should only be used if you need a WritableRaster due to * an interface (such as to construct a BufferedImage), but have no * intention of modifying the contents of the returned Raster. If * you have any doubt about other users of the data in ras, * use copyRaster (above). * * @param ras The raster to make writable. * * @param minX The x location for the upper left corner of the * returned WritableRaster. * * @param minY The y location for the upper left corner of the * returned WritableRaster. * * @return A Writable version of ras with it"s upper left * hand coordinate set to minX, minY (shares it"s DataBuffer * with ras). */ public static WritableRaster makeRasterWritable(Raster ras, int minX, int minY) { WritableRaster ret = Raster.createWritableRaster (ras.getSampleModel(), ras.getDataBuffer(), new Point(0,0)); ret = ret.createWritableChild (ras.getMinX()-ras.getSampleModelTranslateX(), ras.getMinY()-ras.getSampleModelTranslateY(), ras.getWidth(), ras.getHeight(), minX, minY, null); return ret; } /** * Create a new ColorModel with it"s alpha premultiplied state matching * newAlphaPreMult. * @param cm The ColorModel to change the alpha premult state of. * @param newAlphaPreMult The new state of alpha premult. * @return A new colorModel that has isAlphaPremultiplied() * equal to newAlphaPreMult. */ public static ColorModel coerceColorModel(ColorModel cm, boolean newAlphaPreMult) { if (cm.isAlphaPremultiplied() == newAlphaPreMult) return cm; // Easiest way to build proper colormodel for new Alpha state... // Eventually this should switch on known ColorModel types and // only fall back on this hack when the CM type is unknown. WritableRaster wr = cm.createCompatibleWritableRaster(1,1); return cm.coerceData(wr, newAlphaPreMult); } /** * Coerces data within a bufferedImage to match newAlphaPreMult, * Note that this can not change the colormodel of bi so you * * @param wr The raster to change the state of. * @param cm The colormodel currently associated with data in wr. * @param newAlphaPreMult The desired state of alpha Premult for raster. * @return A new colormodel that matches newAlphaPreMult. */ public static ColorModel coerceData(WritableRaster wr, ColorModel cm, boolean newAlphaPreMult) { // System.out.println("CoerceData: " + cm.isAlphaPremultiplied() + // " Out: " + newAlphaPreMult); if (!cm.hasAlpha()) // Nothing to do no alpha channel return cm; if (cm.isAlphaPremultiplied() == newAlphaPreMult) // nothing to do alpha state matches... return cm; // System.out.println("CoerceData: " + wr.getSampleModel()); if (newAlphaPreMult) { multiplyAlpha(wr); } else { divideAlpha(wr); } return coerceColorModel(cm, newAlphaPreMult); } public static void multiplyAlpha(WritableRaster wr) { if (is_BYTE_COMP_Data(wr.getSampleModel())) mult_BYTE_COMP_Data(wr); else if (is_INT_PACK_Data(wr.getSampleModel(), true)) mult_INT_PACK_Data(wr); else { int [] pixel = null; int bands = wr.getNumBands(); float norm = 1f/255f; int x0, x1, y0, y1, a, b; float alpha; x0 = wr.getMinX(); x1 = x0+wr.getWidth(); y0 = wr.getMinY(); y1 = y0+wr.getHeight(); for (int y=y0; y<y1; y++) for (int x=x0; x<x1; x++) { pixel = wr.getPixel(x,y,pixel); a = pixel[bands-1]; if ((a >= 0) && (a < 255)) { alpha = a*norm; for (b=0; b<bands-1; b++) pixel[b] = (int)(pixel[b]*alpha+0.5f); wr.setPixel(x,y,pixel); } } } } public static void divideAlpha(WritableRaster wr) { if (is_BYTE_COMP_Data(wr.getSampleModel())) divide_BYTE_COMP_Data(wr); else if (is_INT_PACK_Data(wr.getSampleModel(), true)) divide_INT_PACK_Data(wr); else { int x0, x1, y0, y1, a, b; float ialpha; int bands = wr.getNumBands(); int [] pixel = null; x0 = wr.getMinX(); x1 = x0+wr.getWidth(); y0 = wr.getMinY(); y1 = y0+wr.getHeight(); for (int y=y0; y<y1; y++) for (int x=x0; x<x1; x++) { pixel = wr.getPixel(x,y,pixel); a = pixel[bands-1]; if ((a > 0) && (a < 255)) { ialpha = 255/(float)a; for (b=0; b<bands-1; b++) pixel[b] = (int)(pixel[b]*ialpha+0.5f); wr.setPixel(x,y,pixel); } } } } public static void copyBand(Raster src, int srcBand, WritableRaster dst, int dstBand) { Rectangle sR = src.getBounds(); Rectangle dR = dst.getBounds(); Rectangle cpR = sR.intersection(dR); copyBand(src, cpR, srcBand, dst, cpR, dstBand); } public static void copyBand(Raster src, Rectangle sR, int sBand, WritableRaster dst, Rectangle dR, int dBand) { int dy = dR.y -sR.y; int dx = dR.x -sR.x; sR = sR.intersection(src.getBounds()); dR = dR.intersection(dst.getBounds()); int width, height; if (dR.width < sR.width) width = dR.width; else width = sR.width; if (dR.height < sR.height) height = dR.height; else height = sR.height; int x = sR.x+dx; int [] samples = null; for (int y=sR.y; y< sR.y+height; y++) { samples = src.getSamples(sR.x, y, width, 1, sBand, samples); dst.setSamples(x, y+dy, width, 1, dBand, samples); } } public static boolean is_INT_PACK_Data(SampleModel sm, boolean requireAlpha) { // Check ColorModel is of type DirectColorModel if(!(sm instanceof SinglePixelPackedSampleModel)) return false; // Check transfer type if(sm.getDataType() != DataBuffer.TYPE_INT) return false; SinglePixelPackedSampleModel sppsm; sppsm = (SinglePixelPackedSampleModel)sm; int [] masks = sppsm.getBitMasks(); if (masks.length == 3) { if (requireAlpha) return false; } else if (masks.length != 4) return false; if(masks[0] != 0x00ff0000) return false; if(masks[1] != 0x0000ff00) return false; if(masks[2] != 0x000000ff) return false; if ((masks.length == 4) && (masks[3] != 0xff000000)) return false; return true; } public static boolean is_BYTE_COMP_Data(SampleModel sm) { // Check ColorModel is of type DirectColorModel if(!(sm instanceof ComponentSampleModel)) return false; // Check transfer type if(sm.getDataType() != DataBuffer.TYPE_BYTE) return false; return true; } protected static void divide_INT_PACK_Data(WritableRaster wr) { // System.out.println("Divide Int"); SinglePixelPackedSampleModel sppsm; sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = sppsm.getScanlineStride(); DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); final int base = (db.getOffset() + sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); // Access the pixel data array final int[] pixels = db.getBankData()[0]; for (int y=0; y<wr.getHeight(); y++) { int sp = base + y*scanStride; final int end = sp + width; while (sp < end) { int pixel = pixels[sp]; int a = pixel>>>24; if (a<=0) { pixels[sp] = 0x00FFFFFF; } else if (a<255) { int aFP = (0x00FF0000/a); pixels[sp] = ((a << 24) | (((((pixel&0xFF0000)>>16)*aFP)&0xFF0000) ) | (((((pixel&0x00FF00)>>8) *aFP)&0xFF0000)>>8 ) | (((((pixel&0x0000FF)) *aFP)&0xFF0000)>>16)); } sp++; } } } protected static void mult_INT_PACK_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); SinglePixelPackedSampleModel sppsm; sppsm = (SinglePixelPackedSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = sppsm.getScanlineStride(); DataBufferInt db = (DataBufferInt)wr.getDataBuffer(); final int base = (db.getOffset() + sppsm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); // Access the pixel data array final int[] pixels = db.getBankData()[0]; for (int y=0; y<wr.getHeight(); y++) { int sp = base + y*scanStride; final int end = sp + width; while (sp < end) { int pixel = pixels[sp]; int a = pixel>>>24; if ((a>=0) && (a<255)) { // this does NOT include a == 255 (0xff) ! pixels[sp] = ((a << 24) | ((((pixel&0xFF0000)*a)>>8)&0xFF0000) | ((((pixel&0x00FF00)*a)>>8)&0x00FF00) | ((((pixel&0x0000FF)*a)>>8)&0x0000FF)); } sp++; } } } protected static void divide_BYTE_COMP_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); ComponentSampleModel csm; csm = (ComponentSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = csm.getScanlineStride(); final int pixStride = csm.getPixelStride(); final int [] bandOff = csm.getBandOffsets(); DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); final int base = (db.getOffset() + csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); int aOff = bandOff[bandOff.length-1]; int bands = bandOff.length-1; // Access the pixel data array final byte[] pixels = db.getBankData()[0]; for (int y=0; y<wr.getHeight(); y++) { int sp = base + y*scanStride; final int end = sp + width*pixStride; while (sp < end) { int a = pixels[sp+aOff]&0xFF; if (a==0) { for (int b = 0; b < bands; b++) pixels[sp+bandOff[b]] = (byte)0xFF; } else if (a<255) { // this does NOT include a == 255 (0xff) ! int aFP = (0x00FF0000/a); for (int b = 0; b < bands; b++) { int i = sp+bandOff[b]; pixels[i] = (byte)(((pixels[i]&0xFF)*aFP)>>>16); } } sp+=pixStride; } } } protected static void mult_BYTE_COMP_Data(WritableRaster wr) { // System.out.println("Multiply Int: " + wr); ComponentSampleModel csm; csm = (ComponentSampleModel)wr.getSampleModel(); final int width = wr.getWidth(); final int scanStride = csm.getScanlineStride(); final int pixStride = csm.getPixelStride(); final int [] bandOff = csm.getBandOffsets(); DataBufferByte db = (DataBufferByte)wr.getDataBuffer(); final int base = (db.getOffset() + csm.getOffset(wr.getMinX()-wr.getSampleModelTranslateX(), wr.getMinY()-wr.getSampleModelTranslateY())); int aOff = bandOff[bandOff.length-1]; int bands = bandOff.length-1; // Access the pixel data array final byte[] pixels = db.getBankData()[0]; for (int y=0; y<wr.getHeight(); y++) { int sp = base + y*scanStride; final int end = sp + width*pixStride; while (sp < end) { int a = pixels[sp+aOff]&0xFF; if (a!=0xFF) for (int b = 0; b < bands; b++) { int i = sp+bandOff[b]; pixels[i] = (byte)(((pixels[i]&0xFF)*a)>>8); } sp+=pixStride; } } } /* This is skanky debugging code that might be useful in the future: if (count == 33) { String label = "sub [" + x + ", " + y + "]: "; org.ImageDisplay.showImage (label, subBI); org.ImageDisplay.printImage (label, subBI, new Rectangle(75-iR.x, 90-iR.y, 32, 32)); } // if ((count++ % 50) == 10) // org.ImageDisplay.showImage("foo: ", subBI); Graphics2D realG2D = g2d; while (realG2D instanceof sun.java2d.ProxyGraphics2D) { realG2D = ((sun.java2d.ProxyGraphics2D)realG2D).getDelegate(); } if (realG2D instanceof sun.awt.image.BufferedImageGraphics2D) { count++; if (count == 34) { RenderedImage ri; ri = ((sun.awt.image.BufferedImageGraphics2D)realG2D).bufImg; // g2d.setComposite(SVGComposite.OVER); // org.ImageDisplay.showImage("Bar: " + count, cr); org.ImageDisplay.printImage("Bar: " + count, cr, new Rectangle(75, 90, 32, 32)); org.ImageDisplay.showImage ("Foo: " + count, ri); org.ImageDisplay.printImage("Foo: " + count, ri, new Rectangle(75, 90, 32, 32)); System.out.println("BI: " + ri); System.out.println("BISM: " + ri.getSampleModel()); System.out.println("BICM: " + ri.getColorModel()); System.out.println("BICM class: " + ri.getColorModel().getClass()); System.out.println("BICS: " + ri.getColorModel().getColorSpace()); System.out.println ("sRGB CS: " + ColorSpace.getInstance(ColorSpace.CS_sRGB)); System.out.println("G2D info"); System.out.println("\tComposite: " + g2d.getComposite()); System.out.println("\tTransform" + g2d.getTransform()); java.awt.RenderingHints rh = g2d.getRenderingHints(); java.util.Set keys = rh.keySet(); java.util.Iterator iter = keys.iterator(); while (iter.hasNext()) { Object o = iter.next(); System.out.println("\t" + o.toString() + " -> " + rh.get(o).toString()); } ri = cr; System.out.println("RI: " + ri); System.out.println("RISM: " + ri.getSampleModel()); System.out.println("RICM: " + ri.getColorModel()); System.out.println("RICM class: " + ri.getColorModel().getClass()); System.out.println("RICS: " + ri.getColorModel().getColorSpace()); } }

  • /
/** * Extracts an alpha raster from a RenderedImage. The method tries to avoid copying data * unnecessarily by checking if the RenderedImage is a BufferedImage which offers suitable * direct methods. * @param image the image * @return the alpha raster */ public static Raster getAlphaRaster(RenderedImage image) { ColorModel cm = image.getColorModel(); if (!cm.hasAlpha() || cm.getTransparency() != ColorModel.TRANSLUCENT) { throw new IllegalStateException("Image doesn"t have an alpha channel"); } Raster alpha; if (image instanceof BufferedImage) { //Optimization possible with BufferedImage (No copying) alpha = ((BufferedImage)image).getAlphaRaster(); } else { WritableRaster wraster = GraphicsUtil.makeRasterWritable(image.getData()); alpha = image.getColorModel().getAlphaRaster(wraster); } return alpha; } } </source>

Dithering a 24-bit RGB image to a monochrome (1-bit or bilevel) image

<source lang="java"> //-----------------------------------------------------------------------// // // // R G B T o B i l e v e l // // // //-----------------------------------------------------------------------// /*

* Copyright (c) 2002 Sun Microsystems, Inc. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* -Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* -Redistribution 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.
*
* Neither the name of Sun Microsystems, Inc. or the names of contributors may
* be used to endorse or promote products derived from this software without
* specific prior written permission.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* You acknowledge that Software is not designed,licensed or intended for use in
* the design, construction, operation or maintenance of any nuclear facility.
*/

package omr.jai; import java.awt.*; import java.awt.color.*; import java.awt.event.*; import java.awt.geom.*; import java.awt.image.*; import java.awt.image.renderable.*; import java.util.*; import javax.media.jai.*; import javax.media.jai.operator.*; import javax.media.jai.widget.*; /**

* Demo code for dithering a 24-bit RGB image to a monochrome (1-bit
* or bilevel) image. The source image must be an 24-bit RGB image.
* The result is displayed.
*
* Usage: java RGBToBilevel filename [true]
*
* If the second argument is present and equal to "true" then error diffusion
* will be used; otherwise ordered dithering will be used.
*/

public class RGBToBilevel extends Frame {

   public static void main(String[] args) {
       new RGBToBilevel(args[0],
                        args.length > 1 ? args[1].equals("true") : false);
   }
   RGBToBilevel(final String fileName,
                boolean isErrorDiffusion)
   {
       // Load the file.
       PlanarImage src = JAI.create("fileload", fileName);
       // Load the ParameterBlock for the dithering operation
       // and set the operation name.
       ParameterBlock pb = new ParameterBlock();
       pb.addSource(src);
       String opName = null;
       if(isErrorDiffusion) {
           opName = "errordiffusion";
           LookupTableJAI lut =
               new LookupTableJAI(new byte[][] {{(byte)0x00, (byte)0xff},
                                                {(byte)0x00, (byte)0xff},
                                                {(byte)0x00, (byte)0xff}});
           pb.add(lut);
           pb.add(KernelJAI.ERROR_FILTER_FLOYD_STEINBERG);
       } else {
           opName = "ordereddither";
           ColorCube cube = ColorCube.createColorCube(DataBuffer.TYPE_BYTE,
                                                      0, new int[] {2, 2, 2});
           pb.add(cube);
           pb.add(KernelJAI.DITHER_MASK_443);
       }
       // Create a layout containing an IndexColorModel which maps
       // zero to zero and unity to 255; force SampleModel to be bilevel.
       ImageLayout layout = new ImageLayout();
       byte[] map = new byte[] {(byte)0x00, (byte)0xff};
       ColorModel cm = new IndexColorModel(1, 2, map, map, map);
       layout.setColorModel(cm);
       SampleModel sm = new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE,
                                                        src.getWidth(),
                                                        src.getHeight(),
                                                        1);
       layout.setSampleModel(sm);
       // Create a hint containing the layout.
       RenderingHints hints = new RenderingHints(JAI.KEY_IMAGE_LAYOUT,
                                                 layout);
       // Dither the image.
       final PlanarImage dst = JAI.create(opName, pb, hints);
       // Exit on window closing.
       addWindowListener(new WindowAdapter() {
               public void windowClosing(WindowEvent we) {
                   JAI.create("filestore", dst, fileName + ".out", "PNG", null);
                   System.exit(0);
               }
           });
       // Display the result.
       //// ATTENTION A REMPLACER : add(new ScrollingImagePanel(dst, dst.getWidth(), dst.getHeight()));
       pack();
       setVisible(true);
   }

}



 </source>   



Gray scale image operation

<source lang="java">

/*

* Copyright (c) 2000 David Flanagan.  All rights reserved.
* This code is from the book Java Examples in a Nutshell, 2nd Edition.
* It is provided AS-IS, WITHOUT ANY WARRANTY either expressed or implied.
* You may study, use, and modify it for any non-commercial purpose.
* You may distribute it non-commercially as long as you retain this notice.
* For a commercial use license, or to purchase the book (recommended),
* visit http://www.davidflanagan.ru/javaexamples2.
*/

import java.awt.Color; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.awt.color.ColorSpace; import java.awt.geom.AffineTransform; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ByteLookupTable; import java.awt.image.ColorConvertOp; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.awt.image.LookupOp; import java.awt.image.RescaleOp; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.net.URL; import javax.swing.JFrame; import javax.swing.JPanel; /** A demonstration of various image processing filters */ public class ImageOps extends JPanel {

   static final int WIDTH = 600, HEIGHT = 675; // Size of our example
   public String getName() {
       return "Image Processing";
   }
   public int getWidth() {
       return WIDTH;
   }
   public int getHeight() {
       return HEIGHT;
   }
   Image image;
   /** This constructor loads the image we will manipulate */

public ImageOps() {

   image = Toolkit.getDefaultToolkit().getImage("a.jpg");
 }
   // These arrays of bytes are used by the LookupImageOp image filters below
   static byte[] brightenTable = new byte[256];
   static byte[] thresholdTable = new byte[256];
   static { // Initialize the arrays
       for (int i = 0; i < 256; i++) {
           brightenTable[i] = (byte) (Math.sqrt(i / 255.0) * 255);
           thresholdTable[i] = (byte) ((i < 225) ? 0 : i);
       }
   }
   // This AffineTransform is used by one of the image filters below
   static AffineTransform mirrorTransform;
   static { // Create and initialize the AffineTransform
       mirrorTransform = AffineTransform.getTranslateInstance(127, 0);
       mirrorTransform.scale(-1.0, 1.0); // flip horizontally
   }
   // These are the labels we"ll display for each of the filtered images
   static String[] filterNames = new String[] { "Original", "Gray Scale", "Negative", "Brighten (linear)", "Brighten (sqrt)", "Threshold", "Blur", "Sharpen", "Edge Detect", "Mirror", "Rotate (center)", "Rotate (lower left)" };
   // The following BufferedImageOp image filter objects perform
   // different types of image processing operations.
   static BufferedImageOp[] filters = new BufferedImageOp[] {
   // 1) No filter here. We"ll display the original image
                                                             null,
                                                             // 2) Convert to Grayscale color space
                                                             new ColorConvertOp(ColorSpace.getInstance(ColorSpace.CS_GRAY), null),
                                                             // 3) Image negative. Multiply each color value by -1.0 and add 255
                                                             new RescaleOp(-1.0f, 255f, null),
                                                             // 4) Brighten using a linear formula that increases all color
                                                             // values
                                                             new RescaleOp(1.25f, 0, null),
                                                             // 5) Brighten using the lookup table defined above
                                                             new LookupOp(new ByteLookupTable(0, brightenTable), null),
                                                             // 6) Threshold using the lookup table defined above
                                                             new LookupOp(new ByteLookupTable(0, thresholdTable), null),
                                                             // 7) Blur by "convolving" the image with a matrix
                                                             new ConvolveOp(new Kernel(3, 3, new float[] { .1111f, .1111f, .1111f, .1111f, .1111f, .1111f, .1111f, .1111f, .1111f, })),
                                                             // 8) Sharpen by using a different matrix
                                                             new ConvolveOp(new Kernel(3, 3, new float[] { 0.0f, -0.75f, 0.0f, -0.75f, 4.0f, -0.75f, 0.0f, -0.75f, 0.0f })),
                                                             // 9) Edge detect using yet another matrix
                                                             new ConvolveOp(new Kernel(3, 3, new float[] { 0.0f, -0.75f, 0.0f, -0.75f, 3.0f, -0.75f, 0.0f, -0.75f, 0.0f })),
                                                             // 10) Compute a mirror image using the transform defined above
                                                             new AffineTransformOp(mirrorTransform, AffineTransformOp.TYPE_BILINEAR),
                                                             // 11) Rotate the image 180 degrees about its center point
                                                             new AffineTransformOp(AffineTransform.getRotateInstance(Math.PI, 64, 95), AffineTransformOp.TYPE_NEAREST_NEIGHBOR),
                                                             // 12) Rotate the image 15 degrees about the bottom left
                                                             new AffineTransformOp(AffineTransform.getRotateInstance(Math.PI / 12, 0, 190), AffineTransformOp.TYPE_NEAREST_NEIGHBOR), };
   /** Draw the example */
   public void paint(Graphics g1) {
       Graphics2D g = (Graphics2D) g1;
       // Create a BufferedImage big enough to hold the Image loaded
       // in the constructor. Then copy that image into the new
       // BufferedImage object so that we can process it.
       BufferedImage bimage = new BufferedImage(image.getWidth(this), image.getHeight(this), BufferedImage.TYPE_INT_RGB);
       Graphics2D ig = bimage.createGraphics();
       ig.drawImage(image, 0, 0, this); // copy the image
       // Set some default graphics attributes
       g.setFont(new Font("SansSerif", Font.BOLD, 12)); // 12pt bold text
       g.setColor(Color.green); // Draw in green
       g.translate(10, 10); // Set some margins
       // Loop through the filters
       for (int i = 0; i < filters.length; i++) {
           // If the filter is null, draw the original image, otherwise,
           // draw the image as processed by the filter
           if (filters[i] == null)
               g.drawImage(bimage, 0, 0, this);
           else
               g.drawImage(filters[i].filter(bimage, null), 0, 0, this);
           g.drawString(filterNames[i], 0, 205); // Label the image
           g.translate(137, 0); // Move over
           if (i % 4 == 3)
               g.translate(-137 * 4, 215); // Move down after 4
       }
   }
   public static void main(String[] a) {
       JFrame f = new JFrame();
       f.addWindowListener(new WindowAdapter() {
           public void windowClosing(WindowEvent e) {
               System.exit(0);
           }
       });
       f.setContentPane(new ImageOps());
       f.pack();
       f.setVisible(true);
   }

}


 </source>   



If the image has transparent pixels

<source lang="java"> /*

* Copyright (c) JForum Team
* All rights reserved.
* Redistribution and use in source and binary forms, 
* with or without modification, are permitted provided 
* that the following conditions are met:
* 1) Redistributions of source code must retain the above 
* copyright notice, this list of conditions and the 
* following  disclaimer.
* 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.
* 3) Neither the name of "Rafael Steil" nor 
* the names of its contributors may be used to endorse 
* or promote products derived from this software without 
* specific prior written permission.
* 
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT 
* HOLDERS 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 COPYRIGHT OWNER 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
* 
* This file creation date: 21/04/2004 - 19:54:16
* The JForum Project
* http://www.jforum.net
*/

import java.awt.Dimension; import java.awt.Image; import java.awt.image.BufferedImage; import java.awt.image.PixelGrabber; import java.io.File; import java.io.IOException; import java.util.Iterator; import java.util.Locale; import javax.imageio.IIOImage; import javax.imageio.ImageIO; import javax.imageio.ImageWriteParam; import javax.imageio.ImageWriter; import javax.imageio.plugins.jpeg.JPEGImageWriteParam; import javax.imageio.stream.ImageOutputStream;

/**

* Utilities methods for image manipulation. It does not support writting of GIF images, but it can
* read from. GIF images will be saved as PNG.
* 
* @author Rafael Steil
* @version $Id: ImageUtils.java,v 1.23 2007/09/09 01:05:22 rafaelsteil Exp $
*/

public class ImageUtils {

 public static final int IMAGE_UNKNOWN = -1;
 public static final int IMAGE_JPEG = 0;
 public static final int IMAGE_PNG = 1;
 public static final int IMAGE_GIF = 2;
 /**
  * Resizes an image
  * 
  * @param imgName The image name to resize. Must be the complet path to the file
  * @param type int
  * @param maxWidth The image"s max width
  * @param maxHeight The image"s max height
  * @return A resized BufferedImage
  */
 public static BufferedImage resizeImage(String imgName, int type, int maxWidth, int maxHeight)
 {
   try {
     return resizeImage(ImageIO.read(new File(imgName)), type, maxWidth, maxHeight);
   }
   catch (IOException e) {
     e.printStackTrace();
   }
 }
 /**
  * Resizes an image.
  * 
  * @param image
  *            The image to resize
  * @param maxWidth
  *            The image"s max width
  * @param maxHeight
  *            The image"s max height
  * @return A resized BufferedImage
  * @param type
  *            int
  */
 public static BufferedImage resizeImage(BufferedImage image, int type, int maxWidth, int maxHeight)
 {
   Dimension largestDimension = new Dimension(maxWidth, maxHeight);
   // Original size
   int imageWidth = image.getWidth(null);
   int imageHeight = image.getHeight(null);
   float aspectRatio = (float) imageWidth / imageHeight;
   if (imageWidth > maxWidth || imageHeight > maxHeight) {
     if ((float) largestDimension.width / largestDimension.height > aspectRatio) {
       largestDimension.width = (int) Math.ceil(largestDimension.height * aspectRatio);
     }
     else {
       largestDimension.height = (int) Math.ceil(largestDimension.width / aspectRatio);
     }
     imageWidth = largestDimension.width;
     imageHeight = largestDimension.height;
   }
   return createHeadlessSmoothBufferedImage(image, type, imageWidth, imageHeight);
 }
 /**
  * Saves an image to the disk.
  * 
  * @param image  The image to save
  * @param toFileName The filename to use
  * @param type The image type. Use ImageUtils.IMAGE_JPEG to save as JPEG images,
  *  or ImageUtils.IMAGE_PNG to save as PNG.
  * @return false if no appropriate writer is found
  */
 public static boolean saveImage(BufferedImage image, String toFileName, int type)
 {
   try {
     return ImageIO.write(image, type == IMAGE_JPEG ? "jpg" : "png", new File(toFileName));
   }
   catch (IOException e) {
     e.printStackTrace();
   }
 }
 /**
  * Compress and save an image to the disk. Currently this method only supports JPEG images.
  * 
  * @param image The image to save
  * @param toFileName The filename to use
  * @param type The image type. Use ImageUtils.IMAGE_JPEG to save as JPEG images,
  * or ImageUtils.IMAGE_PNG to save as PNG.
  */
 public static void saveCompressedImage(BufferedImage image, String toFileName, int type)
 {
   try {
     if (type == IMAGE_PNG) {
       throw new UnsupportedOperationException("PNG compression not implemented");
     }
     Iterator iter = ImageIO.getImageWritersByFormatName("jpg");
     ImageWriter writer;
     writer = (ImageWriter) iter.next();
     ImageOutputStream ios = ImageIO.createImageOutputStream(new File(toFileName));
     writer.setOutput(ios);
     ImageWriteParam iwparam = new JPEGImageWriteParam(Locale.getDefault());
     iwparam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
     iwparam.setCompressionQuality(0.7F);
     writer.write(null, new IIOImage(image, null, null), iwparam);
     ios.flush();
     writer.dispose();
     ios.close();
   }
   catch (IOException e) {
     e.printStackTrace();
   }
 }
 /**
  * Creates a BufferedImage from an Image. This method can
  * function on a completely headless system. This especially includes Linux and Unix systems
  * that do not have the X11 libraries installed, which are required for the AWT subsystem to
  * operate. This method uses nearest neighbor approximation, so it"s quite fast. Unfortunately,
  * the result is nowhere near as nice looking as the createHeadlessSmoothBufferedImage method.
  * 
  * @param image  The image to convert
  * @param w The desired image width
  * @param h The desired image height
  * @return The converted image
  * @param type int
  */
 public static BufferedImage createHeadlessBufferedImage(BufferedImage image, int type, int width, int height)
 {
   if (type == ImageUtils.IMAGE_PNG && hasAlpha(image)) {
     type = BufferedImage.TYPE_INT_ARGB;
   }
   else {
     type = BufferedImage.TYPE_INT_RGB;
   }
   BufferedImage bi = new BufferedImage(width, height, type);
   for (int y = 0; y < height; y++) {
     for (int x = 0; x < width; x++) {
       bi.setRGB(x, y, image.getRGB(x * image.getWidth() / width, y * image.getHeight() / height));
     }
   }
   return bi;
 }
 /**
  * Creates a BufferedImage from an Image. This method can
  * function on a completely headless system. This especially includes Linux and Unix systems
  * that do not have the X11 libraries installed, which are required for the AWT subsystem to
  * operate. The resulting image will be smoothly scaled using bilinear filtering.
  * 
  * @param source The image to convert
  * @param w The desired image width
  * @param h The desired image height
  * @return The converted image
  * @param type  int
  */
 public static BufferedImage createHeadlessSmoothBufferedImage(BufferedImage source, int type, int width, int height)
 {
   if (type == ImageUtils.IMAGE_PNG && hasAlpha(source)) {
     type = BufferedImage.TYPE_INT_ARGB;
   }
   else {
     type = BufferedImage.TYPE_INT_RGB;
   }
   BufferedImage dest = new BufferedImage(width, height, type);
   int sourcex;
   int sourcey;
   double scalex = (double) width / source.getWidth();
   double scaley = (double) height / source.getHeight();
   int x1;
   int y1;
   double xdiff;
   double ydiff;
   int rgb;
   int rgb1;
   int rgb2;
   for (int y = 0; y < height; y++) {
     sourcey = y * source.getHeight() / dest.getHeight();
     ydiff = scale(y, scaley) - sourcey;
     for (int x = 0; x < width; x++) {
       sourcex = x * source.getWidth() / dest.getWidth();
       xdiff = scale(x, scalex) - sourcex;
       x1 = Math.min(source.getWidth() - 1, sourcex + 1);
       y1 = Math.min(source.getHeight() - 1, sourcey + 1);
       rgb1 = getRGBInterpolation(source.getRGB(sourcex, sourcey), source.getRGB(x1, sourcey), xdiff);
       rgb2 = getRGBInterpolation(source.getRGB(sourcex, y1), source.getRGB(x1, y1), xdiff);
       rgb = getRGBInterpolation(rgb1, rgb2, ydiff);
       dest.setRGB(x, y, rgb);
     }
   }
   return dest;
 }
 private static double scale(int point, double scale)
 {
   return point / scale;
 }
 private static int getRGBInterpolation(int value1, int value2, double distance)
 {
   int alpha1 = (value1 & 0xFF000000) >>> 24;
   int red1 = (value1 & 0x00FF0000) >> 16;
   int green1 = (value1 & 0x0000FF00) >> 8;
   int blue1 = (value1 & 0x000000FF);
   int alpha2 = (value2 & 0xFF000000) >>> 24;
   int red2 = (value2 & 0x00FF0000) >> 16;
   int green2 = (value2 & 0x0000FF00) >> 8;
   int blue2 = (value2 & 0x000000FF);
   int rgb = ((int) (alpha1 * (1.0 - distance) + alpha2 * distance) << 24)
     | ((int) (red1 * (1.0 - distance) + red2 * distance) << 16)
     | ((int) (green1 * (1.0 - distance) + green2 * distance) << 8)
     | (int) (blue1 * (1.0 - distance) + blue2 * distance);
   return rgb;
 }
 /**
  * Determines if the image has transparent pixels.
  * 
  * @param image The image to check for transparent pixel.s
  * @return true of false, according to the result
  */
 public static boolean hasAlpha(Image image)
 {
   try {
     PixelGrabber pg = new PixelGrabber(image, 0, 0, 1, 1, false);
     pg.grabPixels();
     return pg.getColorModel().hasAlpha();
   }
   catch (InterruptedException e) {
     return false;
   }
 }

}



 </source>   



Image Color Operation: dark, bright, contrast, negative

<source lang="java"> /*

* Apollo - Motion capture and animation system
* Copyright (c) 2005 Apollo
* 
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* 
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
* 
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
*
* http://www.gnu.org/copyleft/gpl.html
*
* @author Giovane.Kuhn - brain@netuno.ru.br
*
*/

import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.GridLayout; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import java.awt.image.BufferedImage; import java.awt.image.ByteLookupTable; import java.awt.image.LookupOp; import java.awt.image.LookupTable; import java.awt.image.ShortLookupTable; import javax.swing.JButton; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.border.TitledBorder; public class ColorApp extends JFrame {

   DisplayPanel displayPanel;
   JButton brightenButton, darkenButton, contrastIncButton, contrastDecButton, reverseButton, resetButton;
   public ColorApp() {
       super();
       Container container = getContentPane();
       displayPanel = new DisplayPanel();
       container.add(displayPanel);
       JPanel panel = new JPanel();
       panel.setLayout(new GridLayout(3, 2));
       panel.setBorder(new TitledBorder("Click a Button to Perform the Associated Operation and Reset..."));
       brightenButton = new JButton("Brightness >>");
       brightenButton.addActionListener(new ButtonListener());
       darkenButton = new JButton("Darkness >>");
       darkenButton.addActionListener(new ButtonListener());
       contrastIncButton = new JButton("Contrast >>");
       contrastIncButton.addActionListener(new ButtonListener());
       contrastDecButton = new JButton("Contrast <<");
       contrastDecButton.addActionListener(new ButtonListener());
       reverseButton = new JButton("Negative");
       reverseButton.addActionListener(new ButtonListener());
       resetButton = new JButton("Reset");
       resetButton.addActionListener(new ButtonListener());
       panel.add(brightenButton);
       panel.add(darkenButton);
       panel.add(contrastIncButton);
       panel.add(contrastDecButton);
       panel.add(reverseButton);
       panel.add(resetButton);
       container.add(BorderLayout.SOUTH, panel);
       addWindowListener(new WindowEventHandler());
       setSize(displayPanel.getWidth(), displayPanel.getHeight() + 25);
       show();
   }
   class WindowEventHandler extends WindowAdapter {
       public void windowClosing(WindowEvent e) {
           System.exit(0);
       }
   }
   public static void main(String arg[]) {
       new ColorApp();
   }
   class ButtonListener implements ActionListener {
       public void actionPerformed(ActionEvent e) {
           JButton button = (JButton) e.getSource();
           if (button.equals(brightenButton)) {
               displayPanel.brightenLUT();
               displayPanel.applyFilter();
               displayPanel.repaint();
           } else if (button.equals(darkenButton)) {
               displayPanel.darkenLUT();
               displayPanel.applyFilter();
               displayPanel.repaint();
           } else if (button.equals(contrastIncButton)) {
               displayPanel.contrastIncLUT();
               displayPanel.applyFilter();
               displayPanel.repaint();
           } else if (button.equals(contrastDecButton)) {
               displayPanel.contrastDecLUT();
               displayPanel.applyFilter();
               displayPanel.repaint();
           } else if (button.equals(reverseButton)) {
               displayPanel.reverseLUT();
               displayPanel.applyFilter();
               displayPanel.repaint();
           } else if (button.equals(resetButton)) {
               displayPanel.reset();
               displayPanel.repaint();
           }
       }
   }

} class DisplayPanel extends JPanel {

   Image displayImage;
   BufferedImage bi;
   Graphics2D big;
   LookupTable lookupTable;
   DisplayPanel() {
       setBackground(Color.black); // panel background color
       loadImage();
       setSize(displayImage.getWidth(this), displayImage.getWidth(this)); // panel
       createBufferedImage();
   }
   public void loadImage() {
       displayImage = Toolkit.getDefaultToolkit().getImage("a.jpg");
       MediaTracker mt = new MediaTracker(this);
       mt.addImage(displayImage, 1);
       try {
           mt.waitForAll();
       } catch (Exception e) {
           System.out.println("Exception while loading.");
       }
       if (displayImage.getWidth(this) == -1) {
           System.out.println("No jpg file");
           System.exit(0);
       }
   }
   public void createBufferedImage() {
       bi = new BufferedImage(displayImage.getWidth(this), displayImage.getHeight(this), BufferedImage.TYPE_INT_ARGB);
       big = bi.createGraphics();
       big.drawImage(displayImage, 0, 0, this);
   }
   public void brightenLUT() {
       short brighten[] = new short[256];
       for (int i = 0; i < 256; i++) {
           short pixelValue = (short) (i + 10);
           if (pixelValue > 255)
               pixelValue = 255;
           else if (pixelValue < 0)
               pixelValue = 0;
           brighten[i] = pixelValue;
       }
       lookupTable = new ShortLookupTable(0, brighten);
   }
   public void darkenLUT() {
       short brighten[] = new short[256];
       for (int i = 0; i < 256; i++) {
           short pixelValue = (short) (i - 10);
           if (pixelValue > 255)
               pixelValue = 255;
           else if (pixelValue < 0)
               pixelValue = 0;
           brighten[i] = pixelValue;
       }
       lookupTable = new ShortLookupTable(0, brighten);
   }
   public void contrastIncLUT() {
       short brighten[] = new short[256];
       for (int i = 0; i < 256; i++) {
           short pixelValue = (short) (i * 1.2);
           if (pixelValue > 255)
               pixelValue = 255;
           else if (pixelValue < 0)
               pixelValue = 0;
           brighten[i] = pixelValue;
       }
       lookupTable = new ShortLookupTable(0, brighten);
   }
   public void contrastDecLUT() {
       short brighten[] = new short[256];
       for (int i = 0; i < 256; i++) {
           short pixelValue = (short) (i / 1.2);
           if (pixelValue > 255)
               pixelValue = 255;
           else if (pixelValue < 0)
               pixelValue = 0;
           brighten[i] = pixelValue;
       }
       lookupTable = new ShortLookupTable(0, brighten);
   }
   public void reverseLUT() {
       byte reverse[] = new byte[256];
       for (int i = 0; i < 256; i++) {
           reverse[i] = (byte) (255 - i);
       }
       lookupTable = new ByteLookupTable(0, reverse);
   }
   public void reset() {
       big.setColor(Color.black);
       big.clearRect(0, 0, bi.getWidth(this), bi.getHeight(this));
       big.drawImage(displayImage, 0, 0, this);
   }
   public void applyFilter() {
       LookupOp lop = new LookupOp(lookupTable, null);
       lop.filter(bi, bi);
   }
   public void update(Graphics g) {
       g.clearRect(0, 0, getWidth(), getHeight());
       paintComponent(g);
   }
   public void paintComponent(Graphics g) {
       super.paintComponent(g);
       Graphics2D g2D = (Graphics2D) g;
       g2D.drawImage(bi, 0, 0, this);
   }

}


 </source>   



ImageComparator compares a byte[] for equality by creating 2 hashes for the bytearray and comparing thoose hashes.

<source lang="java"> /**

* 
* JFreeReport : a free Java reporting library
* 
*
* Project Info:  http://reporting.pentaho.org/
*
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*
* This library is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* [Java is a trademark or registered trademark of Sun Microsystems, Inc.
* in the United States and other countries.]
*
* ------------
* ImageComparator.java
* ------------
* (C) Copyright 2001-2007, by Object Refinery Ltd, Pentaho Corporation and Contributors.
*/

import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.util.Arrays; /**

* The ImageComparator tries to compare a byte[] for equality by creating 2 hashes for the
* bytearray and comparing thoose hashes. If no digest algorithms are available, then the
* complete byte[] is used for comparison.
* <p>
* Using the digest method trades computing time for space.
*
* @author Thomas Morgner
*/

public class ImageComparator {

 /**
  * A ImageCompareData that uses the complete image data for comparison.
  */
 private static final class CompleteImageCompareData
 {
   /**
    * The image content.
    */
   private final byte[] image;
   /**
    * Create a new CompleteImageCompareData instance.
    *
    * @param image the image data used for comparison.
    */
   private CompleteImageCompareData (final byte[] image)
   {
     this.image = image;
   }
   /**
    * Checks whether the given Object equals this object.
    *
    * @param o the to be compared object
    * @return true, if both objects are equal
    */
   public boolean equals (final Object o)
   {
     if (this == o)
     {
       return true;
     }
     if (!(o instanceof CompleteImageCompareData))
     {
       return false;
     }
     final CompleteImageCompareData data = (CompleteImageCompareData) o;
     if (!Arrays.equals(image, data.image))
     {
       return false;
     }
     return true;
   }
   /**
    * returns a hashcode for this class.
    *
    * @return always 0.
    */
   public int hashCode ()
   {
     return image.length;
   }
 }
 /**
  * An ImageComparator which uses precomputed Message-Digests to compare the image.
  */
 private static final class DigestImageCompareData
 {
   /**
    * An MD5 digest.
    */
   private byte[] digestMD5Data;
   /**
    * An SHA digest.
    */
   private byte[] digestSHAData;
   /**
    * Creates a new DigestImageCompareData instance.
    *
    * @param digestMD5Data the MD5 digest data
    * @param digestSHAData the SHA1 digest data
    */
   private DigestImageCompareData (final byte[] digestMD5Data,
                                   final byte[] digestSHAData)
   {
     if (digestMD5Data == null || digestSHAData == null)
     {
       throw new NullPointerException();
     }
     this.digestMD5Data = digestMD5Data;
     this.digestSHAData = digestSHAData;
   }
   /**
    * Checks whether the given Object equals this object.
    *
    * @param o the to be compared object
    * @return true, if both objects are equal
    */
   public boolean equals (final Object o)
   {
     if (this == o)
     {
       return true;
     }
     if (!(o instanceof DigestImageCompareData))
     {
       return false;
     }
     final DigestImageCompareData data = (DigestImageCompareData) o;
     if (!Arrays.equals(digestMD5Data, data.digestMD5Data))
     {
       return false;
     }
     if (!Arrays.equals(digestSHAData, data.digestSHAData))
     {
       return false;
     }
     return true;
   }
   /**
    * returns a hashcode for this class.
    *
    * @return always 0.
    */
   public int hashCode ()
   {
     return 0;
   }
 }
 /**
  * An MD5 message digest.
  */
 private MessageDigest digestMD5;
 /**
  * An SHA message digest.
  */
 private MessageDigest digestSHA;
 /**
  * Creates a new ImageComparator. The comparator checks whether the MD5 and the SHA
  * message digest implementations are available. If they are not available, an
  * alternative comparison method is used, which is more memory consuming.
  */
 public ImageComparator ()
 {
   try
   {
     digestMD5 = MessageDigest.getInstance("MD5");
   }
   catch (NoSuchAlgorithmException nse)
   {
     System.out.println("No MD5 algorithm available");
   }
   try
   {
     digestSHA = MessageDigest.getInstance("SHA");
   }
   catch (NoSuchAlgorithmException nse)
   {
     System.out.println("No SHA algorithm available");
   }
 }
 /**
  * Creates 2 comparable objects. These objects can be compared for equality.
  *
  * @param image the image data which should be prepared for comparison
  * @param fast  whether to prefer the memory intensive faster compare method to the
  *              digest based comparation. This may result in outofmemory errors on huge
  *              reports or images.
  * @return the prepared image data.
  */
 public Object createCompareData (final byte[] image, final boolean fast)
 {
   if (fast == false && (digestMD5 != null && digestSHA != null))
   {
     final byte[] dataMD5 = digestMD5.digest(image);
     final byte[] dataSHA = digestSHA.digest(image);
     if (dataSHA != null && dataMD5 != null)
     {
       return new DigestImageCompareData(dataMD5, dataSHA);
     }
   }
   return new CompleteImageCompareData(image);
 }

}


 </source>   



Image Filter

<source lang="java"> import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.MediaTracker; import java.awt.Toolkit; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.image.BandCombineOp; import java.awt.image.BufferedImage; import java.awt.image.BufferedImageOp; import java.awt.image.ByteLookupTable; import java.awt.image.ConvolveOp; import java.awt.image.Kernel; import java.awt.image.LookupOp; import java.awt.image.Raster; import java.awt.image.WritableRaster; import java.net.URL; import javax.swing.JFrame; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; public class Java2DExample extends JFrame {

 private JMenu filterMenu = new JMenu("Image Filters");
 private ImagePanel imagePanel;
 private MyFilter invertFilter = new InvertFilter();
 private MyFilter sharpenFilter = new SharpenFilter();
 private MyFilter blurFilter = new BlurFilter();
 private MyFilter colorFilter = new ColorFilter();
 public Java2DExample() {
   super("Java 2D Image Processing Demo");
   imagePanel = new ImagePanel(Java2DExample.class.getResource("yourImage.png"));
   JMenuBar menuBar = new JMenuBar();
   setJMenuBar(menuBar);
   filterMenu.setMnemonic("I");
   JMenuItem originalMenuItem = new JMenuItem("Display Original");
   originalMenuItem.setMnemonic("O");
   originalMenuItem.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent action) {
       imagePanel.displayOriginalImage();
     }
   });
   JMenuItem invertMenuItem = createMenuItem("Invert", "I", invertFilter);
   JMenuItem sharpenMenuItem = createMenuItem("Sharpen", "S", sharpenFilter);
   JMenuItem blurMenuItem = createMenuItem("Blur", "B", blurFilter);
   JMenuItem changeColorsMenuItem = createMenuItem("Change Colors", "C", colorFilter);
   filterMenu.add(originalMenuItem);
   filterMenu.add(invertMenuItem);
   filterMenu.add(sharpenMenuItem);
   filterMenu.add(blurMenuItem);
   filterMenu.add(changeColorsMenuItem);
   menuBar.add(filterMenu);
   getContentPane().add(imagePanel, BorderLayout.CENTER);
 }
 public JMenuItem createMenuItem(String menuItemName, char mnemonic, final MyFilter filter) {
   JMenuItem menuItem = new JMenuItem(menuItemName);
   menuItem.setMnemonic(mnemonic);
   menuItem.addActionListener(new ActionListener() {
     public void actionPerformed(ActionEvent action) {
       imagePanel.applyFilter(filter);
     }
   });
   return menuItem;
 }
 public static void main(String args[]) {
   Java2DExample application = new Java2DExample();
   application.setDefaultCloseOperation(EXIT_ON_CLOSE);
   application.pack();
   application.setVisible(true);
 }

} interface MyFilter {

 public abstract BufferedImage processImage(BufferedImage image);

} class BlurFilter implements MyFilter {

 public BufferedImage processImage(BufferedImage image) {
   float[] blurMatrix = { 1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f,
       1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f, 1.0f / 9.0f };
   BufferedImageOp blurFilter = new ConvolveOp(new Kernel(3, 3, blurMatrix),
       ConvolveOp.EDGE_NO_OP, null);
   return blurFilter.filter(image, null);
 }

} class ImagePanel extends JPanel {

 private BufferedImage displayImage;
 private BufferedImage originalImage;
 private Image image;
 public ImagePanel(URL imageURL) {
   image = Toolkit.getDefaultToolkit().createImage(imageURL);
   MediaTracker mediaTracker = new MediaTracker(this);
   mediaTracker.addImage(image, 0);
   try {
     mediaTracker.waitForAll();
   } catch (InterruptedException e) {
     e.printStackTrace();
   }
   originalImage = new BufferedImage(image.getWidth(null), image.getHeight(null),
       BufferedImage.TYPE_INT_RGB);
   displayImage = originalImage;
   Graphics2D graphics = displayImage.createGraphics();
   graphics.drawImage(image, null, null);
 }
 public void applyFilter(MyFilter filter) {
   displayImage = filter.processImage(displayImage);
   repaint();
 }
 public void displayOriginalImage() {
   displayImage = new BufferedImage(image.getWidth(null), image.getHeight(null),
       BufferedImage.TYPE_INT_RGB);
   Graphics2D graphics = displayImage.createGraphics();
   graphics.drawImage(originalImage, null, null);
   repaint();
 }
 public void paintComponent(Graphics g) {
   super.paintComponent(g);
   Graphics2D graphics = (Graphics2D) g;
   graphics.drawImage(displayImage, 0, 0, null);
 }
 public Dimension getPreferredSize() {
   return new Dimension(displayImage.getWidth(), displayImage.getHeight());
 }
 public Dimension getMinimumSize() {
   return getPreferredSize();
 }

} class SharpenFilter implements MyFilter {

 public BufferedImage processImage(BufferedImage image) {
   float[] sharpenMatrix = { 0.0f, -1.0f, 0.0f, -1.0f, 5.0f, -1.0f, 0.0f, -1.0f, 0.0f };
   BufferedImageOp sharpenFilter = new ConvolveOp(new Kernel(3, 3, sharpenMatrix),
       ConvolveOp.EDGE_NO_OP, null);
   return sharpenFilter.filter(image, null);
 }

} class InvertFilter implements MyFilter {

 public BufferedImage processImage(BufferedImage image) {
   byte[] invertArray = new byte[256];
   for (int counter = 0; counter < 256; counter++)
     invertArray[counter] = (byte) (255 - counter);
   BufferedImageOp invertFilter = new LookupOp(new ByteLookupTable(0, invertArray), null);
   return invertFilter.filter(image, null);
 }

} class ColorFilter implements MyFilter {

 public BufferedImage processImage(BufferedImage image) {
   float[][] colorMatrix = { { 1f, 0f, 0f }, { 0.5f, 1.0f, 0.5f }, { 0.2f, 0.4f, 0.6f } };
   BandCombineOp changeColors = new BandCombineOp(colorMatrix, null);
   Raster sourceRaster = image.getRaster();
   WritableRaster displayRaster = sourceRaster.createCompatibleWritableRaster();
   changeColors.filter(sourceRaster, displayRaster);
   return new BufferedImage(image.getColorModel(), displayRaster, true, null);
 }

}


</source>