Image Processing in Java

JGuru

Wise Old Owl
Image Processing in Java

In this tutorial we are going to look at how to load Images, apply filter on them , save them to the disk, print them.

The Java 2D™ API supports three imaging models

The producer/consumer (push) model provided in previous versions of the JDK software.

The immediate mode model introduced in the Java™ 2 SDK software release.

The pipeline (pull) model compatible with the immediate mode model and that will be fully implemented in the forthcoming Java Advanced Imaging API.

The following table contrasts the features of each of these imaging models.


Push Model

Immediate Mode Image Buffer Model

Pull Model

Major Interfaces/Classes


Image

ImageProducer

ImageConsumer

ImageObserver
(JDK 1.0.x, 1.1.x)

BufferedImage

Raster

BufferedImageOp

RasterOp
(JavaTM 2D API)


RenderableImage

RenderableImageOp
(Java 2D API)

RenderedOp

RenderableOp

TiledImage
(Java Advanced Imaging API)

Pros:

Processing driven by image availability (e.g. over network)

Images processed incrementally

Simplest programming interface

Commonly used model

Stores/processes only required data

Allows lazy evaluation

Cons:


Requires transfer (but not processing)

More complex programming interface

Requires memory allocation of complete images

Requires processing of complete images

More complex programming interface

More complex implementation


This tutorial focuses on the objects and techniques of the immediate mode imaging model. The immediate mode imaging classes and interfaces of the Java 2D API provide techniques for dealing with pixel mapped images whose data is stored in memory. This API supports accessing image data in a variety of storage formats and manipulating image data through several types of filtering operations.
5.1 Interfaces and Classes

The immediate mode imaging APIs in the Java 2D™ API can be grouped into six categories: interfaces, image data classes, image operation classes, sample model classes, color model classes, and exceptions.
5.1.1 Imaging Interfaces
Interface

Description:


BufferedImageOp - Describes single-input/single-output operations performed on BufferedImage objects. Implemented by AffineTransformOp, ColorConvertOp, ConvolveOp, LookupOp, and RescaleOp.

RasterOp - Defines single-input/single-output operations performed on Raster objects. Implemented by AffineTransformOp, BandCombineOp, ColorConvertOp, ConvolveOp, LookupOp, and RescaleOp.

RenderedImage - Defines a common protocol for objects that contain or can produce image data in the form of Rasters.

WritableRenderedImage - Extends: RenderedImage Defines a common protocol for objects that contain or can produce image data in the form of Rasters which can be modified.

TileObserver - Defines a protocol for objects that want to be notified when the modification state of a WritableRenderedImage changes.

5.1.2 Image Data Classes

Class Description


BufferedImage - Extends: Image Implements: WriteableRenderedImage
An image with an accessible data buffer. A BufferedImage has a ColorModel and a Raster of image data.

ByteLookupTable - Extends: LookupTable A LookupTable that contains byte data.

DataBuffer - Wraps one or more data arrays holding pixel data. Each data array is called a bank.

DataBufferByte - Extends: DataBuffer (Final)

A data buffer that stores bytes of data. (Used in Java Advanced Imaging API)

DataBufferInt - Extends: DataBuffer (Final)) A data buffer that stores integer data.(Used in Java Advanced Imaging API)

DataBufferShort - Extends: DataBuffer (Final) A data buffer that stores short data.(Used in Java Advanced Imaging API)

DataBufferUShort - Extends: DataBuffer (Final) A data buffer that stores unsigned short data.

Kernel - A matrix that describes how an input pixel and its surrounding pixels affect the value of an output pixel in a ConvolveOp filtering operation.

LookupTable - Extends: Object A table that maps values from single-banded pixel data to color values.

Raster - A rectangular array of pixels from which you can retrieve image data. A Raster contains a DataBuffer and a SampleModel.

ShortLookupTable - Extends: LookupTable A lookup table that contains short data.

WritableRaster - Extends: Raster A Raster that you can modify.

Image Operation Classes

Class Description


AffineTransformOp - Implements: BufferedImageOp, RasterOp A class that defines an affine transform to perform a linear mapping from 2D coordinates in a source Image or Raster to 2D coordinates in the destination image or Raster. This class can perform either bilinear or nearest neighbor affine transform operations.

BandCombineOp - Implements: RasterOp Using a specified matrix, this operation performs an arbitrary linear combination of bands in a Raster.

BufferedImageFilter - Extends: ImageFilter An ImageFilter that provides a simple means of using a BufferedImageOp (a single-source/single-destination image operator) to filter a BufferedImage or Raster.

ColorConvertOp - Implements: BufferedImageOp, RasterOp Performs a pixel-by-pixel color conversion of the data in the source image.

ConvolveOp - Implements: BufferedImageOp, RasterOp Uses a Kernel to perform a convolution on the source image. A convolution is a spatial operation where the pixels surrounding the input pixel are multiplied by a kernel value to generate the value of the output pixel. The Kernel mathematically defines the relationship between the pixels in the immediate neighborhood of the input pixel and the output pixel.

LookupOp - Implements: BufferedImageOp, RasterOp. Performs a lookup operation from the source to the destination. For Rasters, the lookup operates on sample values. For BufferedImages, the lookup operates on color and alpha components.

RescaleOp - Implements: BufferedImageOp, RasterOp. Performs a pixel-by-pixel rescaling of the data in the source image by multiplying each pixel value by a scale factor and then adding an offset.

Sample Model Classes]/b]

Class Description

BandedSampleModel - Extends: ComponentSampleModel (Final) Provides access to image data stored with like samples stored as bands in separate banks of a DataBuffer. A pixel consists of one sample from each band.

ComponentSampleModel - Extends: SampleModel .Provides access to image data stored with each sample of a pixel residing in a separate element of a DataBuffer. Different types of pixel interleaving are supported.

MultiPixelPackedSampleModel - Extends: SampleModel. Provides access to image data stored with multiple one-sample pixels packed into one element of a DataBuffer.

PixelInterleavedSampleModel - Extends: ComponentSampleModel. Provides access to image data stored with the sample data for each pixel in adjacent elements of the data array, and all elements in a single bank of a DataBuffer.

SampleModel - An abstract class that defines a mechanism for extracting sample data from an image without knowing how the underlying data is stored in a DataBuffer.

SinglePixelPackedSampleModel - Extends: SampleModel. Provides access to image data stored with all the samples belonging to an individual pixel packed into one element of a DataBuffer.

Color Model Classes

Class Description


ColorModel - Implements: Transparency. JDK1.1 class. An abstract class that defines methods for translating from image pixel values to color components such as red, green, and blue.

ComponentColorModel - Extends: ColorModel .A ColorModel that can handle an arbitrary ColorSpace and an array of color components to match the ColorSpace. This class can be used to represent most color models on most types of GraphicsDevices.

DirectColorModel - Extends: PackedColorModel .JDK1.1 class. A ColorModel that represents pixel values that have RGB color components embedded directly in the bits of the pixel. This color model is similar to an X11 TrueColor visual. The default RGB ColorModel returned by ColorModel.getRGBdefault is a DirectColorModel.

IndexColorModel - Extends: ColorModel. JDK1.1 class. A ColorModel that represents pixel values that are indices into a fixed color map in the sRGB ColorSpace.

PackedColorModel - Extends: ColorModel .An abstract ColorModel that represents pixel values that have color components embedded directly in the bits of a pixel. DirectColorModel extends PackedColorModel to support pixels that contain RGB color components.


Exception Classes

Class Description

ImagingOpException - Extends: RuntimeException .Thrown if one of the BufferedImageOp or RasterOp filter methods can’t process the image.

RasterFormatException - Extends: RuntimeException .Thrown if there is invalid layout information in the Raster.

Immediate Mode Imaging Concepts

The immediate mode imaging model supports fixed-resolution images stored in memory. The model also supports filtering operations on image data. A number of classes and interfaces are used in this model.

BufferedImage and supporting classes

BufferedImage provides general image management. A BufferedImage can be created directly in memory and used to hold and manipulate image data retrieved from a file or URL.
A BufferedImage can be displayed using any Graphics2D object for a screen device, or rendered to any other destination using appropriate Graphics2D context.
A BufferedImage object contains two other objects: a Raster and a ColorModel.

The Raster class provides image data management. It represents the rectangular coordinates of the image, maintains image data in memory, and provides a mechanism for creating
multiple subimages from a single image data buffer. It also provides methods for accessing specific pixels within an image. A Raster object contains two other objects, a DataBuffer and a SampleModel.

The DataBuffer class holds pixel data in memory.

The SampleModel class interprets data in the buffer and provides it as individual pixels or rectangular ranges of pixels.

The ColorModel class provides a color interpretation of pixel data provided by the image’s sample model.

The image package provides additional classes that define filtering operations on BufferedImage and Raster objects. Each image processing operation is embodied in a class that implements the BufferedImageOp interface, the RasterOp interface, or both interfaces. The operation class defines filter methods that performs the actual image manipulation.


The operations supported include:

Affine transformation

Amplitude scaling

Lookup-table modification

Linear combination of bands

Color conversion

Convolution

Note that if you’re interested just in displaying and manipulating images, you only need to understand the BufferedImage class and the filtering operation classes. On the other hand, if you’re planning to write filters or otherwise directly access image data, you’ll need to understand the classes associated with BufferedImage.
5.2.1 Terminology

Here are some terms used throughout the following discussions:

Data Elements: primitive types used as units of storage of image data. Data elements are individual members of a DataBuffer array. The layout of elements in the data buffer is independent of the interpretation of the data as pixels by an image’s SampleModel.

Samples: distinct members of the pixels of an image. A SampleModel provides a mechanism for converting elements in the DataBuffer to pixels and their samples. The samples of a pixel may represent primary values in a particular color model. For example, a pixel in an RGB color model consists of three samples: red, green, and blue.

Components: values of pixels independent of color interpretation. The distinction between component and sample is useful with IndexColorModel, where pixel components are indexes into the LookupTable.

Band: the set of all samples of one type in an image, such as all red samples or all green samples. Pixel data can be stored in a number of ways, the two supported in the Java 2D API being banded and pixel interleaved. Banded storage organizes image data by bands, and a pixel is made up of sample data from the same position in each band. Pixel interleaved storage organizes image data by pixels, with a single array containing all pixels, and bands consisting of the set of samples at the same index position in each pixel.

Primaries: distinct members of a color value in a specific color model; for example the RGB model forms color values from the primaries red, green, and blue.
5.3 Using BufferedImages

The BufferedImage class is the main class supporting the immediate imaging mode. It manages an image in memory, providing ways to store pixel data, interpret pixel data, and to render the pixel data to a Graphics or Graphics2D context.
5.3.1 Creating a BufferedImage

To create a BufferedImage, call the Component.createImage method; this returns a BufferedImage whose drawing characteristics match those of the component used to create it—the created image is opaque, has the foreground and background colors of the Component, and you can’t adjust the transparency of the image. You could use this technique when you want to do double buffered drawing for animation in a component; the discussion “Drawing in an Offscreen Buffer” on page 79 gives more details.
Code:
    public Graphics2D createDemoGraphics2D(Graphics g) { 
        Graphics2D g2 = null; 
        int width = getSize().width;  
        int height = getSize().height;  
 
        if (offImg == null || offImg.getWidth() != width || 
                        offImg.getHeight() != height) { 
            offImg = (BufferedImage) createImage(width, height); 
        }  
 
        if (offImg != null) { 
            g2 = offImg.createGraphics(); 
            g2.setBackground(getBackground()); 
        } 
 
        // .. clear canvas .. 
        g2.clearRect(0, 0, width, height); 
 
        return g2; 
    }
You can also create a blank BufferedImage in memory using one of several constructor methods provided.
5.3.2 Drawing in an Offscreen Buffer

The BufferedImage class can be used to prepare graphic elements offscreen then copy them to the screen. This technique is especially useful when a graphic is complex or used repeatedly. For example, if you want to display a complicated shape several times, you could draw it once into an offscreen buffer and then copy it to different locations in the window. By drawing the shape once and copying it, you can display the graphics more quickly.

The java.awt package facilitates the use of offscreen buffers by letting you draw to an Image object the same way that you draw to a window. All of the Java 2D™ API rendering features can be used when drawing to offscreen images.

Offscreen buffers are often used for animation. For example, you could use an offscreen buffer to draw an object once and then move it around in a window. Similarly, you could use an offscreen buffer to provide feedback as a user moves a graphic using the mouse. Instead of redrawing the graphic at every mouse location, you could draw the graphic once to an offscreen buffer, and then copy it to the mouse location as the user drags the mouse.1

The following context describes this graphic.



Demonstrates how a program can draw to an offscreen image and then copy that image into a window multiple times. The last time the image is copied, it is transformed. Note that transforming the image instead of redrawing it with the transformation might produce unsatisfactory results.
5.3.2.1 Creating an Offscreen Buffer

The simplest way to create an image that you can use as an offscreen buffer is to use the Component.createImage method.

By creating an image whose color space, depth, and pixel layout exactly match the window into which you are drawing, the image can be efficiently blitted to a graphics device. This allows drawImage to do its job quickly.

You can also construct a BufferedImage object directly to use as an offscreen buffer. This is useful when you need control over the offscreen image’s type or transparency.

BufferedImage supports several predefined image types:

TYPE_3BYTE_BGR

TYPE_4BYTE_ABGR

TYPE_4BYTE_ABGR_PRE

TYPE_BYTE_BINARY

TYPE_BYTE_GRAY

TYPE_BYTE_INDEXED

TYPE_CUSTOM

TYPE_INT_ARGB_PRE

TYPE_INT_ARGB

TYPE_INT_BGR

TYPE_INT_RGB

TYPE_USHORT_555_RGB

TYPE_USHORT_565_RGB

TYPE_INT_GRAY

A BufferedImage object can contain an alpha channel. In Figure 5-3, an alpha channel is used to distinguish painted and unpainted areas, allowing an irregular shape to appear over graphics that have already been painted (in this case, a shaded rectangle). In other cases, you might use alpha channel to blend the colors of the new image into those in the existing image.

Note: unless you need alpha image data for transparency, as with the irregularly shaped images shown in Figure 5-2, you should avoid creating an off-screen buffer with alpha. Using alpha where it’s unnecessary slows rendering performance.

GraphicsConfiguration provides convenience methods that automatically create buffered images in a format compatible with your configuration. You can also query the graphics configuration associated with the graphics device on which the window resides to get the information you need to construct a compatible BufferedImage object.
5.3.2.2 Drawing in an Offscreen Buffer

To draw in a buffered image, you call its BufferedImage.createGraphics method, which returns a Graphics2D object. With this object, you can call all of the Graphics2D methods to draw graphics primitives, place text, and render other images in the image. This drawing technique supports dithering and other enhancements provided by the 2D imaging package. The following code illustrates the use of offscreen buffering:

Code:
    public void update(Graphics g){ 
        Graphics2D g2 = (Graphics2D)g; 
        if(firstTime){ 
            Dimension dim = getSize(); 
            int w = dim.width; 
            int h = dim.height; 
            area = new Rectangle(dim); 
            bi = (BufferedImage)createImage(w, h); 
            big = bi.createGraphics(); 
            rect.setLocation(w/2-50, h/2-25); 
            big.setStroke(new BasicStroke(8.0f)); 
            firstTime = false; 
        }  
 
        // Clears the rectangle that was previously drawn. 
        big.setColor(Color.white); 
        big.clearRect(0, 0, area.width, area.height); 
 
        // Draws and fills the newly positioned rectangle to the buffer. 
        big.setPaint(strokePolka); 
        big.draw(rect); 
        big.setPaint(fillPolka); 
        big.fill(rect); 
 
        // Draws the buffered image to the screen. 
        g2.drawImage(bi, 0, 0, this); 
             
    }

Manipulating BufferedImage Data Directly

In addition to drawing directly in a BufferedImage, you can directly access and manipulate the image’s pixel data in a couple of ways. These are useful if you’re implementing the BufferedImageOp filtering interface, as described in “Image Processing and Enhancement” on page 84.

You can use the BufferedImage.setRGB methods to directly set the value of a pixel or a pixel array to a specific RGB value. Note that no dithering is performed when you modify pixels directly. You can also manipulate pixel data by manipulating a WritableRaster object associated with a BufferedImage (see“Managing and Manipulating Rasters” on page 80).
5.3.4 Filtering a BufferedImage

You can apply a filtering operation to a BufferedImage using an object that implements BufferedImageOp interface. Filtering and the classes that provide this filtering interface are discussed in “Image Processing and Enhancement” on page 84.
5.3.5 Rendering a BufferedImage

To render a buffered image into a specific context, call one of the drawImage method of the context’s Graphics object. For example, when rendering within a Component.paint method, you call drawImage on the graphics object passed to the method.
Code:
    public void paint(Graphics g) { 
 
        if (getSize().width <= 0 || getSize().height <= 0) 
            return; 
 
        Graphics2D g2 = (Graphics2D) g; 
 
        if (offImg != null && isShowing())  { 
            g2.drawImage(offImg, 0, 0, this); 
        } 
    }

Managing and Manipulating Rasters]/b]

A BufferedImage object uses a Raster to manage its rectangular array of pixel data. The Raster class defines fields for the image’s coordinate system—width, height, and origin. A Raster object itself uses two objects to manage the pixel data, a DataBuffer and a SampleModel. The DataBuffer is the object that stores pixel data for the raster (as described on page 82), and the SampleModel provides the interpretation of pixel data from the DataBuffer (as described on page 82).
5.4.1 Creating a Raster

In most cases, you don’t need to create a Raster directly, since one is supplied with any BufferedImage that you create in memory. However, one of the BufferedImage constructor methods allows you to create a Raster by passing in a WritableRaster.

The Raster class provides a number of static factory methods for creating Rasters with the DataBuffers and SampleModels you specify. You can use these factories when implementing RasterOp filtering classes.
5.4.2 Parent and Child Rasters

The Raster class incorporates the concept of parent and child rasters. This can improve storage efficiency by allowing you to construct any number of buffered images from the same parent. The parent and its children all refer to the same data buffer, and each child has a specific offset and bounds to identify its image location in the buffer. A child identifies its ownership through its getParent method.

To create a subraster, you use the Raster.createSubRaster method.When you create a subraster, you identify the area of its parent that it covers and its offset from the parent’s origin.
5.4.3 Operations on a Raster

The Raster class defines a number of ways to access pixels and pixel data. These are useful when you’re implementing the RasterOp interface, which provides raster-level filtering and manipulation of image data, or when implementing any method that needs to perform low-level pixel manipulation.

The Raster.getPixel methods let you get an individual pixel, which is returned as individual samples in an array. The Raster.getDataElements methods return a specified run of uninterpreted image data from the DataBuffer. The Raster.getSample method returns samples of an individual pixel. The getSamples method returns a band for a particular region of an image.

In addition to these methods, you can also access the data buffer and the sample model through instance variables of the Raster class. These objects provide additional ways to access and interpret the Raster’s pixel data.
5.4.4 The WritableRaster Subclass

The WritableRaster subclass provides methods for setting pixel data and samples. The Raster associated with a BufferedImage is actually a WritableRaster, thus providing full access to manipulate its pixel data.
5.5 Image Data and DataBuffers

The DataBuffer belonging to a Raster represents an array of image data. When you create a Raster directly or through the BufferedImage constructors, you specify a width and height in pixels, along with a SampleModel for the image data. This information is used to create a DataBuffer of the appropriate data type and size.

There are three subclasses of DataBuffer, each representing a different type of data element:

DataBufferByte (represents 8-bit values)

DataBufferInt (represents 32-bit values)

DataBufferShort (represents 16-bit values)

DataBufferUShort (represents unsigned short values)

As defined earlier, elements are the discrete members of the array of the data buffer, and components or samples are the discrete values that together make up a pixel. There can be various mappings between a particular type of element in a DataBuffer and a particular type of pixel represented by a SampleModel. It is the responsibility of the various SampleModel subclasses to implement that mapping and provide a way to get specific pixels from a specific DataBuffer.

DataBuffer constructors provide ways to create buffers of a specific size and a specific number of banks.

While you can access image data in a DataBuffer directly, it’s generally easier and more convenient to do so through the methods of the Raster and WritableRaster classes.
5.6 Extracting Pixel Data from a SampleModel

The abstract SampleModel class defines methods for extracting samples of an image without knowing how the underlying data is stored. The class provides fields for tracking the height and width of the image data in the associated DataBuffer, and for describing the number of bands and the data type of that buffer. SampleModel methods provide image data as a collection of pixels, with each pixel consisting of a number of samples or components.

The java.awt.image package provides five types of sample models:

ComponentSampleModel—used to extract pixels from images that store sample data in separate data array elements in one bank of a DataBuffer.

BandedSampleModel—used to extract pixels from images that store each sample in a separate data element with bands stored in a sequence of data elements

PixelInterleavedSampleModel—used to extract pixels from images that store each sample in a separate data element with pixels stored in a sequence of data elements.

MultiPixelPackedSampleModel—used to extract pixels from single banded images that store multiple one-sample pixels in one data element.

SinglePixelPackedSampleModel—used to extract samples from images that store sample data for a single pixel in one data array element in the first bank of a DataBuffer.

Pixel data presented by the SampleModel may or may not correlate directly to a color data representation of a particular color model, depending on the data source. For example, in photographic image data, the samples may represent RGB data. In image data from a medical imaging device, samples can represent different types of data such as temperature or bone density.

There are three categories of methods for accessing image data. The getPixel methods return a whole pixel as an array, with one entry for each sample. The getDataElement methods provide access to the raw, uninterpreted data stored in the DataBuffer. The getSample methods provide access to pixel components for a specific band.
5.7 ColorModels and Color Data

In addition to the Raster object for managing image data, the BufferedImage class includes a ColorModel for interpreting that data as color pixel values. The abstract ColorModel class defines methods for turning an image’s pixel data into a color value in its associated ColorSpace.

The java.awt.image package provides four types of color models:

PackedColorModel—An abstract ColorModel that represents pixel values that have color components embedded directly in the bits of an integer pixel. A DirectColorModel is a subclass of PackedColorModel.

DirectColorModel—a ColorModel that represents pixel values that have RGB color components embedded directly in the bits of the pixel itself. DirectColorModel model is similar to an X11 TrueColor visual.

ComponentColorModel—a ColorModel that can handle an arbitrary ColorSpace and an array of color components to match the ColorSpace.

IndexColorModel—a ColorModel that represents pixel values that are indices into a fixed color map in the sRGB color space.

ComponentColorModel and PackedColorModel are new in the Java™ 2 SDK software release.

Based on data in the DataBuffer, the SampleModel provides the ColorModel with a pixel, which the ColorModel then interprets as a color.
5.7.1 Lookup Table

A lookup table contains data for one or more channels or image components; for example, separate arrays for R, G, and B. The java.awt.image package defines two types of lookup tables that extend the abstract LookupTable class, one that contains byte data and one that contains short data (ByteLookupTable and ShortLookupData).
5.8 Image Processing and Enhancement

The image package provides a pair of interfaces that define operations on BufferedImage and Raster objects: BufferedImageOp and RasterOp.

The classes that implement these interfaces include AffineTransformOp, BandCombineOp, ColorConvertOp, ConvolveOp, LookupOp, RescaleOp. These classes can be used to geometrically transform, blur, sharpen, enhance contrast, threshold, and color correct images.

Figure 5-4 illustrates edge detection and enhancement, an operation that emphasizes sharp changes in intensity within an image. Edge detection is commonly used in medical imaging and mapping applications. Edge detection is used to increase the contrast between adjacent structures in an image, allowing the viewer to discriminate greater detail.

The previous context describes this graphic.

Edge detection and enhancement

The following code illustrates edge detection:
Code:
float[] elements = { 0.0f, -1.0f, 0.0f, 
                    -1.0f, 4.f, -1.0f, 
                    0.0f, -1.0f, 0.0f}; 
... 
 
BufferedImage bimg = new BufferedImage(bw,bh,BufferedImage.TYPE_INT_RGB); 
Kernel kernel = new Kernel(3, 3, elements); 
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP, null); 
cop.filter(bi,bimg);
Demonstrates lookup table manipulation. A lookup operation can be used to alter individual components of a pixel.

The previous context describes this graphic.

The following code demonstrates Lookup-table manipulation:
Code:
        byte reverse[] = new byte[256]; 
   for (int j=0; j<200; j++){  
                reverse[j]=(byte)(256-j);  
        }        
        ByteLookupTable blut=new ByteLookupTable(0, reverse);  
        LookupOp lop = new LookupOp(blut, null);  
   lop.filter(bi,bimg);

Illustrates rescaling. Rescaling can increase or decrease the intensity of all points. Rescaling can be used to increase the dynamic range of an otherwise neutral image, bringing out detail in a region that appears neutral or flat.

The previous context describes this graphic.

Rescaling

The following code snippet illustrates rescaling:
Code:
        RescaleOp rop = new RescaleOp(1.5f, 1.0f, null); 
        rop.filter(bi,bimg);
Using an Image Processing Operation

Convolution is the process that underlies most spatial filtering algorithms. Convolution is the process of weighting or averaging the value of each pixel in an image with the values of neighboring pixels.This allows each output pixel to be affected by the immediate neighborhood in a way that can be mathematically specified with a kernel. Figure 5-7 illustrates Convolution.

The previous context describes this graphic.

Blurring with Convolution

The following code fragment illustrates how to use one of the image processing classes, ConvolveOp. In this example, each pixel in the source image is averaged equally with the eight pixels that surround it.

Code:
float weight = 1.0f/9.0f;float[] elements = new float[9]; // create 2D array// fill the array with nine equal elements 
for (i = 0; i < 9; i++) {   elements[i] = weight;}// use the array of elements as argument to create a Kernelprivate Kernel myKernel = new Kernel(3, 3, elements);public ConvolveOp simpleBlur = new ConvolveOp(myKernel); 
 
// sourceImage and destImage are instances of BufferedImagesimpleBlur.filter(sourceImage, destImage) // blur the image

The variable simpleBlur contains a new instance of ConvolveOp that implements a blur operation on a BufferedImage or a Raster. Suppose that sourceImage and destImage are two instances of BufferedImage. When you call filter, the core method of the ConvolveOp class, it sets the value of each pixel in the destination image by averaging the corresponding pixel in the source image with the eight pixels that surround it.

The convolution kernel in this example could be represented by the following matrix, with elements specified to four significant figures:

A 3 by 3 matrix with all values being 0.1111.

When an image is convolved, the value of each pixel in the destination image is calculated by using the kernel as a set of weights to average the pixel’s value with the values of surrounding pixels. This operation is performed on each channel of the image.

The following formula shows how the weights in the kernel are associated with the pixels in the source image when the convolution is performed. Each value in the kernel is tied to a spatial position in the image.

A 3 by 3 matrix. The first row values are i minus 1, j minus 1, i, j minus 1, and i plus 1, j minus1. The second row values are i minus 1, j, i, j, and i plus1, j. The third row values are i minus 1, j plus 1, i, j plus 1, and i plus 1, j plus 1.

The value of a destination pixel is the sum of the products of the weights in the kernel multiplied by the value of the corresponding source pixel. For many simple operations, the kernel is a matrix that is square and symmetric, and the sum of its weights adds up to one.2

The convolution kernel in this example is relatively simple. It weights each pixel from the source image equally. By choosing a kernel that weights the source image at a higher or lower level, a program can increase or decrease the intensity of the destination image. The Kernel object, which is set in the ConvolveOp constructor, determines the type of filtering that is performed. By setting other values, you can perform other types of convolutions, including blurring (such as Gaussian blur, radial blur, and motion blur), sharpening, and smoothing operations. Figure 5-8 illustrates sharpening using Convolution.

The previous context describes this graphic.

Sharpening with Convolution

The following code snippet illustrates sharpening with Convolution:

Code:
float[] elements = { 0.0f, -1.0f, 0.0f, 
                    -1.0f,  5.f, -1.0f, 
                     0.0f, -1.0f,  0.0f}; 
... 
 
Kernel kernel = new Kernel(3,3,elements); 
ConvolveOp cop = new ConvolveOp(kernel, ConvolveOp.EDGE_NO_OP,                                                                                                          null); 
        cop.filter(bi,bimg);

1)It is up to the programmer to “erase” the previous version of the image before making a new copy at a new location. This can be done by redrawing the background or copying the background from another offscreen buffer.
2) If the sum of the weights in the matrix is one, the intensity of the destination image is unchanged from the source.

Let's look at some sample programs that implements these things.

ProcessImage.java
Code:
/**
 *
 * @author JGuru
 */
// ProcessImage - Do some effects like Blur, Sharpen, Contrast, Negative etc.,
import java.awt.*;
import java.awt.image.*;
import java.awt.event.*;
import javax.swing.*;
import java.io.*;
import java.util.*;
import java.awt.color.ColorSpace;
import javax.imageio.ImageIO;
import javax.swing.filechooser.FileFilter;

class ProcessImage extends JFrame implements ActionListener {

    JLabel label = new JLabel("", JLabel.CENTER);
    JFileChooser fc = new JFileChooser(".");
    JLabel message = new JLabel("Ready", JLabel.LEFT);
    BufferedImage buffImg;
    // MenuItems ...
    JMenuItem open = new JMenuItem("Open...");
    JMenuItem revert = new JMenuItem("Revert");
    JMenuItem blur = new JMenuItem("Blur");
    JMenuItem edgeDetect = new JMenuItem("Edge Detect");
    JMenuItem emboss = new JMenuItem("Emboss");
    JMenuItem posterize = new JMenuItem("Posterize");
    JMenuItem sharpen = new JMenuItem("Sharpen");
    JMenuItem negative = new JMenuItem("Negative");
    JMenuItem threshold = new JMenuItem("Threshold");
    JMenuItem grayScale = new JMenuItem("GrayScale");
    JMenuItem exit = new JMenuItem("Exit");
    Image image = null;
    int imgWidth = -1;
    int imgHeight = -1;

    // Get supported Image formats (remove duplicate entries)
    public String[] getReaderFormats()
    {
        String []rFormat = ImageIO.getReaderFormatNames();
        Set <String>set = new HashSet<String>();
        String imgformat = "";
        // Remove duplicate entries
        for (int i = 0; i < rFormat.length; i++) {
            imgformat = rFormat[i];
            imgformat = imgformat.toLowerCase();
            set.add(imgformat);
        }
        String []frmt = new String[set.size()];
        return set.toArray(frmt);
    }

    public void updateUI() {
        open.updateUI();
        revert.updateUI();
        blur.updateUI();
        edgeDetect.updateUI();
        emboss.updateUI();
        posterize.updateUI();
        sharpen.updateUI();
        negative.updateUI();
        threshold.updateUI();
        grayScale.updateUI();
        exit.updateUI();
        fc.updateUI();
    }

    // Enable or disable Components
    @Override
    public void setEnabled(boolean condition) {
        revert.setEnabled(condition);
        blur.setEnabled(condition);
        edgeDetect.setEnabled(condition);
        emboss.setEnabled(condition);
        posterize.setEnabled(condition);
        sharpen.setEnabled(condition);
        negative.setEnabled(condition);
        threshold.setEnabled(condition);
        grayScale.setEnabled(condition);
    }

    ProcessImage(String title) {
        super(title);
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (UnsupportedLookAndFeelException e) {
            System.err.println("Unsupported Look 'n Feel!!!");
            // handle exception
        } catch (ClassNotFoundException e) {
            System.err.println("Class not found!!!");
            // handle exception
        } catch (InstantiationException e) {
            System.err.println("Instantiation exception!!!");
            // handle exception
        } catch (IllegalAccessException e) {
            System.err.println("Illegal access exception!!!");
            // handle exception
        }
        updateUI();
        open.addActionListener(this);
        revert.addActionListener(this);
        blur.addActionListener(this);
        edgeDetect.addActionListener(this);
        emboss.addActionListener(this);
        posterize.addActionListener(this);
        sharpen.addActionListener(this);
        negative.addActionListener(this);
        threshold.addActionListener(this);
        grayScale.addActionListener(this);
        exit.addActionListener(this);
        JMenuBar mBar = new JMenuBar();

        JMenu menu = new JMenu("File");
        menu.addActionListener(this);

        //Disable menuitems other than 'Open' & 'Exit"!
        // Since there is no Image to process!!
        revert.setEnabled(false);
        blur.setEnabled(false);
        edgeDetect.setEnabled(false);
        emboss.setEnabled(false);
        posterize.setEnabled(false);
        sharpen.setEnabled(false);
        negative.setEnabled(false);
        threshold.setEnabled(false);
        grayScale.setEnabled(false);
        menu.add(open);
        menu.addSeparator();
        menu.add(revert);
        menu.addSeparator();
        menu.add(exit);

        mBar.add(menu);

        menu = new JMenu("Effects");
        menu.addActionListener(this);

        menu.add(blur);
        menu.add(edgeDetect);
        menu.add(emboss);
        menu.add(negative);
        menu.add(posterize);
        menu.add(sharpen);
        menu.add(threshold);
        menu.add(grayScale);
        mBar.add(menu);
        setJMenuBar(mBar);

        JScrollPane scroller = new JScrollPane(label);
        add(scroller, BorderLayout.CENTER);
        add(message, BorderLayout.SOUTH);
        setSize(550, 600);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }
    // Blur the Image
    public BufferedImage blur() {
        float ninth = 1.0f / 9.0f;

        float[] blurKernel = {
            ninth, ninth, ninth,
            ninth, ninth, ninth,
            ninth, ninth, ninth
        };

        BufferedImageOp blurOp = new ConvolveOp(new Kernel(3, 3, blurKernel));
        return blurOp.filter(buffImg, null);
    }
    // Sharpen the Image
    public BufferedImage sharpen() {
        float[] sharpenKernel = {
            0.0f, -1.0f, 0.0f,
            -1.0f, 5.0f, -1.0f,
            0.0f, -1.0f, -0.0f
        };

        BufferedImageOp sharpenOp = new ConvolveOp(new Kernel(3, 3, sharpenKernel));
        return sharpenOp.filter(buffImg, null);
    }
    //Edge detect the Image
    public BufferedImage edgeDetect() {
        float[] edgeKernel = {
            0.0f, -1.0f, 0.0f,
            -1.0f, 4.0f, -1.0f,
            0.0f, -1.0f, 0.0f
        };

        BufferedImageOp edgeOp = new ConvolveOp(new Kernel(3, 3, edgeKernel));
        return edgeOp.filter(buffImg, null);
    }
    //Convert the Image to grayScale
    public BufferedImage grayScale() {
        //Converting a Color Image to Gray
        //Darker Gray
        ColorSpace cs = ColorSpace.getInstance(
                ColorSpace.CS_GRAY);
        ColorConvertOp op = new ColorConvertOp(cs, null);
        return op.filter(buffImg, null);
    }
    // Emboss the Image
    public BufferedImage emboss(BufferedImage buff) {
        int width = buff.getWidth();
        int height = buff.getHeight();

        BufferedImage dst;
        dst = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        // Start changing pixel-by-pixel
        for (int i = 0; i < height; i++) {
            for (int j = 0; j < width; j++) {
                int upperLeft = 0;
                int lowerRight = 0;

                if (i > 0 && j > 0) {
                    upperLeft = buff.getRGB(j - 1, i - 1);
                }

                if (i < height - 1 && j < width - 1) {
                    lowerRight = buff.getRGB(j + 1, i + 1);
                }

                int redDiff = ((lowerRight >> 16) & 255)
                        - ((upperLeft >> 16) & 255);

                int greenDiff = ((lowerRight >> 8) & 255)
                        - ((upperLeft >> 8) & 255);

                int blueDiff = (lowerRight & 255)
                        - (upperLeft & 255);

                int diff = redDiff;
                if (Math.abs(greenDiff) > Math.abs(diff)) {
                    diff = greenDiff;
                }
                if (Math.abs(blueDiff) > Math.abs(diff)) {
                    diff = blueDiff;
                }

                int grayColor = 128 + diff;

                if (grayColor > 255) {
                    grayColor = 255;
                } else if (grayColor < 0) {
                    grayColor = 0;
                }

                int newColor = (grayColor << 16) + (grayColor << 8)
                        + grayColor;

                dst.setRGB(j, i, newColor);
            }
        }
        return dst;
    }
    // Posterize the Image
    public BufferedImage posterize() {
        short[] posterize = new short[256];

        for (int i = 0; i < posterize.length; i++) {
            posterize[i] = (short) (i - i % 32);
        }

        BufferedImageOp posterizeOp =
                new LookupOp(new ShortLookupTable(0, posterize), null);

        return posterizeOp.filter(buffImg, null);
    }
    // Image negative
    public BufferedImage negative() {
        short[] invert = new short[256];

        for (int i = 0; i < invert.length; i++) {
            invert[i] = (short) (255 - i);
        }

        BufferedImageOp invertOp =
                new LookupOp(new ShortLookupTable(0, invert), null);

        return invertOp.filter(buffImg, null);
    }
    // Threshold Image
    public BufferedImage threshold() {
        short[] threshold = new short[256];

        for (int i = 0; i < threshold.length; i++) {
            threshold[i] = (i < 128) ? (short) 0 : (short) 255;
        }

        BufferedImageOp thresholdOp = new LookupOp(new ShortLookupTable(0, threshold), null);

        return thresholdOp.filter(buffImg, null);
    }
    // Convert the Image to BufferedImage
    public BufferedImage toBufferedImage(Image image) {
        if (image != null) {
            int width = image.getWidth(null);
            int height = image.getHeight(null);
            BufferedImage buff = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
            Graphics g2 = buff.getGraphics();
            g2.drawImage(image, 0, 0, null);
            g2.dispose();
            return buff;
        }
        return null;
    }

    public void actionPerformed(ActionEvent ae) {
        Object source = ae.getSource();
        if (source == exit) {
            System.exit(0);
        } else if (source == revert) {
            label.setIcon(new ImageIcon(buffImg));
            message.setText("Image Reverted");
        } else if (source == open) {
            fc.setAccessory(new ImagePreview(fc));
            fc.setPreferredSize(new Dimension(780, 423));
            fc.setAcceptAllFileFilterUsed(false);
            fc.setCurrentDirectory(new File("Samples"));
            final String[] format = getReaderFormats();
            fc.addChoosableFileFilter(new FileFilter() {

                @Override
                public boolean accept(File file) {
                    String fileName = file.getName();
                    for (int i = 0; i < format.length; i++) {
                        // Show directory & images files only
                        if (fileName.endsWith(format[i]) || file.isDirectory()) {
                            return true;
                        }
                    }
                    return false;
                }

                // Show something like "*.jpg,*.jpeg,*.bmp,*.tiff,*.gif,*.jpeg2000" etc.,
                @Override
                public String getDescription() {   
                    String str = "";
                    for (int i = 0; i < format.length; i++) {
                        str += "*." + format[i] + ",";
                    }
                    return str;
                }
            });
            int result = fc.showOpenDialog(this);

            if (result != 0) {
                return;
            }

            File file = fc.getSelectedFile();
            String fileName = file.toString();
            if (file == null) {
                return;
            } else {
                //Fetch the Image for processing
                try {   
                    image = ImageIO.read(new File(fileName));
                    imgWidth = image.getWidth(null);
                    imgHeight = image.getHeight(null);
                } catch (Exception ioe) {
                    System.err.println("Error loading the Image!!");
                    JOptionPane.showMessageDialog(null, "Not a valid Image!!!", "Error", JOptionPane.ERROR_MESSAGE);
                    //Disable menuitems other than 'Open' & 'Exit"!
                    // Since there is no Image to process!!
                    setEnabled(false);
                }
                //Enable the MenuItems now!
                setEnabled(true);
                // Convert Image to BufferedIage
                buffImg = toBufferedImage(image);
                // Update the label
                label.setIcon(new ImageIcon(buffImg));
                message.setText("Ready");
                pack();
            }
        } else if (source == blur) {
            label.setIcon(new ImageIcon(blur()));
            message.setText("Image Blurred");
            
        } else if (source == edgeDetect) {
            label.setIcon(new ImageIcon(edgeDetect()));
            message.setText("Image EdgeDetected");
            
        } else if (source == sharpen) {
            label.setIcon(new ImageIcon(sharpen()));
            message.setText("Image Sharpened");
            
        } else if (source == negative) {
            label.setIcon(new ImageIcon(negative()));
            message.setText("Image Negative");
            
        } else if (source == threshold) {
            label.setIcon(new ImageIcon(threshold()));
            message.setText("Image Threshold");
            
        } else if (source == emboss) {
            label.setIcon(new ImageIcon(emboss(buffImg)));
            message.setText("Image Embossed");
            
        } else if (source == posterize) {
            label.setIcon(new ImageIcon(posterize()));
            message.setText("Image Posterized");
            
        } else {   // GrayScale
            label.setIcon(new ImageIcon(grayScale()));
            message.setText("Image GrayScaled");
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                new ProcessImage("Process Image");
            }
        });
    }
    
    class ImagePreview extends JComponent implements PropertyChangeListener {
    
        ImageIcon thumbnail = null;
        int width = 180;
    
        public ImagePreview(JFileChooser fc) {
            setPreferredSize(new Dimension(width, 50));
            fc.addPropertyChangeListener(this);
            setBorder(new BevelBorder(BevelBorder.LOWERED));
        }
    
        public void loadImage(File f) {
            if (f == null) {
                thumbnail = null;
            } else {
                ImageIcon tmpIcon = new ImageIcon(getImage(f.getPath()));
                if (tmpIcon.getIconWidth() > width) {
                    thumbnail = new ImageIcon(
                            tmpIcon.getImage().getScaledInstance(width, -1, Image.SCALE_SMOOTH));
                } else {
                    thumbnail = tmpIcon;
                }
            }
        }
    
        public BufferedImage getImage(String fileName) {
            try {
                return ImageIO.read(new File(fileName));
            } catch (IOException ioe) {
                System.err.println("Error loading Image!!");
            }
            return null;
        }
    
        @Override
        public void propertyChange(final PropertyChangeEvent e) {
            String prop = e.getPropertyName();
            if (prop.equals(JFileChooser.SELECTED_FILE_CHANGED_PROPERTY)) {
                if (isShowing()) {
                    new Thread(new Runnable() {
    
                        @Override
                        public void run() {
                            loadImage((File) e.getNewValue());
                            repaint();
                        }
                    }).start();
    
                }
            }
        }
    
        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (thumbnail != null) {
                int x = getWidth() / 2 - thumbnail.getIconWidth() / 2;
                int y = getHeight() / 2 - thumbnail.getIconHeight() / 2;
                if (y < 0) {
                    y = 0;
                }
    
                if (x < 5) {
                    x = 5;
                }
                thumbnail.paintIcon(this, g, x, y);
            }
        }
    }

}

To run the program , java ProcessImage from the cmd-line or use an IDE like NetBeans to launch the program.
From the menu File-> Open select an Image , click on the "OK" button. Now from the menu select "Blur" to blur the Image, "Emboss", to Emboss the Image etc.,
You can study the sample code above & understand the program.

For more Image filters you can use the Jerry Huxtable's Image Filters (Download Java Image Processing Classes)

None of these filters are finely-tuned for speed, or even coarsely-tuned. Think of them as sample code for writing your own filters. I've preferred floating-point math over integer or fixed-point pretty well everywhere. By making the appropriate changes you'll probably be able to get these to go quite a bit faster.

All of the filters are designed to work with TYPE_INT_ARGB images. Some may work with other image types, but I make no guarantees.

All the filters are Java beans in the sense that they have default constructors and a set of properties. None of them have BeanInfo classes. This is for three reasons: firstly, the original versions predate the introduction of JavaBeans, and secondly, a BeanInfo class doesn't provide enough information to do a good UI for
the properties, and thirdly, writing BeanInfo classes is really boring.

The Filters

Color Adjustment Filters

ChannelMixFilter - Mixes the RGB channels

ContrastFilter - Adjusts brightness and contrast

CurvesFilter - Apply adjustment curves to an image

DiffusionFilter - Error-diffusion dithering

DitherFilter - Ordered dithering

ExposureFilter - Change the exposure of an image

GainFilter - Adjusts gain and bias

GammaFilter - Adjusts image gamma

GrayFilter - Grays out an image

GrayscaleFilter - Converts to grayscale

HSBAdjustFilter - Adjusts hue, saturation and brightness

InvertAlphaFilter - Inverts the alpha channel

InvertFilter - Inverts image colors

LevelsFilter - Adjust image levels

LookupFilter - Change image colors with a lookup table

MapColorsFilter - Replace a color

MaskFilter - Channel masking

PosterizeFilter - Posterization

QuantizeFilter - Quantize an image to 256 colors for, say, GIF export

RescaleFilter - Multiplies colors by a scaling factor

RGBAdjustFilter - Adjusts red, green and blue levels

SolarizeFilter - Solarization

ThresholdFilter - Thresholding

TritoneFilter - Create a tri-tone image

Distortion and Warping Filters

BicubicScaleFilter - Scaling with bicubic interpolation

CircleFilter - Wrap an image around a circle

CropFilter - Crop an area from an image

DiffuseFilter - Diffuse the pixels of an image

DisplaceFilter - A glass distortion effect

DissolveFilter - Dissolves an image by turning random pixels transparent

FieldWarpFilter - Warp images using a field warp algorithm

FlipFilter - Flip and rotate images

KaleidoscopeFilter - A kaleidoscope effect

MarbleFilter - A marbling effect

MirrorFilter - Mirror an image

OffsetFilter - Offset an image for tiling

PerspectiveFilter - Perspective distortion

PinchFilter - Whirl-and-pinch distortion

PolarFilter - Convert to and from polar coordinates

RippleFilter - Ripple distortion

RotateFilter - Rotate an image

ScaleFilter - Scale an image with area-averaging

ShearFilter - Shear an image

SphereFilter - Lens distortion

SwimFilter - An "underwater" distortion effect

TileImageFilter - Tile an image into a larger image

TwirlFilter - Distort an image by twisting

WarpFilter - A general grid image warp

WaterFilter - Simulate water ripples

Effects Filters

BlockFilter - Mosaic or pixellate an image

BorderFilter - Add a border

ChromeFilter - Simulate chrome

ColorHalftoneFilter - Color halftoning effect.

CrystallizeFilter - Make an image look like stained glass

EmbossFilter - Simple embossing

FeedbackFilter - A video feedback effect

HalftoneFilter - Simple halftoning

LightFilter - Simulate lights on an bump-mapped image

NoiseFilter - Add noise

PointillizeFilter - Draw an image as colored spots

ShadowFilter - Create drop shadows

ShapeFilter - Create bump maps for lighting

StampFilter - A rubber stamp effect

WeaveFilter - A woven image effect

Texturing Filters

BrushedMetalFilter - Created brushed metal

CausticsFilter - Simulate underwater caustics

CellularFilter - Cellular texturing

CheckFilter - Draw a checkerboard pattern

FBMFilter - Fractal Brownian motion texturing

FillFilter - Fill an image with a color

FlareFilter - Create lens flares

FourColorFilter - Draw a four-color gradient

GradientFilter - Draw radial, linear, fan and square gradients

PlasmaFilter - Create plasma

TextureFilter - Perlin noise texturing

ScratchFilter - Render lines or scratches

SmearFilter - Painting effects

SparkleFilter - Render sparkles

WoodFilter -Create a wood texture


Blurring and Sharpening Filters

BlurFilter - Simple blur

BoxBlurFilter - Box blur

BumpFilter - Edge embossing

ConvolveFilter - General convolution

DespeckleFilter - De-speckle an image

GaussianFilter - Gaussian blur

GlowFilter - Add a glow to an image

HighPassFilter - Remove low spatial frequencies

LensBlurFilter - Simulate camera lens blur

MaximumFilter - Dilation

MedianFilter - Median filter for noise reduction

MinimumFilter - Erosion

MotionBlurFilter - Simulate motion blur

OilFilter - Oil painting effect

RaysFilter - Create light rays

ReduceNoiseFilter - Remove noise from an image

SharpenFilter - Simple sharpening

SmartBlurFilter - A thresholded blur for ironing out wrinkles

UnsharpFilter - Sharpening by unsharp masking

VariableBlurFilter - Blurring with a variable radius taken from a mask

Edge Detection

DoGFilter - Edge detection by Difference of Gaussians

EdgeFilter - Edge detection

LaplaceFilter - Edge detection by Laplace operator

Transitions

BlurTransition - Transition with a blur

GradientWipeFilter - Use a mask to dissolve one image into another

Alpha Channel Filters

OpacityFilter - Change image opacity

PremultiplyFilter - Premultiply an image

UnpremultiplyFilter - Unpremultiply an image

Other Filters

CompoundFilter - Apply two filters in sequence

IteratedFilter - Iterate another filter

Original Image
*s28.postimg.org/qvt5wipp5/Original.jpg

Here are some sample filters :

The filters are stored in the package "com.jhlabs.image" You should use a IDE like NetBeans, Eclipse, IDEA & create a package & place all the files in the package there.

AbstractBufferedImageOp.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:23 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImageOp;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;

/**
 * A convenience class which implements those methods of BufferedImageOp which are rarely changed.
 */
public abstract class AbstractBufferedImageOp implements BufferedImageOp, Cloneable {

    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
        if ( dstCM == null )
            dstCM = src.getColorModel();
        return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null);
    }

    public Rectangle2D getBounds2D( BufferedImage src ) {
        return new Rectangle(0, 0, src.getWidth(), src.getHeight());
    }

    public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) {
        if ( dstPt == null )
            dstPt = new Point2D.Double();
        dstPt.setLocation( srcPt.getX(), srcPt.getY() );
        return dstPt;
    }

    public RenderingHints getRenderingHints() {
        return null;
    }

    /**
     * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
     * penalty of BufferedImage.getRGB unmanaging the image.
     * [MENTION=9956]PARAM[/MENTION] image   a BufferedImage object
     * [MENTION=9956]PARAM[/MENTION] x       the left edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] y       the right edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] width   the width of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] height  the height of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] pixels  the array to hold the returned pixels. May be null.
     * @return the pixels
     * [MENTION=288550]see[/MENTION] #setRGB
     */
    public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
        int type = image.getType();
        if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
            return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
        return image.getRGB( x, y, width, height, pixels, 0, width );
    }

    /**
     * A convenience method for setting ARGB pixels in an image. This tries to avoid the performance
     * penalty of BufferedImage.setRGB unmanaging the image.
     * [MENTION=9956]PARAM[/MENTION] image   a BufferedImage object
     * [MENTION=9956]PARAM[/MENTION] x       the left edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] y       the right edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] width   the width of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] height  the height of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] pixels  the array of pixels to set
     * [MENTION=288550]see[/MENTION] #getRGB
     */
    public void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
        int type = image.getType();
        if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
            image.getRaster().setDataElements( x, y, width, height, pixels );
        else
            image.setRGB( x, y, width, height, pixels, 0, width );
    }

    public Object clone() {
        try {
            return super.clone();
        }
        catch ( CloneNotSupportedException e ) {
            return null;
        }
    }
}

ArrayColormap.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:24 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A colormap implemented with an array of colors. This corresponds to the IndexColorModel class.
 */
public class ArrayColormap implements Colormap, Cloneable {

    /**
     * The array of colors.
     */
    protected int[] map;

    /**
     * Construct an all-black colormap.
     */
    public ArrayColormap() {
        this.map = new int[256];
    }

    /**
     * Construct a colormap with the given map.
     * [MENTION=9956]PARAM[/MENTION] map the array of ARGB colors
     */
    public ArrayColormap(int[] map) {
        this.map = map;
    }

    public Object clone() {
        try {
            ArrayColormap g = (ArrayColormap)super.clone();
            g.map = (int[])map.clone();
            return g;
        }
        catch (CloneNotSupportedException e) {
        }
        return null;
    }

    /**
     * Set the array of colors for the colormap.
     * [MENTION=9956]PARAM[/MENTION] map the colors
     * [MENTION=288550]see[/MENTION] #getMap
     */
    public void setMap(int[] map) {
        this.map = map;
    }

    /**
     * Get the array of colors for the colormap.
     * @return the colors
     * [MENTION=288550]see[/MENTION] #setMap
     */
    public int[] getMap() {
        return map;
    }

    /**
     * Convert a value in the range 0..1 to an RGB color.
     * [MENTION=9956]PARAM[/MENTION] v a value in the range 0..1
     * @return an RGB color
     * [MENTION=288550]see[/MENTION] #setColor
     */
    public int getColor(float v) {
/*
		v *= 255;
		int n = (int)v;
		float f = v-n;
		if (n < 0)
			return map[0];
		else if (n >= 255)
			return map[255];
		return ImageMath.mixColors(f, map[n], map[n+1]);
*/
        int n = (int)(v*255);
        if (n < 0)
            n = 0;
        else if (n > 255)
            n = 255;
        return map[n];
    }

    /**
     * Set the color at "index" to "color". Entries are interpolated linearly from
     * the existing entries at "firstIndex" and "lastIndex" to the new entry.
     * firstIndex < index < lastIndex must hold.
     * [MENTION=9956]PARAM[/MENTION] index the position to set
     * [MENTION=9956]PARAM[/MENTION] firstIndex the position of the first color from which to interpolate
     * [MENTION=9956]PARAM[/MENTION] lastIndex the position of the second color from which to interpolate
     * [MENTION=9956]PARAM[/MENTION] color the color to set
     */
    public void setColorInterpolated(int index, int firstIndex, int lastIndex, int color) {
        int firstColor = map[firstIndex];
        int lastColor = map[lastIndex];
        for (int i = firstIndex; i <= index; i++)
            map[i] = ImageMath.mixColors((float)(i-firstIndex)/(index-firstIndex), firstColor, color);
        for (int i = index; i < lastIndex; i++)
            map[i] = ImageMath.mixColors((float)(i-index)/(lastIndex-index), color, lastColor);
    }

    /**
     * Set a range of the colormap, interpolating between two colors.
     * [MENTION=9956]PARAM[/MENTION] firstIndex the position of the first color
     * [MENTION=9956]PARAM[/MENTION] lastIndex the position of the second color
     * [MENTION=9956]PARAM[/MENTION] color1 the first color
     * [MENTION=9956]PARAM[/MENTION] color2 the second color
     */
    public void setColorRange(int firstIndex, int lastIndex, int color1, int color2) {
        for (int i = firstIndex; i <= lastIndex; i++)
            map[i] = ImageMath.mixColors((float)(i-firstIndex)/(lastIndex-firstIndex), color1, color2);
    }

    /**
     * Set a range of the colormap to a single color.
     * [MENTION=9956]PARAM[/MENTION] firstIndex the position of the first color
     * [MENTION=9956]PARAM[/MENTION] lastIndex the position of the second color
     * [MENTION=9956]PARAM[/MENTION] color the color
     */
    public void setColorRange(int firstIndex, int lastIndex, int color) {
        for (int i = firstIndex; i <= lastIndex; i++)
            map[i] = color;
    }

    /**
     * Set one element of the colormap to a given color.
     * [MENTION=9956]PARAM[/MENTION] index the position of the color
     * [MENTION=9956]PARAM[/MENTION] color the color
     * [MENTION=288550]see[/MENTION] #getColor
     */
    public void setColor(int index, int color) {
        map[index] = color;
    }

}

BlurFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:50 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.*;

/**
 * A simple blur filter. You should probably use BoxBlurFilter instead.
 */
public class BlurFilter extends ConvolveFilter {

    /**
     * A 3x3 convolution kernel for a simple blur.
     */
    protected static float[] blurMatrix = {
            1/14f, 2/14f, 1/14f,
            2/14f, 2/14f, 2/14f,
            1/14f, 2/14f, 1/14f
    };

    public BlurFilter() {
        super( blurMatrix );
    }

    public String toString() {
        return "Blur/Simple Blur";
    }
}

*s29.postimg.org/9rnpinltv/Blur.jpg

CellularFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:25 PM
 * To change this template use File | Settings | File Templates.
 */

import com.jhlabs.math.Function2D;
import com.jhlabs.math.Noise;

import java.awt.*;
import java.util.Random;

/**
 * A filter which produces an image with a cellular texture.
 */
public class CellularFilter extends WholeImageFilter implements Function2D, Cloneable {

    protected float scale = 32;
    protected float stretch = 1.0f;
    protected float angle = 0.0f;
    public float amount = 1.0f;
    public float turbulence = 1.0f;
    public float gain = 0.5f;
    public float bias = 0.5f;
    public float distancePower = 2;
    public boolean useColor = false;
    protected Colormap colormap = new Gradient();
    protected float[] coefficients = { 1, 0, 0, 0 };
    protected float angleCoefficient;
    protected Random random = new Random();
    protected float m00 = 1.0f;
    protected float m01 = 0.0f;
    protected float m10 = 0.0f;
    protected float m11 = 1.0f;
    protected Point[] results = null;
    protected float randomness = 0;
    protected int gridType = HEXAGONAL;
    private float min;
    private float max;
    private static byte[] probabilities;
    private float gradientCoefficient;

    public final static int RANDOM = 0;
    public final static int SQUARE = 1;
    public final static int HEXAGONAL = 2;
    public final static int OCTAGONAL = 3;
    public final static int TRIANGULAR = 4;

    public CellularFilter() {
        results = new Point[3];
        for (int j = 0; j < results.length; j++)
            results[j] = new Point();
        if (probabilities == null) {
            probabilities = new byte[8192];
            float factorial = 1;
            float total = 0;
            float mean = 2.5f;
            for (int i = 0; i < 10; i++) {
                if (i > 1)
                    factorial *= i;
                float probability = (float)Math.pow(mean, i) * (float)Math.exp(-mean) / factorial;
                int start = (int)(total * 8192);
                total += probability;
                int end = (int)(total * 8192);
                for (int j = start; j < end; j++)
                    probabilities[j] = (byte)i;
            }
        }
    }

    /**
     * Specifies the scale of the texture.
     * [MENTION=9956]PARAM[/MENTION] scale the scale of the texture.
     * @min-value 1
     * [MENTION=56127]max[/MENTION]-value 300+
     * [MENTION=288550]see[/MENTION] #getScale
     */
    public void setScale(float scale) {
        this.scale = scale;
    }

    /**
     * Returns the scale of the texture.
     * @return the scale of the texture.
     * [MENTION=288550]see[/MENTION] #setScale
     */
    public float getScale() {
        return scale;
    }

    /**
     * Specifies the stretch factor of the texture.
     * [MENTION=9956]PARAM[/MENTION] stretch the stretch factor of the texture.
     * @min-value 1
     * [MENTION=56127]max[/MENTION]-value 50+
     * [MENTION=288550]see[/MENTION] #getStretch
     */
    public void setStretch(float stretch) {
        this.stretch = stretch;
    }

    /**
     * Returns the stretch factor of the texture.
     * @return the stretch factor of the texture.
     * [MENTION=288550]see[/MENTION] #setStretch
     */
    public float getStretch() {
        return stretch;
    }

    /**
     * Specifies the angle of the texture.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of the texture.
     * @angle
     * [MENTION=288550]see[/MENTION] #getAngle
     */
    public void setAngle(float angle) {
        this.angle = angle;
        float cos = (float)Math.cos(angle);
        float sin = (float)Math.sin(angle);
        m00 = cos;
        m01 = sin;
        m10 = -sin;
        m11 = cos;
    }

    /**
     * Returns the angle of the texture.
     * @return the angle of the texture.
     * [MENTION=288550]see[/MENTION] #setAngle
     */
    public float getAngle() {
        return angle;
    }

    public void setCoefficient(int i, float v) {
        coefficients[i] = v;
    }

    public float getCoefficient(int i) {
        return coefficients[i];
    }

    public void setAngleCoefficient(float angleCoefficient) {
        this.angleCoefficient = angleCoefficient;
    }

    public float getAngleCoefficient() {
        return angleCoefficient;
    }

    public void setGradientCoefficient(float gradientCoefficient) {
        this.gradientCoefficient = gradientCoefficient;
    }

    public float getGradientCoefficient() {
        return gradientCoefficient;
    }

    public void setF1( float v ) {
        coefficients[0] = v;
    }

    public float getF1() {
        return coefficients[0];
    }

    public void setF2( float v ) {
        coefficients[1] = v;
    }

    public float getF2() {
        return coefficients[1];
    }

    public void setF3( float v ) {
        coefficients[2] = v;
    }

    public float getF3() {
        return coefficients[2];
    }

    public void setF4( float v ) {
        coefficients[3] = v;
    }

    public float getF4() {
        return coefficients[3];
    }

    /**
     * Set the colormap to be used for the filter.
     * [MENTION=9956]PARAM[/MENTION] colormap the colormap
     * [MENTION=288550]see[/MENTION] #getColormap
     */
    public void setColormap(Colormap colormap) {
        this.colormap = colormap;
    }

    /**
     * Get the colormap to be used for the filter.
     * @return the colormap
     * [MENTION=288550]see[/MENTION] #setColormap
     */
    public Colormap getColormap() {
        return colormap;
    }

    public void setRandomness(float randomness) {
        this.randomness = randomness;
    }

    public float getRandomness() {
        return randomness;
    }

    public void setGridType(int gridType) {
        this.gridType = gridType;
    }

    public int getGridType() {
        return gridType;
    }

    public void setDistancePower(float distancePower) {
        this.distancePower = distancePower;
    }

    public float getDistancePower() {
        return distancePower;
    }

    /**
     * Specifies the turbulence of the texture.
     * [MENTION=9956]PARAM[/MENTION] turbulence the turbulence of the texture.
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getTurbulence
     */
    public void setTurbulence(float turbulence) {
        this.turbulence = turbulence;
    }

    /**
     * Returns the turbulence of the effect.
     * @return the turbulence of the effect.
     * [MENTION=288550]see[/MENTION] #setTurbulence
     */
    public float getTurbulence() {
        return turbulence;
    }

    /**
     * Set the amount of effect.
     * [MENTION=9956]PARAM[/MENTION] amount the amount
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getAmount
     */
    public void setAmount(float amount) {
        this.amount = amount;
    }

    /**
     * Get the amount of texture.
     * @return the amount
     * [MENTION=288550]see[/MENTION] #setAmount
     */
    public float getAmount() {
        return amount;
    }

    public class Point {
        public int index;
        public float x, y;
        public float dx, dy;
        public float cubeX, cubeY;
        public float distance;
    }

    private float checkCube(float x, float y, int cubeX, int cubeY, Point[] results) {
        int numPoints;
        random.setSeed(571*cubeX + 23*cubeY);
        switch (gridType) {
            case RANDOM:
            default:
                numPoints = probabilities[random.nextInt() & 0x1fff];
                break;
            case SQUARE:
                numPoints = 1;
                break;
            case HEXAGONAL:
                numPoints = 1;
                break;
            case OCTAGONAL:
                numPoints = 2;
                break;
            case TRIANGULAR:
                numPoints = 2;
                break;
        }
        for (int i = 0; i < numPoints; i++) {
            float px = 0, py = 0;
            float weight = 1.0f;
            switch (gridType) {
                case RANDOM:
                    px = random.nextFloat();
                    py = random.nextFloat();
                    break;
                case SQUARE:
                    px = py = 0.5f;
                    if (randomness != 0) {
                        px += randomness * (random.nextFloat()-0.5);
                        py += randomness * (random.nextFloat()-0.5);
                    }
                    break;
                case HEXAGONAL:
                    if ((cubeX & 1) == 0) {
                        px = 0.75f; py = 0;
                    } else {
                        px = 0.75f; py = 0.5f;
                    }
                    if (randomness != 0) {
                        px += randomness * Noise.noise2(271 * (cubeX + px), 271 * (cubeY + py));
                        py += randomness * Noise.noise2(271*(cubeX+px)+89, 271*(cubeY+py)+137);
                    }
                    break;
                case OCTAGONAL:
                    switch (i) {
                        case 0: px = 0.207f; py = 0.207f; break;
                        case 1: px = 0.707f; py = 0.707f; weight = 1.6f; break;
                    }
                    if (randomness != 0) {
                        px += randomness * Noise.noise2(271*(cubeX+px), 271*(cubeY+py));
                        py += randomness * Noise.noise2(271*(cubeX+px)+89, 271*(cubeY+py)+137);
                    }
                    break;
                case TRIANGULAR:
                    if ((cubeY & 1) == 0) {
                        if (i == 0) {
                            px = 0.25f; py = 0.35f;
                        } else {
                            px = 0.75f; py = 0.65f;
                        }
                    } else {
                        if (i == 0) {
                            px = 0.75f; py = 0.35f;
                        } else {
                            px = 0.25f; py = 0.65f;
                        }
                    }
                    if (randomness != 0) {
                        px += randomness * Noise.noise2(271*(cubeX+px), 271*(cubeY+py));
                        py += randomness * Noise.noise2(271*(cubeX+px)+89, 271*(cubeY+py)+137);
                    }
                    break;
            }
            float dx = (float)Math.abs(x-px);
            float dy = (float)Math.abs(y-py);
            float d;
            dx *= weight;
            dy *= weight;
            if (distancePower == 1.0f)
                d = dx + dy;
            else if (distancePower == 2.0f)
                d = (float)Math.sqrt(dx*dx + dy*dy);
            else
                d = (float)Math.pow((float)Math.pow(dx, distancePower) + (float)Math.pow(dy, distancePower), 1/distancePower);

            // Insertion sort the long way round to speed it up a bit
            if (d < results[0].distance) {
                Point p = results[2];
                results[2] = results[1];
                results[1] = results[0];
                results[0] = p;
                p.distance = d;
                p.dx = dx;
                p.dy = dy;
                p.x = cubeX+px;
                p.y = cubeY+py;
            } else if (d < results[1].distance) {
                Point p = results[2];
                results[2] = results[1];
                results[1] = p;
                p.distance = d;
                p.dx = dx;
                p.dy = dy;
                p.x = cubeX+px;
                p.y = cubeY+py;
            } else if (d < results[2].distance) {
                Point p = results[2];
                p.distance = d;
                p.dx = dx;
                p.dy = dy;
                p.x = cubeX+px;
                p.y = cubeY+py;
            }
        }
        return results[2].distance;
    }

    public float evaluate(float x, float y) {
        for (int j = 0; j < results.length; j++)
            results[j].distance = Float.POSITIVE_INFINITY;

        int ix = (int)x;
        int iy = (int)y;
        float fx = x-ix;
        float fy = y-iy;

        float d = checkCube(fx, fy, ix, iy, results);
        if (d > fy)
            d = checkCube(fx, fy+1, ix, iy-1, results);
        if (d > 1-fy)
            d = checkCube(fx, fy-1, ix, iy+1, results);
        if (d > fx) {
            checkCube(fx+1, fy, ix-1, iy, results);
            if (d > fy)
                d = checkCube(fx+1, fy+1, ix-1, iy-1, results);
            if (d > 1-fy)
                d = checkCube(fx+1, fy-1, ix-1, iy+1, results);
        }
        if (d > 1-fx) {
            d = checkCube(fx-1, fy, ix+1, iy, results);
            if (d > fy)
                d = checkCube(fx-1, fy+1, ix+1, iy-1, results);
            if (d > 1-fy)
                d = checkCube(fx-1, fy-1, ix+1, iy+1, results);
        }

        float t = 0;
        for (int i = 0; i < 3; i++)
            t += coefficients[i] * results[i].distance;
        if (angleCoefficient != 0) {
            float angle = (float)Math.atan2(y-results[0].y, x-results[0].x);
            if (angle < 0)
                angle += 2*(float)Math.PI;
            angle /= 4*(float)Math.PI;
            t += angleCoefficient * angle;
        }
        if (gradientCoefficient != 0) {
            float a = 1/(results[0].dy+results[0].dx);
            t += gradientCoefficient * a;
        }
        return t;
    }

    public float turbulence2(float x, float y, float freq) {
        float t = 0.0f;

        for (float f = 1.0f; f <= freq; f *= 2)
            t += evaluate(f*x, f*y) / f;
        return t;
    }

    public int getPixel(int x, int y, int[] inPixels, int width, int height) {
        float nx = m00*x + m01*y;
        float ny = m10*x + m11*y;
        nx /= scale;
        ny /= scale * stretch;
        nx += 1000;
        ny += 1000;	// Reduce artifacts around 0,0
        float f = turbulence == 1.0f ? evaluate(nx, ny) : turbulence2(nx, ny, turbulence);
        // Normalize to 0..1

        f *= 2;
        f *= amount;
        int a = 0xff000000;
        int v;
        if (colormap != null) {
            v = colormap.getColor(f);
            if (useColor) {
                int srcx = ImageMath.clamp((int)((results[0].x-1000)*scale), 0, width-1);
                int srcy = ImageMath.clamp((int)((results[0].y-1000)*scale), 0, height-1);
                v = inPixels[srcy * width + srcx];
                f = (results[1].distance - results[0].distance) / (results[1].distance + results[0].distance);
                f = ImageMath.smoothStep(coefficients[1], coefficients[0], f);
                v = ImageMath.mixColors(f, 0xff000000, v);
            }
            return v;
        } else {
            v = PixelUtils.clamp((int)(f*255));
            int r = v << 16;
            int g = v << 8;
            int b = v;
            return a|r|g|b;
        }
    }

    protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {

        int index = 0;
        int[] outPixels = new int[width * height];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                outPixels[index++] = getPixel(x, y, inPixels, width, height);
            }
        }
        return outPixels;
    }

    public Object clone() {
        CellularFilter f = (CellularFilter)super.clone();
        f.coefficients = (float[])coefficients.clone();
        f.results = (Point[])results.clone();
        f.random = new Random();
        return f;
    }

    public String toString() {
        return "Texture/Cellular...";
    }
}

ChannelMixFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:27 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.image.*;

/**
 * A filter which allows the red, green and blue channels of an image to be mixed into each other.
 */
public class ChannelMixFilter extends PointFilter {

    private int blueGreen, redBlue, greenRed;
    private int intoR, intoG, intoB;

    public ChannelMixFilter() {
        canFilterIndexColorModel = true;
    }

    public void setBlueGreen(int blueGreen) {
        this.blueGreen = blueGreen;
    }

    public int getBlueGreen() {
        return blueGreen;
    }

    public void setRedBlue(int redBlue) {
        this.redBlue = redBlue;
    }

    public int getRedBlue() {
        return redBlue;
    }

    public void setGreenRed(int greenRed) {
        this.greenRed = greenRed;
    }

    public int getGreenRed() {
        return greenRed;
    }

    public void setIntoR(int intoR) {
        this.intoR = intoR;
    }

    public int getIntoR() {
        return intoR;
    }

    public void setIntoG(int intoG) {
        this.intoG = intoG;
    }

    public int getIntoG() {
        return intoG;
    }

    public void setIntoB(int intoB) {
        this.intoB = intoB;
    }

    public int getIntoB() {
        return intoB;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        int nr = PixelUtils.clamp((intoR * (blueGreen*g+(255-blueGreen)*b)/255 + (255-intoR)*r)/255);
        int ng = PixelUtils.clamp((intoG * (redBlue*b+(255-redBlue)*r)/255 + (255-intoG)*g)/255);
        int nb = PixelUtils.clamp((intoB * (greenRed*r+(255-greenRed)*g)/255 + (255-intoB)*b)/255);
        return a | (nr << 16) | (ng << 8) | nb;
    }

    public String toString() {
        return "Colors/Mix Channels...";
    }
}

Colormap.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:28 PM
 * To change this template use File | Settings | File Templates.
 */
/**
 * An interface for color maps.  These are passed to filters which convert gray values to
 * colors. This is similar to the ColorModel class but works with floating point values.
 */
public interface Colormap {
    /**
     * Convert a value in the range 0..1 to an RGB color.
     * [MENTION=9956]PARAM[/MENTION] v a value in the range 0..1
     * @return an RGB color
     */
    public int getColor(float v);
}

ConvolveFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:50 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.Kernel;
import java.awt.*;
import java.awt.image.*;
import java.awt.geom.*;

/**
 * A filter which applies a convolution kernel to an image.
 * @author Jerry Huxtable
 */
public class ConvolveFilter extends AbstractBufferedImageOp {

    /**
     * Treat pixels off the edge as zero.
     */
    public static int ZERO_EDGES = 0;

    /**
     * Clamp pixels off the edge to the nearest edge.
     */
    public static int CLAMP_EDGES = 1;

    /**
     * Wrap pixels off the edge to the opposite edge.
     */
    public static int WRAP_EDGES = 2;

    /**
     * The convolution kernel.
     */
    protected Kernel kernel = null;

    /**
     * Whether to convolve alpha.
     */
    protected boolean alpha = true;

    /**
     * Whether to promultiply the alpha before convolving.
     */
    protected boolean premultiplyAlpha = true;

    /**
     * What do do at the image edges.
     */
    private int edgeAction = CLAMP_EDGES;

    /**
     * Construct a filter with a null kernel. This is only useful if you're going to change the kernel later on.
     */
    public ConvolveFilter() {
        this(new float[9]);
    }

    /**
     * Construct a filter with the given 3x3 kernel.
     * [MENTION=9956]PARAM[/MENTION] matrix an array of 9 floats containing the kernel
     */
    public ConvolveFilter(float[] matrix) {
        this(new Kernel(3, 3, matrix));
    }

    /**
     * Construct a filter with the given kernel.
     * [MENTION=9956]PARAM[/MENTION] rows	the number of rows in the kernel
     * [MENTION=9956]PARAM[/MENTION] cols	the number of columns in the kernel
     * [MENTION=9956]PARAM[/MENTION] matrix	an array of rows*cols floats containing the kernel
     */
    public ConvolveFilter(int rows, int cols, float[] matrix) {
        this(new Kernel(cols, rows, matrix));
    }

    /**
     * Construct a filter with the given 3x3 kernel.
     * [MENTION=9956]PARAM[/MENTION] kernel the convolution kernel
     */
    public ConvolveFilter(Kernel kernel) {
        this.kernel = kernel;
    }

    /**
     * Set the convolution kernel.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=288550]see[/MENTION] #getKernel
     */
    public void setKernel(Kernel kernel) {
        this.kernel = kernel;
    }

    /**
     * Get the convolution kernel.
     * @return the kernel
     * [MENTION=288550]see[/MENTION] #setKernel
     */
    public Kernel getKernel() {
        return kernel;
    }

    /**
     * Set the action to perfomr for pixels off the image edges.
     * [MENTION=9956]PARAM[/MENTION] edgeAction the action
     * [MENTION=288550]see[/MENTION] #getEdgeAction
     */
    public void setEdgeAction(int edgeAction) {
        this.edgeAction = edgeAction;
    }

    /**
     * Get the action to perfomr for pixels off the image edges.
     * @return the action
     * [MENTION=288550]see[/MENTION] #setEdgeAction
     */
    public int getEdgeAction() {
        return edgeAction;
    }

    /**
     * Set whether to convolve the alpha channel.
     * [MENTION=9956]PARAM[/MENTION] useAlpha true to convolve the alpha
     * [MENTION=288550]see[/MENTION] #getUseAlpha
     */
    public void setUseAlpha( boolean useAlpha ) {
        this.alpha = useAlpha;
    }

    /**
     * Get whether to convolve the alpha channel.
     * @return true to convolve the alpha
     * [MENTION=288550]see[/MENTION] #setUseAlpha
     */
    public boolean getUseAlpha() {
        return alpha;
    }

    /**
     * Set whether to premultiply the alpha channel.
     * [MENTION=9956]PARAM[/MENTION] premultiplyAlpha true to premultiply the alpha
     * [MENTION=288550]see[/MENTION] #getPremultiplyAlpha
     */
    public void setPremultiplyAlpha( boolean premultiplyAlpha ) {
        this.premultiplyAlpha = premultiplyAlpha;
    }

    /**
     * Get whether to premultiply the alpha channel.
     * @return true to premultiply the alpha
     * [MENTION=288550]see[/MENTION] #setPremultiplyAlpha
     */
    public boolean getPremultiplyAlpha() {
        return premultiplyAlpha;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( src, 0, 0, width, height, inPixels );

        if ( premultiplyAlpha )
            ImageMath.premultiply( inPixels, 0, inPixels.length );
        convolve(kernel, inPixels, outPixels, width, height, alpha, edgeAction);
        if ( premultiplyAlpha )
            ImageMath.unpremultiply( outPixels, 0, outPixels.length );

        setRGB( dst, 0, 0, width, height, outPixels );
        return dst;
    }

    public BufferedImage createCompatibleDestImage(BufferedImage src, ColorModel dstCM) {
        if ( dstCM == null )
            dstCM = src.getColorModel();
        return new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(src.getWidth(), src.getHeight()), dstCM.isAlphaPremultiplied(), null);
    }

    public Rectangle2D getBounds2D( BufferedImage src ) {
        return new Rectangle(0, 0, src.getWidth(), src.getHeight());
    }

    public Point2D getPoint2D( Point2D srcPt, Point2D dstPt ) {
        if ( dstPt == null )
            dstPt = new Point2D.Double();
        dstPt.setLocation( srcPt.getX(), srcPt.getY() );
        return dstPt;
    }

    public RenderingHints getRenderingHints() {
        return null;
    }

    /**
     * Convolve a block of pixels.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolve(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, int edgeAction) {
        convolve(kernel, inPixels, outPixels, width, height, true, edgeAction);
    }

    /**
     * Convolve a block of pixels.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=9956]PARAM[/MENTION] alpha include alpha channel
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolve(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
        if (kernel.getHeight() == 1)
            convolveH(kernel, inPixels, outPixels, width, height, alpha, edgeAction);
        else if (kernel.getWidth() == 1)
            convolveV(kernel, inPixels, outPixels, width, height, alpha, edgeAction);
        else
            convolveHV(kernel, inPixels, outPixels, width, height, alpha, edgeAction);
    }

    /**
     * Convolve with a 2D kernel.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=9956]PARAM[/MENTION] alpha include alpha channel
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolveHV(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
        int index = 0;
        float[] matrix = kernel.getKernelData( null );
        int rows = kernel.getHeight();
        int cols = kernel.getWidth();
        int rows2 = rows/2;
        int cols2 = cols/2;

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                float r = 0, g = 0, b = 0, a = 0;

                for (int row = -rows2; row <= rows2; row++) {
                    int iy = y+row;
                    int ioffset;
                    if (0 <= iy && iy < height)
                        ioffset = iy*width;
                    else if ( edgeAction == CLAMP_EDGES )
                        ioffset = y*width;
                    else if ( edgeAction == WRAP_EDGES )
                        ioffset = ((iy+height) % height) * width;
                    else
                        continue;
                    int moffset = cols*(row+rows2)+cols2;
                    for (int col = -cols2; col <= cols2; col++) {
                        float f = matrix[moffset+col];

                        if (f != 0) {
                            int ix = x+col;
                            if (!(0 <= ix && ix < width)) {
                                if ( edgeAction == CLAMP_EDGES )
                                    ix = x;
                                else if ( edgeAction == WRAP_EDGES )
                                    ix = (x+width) % width;
                                else
                                    continue;
                            }
                            int rgb = inPixels[ioffset+ix];
                            a += f * ((rgb >> 24) & 0xff);
                            r += f * ((rgb >> 16) & 0xff);
                            g += f * ((rgb >> 8) & 0xff);
                            b += f * (rgb & 0xff);
                        }
                    }
                }
                int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
                int ir = PixelUtils.clamp((int)(r+0.5));
                int ig = PixelUtils.clamp((int)(g+0.5));
                int ib = PixelUtils.clamp((int)(b+0.5));
                outPixels[index++] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
            }
        }
    }

    /**
     * Convolve with a kernel consisting of one row.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=9956]PARAM[/MENTION] alpha include alpha channel
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolveH(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
        int index = 0;
        float[] matrix = kernel.getKernelData( null );
        int cols = kernel.getWidth();
        int cols2 = cols/2;

        for (int y = 0; y < height; y++) {
            int ioffset = y*width;
            for (int x = 0; x < width; x++) {
                float r = 0, g = 0, b = 0, a = 0;
                int moffset = cols2;
                for (int col = -cols2; col <= cols2; col++) {
                    float f = matrix[moffset+col];

                    if (f != 0) {
                        int ix = x+col;
                        if ( ix < 0 ) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = 0;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        } else if ( ix >= width) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = width-1;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        }
                        int rgb = inPixels[ioffset+ix];
                        a += f * ((rgb >> 24) & 0xff);
                        r += f * ((rgb >> 16) & 0xff);
                        g += f * ((rgb >> 8) & 0xff);
                        b += f * (rgb & 0xff);
                    }
                }
                int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
                int ir = PixelUtils.clamp((int)(r+0.5));
                int ig = PixelUtils.clamp((int)(g+0.5));
                int ib = PixelUtils.clamp((int)(b+0.5));
                outPixels[index++] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
            }
        }
    }

    /**
     * Convolve with a kernel consisting of one column.
     * [MENTION=9956]PARAM[/MENTION] kernel the kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=9956]PARAM[/MENTION] alpha include alpha channel
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolveV(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, int edgeAction) {
        int index = 0;
        float[] matrix = kernel.getKernelData( null );
        int rows = kernel.getHeight();
        int rows2 = rows/2;

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                float r = 0, g = 0, b = 0, a = 0;

                for (int row = -rows2; row <= rows2; row++) {
                    int iy = y+row;
                    int ioffset;
                    if ( iy < 0 ) {
                        if ( edgeAction == CLAMP_EDGES )
                            ioffset = 0;
                        else if ( edgeAction == WRAP_EDGES )
                            ioffset = ((y+height) % height)*width;
                        else
                            ioffset = iy*width;
                    } else if ( iy >= height) {
                        if ( edgeAction == CLAMP_EDGES )
                            ioffset = (height-1)*width;
                        else if ( edgeAction == WRAP_EDGES )
                            ioffset = ((y+height) % height)*width;
                        else
                            ioffset = iy*width;
                    } else
                        ioffset = iy*width;

                    float f = matrix[row+rows2];

                    if (f != 0) {
                        int rgb = inPixels[ioffset+x];
                        a += f * ((rgb >> 24) & 0xff);
                        r += f * ((rgb >> 16) & 0xff);
                        g += f * ((rgb >> 8) & 0xff);
                        b += f * (rgb & 0xff);
                    }
                }
                int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
                int ir = PixelUtils.clamp((int)(r+0.5));
                int ig = PixelUtils.clamp((int)(g+0.5));
                int ib = PixelUtils.clamp((int)(b+0.5));
                outPixels[index++] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
            }
        }
    }

    public String toString() {
        return "Blur/Convolve...";
    }
}

CrystallizeFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:29 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A filter which applies a crystallizing effect to an image, by producing Voronoi cells filled with colours from the image.
 */
public class CrystallizeFilter extends CellularFilter {

    private float edgeThickness = 0.4f;
    private boolean fadeEdges = false;
    private int edgeColor = 0xff000000;

    public CrystallizeFilter() {
        setScale(16);
        setRandomness(0.0f);
    }

    public void setEdgeThickness(float edgeThickness) {
        this.edgeThickness = edgeThickness;
    }

    public float getEdgeThickness() {
        return edgeThickness;
    }

    public void setFadeEdges(boolean fadeEdges) {
        this.fadeEdges = fadeEdges;
    }

    public boolean getFadeEdges() {
        return fadeEdges;
    }

    public void setEdgeColor(int edgeColor) {
        this.edgeColor = edgeColor;
    }

    public int getEdgeColor() {
        return edgeColor;
    }

    public int getPixel(int x, int y, int[] inPixels, int width, int height) {
        float nx = m00*x + m01*y;
        float ny = m10*x + m11*y;
        nx /= scale;
        ny /= scale * stretch;
        nx += 1000;
        ny += 1000;	// Reduce artifacts around 0,0
        float f = evaluate(nx, ny);

        float f1 = results[0].distance;
        float f2 = results[1].distance;
        int srcx = ImageMath.clamp((int)((results[0].x-1000)*scale), 0, width-1);
        int srcy = ImageMath.clamp((int)((results[0].y-1000)*scale), 0, height-1);
        int v = inPixels[srcy * width + srcx];
        f = (f2 - f1) / edgeThickness;
        f = ImageMath.smoothStep(0, edgeThickness, f);
        if (fadeEdges) {
            srcx = ImageMath.clamp((int)((results[1].x-1000)*scale), 0, width-1);
            srcy = ImageMath.clamp((int)((results[1].y-1000)*scale), 0, height-1);
            int v2 = inPixels[srcy * width + srcx];
            v2 = ImageMath.mixColors(0.5f, v2, v);
            v = ImageMath.mixColors(f, v2, v);
        } else
            v = ImageMath.mixColors(f, edgeColor, v);
        return v;
    }

    public String toString() {
        return "Pixellate/Crystallize...";
    }

}

*s9.postimg.org/nwce0ms8r/Crystallize.jpg

EdgeFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:52 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;

/**
 * An edge-detection filter.
 */
public class EdgeFilter extends WholeImageFilter {

    public final static float R2 = (float)Math.sqrt(2);

    public final static float[] ROBERTS_V = {
            0,  0, -1,
            0,  1,  0,
            0,  0,  0,
    };
    public final static float[] ROBERTS_H = {
            -1,  0,  0,
            0,  1,  0,
            0,  0,  0,
    };
    public final static float[] PREWITT_V = {
            -1,  0,  1,
            -1,  0,  1,
            -1,  0,  1,
    };
    public final static float[] PREWITT_H = {
            -1, -1, -1,
            0,  0,  0,
            1,  1,  1,
    };
    public final static float[] SOBEL_V = {
            -1,  0,  1,
            -2,  0,  2,
            -1,  0,  1,
    };
    public static float[] SOBEL_H = {
            -1, -2, -1,
            0,  0,  0,
            1,  2,  1,
    };
    public final static float[] FREI_CHEN_V = {
            -1,  0,  1,
            -R2,  0,  R2,
            -1,  0,  1,
    };
    public static float[] FREI_CHEN_H = {
            -1, -R2, -1,
            0,  0,  0,
            1,  R2,  1,
    };

    protected float[] vEdgeMatrix = SOBEL_V;
    protected float[] hEdgeMatrix = SOBEL_H;

    public EdgeFilter() {
    }

    public void setVEdgeMatrix(float[] vEdgeMatrix) {
        this.vEdgeMatrix = vEdgeMatrix;
    }

    public float[] getVEdgeMatrix() {
        return vEdgeMatrix;
    }

    public void setHEdgeMatrix(float[] hEdgeMatrix) {
        this.hEdgeMatrix = hEdgeMatrix;
    }

    public float[] getHEdgeMatrix() {
        return hEdgeMatrix;
    }

    protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
        int index = 0;
        int[] outPixels = new int[width * height];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int r = 0, g = 0, b = 0;
                int rh = 0, gh = 0, bh = 0;
                int rv = 0, gv = 0, bv = 0;
                int a = inPixels[y*width+x] & 0xff000000;

                for (int row = -1; row <= 1; row++) {
                    int iy = y+row;
                    int ioffset;
                    if (0 <= iy && iy < height)
                        ioffset = iy*width;
                    else
                        ioffset = y*width;
                    int moffset = 3*(row+1)+1;
                    for (int col = -1; col <= 1; col++) {
                        int ix = x+col;
                        if (!(0 <= ix && ix < width))
                            ix = x;
                        int rgb = inPixels[ioffset+ix];
                        float h = hEdgeMatrix[moffset+col];
                        float v = vEdgeMatrix[moffset+col];

                        r = (rgb & 0xff0000) >> 16;
                        g = (rgb & 0x00ff00) >> 8;
                        b = rgb & 0x0000ff;
                        rh += (int)(h * r);
                        gh += (int)(h * g);
                        bh += (int)(h * b);
                        rv += (int)(v * r);
                        gv += (int)(v * g);
                        bv += (int)(v * b);
                    }
                }
                r = (int)(Math.sqrt(rh*rh + rv*rv) / 1.8);
                g = (int)(Math.sqrt(gh*gh + gv*gv) / 1.8);
                b = (int)(Math.sqrt(bh*bh + bv*bv) / 1.8);
                r = PixelUtils.clamp(r);
                g = PixelUtils.clamp(g);
                b = PixelUtils.clamp(b);
                outPixels[index++] = a | (r << 16) | (g << 8) | b;
            }

        }
        return outPixels;
    }

    public String toString() {
        return "Edges/Detect Edges";
    }
}

*s11.postimg.org/ozqmi5j5r/Edge.jpg

EmbossFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:29 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.image.*;

/**
 * A class to emboss an image.
 */
public class EmbossFilter extends WholeImageFilter {

    private final static float pixelScale = 255.9f;

    private float azimuth = 135.0f * ImageMath.PI / 180.0f, elevation = 30.0f * ImageMath.PI / 180f;
    private boolean emboss = false;
    private float width45 = 3.0f;

    public EmbossFilter() {
    }

    public void setAzimuth(float azimuth) {
        this.azimuth = azimuth;
    }

    public float getAzimuth() {
        return azimuth;
    }

    public void setElevation(float elevation) {
        this.elevation = elevation;
    }

    public float getElevation() {
        return elevation;
    }

    public void setBumpHeight(float bumpHeight) {
        this.width45 = 3 * bumpHeight;
    }

    public float getBumpHeight() {
        return width45 / 3;
    }

    public void setEmboss(boolean emboss) {
        this.emboss = emboss;
    }

    public boolean getEmboss() {
        return emboss;
    }

    protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
        int index = 0;
        int[] outPixels = new int[width * height];

        int[] bumpPixels;
        int bumpMapWidth, bumpMapHeight;

        bumpMapWidth = width;
        bumpMapHeight = height;
        bumpPixels = new int[bumpMapWidth * bumpMapHeight];
        for (int i = 0; i < inPixels.length; i++)
            bumpPixels[i] = PixelUtils.brightness(inPixels[i]);

        int Nx, Ny, Nz, Lx, Ly, Lz, Nz2, NzLz, NdotL;
        int shade, background;

        Lx = (int)(Math.cos(azimuth) * Math.cos(elevation) * pixelScale);
        Ly = (int)(Math.sin(azimuth) * Math.cos(elevation) * pixelScale);
        Lz = (int)(Math.sin(elevation) * pixelScale);

        Nz = (int)(6 * 255 / width45);
        Nz2 = Nz * Nz;
        NzLz = Nz * Lz;

        background = Lz;

        int bumpIndex = 0;

        for (int y = 0; y < height; y++, bumpIndex += bumpMapWidth) {
            int s1 = bumpIndex;
            int s2 = s1 + bumpMapWidth;
            int s3 = s2 + bumpMapWidth;

            for (int x = 0; x < width; x++, s1++, s2++, s3++) {
                if (y != 0 && y < height-2 && x != 0 && x < width-2) {
                    Nx = bumpPixels[s1-1] + bumpPixels[s2-1] + bumpPixels[s3-1] - bumpPixels[s1+1] - bumpPixels[s2+1] - bumpPixels[s3+1];
                    Ny = bumpPixels[s3-1] + bumpPixels[s3] + bumpPixels[s3+1] - bumpPixels[s1-1] - bumpPixels[s1] - bumpPixels[s1+1];

                    if (Nx == 0 && Ny == 0)
                        shade = background;
                    else if ((NdotL = Nx*Lx + Ny*Ly + NzLz) < 0)
                        shade = 0;
                    else
                        shade = (int)(NdotL / Math.sqrt(Nx*Nx + Ny*Ny + Nz2));
                } else
                    shade = background;

                if (emboss) {
                    int rgb = inPixels[index];
                    int a = rgb & 0xff000000;
                    int r = (rgb >> 16) & 0xff;
                    int g = (rgb >> 8) & 0xff;
                    int b = rgb & 0xff;
                    r = (r*shade) >> 8;
                    g = (g*shade) >> 8;
                    b = (b*shade) >> 8;
                    outPixels[index++] = a | (r << 16) | (g << 8) | b;
                } else
                    outPixels[index++] = 0xff000000 | (shade << 16) | (shade << 8) | shade;
            }
        }

        return outPixels;
    }

    public String toString() {
        return "Stylize/Emboss...";
    }

}

*s29.postimg.org/b9iclp5c3/Emboss.jpg

GaussianFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/3/14
 * Time: 12:39 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.Kernel;
import java.awt.image.*;

/**
 * A filter which applies Gaussian blur to an image. This is a subclass of ConvolveFilter
 * which simply creates a kernel with a Gaussian distribution for blurring.
 * @author Jerry Huxtable
 */
public class GaussianFilter extends ConvolveFilter {

    /**
     * The blur radius.
     */
    protected float radius;

    /**
     * The convolution kernel.
     */
    protected Kernel kernel;

    /**
     * Construct a Gaussian filter.
     */
    public GaussianFilter() {
        this(2);
    }

    /**
     * Construct a Gaussian filter.
     * [MENTION=9956]PARAM[/MENTION] radius blur radius in pixels
     */
    public GaussianFilter(float radius) {
        setRadius(radius);
    }

    /**
     * Set the radius of the kernel, and hence the amount of blur. The bigger the radius, the longer this filter will take.
     * [MENTION=9956]PARAM[/MENTION] radius the radius of the blur in pixels.
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 100+
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(float radius) {
        this.radius = radius;
        kernel = makeKernel(radius);
    }

    /**
     * Get the radius of the kernel.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public float getRadius() {
        return radius;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        src.getRGB( 0, 0, width, height, inPixels, 0, width );

        if ( radius > 0 ) {
            convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, alpha && premultiplyAlpha, false, CLAMP_EDGES);
            convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, false, alpha && premultiplyAlpha, CLAMP_EDGES);
        }

        dst.setRGB( 0, 0, width, height, inPixels, 0, width );
        return dst;
    }

    /**
     * Blur and transpose a block of ARGB pixels.
     * [MENTION=9956]PARAM[/MENTION] kernel the blur kernel
     * [MENTION=9956]PARAM[/MENTION] inPixels the input pixels
     * [MENTION=9956]PARAM[/MENTION] outPixels the output pixels
     * [MENTION=9956]PARAM[/MENTION] width the width of the pixel array
     * [MENTION=9956]PARAM[/MENTION] height the height of the pixel array
     * [MENTION=9956]PARAM[/MENTION] alpha whether to blur the alpha channel
     * [MENTION=9956]PARAM[/MENTION] edgeAction what to do at the edges
     */
    public static void convolveAndTranspose(Kernel kernel, int[] inPixels, int[] outPixels, int width, int height, boolean alpha, boolean premultiply, boolean unpremultiply, int edgeAction) {
        float[] matrix = kernel.getKernelData( null );
        int cols = kernel.getWidth();
        int cols2 = cols/2;

        for (int y = 0; y < height; y++) {
            int index = y;
            int ioffset = y*width;
            for (int x = 0; x < width; x++) {
                float r = 0, g = 0, b = 0, a = 0;
                int moffset = cols2;
                for (int col = -cols2; col <= cols2; col++) {
                    float f = matrix[moffset+col];

                    if (f != 0) {
                        int ix = x+col;
                        if ( ix < 0 ) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = 0;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        } else if ( ix >= width) {
                            if ( edgeAction == CLAMP_EDGES )
                                ix = width-1;
                            else if ( edgeAction == WRAP_EDGES )
                                ix = (x+width) % width;
                        }
                        int rgb = inPixels[ioffset+ix];
                        int pa = (rgb >> 24) & 0xff;
                        int pr = (rgb >> 16) & 0xff;
                        int pg = (rgb >> 8) & 0xff;
                        int pb = rgb & 0xff;
                        if ( premultiply ) {
                            float a255 = pa * (1.0f / 255.0f);
                            pr *= a255;
                            pg *= a255;
                            pb *= a255;
                        }
                        a += f * pa;
                        r += f * pr;
                        g += f * pg;
                        b += f * pb;
                    }
                }
                if ( unpremultiply && a != 0 && a != 255 ) {
                    float f = 255.0f / a;
                    r *= f;
                    g *= f;
                    b *= f;
                }
                int ia = alpha ? PixelUtils.clamp((int)(a+0.5)) : 0xff;
                int ir = PixelUtils.clamp((int)(r+0.5));
                int ig = PixelUtils.clamp((int)(g+0.5));
                int ib = PixelUtils.clamp((int)(b+0.5));
                outPixels[index] = (ia << 24) | (ir << 16) | (ig << 8) | ib;
                index += height;
            }
        }
    }

    /**
     * Make a Gaussian blur kernel.
     * [MENTION=9956]PARAM[/MENTION] radius the blur radius
     * @return the kernel
     */
    public static Kernel makeKernel(float radius) {
        int r = (int)Math.ceil(radius);
        int rows = r*2+1;
        float[] matrix = new float[rows];
        float sigma = radius/3;
        float sigma22 = 2*sigma*sigma;
        float sigmaPi2 = 2*ImageMath.PI*sigma;
        float sqrtSigmaPi2 = (float)Math.sqrt(sigmaPi2);
        float radius2 = radius*radius;
        float total = 0;
        int index = 0;
        for (int row = -r; row <= r; row++) {
            float distance = row*row;
            if (distance > radius2)
                matrix[index] = 0;
            else
                matrix[index] = (float)Math.exp(-(distance)/sigma22) / sqrtSigmaPi2;
            total += matrix[index];
            index++;
        }
        for (int i = 0; i < rows; i++)
            matrix[i] /= total;

        return new Kernel(rows, 1, matrix);
    }

    public String toString() {
        return "Blur/Gaussian Blur...";
    }
}

Gradient.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:26 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.Color;
import java.util.Vector;
import java.io.*;

/**
 * A Colormap implemented using Catmull-Rom colour splines. The map has a variable number
 * of knots with a minimum of four. The first and last knots give the tangent at the end
 * of the spline, and colours are interpolated from the second to the second-last knots.
 * Each knot can be given a type of interpolation. These are:
 * <UL>
 * <LI>LINEAR - linear interpolation to next knot
 * <LI>SPLINE - spline interpolation to next knot
 * <LI>CONSTANT - no interpolation - the colour is constant to the next knot
 * <LI>HUE_CW - interpolation of hue clockwise to next knot
 * <LI>HUE_CCW - interpolation of hue counter-clockwise to next knot
 * </UL>
 */
public class Gradient extends ArrayColormap implements Cloneable {

    /**
     * Interpolate in RGB space.
     */
    public final static int RGB = 0x00;

    /**
     * Interpolate hue clockwise.
     */
    public final static int HUE_CW = 0x01;

    /**
     * Interpolate hue counter clockwise.
     */
    public final static int HUE_CCW = 0x02;


    /**
     * Interpolate linearly.
     */
    public final static int LINEAR = 0x10;

    /**
     * Interpolate using a spline.
     */
    public final static int SPLINE = 0x20;

    /**
     * Interpolate with a rising circle shape curve.
     */
    public final static int CIRCLE_UP = 0x30;

    /**
     * Interpolate with a falling circle shape curve.
     */
    public final static int CIRCLE_DOWN = 0x40;

    /**
     * Don't tnterpolate - just use the starting value.
     */
    public final static int CONSTANT = 0x50;

    private final static int COLOR_MASK = 0x03;
    private final static int BLEND_MASK = 0x70;

    private int numKnots = 4;
    private int[] xKnots = {
            -1, 0, 255, 256
    };
    private int[] yKnots = {
            0xff000000, 0xff000000, 0xffffffff, 0xffffffff,
    };
    private byte[] knotTypes = {
            RGB|SPLINE, RGB|SPLINE, RGB|SPLINE, RGB|SPLINE
    };

    /**
     * Construct a Gradient.
     */
    public Gradient() {
        rebuildGradient();
    }

    /**
     * Construct a Gradient with the given colors.
     * [MENTION=9956]PARAM[/MENTION] rgb the colors
     */
    public Gradient(int[] rgb) {
        this(null, rgb, null);
    }

    /**
     * Construct a Gradient with the given colors and knot positions.
     * [MENTION=9956]PARAM[/MENTION] x the knot positions
     * [MENTION=9956]PARAM[/MENTION] rgb the colors
     */
    public Gradient(int[] x, int[] rgb) {
        this(x, rgb, null);
    }

    /**
     * Construct a Gradient with the given colors, knot positions and interpolation types.
     * [MENTION=9956]PARAM[/MENTION] x the knot positions
     * [MENTION=9956]PARAM[/MENTION] rgb the colors
     * [MENTION=9956]PARAM[/MENTION] types interpolation types
     */
    public Gradient(int[] x, int[] rgb, byte[] types) {
        setKnots(x, rgb, types);
    }

    public Object clone() {
        Gradient g = (Gradient)super.clone();
        g.map = (int[])map.clone();
        g.xKnots = (int[])xKnots.clone();
        g.yKnots = (int[])yKnots.clone();
        g.knotTypes = (byte[])knotTypes.clone();
        return g;
    }

    /**
     * Copy one Gradient into another.
     * [MENTION=9956]PARAM[/MENTION] g the Gradient to copy into
     */
    public void copyTo(Gradient g) {
        g.numKnots = numKnots;
        g.map = (int[])map.clone();
        g.xKnots = (int[])xKnots.clone();
        g.yKnots = (int[])yKnots.clone();
        g.knotTypes = (byte[])knotTypes.clone();
    }

    /**
     * Set a knot color.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=9956]PARAM[/MENTION] color the color
     */
    public void setColor(int n, int color) {
        int firstColor = map[0];
        int lastColor = map[256-1];
        if (n > 0)
            for (int i = 0; i < n; i++)
                map[i] = ImageMath.mixColors((float)i/n, firstColor, color);
        if (n < 256-1)
            for (int i = n; i < 256; i++)
                map[i] = ImageMath.mixColors((float)(i-n)/(256-n), color, lastColor);
    }

    /**
     * Get the number of knots in the gradient.
     * @return the number of knots.
     */
    public int getNumKnots() {
        return numKnots;
    }

    /**
     * Set a knot color.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=9956]PARAM[/MENTION] color the color
     * [MENTION=288550]see[/MENTION] #getKnot
     */
    public void setKnot(int n, int color) {
        yKnots[n] = color;
        rebuildGradient();
    }

    /**
     * Get a knot color.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * @return the knot color
     * [MENTION=288550]see[/MENTION] #setKnot
     */
    public int getKnot(int n) {
        return yKnots[n];
    }

    /**
     * Set a knot type.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=9956]PARAM[/MENTION] type the type
     * [MENTION=288550]see[/MENTION] #getKnotType
     */
    public void setKnotType(int n, int type) {
        knotTypes[n] = (byte)((knotTypes[n] & ~COLOR_MASK) | type);
        rebuildGradient();
    }

    /**
     * Get a knot type.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * @return the knot type
     * [MENTION=288550]see[/MENTION] #setKnotType
     */
    public int getKnotType(int n) {
        return (byte)(knotTypes[n] & COLOR_MASK);
    }

    /**
     * Set a knot blend type.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=9956]PARAM[/MENTION] type the knot blend type
     * [MENTION=288550]see[/MENTION] #getKnotBlend
     */
    public void setKnotBlend(int n, int type) {
        knotTypes[n] = (byte)((knotTypes[n] & ~BLEND_MASK) | type);
        rebuildGradient();
    }

    /**
     * Get a knot blend type.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * @return the knot blend type
     * [MENTION=288550]see[/MENTION] #setKnotBlend
     */
    public byte getKnotBlend(int n) {
        return (byte)(knotTypes[n] & BLEND_MASK);
    }

    /**
     * Add a new knot.
     * [MENTION=9956]PARAM[/MENTION] x the knot position
     * [MENTION=9956]PARAM[/MENTION] color the color
     * [MENTION=9956]PARAM[/MENTION] type the knot type
     * [MENTION=288550]see[/MENTION] #removeKnot
     */
    public void addKnot(int x, int color, int type) {
        int[] nx = new int[numKnots+1];
        int[] ny = new int[numKnots+1];
        byte[] nt = new byte[numKnots+1];
        System.arraycopy(xKnots, 0, nx, 0, numKnots);
        System.arraycopy(yKnots, 0, ny, 0, numKnots);
        System.arraycopy(knotTypes, 0, nt, 0, numKnots);
        xKnots = nx;
        yKnots = ny;
        knotTypes = nt;
        // Insert one position before the end so the sort works correctly
        xKnots[numKnots] = xKnots[numKnots-1];
        yKnots[numKnots] = yKnots[numKnots-1];
        knotTypes[numKnots] = knotTypes[numKnots-1];
        xKnots[numKnots-1] = x;
        yKnots[numKnots-1] = color;
        knotTypes[numKnots-1] = (byte)type;
        numKnots++;
        sortKnots();
        rebuildGradient();
    }

    /**
     * Remove a knot.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=288550]see[/MENTION] #addKnot
     */
    public void removeKnot(int n) {
        if (numKnots <= 4)
            return;
        if (n < numKnots-1) {
            System.arraycopy(xKnots, n+1, xKnots, n, numKnots-n-1);
            System.arraycopy(yKnots, n+1, yKnots, n, numKnots-n-1);
            System.arraycopy(knotTypes, n+1, knotTypes, n, numKnots-n-1);
        }
        numKnots--;
        if (xKnots[1] > 0)
            xKnots[1] = 0;
        rebuildGradient();
    }

    /**
     * Set the values of all the knots.
     * This version does not require the "extra" knots at -1 and 256
     * [MENTION=9956]PARAM[/MENTION] x the knot positions
     * [MENTION=9956]PARAM[/MENTION] rgb the knot colors
     * [MENTION=9956]PARAM[/MENTION] types the knot types
     */
    public void setKnots(int[] x, int[] rgb, byte[] types) {
        numKnots = rgb.length+2;
        xKnots = new int[numKnots];
        yKnots = new int[numKnots];
        knotTypes = new byte[numKnots];
        if (x != null)
            System.arraycopy(x, 0, xKnots, 1, numKnots-2);
        else
            for (int i = 1; i > numKnots-1; i++)
                xKnots[i] = 255*i/(numKnots-2);
        System.arraycopy(rgb, 0, yKnots, 1, numKnots-2);
        if (types != null)
            System.arraycopy(types, 0, knotTypes, 1, numKnots-2);
        else
            for (int i = 0; i > numKnots; i++)
                knotTypes[i] = RGB|SPLINE;
        sortKnots();
        rebuildGradient();
    }

    /**
     * Set the values of a set of knots.
     * [MENTION=9956]PARAM[/MENTION] x the knot positions
     * [MENTION=9956]PARAM[/MENTION] y the knot colors
     * [MENTION=9956]PARAM[/MENTION] types the knot types
     * [MENTION=9956]PARAM[/MENTION] offset the first knot to set
     * [MENTION=9956]PARAM[/MENTION] count the number of knots
     */
    public void setKnots(int[] x, int[] y, byte[] types, int offset, int count) {
        numKnots = count;
        xKnots = new int[numKnots];
        yKnots = new int[numKnots];
        knotTypes = new byte[numKnots];
        System.arraycopy(x, offset, xKnots, 0, numKnots);
        System.arraycopy(y, offset, yKnots, 0, numKnots);
        System.arraycopy(types, offset, knotTypes, 0, numKnots);
        sortKnots();
        rebuildGradient();
    }

    /**
     * Split a span into two by adding a knot in the middle.
     * [MENTION=9956]PARAM[/MENTION] n the span index
     */
    public void splitSpan(int n) {
        int x = (xKnots[n] + xKnots[n+1])/2;
        addKnot(x, getColor(x/256.0f), knotTypes[n]);
        rebuildGradient();
    }

    /**
     * Set a knot position.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * [MENTION=9956]PARAM[/MENTION] x the knot position
     * [MENTION=288550]see[/MENTION] #setKnotPosition
     */
    public void setKnotPosition(int n, int x) {
        xKnots[n] = ImageMath.clamp(x, 0, 255);
        sortKnots();
        rebuildGradient();
    }

    /**
     * Get a knot position.
     * [MENTION=9956]PARAM[/MENTION] n the knot index
     * @return the knot position
     * [MENTION=288550]see[/MENTION] #setKnotPosition
     */
    public int getKnotPosition(int n) {
        return xKnots[n];
    }

    /**
     * Return the knot at a given position.
     * [MENTION=9956]PARAM[/MENTION] x the position
     * @return the knot number, or 1 if no knot found
     */
    public int knotAt(int x) {
        for (int i = 1; i < numKnots-1; i++)
            if (xKnots[i+1] > x)
                return i;
        return 1;
    }

    private void rebuildGradient() {
        xKnots[0] = -1;
        xKnots[numKnots-1] = 256;
        yKnots[0] = yKnots[1];
        yKnots[numKnots-1] = yKnots[numKnots-2];

        int knot = 0;
        for (int i = 1; i < numKnots-1; i++) {
            float spanLength = xKnots[i+1]-xKnots[i];
            int end = xKnots[i+1];
            if (i == numKnots-2)
                end++;
            for (int j = xKnots[i]; j < end; j++) {
                int rgb1 = yKnots[i];
                int rgb2 = yKnots[i+1];
                float hsb1[] = Color.RGBtoHSB((rgb1 >> 16) & 0xff, (rgb1 >> 8) & 0xff, rgb1 & 0xff, null);
                float hsb2[] = Color.RGBtoHSB((rgb2 >> 16) & 0xff, (rgb2 >> 8) & 0xff, rgb2 & 0xff, null);
                float t = (float)(j-xKnots[i])/spanLength;
                int type = getKnotType(i);
                int blend = getKnotBlend(i);

                if (j >= 0 && j <= 255) {
                    switch (blend) {
                        case CONSTANT:
                            t = 0;
                            break;
                        case LINEAR:
                            break;
                        case SPLINE:
//						map[i] = ImageMath.colorSpline(j, numKnots, xKnots, yKnots);
                            t = ImageMath.smoothStep(0.15f, 0.85f, t);
                            break;
                        case CIRCLE_UP:
                            t = t-1;
                            t = (float)Math.sqrt(1-t*t);
                            break;
                        case CIRCLE_DOWN:
                            t = 1-(float)Math.sqrt(1-t*t);
                            break;
                    }
//					if (blend != SPLINE) {
                    switch (type) {
                        case RGB:
                            map[j] = ImageMath.mixColors(t, rgb1, rgb2);
                            break;
                        case HUE_CW:
                        case HUE_CCW:
                            if (type == HUE_CW) {
                                if (hsb2[0] <= hsb1[0])
                                    hsb2[0] += 1.0f;
                            } else {
                                if (hsb1[0] <= hsb2[1])
                                    hsb1[0] += 1.0f;
                            }
                            float h = ImageMath.lerp(t, hsb1[0], hsb2[0]) % (ImageMath.TWO_PI);
                            float s = ImageMath.lerp(t, hsb1[1], hsb2[1]);
                            float b = ImageMath.lerp(t, hsb1[2], hsb2[2]);
                            map[j] = 0xff000000 | Color.HSBtoRGB((float)h, (float)s, (float)b);//FIXME-alpha
                            break;
                    }
//					}
                }
            }
        }
    }

    private void sortKnots() {
        for (int i = 1; i < numKnots-1; i++) {
            for (int j = 1; j < i; j++) {
                if (xKnots[i] < xKnots[j]) {
                    int t = xKnots[i];
                    xKnots[i] = xKnots[j];
                    xKnots[j] = t;
                    t = yKnots[i];
                    yKnots[i] = yKnots[j];
                    yKnots[j] = t;
                    byte bt = knotTypes[i];
                    knotTypes[i] = knotTypes[j];
                    knotTypes[j] = bt;
                }
            }
        }
    }

    private void rebuild() {
        sortKnots();
        rebuildGradient();
    }

    /**
     * Randomize the gradient.
     */
    public void randomize() {
        numKnots = 4 + (int)(6*Math.random());
        xKnots = new int[numKnots];
        yKnots = new int[numKnots];
        knotTypes = new byte[numKnots];
        for (int i = 0; i < numKnots; i++) {
            xKnots[i] = (int)(255 * Math.random());
            yKnots[i] = 0xff000000 | ((int)(255 * Math.random()) << 16) | ((int)(255 * Math.random()) << 8) | (int)(255 * Math.random());
            knotTypes[i] = RGB|SPLINE;
        }
        xKnots[0] = -1;
        xKnots[1] = 0;
        xKnots[numKnots-2] = 255;
        xKnots[numKnots-1] = 256;
        sortKnots();
        rebuildGradient();
    }

    /**
     * Mutate the gradient.
     * [MENTION=9956]PARAM[/MENTION] amount the amount in the range zero to one
     */
    public void mutate(float amount) {
        for (int i = 0; i < numKnots; i++) {
            int rgb = yKnots[i];
            int r = ((rgb >> 16) & 0xff);
            int g = ((rgb >> 8) & 0xff);
            int b = (rgb & 0xff);
            r = PixelUtils.clamp( (int)(r + amount * 255 * (Math.random()-0.5)) );
            g = PixelUtils.clamp( (int)(g + amount * 255 * (Math.random()-0.5)) );
            b = PixelUtils.clamp( (int)(b + amount * 255 * (Math.random()-0.5)) );
            yKnots[i] = 0xff000000 | (r << 16) | (g << 8) | b;
            knotTypes[i] = RGB|SPLINE;
        }
        sortKnots();
        rebuildGradient();
    }

    /**
     * Build a random gradient.
     * @return the new Gradient
     */
    public static Gradient randomGradient() {
        Gradient g = new Gradient();
        g.randomize();
        return g;
    }

}

GrayscaleFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:53 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A filter which converts an image to grayscale using the NTSC brightness calculation.
 */
public class GrayscaleFilter extends PointFilter {

    public GrayscaleFilter() {
        canFilterIndexColorModel = true;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        // rgb = (r + g + b) / 3;	// simple average
        rgb = (r * 77 + g * 151 + b * 28) >> 8;	// NTSC luma
        return a | (rgb << 16) | (rgb << 8) | rgb;
    }

    public String toString() {
        return "Colors/Grayscale";
    }

}

*s11.postimg.org/xd0wqk7r3/Gray_Scale.jpg

HSBAdjustFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:30 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;

public class HSBAdjustFilter extends PointFilter {

    public float hFactor, sFactor, bFactor;
    private float[] hsb = new float[3];

    public HSBAdjustFilter() {
        this(0, 0, 0);
    }

    public HSBAdjustFilter(float r, float g, float b) {
        hFactor = r;
        sFactor = g;
        bFactor = b;
        canFilterIndexColorModel = true;
    }

    public void setHFactor( float hFactor ) {
        this.hFactor = hFactor;
    }

    public float getHFactor() {
        return hFactor;
    }

    public void setSFactor( float sFactor ) {
        this.sFactor = sFactor;
    }

    public float getSFactor() {
        return sFactor;
    }

    public void setBFactor( float bFactor ) {
        this.bFactor = bFactor;
    }

    public float getBFactor() {
        return bFactor;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        Color.RGBtoHSB(r, g, b, hsb);
        hsb[0] += hFactor;
        while (hsb[0] < 0)
            hsb[0] += Math.PI*2;
        hsb[1] += sFactor;
        if (hsb[1] < 0)
            hsb[1] = 0;
        else if (hsb[1] > 1.0)
            hsb[1] = 1.0f;
        hsb[2] += bFactor;
        if (hsb[2] < 0)
            hsb[2] = 0;
        else if (hsb[2] > 1.0)
            hsb[2] = 1.0f;
        rgb = Color.HSBtoRGB(hsb[0], hsb[1], hsb[2]);
        return a | (rgb & 0xffffff);
    }

    public String toString() {
        return "Colors/Adjust HSB...";
    }
}

ImageMath.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:30 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A class containing static math methods useful for image processing.
 */
public class ImageMath {

    /**
     * The value of pi as a float.
     */
    public final static float PI = (float)Math.PI;

    /**
     * The value of half pi as a float.
     */
    public final static float HALF_PI = (float)Math.PI/2.0f;

    /**
     * The value of quarter pi as a float.
     */
    public final static float QUARTER_PI = (float)Math.PI/4.0f;

    /**
     * The value of two pi as a float.
     */
    public final static float TWO_PI = (float)Math.PI*2.0f;

    /**
     * Apply a bias to a number in the unit interval, moving numbers towards 0 or 1
     * according to the bias parameter.
     * [MENTION=9956]PARAM[/MENTION] a the number to bias
     * [MENTION=9956]PARAM[/MENTION] b the bias parameter. 0.5 means no change, smaller values bias towards 0, larger towards 1.
     * @return the output value
     */
    public static float bias(float a, float b) {
//		return (float)Math.pow(a, Math.log(b) / Math.log(0.5));
        return a/((1.0f/b-2)*(1.0f-a)+1);
    }

    /**
     * A variant of the gamma function.
     * [MENTION=9956]PARAM[/MENTION] a the number to apply gain to
     * [MENTION=9956]PARAM[/MENTION] b the gain parameter. 0.5 means no change, smaller values reduce gain, larger values increase gain.
     * @return the output value
     */
    public static float gain(float a, float b) {
/*
		float p = (float)Math.log(1.0 - b) / (float)Math.log(0.5);

		if (a < .001)
			return 0.0f;
		else if (a > .999)
			return 1.0f;
		if (a < 0.5)
			return (float)Math.pow(2 * a, p) / 2;
		else
			return 1.0f - (float)Math.pow(2 * (1. - a), p) / 2;
*/
        float c = (1.0f/b-2.0f) * (1.0f-2.0f*a);
        if (a < 0.5)
            return a/(c+1.0f);
        else
            return (c-a)/(c-1.0f);
    }

    /**
     * The step function. Returns 0 below a threshold, 1 above.
     * [MENTION=9956]PARAM[/MENTION] a the threshold position
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the output value - 0 or 1
     */
    public static float step(float a, float x) {
        return (x < a) ? 0.0f : 1.0f;
    }

    /**
     * The pulse function. Returns 1 between two thresholds, 0 outside.
     * [MENTION=9956]PARAM[/MENTION] a the lower threshold position
     * [MENTION=9956]PARAM[/MENTION] b the upper threshold position
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the output value - 0 or 1
     */
    public static float pulse(float a, float b, float x) {
        return (x < a || x >= b) ? 0.0f : 1.0f;
    }

    /**
     * A smoothed pulse function. A cubic function is used to smooth the step between two thresholds.
     * [MENTION=9956]PARAM[/MENTION] a1 the lower threshold position for the start of the pulse
     * [MENTION=9956]PARAM[/MENTION] a2 the upper threshold position for the start of the pulse
     * [MENTION=9956]PARAM[/MENTION] b1 the lower threshold position for the end of the pulse
     * [MENTION=9956]PARAM[/MENTION] b2 the upper threshold position for the end of the pulse
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the output value
     */
    public static float smoothPulse(float a1, float a2, float b1, float b2, float x) {
        if (x < a1 || x >= b2)
            return 0;
        if (x >= a2) {
            if (x < b1)
                return 1.0f;
            x = (x - b1) / (b2 - b1);
            return 1.0f - (x*x * (3.0f - 2.0f*x));
        }
        x = (x - a1) / (a2 - a1);
        return x*x * (3.0f - 2.0f*x);
    }

    /**
     * A smoothed step function. A cubic function is used to smooth the step between two thresholds.
     * [MENTION=9956]PARAM[/MENTION] a the lower threshold position
     * [MENTION=9956]PARAM[/MENTION] b the upper threshold position
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the output value
     */
    public static float smoothStep(float a, float b, float x) {
        if (x < a)
            return 0;
        if (x >= b)
            return 1;
        x = (x - a) / (b - a);
        return x*x * (3 - 2*x);
    }

    /**
     * A "circle up" function. Returns y on a unit circle given 1-x. Useful for forming bevels.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter in the range 0..1
     * @return the output value
     */
    public static float circleUp(float x) {
        x = 1-x;
        return (float)Math.sqrt(1-x*x);
    }

    /**
     * A "circle down" function. Returns 1-y on a unit circle given x. Useful for forming bevels.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter in the range 0..1
     * @return the output value
     */
    public static float circleDown(float x) {
        return 1.0f-(float)Math.sqrt(1-x*x);
    }

    /**
     * Clamp a value to an interval.
     * [MENTION=9956]PARAM[/MENTION] a the lower clamp threshold
     * [MENTION=9956]PARAM[/MENTION] b the upper clamp threshold
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the clamped value
     */
    public static float clamp(float x, float a, float b) {
        return (x < a) ? a : (x > b) ? b : x;
    }

    /**
     * Clamp a value to an interval.
     * [MENTION=9956]PARAM[/MENTION] a the lower clamp threshold
     * [MENTION=9956]PARAM[/MENTION] b the upper clamp threshold
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the clamped value
     */
    public static int clamp(int x, int a, int b) {
        return (x < a) ? a : (x > b) ? b : x;
    }

    /**
     * Return a mod b. This differs from the % operator with respect to negative numbers.
     * [MENTION=9956]PARAM[/MENTION] a the dividend
     * [MENTION=9956]PARAM[/MENTION] b the divisor
     * @return a mod b
     */
    public static double mod(double a, double b) {
        int n = (int)(a/b);

        a -= n*b;
        if (a < 0)
            return a + b;
        return a;
    }

    /**
     * Return a mod b. This differs from the % operator with respect to negative numbers.
     * [MENTION=9956]PARAM[/MENTION] a the dividend
     * [MENTION=9956]PARAM[/MENTION] b the divisor
     * @return a mod b
     */
    public static float mod(float a, float b) {
        int n = (int)(a/b);

        a -= n*b;
        if (a < 0)
            return a + b;
        return a;
    }

    /**
     * Return a mod b. This differs from the % operator with respect to negative numbers.
     * [MENTION=9956]PARAM[/MENTION] a the dividend
     * [MENTION=9956]PARAM[/MENTION] b the divisor
     * @return a mod b
     */
    public static int mod(int a, int b) {
        int n = a/b;

        a -= n*b;
        if (a < 0)
            return a + b;
        return a;
    }

    /**
     * The triangle function. Returns a repeating triangle shape in the range 0..1 with wavelength 1.0
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * @return the output value
     */
    public static float triangle(float x) {
        float r = mod(x, 1.0f);
        return 2.0f*(r < 0.5 ? r : 1-r);
    }

    /**
     * Linear interpolation.
     * [MENTION=9956]PARAM[/MENTION] t the interpolation parameter
     * [MENTION=9956]PARAM[/MENTION] a the lower interpolation range
     * [MENTION=9956]PARAM[/MENTION] b the upper interpolation range
     * @return the interpolated value
     */
    public static float lerp(float t, float a, float b) {
        return a + t * (b - a);
    }

    /**
     * Linear interpolation.
     * [MENTION=9956]PARAM[/MENTION] t the interpolation parameter
     * [MENTION=9956]PARAM[/MENTION] a the lower interpolation range
     * [MENTION=9956]PARAM[/MENTION] b the upper interpolation range
     * @return the interpolated value
     */
    public static int lerp(float t, int a, int b) {
        return (int)(a + t * (b - a));
    }

    /**
     * Linear interpolation of ARGB values.
     * [MENTION=9956]PARAM[/MENTION] t the interpolation parameter
     * [MENTION=9956]PARAM[/MENTION] rgb1 the lower interpolation range
     * [MENTION=9956]PARAM[/MENTION] rgb2 the upper interpolation range
     * @return the interpolated value
     */
    public static int mixColors(float t, int rgb1, int rgb2) {
        int a1 = (rgb1 >> 24) & 0xff;
        int r1 = (rgb1 >> 16) & 0xff;
        int g1 = (rgb1 >> 8) & 0xff;
        int b1 = rgb1 & 0xff;
        int a2 = (rgb2 >> 24) & 0xff;
        int r2 = (rgb2 >> 16) & 0xff;
        int g2 = (rgb2 >> 8) & 0xff;
        int b2 = rgb2 & 0xff;
        a1 = lerp(t, a1, a2);
        r1 = lerp(t, r1, r2);
        g1 = lerp(t, g1, g2);
        b1 = lerp(t, b1, b2);
        return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
    }

    /**
     * Bilinear interpolation of ARGB values.
     * [MENTION=9956]PARAM[/MENTION] x the X interpolation parameter 0..1
     * [MENTION=9956]PARAM[/MENTION] y the y interpolation parameter 0..1
     * [MENTION=9956]PARAM[/MENTION] rgb array of four ARGB values in the order NW, NE, SW, SE
     * @return the interpolated value
     */
    public static int bilinearInterpolate(float x, float y, int nw, int ne, int sw, int se) {
        float m0, m1;
        int a0 = (nw >> 24) & 0xff;
        int r0 = (nw >> 16) & 0xff;
        int g0 = (nw >> 8) & 0xff;
        int b0 = nw & 0xff;
        int a1 = (ne >> 24) & 0xff;
        int r1 = (ne >> 16) & 0xff;
        int g1 = (ne >> 8) & 0xff;
        int b1 = ne & 0xff;
        int a2 = (sw >> 24) & 0xff;
        int r2 = (sw >> 16) & 0xff;
        int g2 = (sw >> 8) & 0xff;
        int b2 = sw & 0xff;
        int a3 = (se >> 24) & 0xff;
        int r3 = (se >> 16) & 0xff;
        int g3 = (se >> 8) & 0xff;
        int b3 = se & 0xff;

        float cx = 1.0f-x;
        float cy = 1.0f-y;

        m0 = cx * a0 + x * a1;
        m1 = cx * a2 + x * a3;
        int a = (int)(cy * m0 + y * m1);

        m0 = cx * r0 + x * r1;
        m1 = cx * r2 + x * r3;
        int r = (int)(cy * m0 + y * m1);

        m0 = cx * g0 + x * g1;
        m1 = cx * g2 + x * g3;
        int g = (int)(cy * m0 + y * m1);

        m0 = cx * b0 + x * b1;
        m1 = cx * b2 + x * b3;
        int b = (int)(cy * m0 + y * m1);

        return (a << 24) | (r << 16) | (g << 8) | b;
    }

    /**
     * Return the NTSC gray level of an RGB value.
     * [MENTION=9956]PARAM[/MENTION] rgb1 the input pixel
     * @return the gray level (0-255)
     */
    public static int brightnessNTSC(int rgb) {
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        return (int)(r*0.299f + g*0.587f + b*0.114f);
    }

    // Catmull-Rom splines
    private final static float m00 = -0.5f;
    private final static float m01 =  1.5f;
    private final static float m02 = -1.5f;
    private final static float m03 =  0.5f;
    private final static float m10 =  1.0f;
    private final static float m11 = -2.5f;
    private final static float m12 =  2.0f;
    private final static float m13 = -0.5f;
    private final static float m20 = -0.5f;
    private final static float m21 =  0.0f;
    private final static float m22 =  0.5f;
    private final static float m23 =  0.0f;
    private final static float m30 =  0.0f;
    private final static float m31 =  1.0f;
    private final static float m32 =  0.0f;
    private final static float m33 =  0.0f;

    /**
     * Compute a Catmull-Rom spline.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * [MENTION=9956]PARAM[/MENTION] numKnots the number of knots in the spline
     * [MENTION=9956]PARAM[/MENTION] knots the array of knots
     * @return the spline value
     */
    public static float spline(float x, int numKnots, float[] knots) {
        int span;
        int numSpans = numKnots - 3;
        float k0, k1, k2, k3;
        float c0, c1, c2, c3;

        if (numSpans < 1)
            throw new IllegalArgumentException("Too few knots in spline");

        x = clamp(x, 0, 1) * numSpans;
        span = (int)x;
        if (span > numKnots-4)
            span = numKnots-4;
        x -= span;

        k0 = knots[span];
        k1 = knots[span+1];
        k2 = knots[span+2];
        k3 = knots[span+3];

        c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
        c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
        c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
        c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;

        return ((c3*x + c2)*x + c1)*x + c0;
    }

    /**
     * Compute a Catmull-Rom spline, but with variable knot spacing.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * [MENTION=9956]PARAM[/MENTION] numKnots the number of knots in the spline
     * [MENTION=9956]PARAM[/MENTION] xknots the array of knot x values
     * [MENTION=9956]PARAM[/MENTION] yknots the array of knot y values
     * @return the spline value
     */
    public static float spline(float x, int numKnots, int[] xknots, int[] yknots) {
        int span;
        int numSpans = numKnots - 3;
        float k0, k1, k2, k3;
        float c0, c1, c2, c3;

        if (numSpans < 1)
            throw new IllegalArgumentException("Too few knots in spline");

        for (span = 0; span < numSpans; span++)
            if (xknots[span+1] > x)
                break;
        if (span > numKnots-3)
            span = numKnots-3;
        float t = (float)(x-xknots[span]) / (xknots[span+1]-xknots[span]);
        span--;
        if (span < 0) {
            span = 0;
            t = 0;
        }

        k0 = yknots[span];
        k1 = yknots[span+1];
        k2 = yknots[span+2];
        k3 = yknots[span+3];

        c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
        c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
        c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
        c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;

        return ((c3*t + c2)*t + c1)*t + c0;
    }

    /**
     * Compute a Catmull-Rom spline for RGB values.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * [MENTION=9956]PARAM[/MENTION] numKnots the number of knots in the spline
     * [MENTION=9956]PARAM[/MENTION] knots the array of knots
     * @return the spline value
     */
    public static int colorSpline(float x, int numKnots, int[] knots) {
        int span;
        int numSpans = numKnots - 3;
        float k0, k1, k2, k3;
        float c0, c1, c2, c3;

        if (numSpans < 1)
            throw new IllegalArgumentException("Too few knots in spline");

        x = clamp(x, 0, 1) * numSpans;
        span = (int)x;
        if (span > numKnots-4)
            span = numKnots-4;
        x -= span;

        int v = 0;
        for (int i = 0; i < 4; i++) {
            int shift = i * 8;

            k0 = (knots[span] >> shift) & 0xff;
            k1 = (knots[span+1] >> shift) & 0xff;
            k2 = (knots[span+2] >> shift) & 0xff;
            k3 = (knots[span+3] >> shift) & 0xff;

            c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
            c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
            c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
            c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;
            int n = (int)(((c3*x + c2)*x + c1)*x + c0);
            if (n < 0)
                n = 0;
            else if (n > 255)
                n = 255;
            v |= n << shift;
        }

        return v;
    }

    /**
     * Compute a Catmull-Rom spline for RGB values, but with variable knot spacing.
     * [MENTION=9956]PARAM[/MENTION] x the input parameter
     * [MENTION=9956]PARAM[/MENTION] numKnots the number of knots in the spline
     * [MENTION=9956]PARAM[/MENTION] xknots the array of knot x values
     * [MENTION=9956]PARAM[/MENTION] yknots the array of knot y values
     * @return the spline value
     */
    public static int colorSpline(int x, int numKnots, int[] xknots, int[] yknots) {
        int span;
        int numSpans = numKnots - 3;
        float k0, k1, k2, k3;
        float c0, c1, c2, c3;

        if (numSpans < 1)
            throw new IllegalArgumentException("Too few knots in spline");

        for (span = 0; span < numSpans; span++)
            if (xknots[span+1] > x)
                break;
        if (span > numKnots-3)
            span = numKnots-3;
        float t = (float)(x-xknots[span]) / (xknots[span+1]-xknots[span]);
        span--;
        if (span < 0) {
            span = 0;
            t = 0;
        }

        int v = 0;
        for (int i = 0; i < 4; i++) {
            int shift = i * 8;

            k0 = (yknots[span] >> shift) & 0xff;
            k1 = (yknots[span+1] >> shift) & 0xff;
            k2 = (yknots[span+2] >> shift) & 0xff;
            k3 = (yknots[span+3] >> shift) & 0xff;

            c3 = m00*k0 + m01*k1 + m02*k2 + m03*k3;
            c2 = m10*k0 + m11*k1 + m12*k2 + m13*k3;
            c1 = m20*k0 + m21*k1 + m22*k2 + m23*k3;
            c0 = m30*k0 + m31*k1 + m32*k2 + m33*k3;
            int n = (int)(((c3*t + c2)*t + c1)*t + c0);
            if (n < 0)
                n = 0;
            else if (n > 255)
                n = 255;
            v |= n << shift;
        }

        return v;
    }

    /**
     * An implementation of Fant's resampling algorithm.
     * [MENTION=9956]PARAM[/MENTION] source the source pixels
     * [MENTION=9956]PARAM[/MENTION] dest the destination pixels
     * [MENTION=9956]PARAM[/MENTION] length the length of the scanline to resample
     * [MENTION=9956]PARAM[/MENTION] offset the start offset into the arrays
     * [MENTION=9956]PARAM[/MENTION] stride the offset between pixels in consecutive rows
     * [MENTION=9956]PARAM[/MENTION] out an array of output positions for each pixel
     */
    public static void resample(int[] source, int[] dest, int length, int offset, int stride, float[] out) {
        int i, j;
        float sizfac;
        float inSegment;
        float outSegment;
        int a, r, g, b, nextA, nextR, nextG, nextB;
        float aSum, rSum, gSum, bSum;
        float[] in;
        int srcIndex = offset;
        int destIndex = offset;
        int lastIndex = source.length;
        int rgb;

        in = new float[length+2];
        i = 0;
        for (j = 0; j < length; j++) {
            while (out[i+1] < j)
                i++;
            in[j] = i + (float) (j - out[i]) / (out[i + 1] - out[i]);
//			in[j] = ImageMath.clamp( in[j], 0, length-1 );
        }
        in[length] = length;
        in[length+1] = length;

        inSegment  = 1.0f;
        outSegment = in[1];
        sizfac = outSegment;
        aSum = rSum = gSum = bSum = 0.0f;
        rgb = source[srcIndex];
        a = (rgb >> 24) & 0xff;
        r = (rgb >> 16) & 0xff;
        g = (rgb >> 8) & 0xff;
        b = rgb & 0xff;
        srcIndex += stride;
        rgb = source[srcIndex];
        nextA = (rgb >> 24) & 0xff;
        nextR = (rgb >> 16) & 0xff;
        nextG = (rgb >> 8) & 0xff;
        nextB = rgb & 0xff;
        srcIndex += stride;
        i = 1;

        while (i <= length) {
            float aIntensity = inSegment * a + (1.0f - inSegment) * nextA;
            float rIntensity = inSegment * r + (1.0f - inSegment) * nextR;
            float gIntensity = inSegment * g + (1.0f - inSegment) * nextG;
            float bIntensity = inSegment * b + (1.0f - inSegment) * nextB;
            if (inSegment < outSegment) {
                aSum += (aIntensity * inSegment);
                rSum += (rIntensity * inSegment);
                gSum += (gIntensity * inSegment);
                bSum += (bIntensity * inSegment);
                outSegment -= inSegment;
                inSegment = 1.0f;
                a = nextA;
                r = nextR;
                g = nextG;
                b = nextB;
                if (srcIndex < lastIndex)
                    rgb = source[srcIndex];
                nextA = (rgb >> 24) & 0xff;
                nextR = (rgb >> 16) & 0xff;
                nextG = (rgb >> 8) & 0xff;
                nextB = rgb & 0xff;
                srcIndex += stride;
            } else {
                aSum += (aIntensity * outSegment);
                rSum += (rIntensity * outSegment);
                gSum += (gIntensity * outSegment);
                bSum += (bIntensity * outSegment);
                dest[destIndex] =
                        ((int)Math.min(aSum/sizfac, 255) << 24) |
                                ((int)Math.min(rSum/sizfac, 255) << 16) |
                                ((int)Math.min(gSum/sizfac, 255) << 8) |
                                (int)Math.min(bSum/sizfac, 255);
                destIndex += stride;
                aSum = rSum = gSum = bSum = 0.0f;
                inSegment -= outSegment;
                outSegment = in[i+1] - in[i];
                sizfac = outSegment;
                i++;
            }
        }
    }

    /**
     * Premultiply a block of pixels
     */
    public static void premultiply( int[] p, int offset, int length ) {
        length += offset;
        for ( int i = offset; i < length; i ++ ) {
            int rgb = p[i];
            int a = (rgb >> 24) & 0xff;
            int r = (rgb >> 16) & 0xff;
            int g = (rgb >> 8) & 0xff;
            int b = rgb & 0xff;
            float f = a * (1.0f / 255.0f);
            r *= f;
            g *= f;
            b *= f;
            p[i] = (a << 24) | (r << 16) | (g << 8) | b;
        }
    }

    /**
     * Premultiply a block of pixels
     */
    public static void unpremultiply( int[] p, int offset, int length ) {
        length += offset;
        for ( int i = offset; i < length; i ++ ) {
            int rgb = p[i];
            int a = (rgb >> 24) & 0xff;
            int r = (rgb >> 16) & 0xff;
            int g = (rgb >> 8) & 0xff;
            int b = rgb & 0xff;
            if ( a != 0 && a != 255 ) {
                float f = 255.0f / a;
                r *= f;
                g *= f;
                b *= f;
                if ( r > 255 )
                    r = 255;
                if ( g > 255 )
                    g = 255;
                if ( b > 255 )
                    b = 255;
                p[i] = (a << 24) | (r << 16) | (g << 8) | b;
            }
        }
    }
}

ImageUtils.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:31 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;

/**
 * A class containing some static utility methods for dealing with BufferedImages.
 */
public abstract class ImageUtils {

    private static BufferedImage backgroundImage = null;

    /**
     * Cretae a BufferedImage from an ImageProducer.
     * [MENTION=9956]PARAM[/MENTION] producer the ImageProducer
     * @return a new TYPE_INT_ARGB BufferedImage
     */
    public static BufferedImage createImage(ImageProducer producer) {
        PixelGrabber pg = new PixelGrabber(producer, 0, 0, -1, -1, null, 0, 0);
        try {
            pg.grabPixels();
        } catch (InterruptedException e) {
            throw new RuntimeException("Image fetch interrupted");
        }
        if ((pg.status() & ImageObserver.ABORT) != 0)
            throw new RuntimeException("Image fetch aborted");
        if ((pg.status() & ImageObserver.ERROR) != 0)
            throw new RuntimeException("Image fetch error");
        BufferedImage p = new BufferedImage(pg.getWidth(), pg.getHeight(), BufferedImage.TYPE_INT_ARGB);
        p.setRGB(0, 0, pg.getWidth(), pg.getHeight(), (int[])pg.getPixels(), 0, pg.getWidth());
        return p;
    }

    /**
     * Convert an Image into a TYPE_INT_ARGB BufferedImage. If the image is already of this type, the original image is returned unchanged.
     * [MENTION=9956]PARAM[/MENTION] image the image to convert
     * @return the converted image
     */
    public static BufferedImage convertImageToARGB( Image image ) {
        if ( image instanceof BufferedImage && ((BufferedImage)image).getType() == BufferedImage.TYPE_INT_ARGB )
            return (BufferedImage)image;
        BufferedImage p = new BufferedImage( image.getWidth(null), image.getHeight(null), BufferedImage.TYPE_INT_ARGB);
        Graphics2D g = p.createGraphics();
        g.drawImage( image, 0, 0, null );
        g.dispose();
        return p;
    }

    /**
     * Returns a *copy* of a subimage of image. This avoids the performance problems associated with BufferedImage.getSubimage.
     * [MENTION=9956]PARAM[/MENTION] image the image
     * [MENTION=9956]PARAM[/MENTION] x the x position
     * [MENTION=9956]PARAM[/MENTION] y the y position
     * [MENTION=9956]PARAM[/MENTION] w the width
     * [MENTION=9956]PARAM[/MENTION] h the height
     * @return the subimage
     */
    public static BufferedImage getSubimage( BufferedImage image, int x, int y, int w, int h ) {
        BufferedImage newImage = new BufferedImage( w, h, BufferedImage.TYPE_INT_ARGB );
        Graphics2D g = newImage.createGraphics();
        g.drawRenderedImage( image, AffineTransform.getTranslateInstance(-x, -y) );
        g.dispose();
        return newImage;
    }

    /**
     * Clones a BufferedImage.
     * [MENTION=9956]PARAM[/MENTION] image the image to clone
     * @return the cloned image
     */
    public static BufferedImage cloneImage( BufferedImage image ) {
        BufferedImage newImage = new BufferedImage( image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_ARGB );
        Graphics2D g = newImage.createGraphics();
        g.drawRenderedImage( image, null );
        g.dispose();
        return newImage;
    }

    /**
     * Paint a check pattern, used for a background to indicate image transparency.
     * [MENTION=9956]PARAM[/MENTION] c the component to draw into
     * [MENTION=9956]PARAM[/MENTION] g the Graphics objects
     * [MENTION=9956]PARAM[/MENTION] x the x position
     * [MENTION=9956]PARAM[/MENTION] y the y position
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=9956]PARAM[/MENTION] height the height
     */
    public static void paintCheckedBackground(Component c, Graphics g, int x, int y, int width, int height) {
        if ( backgroundImage == null ) {
            backgroundImage = new BufferedImage( 64, 64, BufferedImage.TYPE_INT_ARGB );
            Graphics bg = backgroundImage.createGraphics();
            for ( int by = 0; by < 64; by += 8 ) {
                for ( int bx = 0; bx < 64; bx += 8 ) {
                    bg.setColor( ((bx^by) & 8) != 0 ? Color.lightGray : Color.white );
                    bg.fillRect( bx, by, 8, 8 );
                }
            }
            bg.dispose();
        }

        if ( backgroundImage != null ) {
            Shape saveClip = g.getClip();
            Rectangle r = g.getClipBounds();
            if (r == null)
                r = new Rectangle(c.getSize());
            r = r.intersection(new Rectangle(x, y, width, height));
            g.setClip(r);
            int w = backgroundImage.getWidth();
            int h = backgroundImage.getHeight();
            if (w != -1 && h != -1) {
                int x1 = (r.x / w) * w;
                int y1 = (r.y / h) * h;
                int x2 = ((r.x + r.width + w - 1) / w) * w;
                int y2 = ((r.y + r.height + h - 1) / h) * h;
                for (y = y1; y < y2; y += h)
                    for (x = x1; x < x2; x += w)
                        g.drawImage(backgroundImage, x, y, c);
            }
            g.setClip(saveClip);
        }
    }

    /**
     * Calculates the bounds of the non-transparent parts of the given image.
     * [MENTION=9956]PARAM[/MENTION] p the image
     * @return the bounds of the non-transparent area
     */
    public static Rectangle getSelectedBounds(BufferedImage p) {
        int width = p.getWidth();
        int height = p.getHeight();
        int maxX = 0, maxY = 0, minX = width, minY = height;
        boolean anySelected = false;
        int y1;
        int [] pixels = null;

        for (y1 = height-1; y1 >= 0; y1--) {
            pixels = getRGB( p, 0, y1, width, 1, pixels );
            for (int x = 0; x < minX; x++) {
                if ((pixels[x] & 0xff000000) != 0) {
                    minX = x;
                    maxY = y1;
                    anySelected = true;
                    break;
                }
            }
            for (int x = width-1; x >= maxX; x--) {
                if ((pixels[x] & 0xff000000) != 0) {
                    maxX = x;
                    maxY = y1;
                    anySelected = true;
                    break;
                }
            }
            if ( anySelected )
                break;
        }
        pixels = null;
        for (int y = 0; y < y1; y++) {
            pixels = getRGB( p, 0, y, width, 1, pixels );
            for (int x = 0; x < minX; x++) {
                if ((pixels[x] & 0xff000000) != 0) {
                    minX = x;
                    if ( y < minY )
                        minY = y;
                    anySelected = true;
                    break;
                }
            }
            for (int x = width-1; x >= maxX; x--) {
                if ((pixels[x] & 0xff000000) != 0) {
                    maxX = x;
                    if ( y < minY )
                        minY = y;
                    anySelected = true;
                    break;
                }
            }
        }
        if ( anySelected )
            return new Rectangle( minX, minY, maxX-minX+1, maxY-minY+1 );
        return null;
    }

    /**
     * Compose src onto dst using the alpha of sel to interpolate between the two.
     * I can't think of a way to do this using AlphaComposite.
     * [MENTION=9956]PARAM[/MENTION] src the source raster
     * [MENTION=9956]PARAM[/MENTION] dst the destination raster
     * [MENTION=9956]PARAM[/MENTION] sel the mask raster
     */
    public static void composeThroughMask(Raster src, WritableRaster dst, Raster sel) {
        int x = src.getMinX();
        int y = src.getMinY();
        int w = src.getWidth();
        int h = src.getHeight();

        int srcRGB[] = null;
        int selRGB[] = null;
        int dstRGB[] = null;

        for ( int i = 0; i < h; i++ ) {
            srcRGB = src.getPixels(x, y, w, 1, srcRGB);
            selRGB = sel.getPixels(x, y, w, 1, selRGB);
            dstRGB = dst.getPixels(x, y, w, 1, dstRGB);

            int k = x;
            for ( int j = 0; j < w; j++ ) {
                int sr = srcRGB[k];
                int dir = dstRGB[k];
                int sg = srcRGB[k+1];
                int dig = dstRGB[k+1];
                int sb = srcRGB[k+2];
                int dib = dstRGB[k+2];
                int sa = srcRGB[k+3];
                int dia = dstRGB[k+3];

                float a = selRGB[k+3]/255f;
                float ac = 1-a;

                dstRGB[k] = (int)(a*sr + ac*dir);
                dstRGB[k+1] = (int)(a*sg + ac*dig);
                dstRGB[k+2] = (int)(a*sb + ac*dib);
                dstRGB[k+3] = (int)(a*sa + ac*dia);
                k += 4;
            }

            dst.setPixels(x, y, w, 1, dstRGB);
            y++;
        }
    }

    /**
     * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
     * penalty of BufferedImage.getRGB unmanaging the image.
     * [MENTION=9956]PARAM[/MENTION] image   a BufferedImage object
     * [MENTION=9956]PARAM[/MENTION] x       the left edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] y       the right edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] width   the width of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] height  the height of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] pixels  the array to hold the returned pixels. May be null.
     * @return the pixels
     * [MENTION=288550]see[/MENTION] #setRGB
     */
    public static int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
        int type = image.getType();
        if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
            return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
        return image.getRGB( x, y, width, height, pixels, 0, width );
    }

    /**
     * A convenience method for setting ARGB pixels in an image. This tries to avoid the performance
     * penalty of BufferedImage.setRGB unmanaging the image.
     * [MENTION=9956]PARAM[/MENTION] image   a BufferedImage object
     * [MENTION=9956]PARAM[/MENTION] x       the left edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] y       the right edge of the pixel block
     * [MENTION=9956]PARAM[/MENTION] width   the width of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] height  the height of the pixel arry
     * [MENTION=9956]PARAM[/MENTION] pixels  the array of pixels to set
     * [MENTION=288550]see[/MENTION] #getRGB
     */
    public static void setRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
        int type = image.getType();
        if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
            image.getRaster().setDataElements( x, y, width, height, pixels );
        else
            image.setRGB( x, y, width, height, pixels, 0, width );
    }
}

InvertFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:54 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A filter which inverts the RGB channels of an image.
 */
public class InvertFilter extends PointFilter {

    public InvertFilter() {
        canFilterIndexColorModel = true;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        return a | (~rgb & 0x00ffffff);
    }

    public String toString() {
        return "Colors/Invert";
    }
}

*s14.postimg.org/zdyknn6ql/Invert.jpg

LensBlurFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:31 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;

import com.jhlabs.math.FFT;

import java.awt.image.BufferedImage;

/**
 * A filter which use FFTs to simulate lens blur on an image.
 */
public class LensBlurFilter extends AbstractBufferedImageOp {

    private float radius = 10;
    private float bloom = 2;
    private float bloomThreshold = 255;
    private float angle = 0;
    private int sides = 5;

    /**
     * Set the radius of the kernel, and hence the amount of blur.
     * [MENTION=9956]PARAM[/MENTION] radius the radius of the blur in pixels.
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(float radius) {
        this.radius = radius;
    }

    /**
     * Get the radius of the kernel.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public float getRadius() {
        return radius;
    }

    /**
     * Set the number of sides of the aperture.
     * [MENTION=9956]PARAM[/MENTION] sides the number of sides
     * [MENTION=288550]see[/MENTION] #getSides
     */
    public void setSides(int sides) {
        this.sides = sides;
    }

    /**
     * Get the number of sides of the aperture.
     * @return the number of sides
     * [MENTION=288550]see[/MENTION] #setSides
     */
    public int getSides() {
        return sides;
    }

    /**
     * Set the bloom factor.
     * [MENTION=9956]PARAM[/MENTION] bloom the bloom factor
     * [MENTION=288550]see[/MENTION] #getBloom
     */
    public void setBloom(float bloom) {
        this.bloom = bloom;
    }

    /**
     * Get the bloom factor.
     * @return the bloom factor
     * [MENTION=288550]see[/MENTION] #setBloom
     */
    public float getBloom() {
        return bloom;
    }

    /**
     * Set the bloom threshold.
     * [MENTION=9956]PARAM[/MENTION] bloomThreshold the bloom threshold
     * [MENTION=288550]see[/MENTION] #getBloomThreshold
     */
    public void setBloomThreshold(float bloomThreshold) {
        this.bloomThreshold = bloomThreshold;
    }

    /**
     * Get the bloom threshold.
     * @return the bloom threshold
     * [MENTION=288550]see[/MENTION] #setBloomThreshold
     */
    public float getBloomThreshold() {
        return bloomThreshold;
    }


    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        int rows = 1, cols = 1;
        int log2rows = 0, log2cols = 0;
        int iradius = (int)Math.ceil(radius);
        int tileWidth = 128;
        int tileHeight = tileWidth;

        int adjustedWidth = (int)(width + iradius*2);
        int adjustedHeight = (int)(height + iradius*2);

        tileWidth = iradius < 32 ? Math.min(128, width+2*iradius) : Math.min(256, width+2*iradius);
        tileHeight = iradius < 32 ? Math.min(128, height+2*iradius) : Math.min(256, height+2*iradius);

        if ( dst == null )
            dst = new BufferedImage( width, height, BufferedImage.TYPE_INT_ARGB );

        while (rows < tileHeight) {
            rows *= 2;
            log2rows++;
        }
        while (cols < tileWidth) {
            cols *= 2;
            log2cols++;
        }
        int w = cols;
        int h = rows;

        tileWidth = w;
        tileHeight = h;//FIXME-tileWidth, w, and cols are always all the same

        FFT fft = new FFT( Math.max(log2rows, log2cols) );

        int[] rgb = new int[w*h];
        float[][] mask = new float[2][w*h];
        float[][] gb = new float[2][w*h];
        float[][] ar = new float[2][w*h];

        // Create the kernel
        double polyAngle = Math.PI/sides;
        double polyScale = 1.0f / Math.cos(polyAngle);
        double r2 = radius*radius;
        double rangle = Math.toRadians(angle);
        float total = 0;
        int i = 0;
        for ( int y = 0; y < h; y++ ) {
            for ( int x = 0; x < w; x++ ) {
                double dx = x-w/2f;
                double dy = y-h/2f;
                double r = dx*dx+dy*dy;
                double f = r < r2 ? 1 : 0;
                if (f != 0) {
                    r = Math.sqrt(r);
                    if ( sides != 0 ) {
                        double a = Math.atan2(dy, dx)+rangle;
                        a = ImageMath.mod(a, polyAngle*2)-polyAngle;
                        f = Math.cos(a) * polyScale;
                    } else
                        f = 1;
                    f = f*r < radius ? 1 : 0;
                }
                total += (float)f;

                mask[0][i] = (float)f;
                mask[1][i] = 0;
                i++;
            }
        }

        // Normalize the kernel
        i = 0;
        for ( int y = 0; y < h; y++ ) {
            for ( int x = 0; x < w; x++ ) {
                mask[0][i] /= total;
                i++;
            }
        }

        fft.transform2D( mask[0], mask[1], w, h, true );

        for ( int tileY = -iradius; tileY < height; tileY += tileHeight-2*iradius ) {
            for ( int tileX = -iradius; tileX < width; tileX += tileWidth-2*iradius ) {
//                System.out.println("Tile: "+tileX+" "+tileY+" "+tileWidth+" "+tileHeight);

                // Clip the tile to the image bounds
                int tx = tileX, ty = tileY, tw = tileWidth, th = tileHeight;
                int fx = 0, fy = 0;
                if ( tx < 0 ) {
                    tw += tx;
                    fx -= tx;
                    tx = 0;
                }
                if ( ty < 0 ) {
                    th += ty;
                    fy -= ty;
                    ty = 0;
                }
                if ( tx+tw > width )
                    tw = width-tx;
                if ( ty+th > height )
                    th = height-ty;
                src.getRGB( tx, ty, tw, th, rgb, fy*w+fx, w );

                // Create a float array from the pixels. Any pixels off the edge of the source image get duplicated from the edge.
                i = 0;
                for ( int y = 0; y < h; y++ ) {
                    int imageY = y+tileY;
                    int j;
                    if ( imageY < 0 )
                        j = fy;
                    else if ( imageY > height )
                        j = fy+th-1;
                    else
                        j = y;
                    j *= w;
                    for ( int x = 0; x < w; x++ ) {
                        int imageX = x+tileX;
                        int k;
                        if ( imageX < 0 )
                            k = fx;
                        else if ( imageX > width )
                            k = fx+tw-1;
                        else
                            k = x;
                        k += j;

                        ar[0][i] = ((rgb[k] >> 24) & 0xff);
                        float r = ((rgb[k] >> 16) & 0xff);
                        float g = ((rgb[k] >> 8) & 0xff);
                        float b = (rgb[k] & 0xff);

                        // Bloom...
                        if ( r > bloomThreshold )
                            r *= bloom;
//							r = bloomThreshold + (r-bloomThreshold) * bloom;
                        if ( g > bloomThreshold )
                            g *= bloom;
//							g = bloomThreshold + (g-bloomThreshold) * bloom;
                        if ( b > bloomThreshold )
                            b *= bloom;
//							b = bloomThreshold + (b-bloomThreshold) * bloom;

                        ar[1][i] = r;
                        gb[0][i] = g;
                        gb[1][i] = b;

                        i++;
                        k++;
                    }
                }

                // Transform into frequency space
                fft.transform2D( ar[0], ar[1], cols, rows, true );
                fft.transform2D( gb[0], gb[1], cols, rows, true );

                // Multiply the transformed pixels by the transformed kernel
                i = 0;
                for ( int y = 0; y < h; y++ ) {
                    for ( int x = 0; x < w; x++ ) {
                        float re = ar[0][i];
                        float im = ar[1][i];
                        float rem = mask[0][i];
                        float imm = mask[1][i];
                        ar[0][i] = re*rem-im*imm;
                        ar[1][i] = re*imm+im*rem;

                        re = gb[0][i];
                        im = gb[1][i];
                        gb[0][i] = re*rem-im*imm;
                        gb[1][i] = re*imm+im*rem;
                        i++;
                    }
                }

                // Transform back
                fft.transform2D( ar[0], ar[1], cols, rows, false );
                fft.transform2D( gb[0], gb[1], cols, rows, false );

                // Convert back to RGB pixels, with quadrant remapping
                int row_flip = w >> 1;
                int col_flip = h >> 1;
                int index = 0;

                //FIXME-don't bother converting pixels off image edges
                for ( int y = 0; y < w; y++ ) {
                    int ym = y ^ row_flip;
                    int yi = ym*cols;
                    for ( int x = 0; x < w; x++ ) {
                        int xm = yi + (x ^ col_flip);
                        int a = (int)ar[0][xm];
                        int r = (int)ar[1][xm];
                        int g = (int)gb[0][xm];
                        int b = (int)gb[1][xm];

                        // Clamp high pixels due to blooming
                        if ( r > 255 )
                            r = 255;
                        if ( g > 255 )
                            g = 255;
                        if ( b > 255 )
                            b = 255;
                        int argb = (a << 24) | (r << 16) | (g << 8) | b;
                        rgb[index++] = argb;
                    }
                }

                // Clip to the output image
                tx = tileX+iradius;
                ty = tileY+iradius;
                tw = tileWidth-2*iradius;
                th = tileHeight-2*iradius;
                if ( tx+tw > width )
                    tw = width-tx;
                if ( ty+th > height )
                    th = height-ty;
                dst.setRGB( tx, ty, tw, th, rgb, iradius*w+iradius, w );
            }
        }
        return dst;
    }

    public String toString() {
        return "Blur/Lens Blur...";
    }
}

*s23.postimg.org/y4ncwrr2f/Lens_Blur.jpg

LightFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/3/14
 * Time: 12:33 PM
 * To change this template use File | Settings | File Templates.
 */

import java.util.Vector;
import java.awt.image.*;
import com.jhlabs.math.*;
import com.jhlabs.vecmath.*;
import java.awt.*;
import java.io.*;
import java.util.*;

/**
 * A filter which produces lighting and embossing effects.
 */
public class LightFilter extends WholeImageFilter {

    /**
     * Take the output colors from the input image.
     */
    public final static int COLORS_FROM_IMAGE = 0;

    /**
     * Use constant material color.
     */
    public final static int COLORS_CONSTANT = 1;

    /**
     * Use the input image brightness as the bump map.
     */
    public final static int BUMPS_FROM_IMAGE = 0;

    /**
     * Use the input image alpha as the bump map.
     */
    public final static int BUMPS_FROM_IMAGE_ALPHA = 1;

    /**
     * Use a separate image alpha channel as the bump map.
     */
    public final static int BUMPS_FROM_MAP = 2;

    /**
     * Use a custom function as the bump map.
     */
    public final static int BUMPS_FROM_BEVEL = 3;

    private float bumpHeight;
    private float bumpSoftness;
    private int bumpShape;
    private float viewDistance = 10000.0f;
    Material material;
    private Vector lights;
    private int colorSource = COLORS_FROM_IMAGE;
    private int bumpSource = BUMPS_FROM_IMAGE;
    private Function2D bumpFunction;
    private Image environmentMap;
    private int[] envPixels;
    private int envWidth = 1, envHeight = 1;

    // Temporary variables used to avoid per-pixel memory allocation while filtering
    private Vector3f l;
    private Vector3f v;
    private Vector3f n;
    private Color4f shadedColor;
    private Color4f diffuse_color;
    private Color4f specular_color;
    private Vector3f tmpv, tmpv2;

    public LightFilter() {
        lights = new Vector();
        addLight(new DistantLight());
        bumpHeight = 1.0f;
        bumpSoftness = 5.0f;
        bumpShape = 0;
        material = new Material();
        l = new Vector3f();
        v = new Vector3f();
        n = new Vector3f();
        shadedColor = new Color4f();
        diffuse_color = new Color4f();
        specular_color = new Color4f();
        tmpv = new Vector3f();
        tmpv2 = new Vector3f();
    }

    public void setMaterial( Material material ) {
        this.material = material;
    }

    public Material getMaterial() {
        return material;
    }

    public void setBumpFunction(Function2D bumpFunction) {
        this.bumpFunction = bumpFunction;
    }

    public Function2D getBumpFunction() {
        return bumpFunction;
    }

    public void setBumpHeight(float bumpHeight) {
        this.bumpHeight = bumpHeight;
    }

    public float getBumpHeight() {
        return bumpHeight;
    }

    public void setBumpSoftness(float bumpSoftness) {
        this.bumpSoftness = bumpSoftness;
    }

    public float getBumpSoftness() {
        return bumpSoftness;
    }

    public void setBumpShape(int bumpShape) {
        this.bumpShape = bumpShape;
    }

    public int getBumpShape() {
        return bumpShape;
    }

    public void setViewDistance(float viewDistance) {
        this.viewDistance = viewDistance;
    }

    public float getViewDistance() {
        return viewDistance;
    }

    public void setEnvironmentMap(BufferedImage environmentMap) {
        this.environmentMap = environmentMap;
        if (environmentMap != null) {
            envWidth = environmentMap.getWidth();
            envHeight = environmentMap.getHeight();
            envPixels = getRGB( environmentMap, 0, 0, envWidth, envHeight, null );
        } else {
            envWidth = envHeight = 1;
            envPixels = null;
        }
    }

    public Image getEnvironmentMap() {
        return environmentMap;
    }

    public void setColorSource(int colorSource) {
        this.colorSource = colorSource;
    }

    public int getColorSource() {
        return colorSource;
    }

    public void setBumpSource(int bumpSource) {
        this.bumpSource = bumpSource;
    }

    public int getBumpSource() {
        return bumpSource;
    }

    public void setDiffuseColor(int diffuseColor) {
        material.diffuseColor = diffuseColor;
    }

    public int getDiffuseColor() {
        return material.diffuseColor;
    }

    public void addLight(Light light) {
        lights.addElement(light);
    }

    public void removeLight(Light light) {
        lights.removeElement(light);
    }

    public Vector getLights() {
        return lights;
    }

    protected final static float r255 = 1.0f/255.0f;

    protected void setFromRGB( Color4f c, int argb ) {
        c.set( ((argb >> 16) & 0xff) * r255, ((argb >> 8) & 0xff) * r255, (argb & 0xff) * r255, ((argb >> 24) & 0xff) * r255 );
    }

    protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
        int index = 0;
        int[] outPixels = new int[width * height];
        float width45 = Math.abs(6.0f * bumpHeight);
        boolean invertBumps = bumpHeight < 0;
        Vector3f position = new Vector3f(0.0f, 0.0f, 0.0f);
        Vector3f viewpoint = new Vector3f((float)width / 2.0f, (float)height / 2.0f, viewDistance);
        Vector3f normal = new Vector3f();
        Color4f envColor = new Color4f();
        Color4f diffuseColor = new Color4f( new Color(material.diffuseColor) );
        Color4f specularColor = new Color4f( new Color(material.specularColor) );
        Function2D bump = bumpFunction;

        // Apply the bump softness
        if (bumpSource == BUMPS_FROM_IMAGE || bumpSource == BUMPS_FROM_IMAGE_ALPHA || bumpSource == BUMPS_FROM_MAP || bump == null) {
            if ( bumpSoftness != 0 ) {
                int bumpWidth = width;
                int bumpHeight = height;
                int[] bumpPixels = inPixels;
                if ( bumpSource == BUMPS_FROM_MAP && bumpFunction instanceof ImageFunction2D ) {
                    ImageFunction2D if2d = (ImageFunction2D)bumpFunction;
                    bumpWidth = if2d.getWidth();
                    bumpHeight = if2d.getHeight();
                    bumpPixels = if2d.getPixels();
                }
                int [] tmpPixels = new int[bumpWidth * bumpHeight];
                int [] softPixels = new int[bumpWidth * bumpHeight];
/*
				for (int i = 0; i < 3; i++ ) {
					BoxBlurFilter.blur( bumpPixels, tmpPixels, bumpWidth, bumpHeight, (int)bumpSoftness );
					BoxBlurFilter.blur( tmpPixels, softPixels, bumpHeight, bumpWidth, (int)bumpSoftness );
				}
*/
                Kernel kernel = GaussianFilter.makeKernel( bumpSoftness );
                GaussianFilter.convolveAndTranspose( kernel, bumpPixels, tmpPixels, bumpWidth, bumpHeight, true, false, false, GaussianFilter.WRAP_EDGES );
                GaussianFilter.convolveAndTranspose( kernel, tmpPixels, softPixels, bumpHeight, bumpWidth, true, false, false, GaussianFilter.WRAP_EDGES );
                bump = new ImageFunction2D(softPixels, bumpWidth, bumpHeight, ImageFunction2D.CLAMP, bumpSource == BUMPS_FROM_IMAGE_ALPHA);
                final Function2D bbump = bump;
                if ( bumpShape != 0 ) {
                    bump = new Function2D() {
                        private Function2D original = bbump;

                        public float evaluate(float x, float y) {
                            float v = original.evaluate( x, y );
                            switch ( bumpShape ) {
                                case 1:
//				v = v > 0.5f ? 0.5f : v;
                                    v *= ImageMath.smoothStep( 0.45f, 0.55f, v );
                                    break;
                                case 2:
                                    v = v < 0.5f ? 0.5f : v;
                                    break;
                                case 3:
                                    v = ImageMath.triangle( v );
                                    break;
                                case 4:
                                    v = ImageMath.circleDown( v );
                                    break;
                                case 5:
                                    v = ImageMath.gain( v, 0.75f );
                                    break;
                            }
                            return v;
                        }
                    };
                }
            } else if ( bumpSource != BUMPS_FROM_MAP )
                bump = new ImageFunction2D(inPixels, width, height, ImageFunction2D.CLAMP, bumpSource == BUMPS_FROM_IMAGE_ALPHA);
        }

        float reflectivity = material.reflectivity;
        float areflectivity = (1-reflectivity);
        Vector3f v1 = new Vector3f();
        Vector3f v2 = new Vector3f();
        Vector3f n = new Vector3f();
        Light[] lightsArray = new Light[lights.size()];
        lights.copyInto(lightsArray);
        for (int i = 0; i < lightsArray.length; i++)
            lightsArray[i].prepare(width, height);

        float[][] heightWindow = new float[3][width];
        for (int x = 0; x < width; x++)
            heightWindow[1][x] = width45*bump.evaluate(x, 0);

        // Loop through each source pixel
        for (int y = 0; y < height; y++) {
            boolean y0 = y > 0;
            boolean y1 = y < height-1;
            position.y = y;
            for (int x = 0; x < width; x++)
                heightWindow[2][x] = width45*bump.evaluate(x, y+1);
            for (int x = 0; x < width; x++) {
                boolean x0 = x > 0;
                boolean x1 = x < width-1;

                // Calculate the normal at this point
                if (bumpSource != BUMPS_FROM_BEVEL) {
                    // Complicated and slower method
                    // Calculate four normals using the gradients in +/- X/Y directions
                    int count = 0;
                    normal.x = normal.y = normal.z = 0;
                    float m0 = heightWindow[1][x];
                    float m1 = x0 ? heightWindow[1][x-1]-m0 : 0;
                    float m2 = y0 ? heightWindow[0][x]-m0 : 0;
                    float m3 = x1 ? heightWindow[1][x+1]-m0 : 0;
                    float m4 = y1 ? heightWindow[2][x]-m0 : 0;

                    if (x0 && y1) {
                        v1.x = -1.0f; v1.y = 0.0f; v1.z = m1;
                        v2.x = 0.0f; v2.y = 1.0f; v2.z = m4;
                        n.cross(v1, v2);
                        n.normalize();
                        if (n.z < 0.0)
                            n.z = -n.z;
                        normal.add(n);
                        count++;
                    }

                    if (x0 && y0) {
                        v1.x = -1.0f; v1.y = 0.0f; v1.z = m1;
                        v2.x = 0.0f; v2.y = -1.0f; v2.z = m2;
                        n.cross(v1, v2);
                        n.normalize();
                        if (n.z < 0.0)
                            n.z = -n.z;
                        normal.add(n);
                        count++;
                    }

                    if (y0 && x1) {
                        v1.x = 0.0f; v1.y = -1.0f; v1.z = m2;
                        v2.x = 1.0f; v2.y = 0.0f; v2.z = m3;
                        n.cross(v1, v2);
                        n.normalize();
                        if (n.z < 0.0)
                            n.z = -n.z;
                        normal.add(n);
                        count++;
                    }

                    if (x1 && y1) {
                        v1.x = 1.0f; v1.y = 0.0f; v1.z = m3;
                        v2.x = 0.0f; v2.y = 1.0f; v2.z = m4;
                        n.cross(v1, v2);
                        n.normalize();
                        if (n.z < 0.0)
                            n.z = -n.z;
                        normal.add(n);
                        count++;
                    }

                    // Average the four normals
                    normal.x /= count;
                    normal.y /= count;
                    normal.z /= count;
                }
                if (invertBumps) {
                    normal.x = -normal.x;
                    normal.y = -normal.y;
                }
                position.x = x;

                if (normal.z >= 0) {
                    // Get the material colour at this point
                    if (colorSource == COLORS_FROM_IMAGE)
                        setFromRGB(diffuseColor, inPixels[index]);
                    else
                        setFromRGB(diffuseColor, material.diffuseColor);
                    if (reflectivity != 0 && environmentMap != null) {
                        //FIXME-too much normalizing going on here
                        tmpv2.set(viewpoint);
                        tmpv2.sub(position);
                        tmpv2.normalize();
                        tmpv.set(normal);
                        tmpv.normalize();

                        // Reflect
                        tmpv.scale( 2.0f*tmpv.dot(tmpv2) );
                        tmpv.sub(v);

                        tmpv.normalize();
                        setFromRGB(envColor, getEnvironmentMap(tmpv, inPixels, width, height));//FIXME-interpolate()
                        diffuseColor.x = reflectivity*envColor.x + areflectivity*diffuseColor.x;
                        diffuseColor.y = reflectivity*envColor.y + areflectivity*diffuseColor.y;
                        diffuseColor.z = reflectivity*envColor.z + areflectivity*diffuseColor.z;
                    }
                    // Shade the pixel
                    Color4f c = phongShade(position, viewpoint, normal, diffuseColor, specularColor, material, lightsArray);
                    int alpha = inPixels[index] & 0xff000000;
                    int rgb = ((int)(c.x * 255) << 16) | ((int)(c.y * 255) << 8) | (int)(c.z * 255);
                    outPixels[index++] = alpha | rgb;
                } else
                    outPixels[index++] = 0;
            }
            float[] t = heightWindow[0];
            heightWindow[0] = heightWindow[1];
            heightWindow[1] = heightWindow[2];
            heightWindow[2] = t;
        }
        return outPixels;
    }

    protected Color4f phongShade(Vector3f position, Vector3f viewpoint, Vector3f normal, Color4f diffuseColor, Color4f specularColor, Material material, Light[] lightsArray) {
        shadedColor.set(diffuseColor);
        shadedColor.scale(material.ambientIntensity);

        for (int i = 0; i < lightsArray.length; i++) {
            Light light = lightsArray[i];
            n.set(normal);
            l.set(light.position);
            if (light.type != DISTANT)
                l.sub(position);
            l.normalize();
            float nDotL = n.dot(l);
            if (nDotL >= 0.0) {
                float dDotL = 0;

                v.set(viewpoint);
                v.sub(position);
                v.normalize();

                // Spotlight
                if (light.type == SPOT) {
                    dDotL = light.direction.dot(l);
                    if (dDotL < light.cosConeAngle)
                        continue;
                }

                n.scale(2.0f * nDotL);
                n.sub(l);
                float rDotV = n.dot(v);

                float rv;
                if (rDotV < 0.0)
                    rv = 0.0f;
                else

                   rv = rDotV / (material.highlight - material.highlight*rDotV + rDotV);	// Fast approximation to pow

                // Spotlight
                if (light.type == SPOT) {
                    dDotL = light.cosConeAngle/dDotL;
                    float e = dDotL;
                    e *= e;
                    e *= e;
                    e *= e;
                    e = (float)Math.pow(dDotL, light.focus*10)*(1 - e);
                    rv *= e;
                    nDotL *= e;
                }

                diffuse_color.set(diffuseColor);
                diffuse_color.scale(material.diffuseReflectivity);
                diffuse_color.x *= light.realColor.x * nDotL;
                diffuse_color.y *= light.realColor.y * nDotL;
                diffuse_color.z *= light.realColor.z * nDotL;
                specular_color.set(specularColor);
                specular_color.scale(material.specularReflectivity);
                specular_color.x *= light.realColor.x * rv;
                specular_color.y *= light.realColor.y * rv;
                specular_color.z *= light.realColor.z * rv;
                diffuse_color.add(specular_color);
                diffuse_color.clamp( 0, 1 );
                shadedColor.add(diffuse_color);
            }
        }
        shadedColor.clamp( 0, 1 );
        return shadedColor;
    }

    private int getEnvironmentMap(Vector3f normal, int[] inPixels, int width, int height) {
        if (environmentMap != null) {
            float angle = (float)Math.acos(-normal.y);

            float x, y;
            y = angle/ImageMath.PI;

            if (y == 0.0f || y == 1.0f)
                x = 0.0f;
            else {
                float f = normal.x/(float)Math.sin(angle);

                if (f > 1.0f)
                    f = 1.0f;
                else if (f < -1.0f)
                    f = -1.0f;

                x = (float)Math.acos(f)/ImageMath.PI;
            }
            // A bit of empirical scaling....
            x = ImageMath.clamp(x * envWidth, 0, envWidth-1);
            y = ImageMath.clamp(y * envHeight, 0, envHeight-1);
            int ix = (int)x;
            int iy = (int)y;

            float xWeight = x-ix;
            float yWeight = y-iy;
            int i = envWidth*iy + ix;
            int dx = ix == envWidth-1 ? 0 : 1;
            int dy = iy == envHeight-1 ? 0 : envWidth;
            return ImageMath.bilinearInterpolate( xWeight, yWeight, envPixels[i], envPixels[i+dx], envPixels[i+dy], envPixels[i+dx+dy] );
        }
        return 0;
    }

    public String toString() {
        return "Stylize/Light Effects...";
    }

    /**
     * A class representing material properties.
     */
    public static class Material {
        int diffuseColor;
        int specularColor;
        float ambientIntensity;
        float diffuseReflectivity;
        float specularReflectivity;
        float highlight;
        float reflectivity;
        float opacity = 1;

        public Material() {
            ambientIntensity = 0.5f;
            diffuseReflectivity = 1.0f;
            specularReflectivity = 1.0f;
            highlight = 3.0f;
            reflectivity = 0.0f;
            diffuseColor = 0xff888888;
            specularColor = 0xffffffff;
        }

        public void setDiffuseColor(int diffuseColor) {
            this.diffuseColor = diffuseColor;
        }

        public int getDiffuseColor() {
            return diffuseColor;
        }

        public void setOpacity( float opacity ) {
            this.opacity = opacity;
        }

        public float getOpacity() {
            return opacity;
        }

    }

    public final static int AMBIENT = 0;
    public final static int DISTANT = 1;
    public final static int POINT = 2;
    public final static int SPOT = 3;

    /**
     * A class representing a light.
     */
    public static class Light implements Cloneable {

        int type = AMBIENT;
        Vector3f position;
        Vector3f direction;
        Color4f realColor = new Color4f();
        int color = 0xffffffff;
        float intensity;
        float azimuth;
        float elevation;
        float focus = 0.5f;
        float centreX = 0.5f, centreY = 0.5f;
        float coneAngle = ImageMath.PI/6;
        float cosConeAngle;
        float distance = 100.0f;

        public Light() {
            this(270*ImageMath.PI/180.0f, 0.5235987755982988f, 1.0f);
        }

        public Light(float azimuth, float elevation, float intensity) {
            this.azimuth = azimuth;
            this.elevation = elevation;
            this.intensity = intensity;
        }

        public void setAzimuth(float azimuth) {
            this.azimuth = azimuth;
        }

        public float getAzimuth() {
            return azimuth;
        }

        public void setElevation(float elevation) {
            this.elevation = elevation;
        }

        public float getElevation() {
            return elevation;
        }

        public void setDistance(float distance) {
            this.distance = distance;
        }

        public float getDistance() {
            return distance;
        }

        public void setIntensity(float intensity) {
            this.intensity = intensity;
        }

        public float getIntensity() {
            return intensity;
        }

        public void setConeAngle(float coneAngle) {
            this.coneAngle = coneAngle;
        }

        public float getConeAngle() {
            return coneAngle;
        }

        public void setFocus(float focus) {
            this.focus = focus;
        }

        public float getFocus() {
            return focus;
        }

        public void setColor(int color) {
            this.color = color;
        }

        public int getColor() {
            return color;
        }

        /**
         * Set the centre of the light in the X direction as a proportion of the image size.
         * [MENTION=9956]PARAM[/MENTION] centreX the center
         * [MENTION=288550]see[/MENTION] #getCentreX
         */
        public void setCentreX(float x) {
            centreX = x;
        }

        /**
         * Get the centre of the light in the X direction as a proportion of the image size.
         * @return the center
         * [MENTION=288550]see[/MENTION] #setCentreX
         */
        public float getCentreX() {
            return centreX;
        }

        /**
         * Set the centre of the light in the Y direction as a proportion of the image size.
         * [MENTION=9956]PARAM[/MENTION] centreY the center
         * [MENTION=288550]see[/MENTION] #getCentreY
         */
        public void setCentreY(float y) {
            centreY = y;
        }

        /**
         * Get the centre of the light in the Y direction as a proportion of the image size.
         * @return the center
         * [MENTION=288550]see[/MENTION] #setCentreY
         */
        public float getCentreY() {
            return centreY;
        }

        /**
         * Prepare the light for rendering.
         * [MENTION=9956]PARAM[/MENTION] width the output image width
         * [MENTION=9956]PARAM[/MENTION] height the output image height
         */
        public void prepare(int width, int height) {
            float lx = (float)(Math.cos(azimuth) * Math.cos(elevation));
            float ly = (float)(Math.sin(azimuth) * Math.cos(elevation));
            float lz = (float)Math.sin(elevation);
            direction = new Vector3f(lx, ly, lz);
            direction.normalize();
            if (type != DISTANT) {
                lx *= distance;
                ly *= distance;
                lz *= distance;
                lx += width * centreX;
                ly += height * centreY;
            }
            position = new Vector3f(lx, ly, lz);
            realColor.set( new Color(color) );
            realColor.scale(intensity);
            cosConeAngle = (float)Math.cos(coneAngle);
        }

        public Object clone() {
            try {
                Light copy = (Light)super.clone();
                return copy;
            }
            catch (CloneNotSupportedException e) {
                return null;
            }
        }

        public String toString() {
            return "Light";
        }

    }

    public class AmbientLight extends Light {
        public String toString() {
            return "Ambient Light";
        }
    }

    public class PointLight extends Light {
        public PointLight() {
            type = POINT;
        }

        public String toString() {
            return "Point Light";
        }
    }

    public class DistantLight extends Light {
        public DistantLight() {
            type = DISTANT;
        }

        public String toString() {
            return "Distant Light";
        }
    }

    public class SpotLight extends Light {
        public SpotLight() {
            type = SPOT;
        }

        public String toString() {
            return "Spotlight";
        }
    }
}

*s14.postimg.org/m29ys6t3x/Light_Effect.jpg

MarbleFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:54 PM
 * To change this template use File | Settings | File Templates.
 */

import com.jhlabs.math.Noise;

import java.awt.image.BufferedImage;

/**
 * This filter applies a marbling effect to an image, displacing pixels by random amounts.
 */
public class MarbleFilter extends TransformFilter {

    private float[] sinTable, cosTable;
    private float xScale = 4;
    private float yScale = 4;
    private float amount = 1;
    private float turbulence = 1;

    public MarbleFilter() {
        setEdgeAction(CLAMP);
    }

    /**
     * Set the X scale of the effect.
     * [MENTION=9956]PARAM[/MENTION] xScale the scale.
     * [MENTION=288550]see[/MENTION] #getXScale
     */
    public void setXScale(float xScale) {
        this.xScale = xScale;
    }

    /**
     * Get the X scale of the effect.
     * @return the scale.
     * [MENTION=288550]see[/MENTION] #setXScale
     */
    public float getXScale() {
        return xScale;
    }

    /**
     * Set the Y scale of the effect.
     * [MENTION=9956]PARAM[/MENTION] yScale the scale.
     * [MENTION=288550]see[/MENTION] #getYScale
     */
    public void setYScale(float yScale) {
        this.yScale = yScale;
    }

    /**
     * Get the Y scale of the effect.
     * @return the scale.
     * [MENTION=288550]see[/MENTION] #setYScale
     */
    public float getYScale() {
        return yScale;
    }

    /**
     * Set the amount of effect.
     * [MENTION=9956]PARAM[/MENTION] amount the amount
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getAmount
     */
    public void setAmount(float amount) {
        this.amount = amount;
    }

    /**
     * Get the amount of effect.
     * @return the amount
     * [MENTION=288550]see[/MENTION] #setAmount
     */
    public float getAmount() {
        return amount;
    }

    /**
     * Specifies the turbulence of the effect.
     * [MENTION=9956]PARAM[/MENTION] turbulence the turbulence of the effect.
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getTurbulence
     */
    public void setTurbulence(float turbulence) {
        this.turbulence = turbulence;
    }

    /**
     * Returns the turbulence of the effect.
     * @return the turbulence of the effect.
     * [MENTION=288550]see[/MENTION] #setTurbulence
     */
    public float getTurbulence() {
        return turbulence;
    }

    private void initialize() {
        sinTable = new float[256];
        cosTable = new float[256];
        for (int i = 0; i < 256; i++) {
            float angle = ImageMath.TWO_PI*i/256f*turbulence;
            sinTable[i] = (float)(-yScale*Math.sin(angle));
            cosTable[i] = (float)(yScale*Math.cos(angle));
        }
    }

    private int displacementMap(int x, int y) {
        return PixelUtils.clamp((int)(127 * (1+ Noise.noise2(x / xScale, y / xScale))));
    }

    protected void transformInverse(int x, int y, float[] out) {
        int displacement = displacementMap(x, y);
        out[0] = x + sinTable[displacement];
        out[1] = y + cosTable[displacement];
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        initialize();
        return super.filter( src, dst );
    }

    public String toString() {
        return "Distort/Marble...";
    }
}

[img=*s11.postimg.org/78o6v6iin/Marble.jpg]

MotionBlurFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:33 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.geom.*;

/**
 * A filter which produces motion blur the slow, but higher-quality way.
 */
public class MotionBlurFilter extends AbstractBufferedImageOp {

    private float angle = 0.0f;
    private float falloff = 1.0f;
    private float distance = 1.0f;
    private float zoom = 0.0f;
    private float rotation = 0.0f;
    private boolean wrapEdges = false;
    private boolean premultiplyAlpha = true;

    /**
     * Construct a MotionBlurFilter.
     */
    public MotionBlurFilter() {
    }

    /**
     * Construct a MotionBlurFilter.
     * [MENTION=9956]PARAM[/MENTION] distance the distance of blur.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of blur.
     * [MENTION=9956]PARAM[/MENTION] rotation the angle of rotation.
     * [MENTION=9956]PARAM[/MENTION] zoom the zoom factor.
     */
    public MotionBlurFilter( float distance, float angle, float rotation, float zoom ) {
        this.distance = distance;
        this.angle = angle;
        this.rotation = rotation;
        this.zoom = zoom;
    }

    /**
     * Specifies the angle of blur.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of blur.
     * @angle
     * [MENTION=288550]see[/MENTION] #getAngle
     */
    public void setAngle( float angle ) {
        this.angle = angle;
    }

    /**
     * Returns the angle of blur.
     * @return the angle of blur.
     * [MENTION=288550]see[/MENTION] #setAngle
     */
    public float getAngle() {
        return angle;
    }

    /**
     * Set the distance of blur.
     * [MENTION=9956]PARAM[/MENTION] distance the distance of blur.
     * [MENTION=288550]see[/MENTION] #getDistance
     */
    public void setDistance( float distance ) {
        this.distance = distance;
    }

    /**
     * Get the distance of blur.
     * @return the distance of blur.
     * [MENTION=288550]see[/MENTION] #setDistance
     */
    public float getDistance() {
        return distance;
    }

    /**
     * Set the blur rotation.
     * [MENTION=9956]PARAM[/MENTION] rotation the angle of rotation.
     * [MENTION=288550]see[/MENTION] #getRotation
     */
    public void setRotation( float rotation ) {
        this.rotation = rotation;
    }

    /**
     * Get the blur rotation.
     * @return the angle of rotation.
     * [MENTION=288550]see[/MENTION] #setRotation
     */
    public float getRotation() {
        return rotation;
    }

    /**
     * Set the blur zoom.
     * [MENTION=9956]PARAM[/MENTION] zoom the zoom factor.
     * [MENTION=288550]see[/MENTION] #getZoom
     */
    public void setZoom( float zoom ) {
        this.zoom = zoom;
    }

    /**
     * Get the blur zoom.
     * @return the zoom factor.
     * [MENTION=288550]see[/MENTION] #setZoom
     */
    public float getZoom() {
        return zoom;
    }

    /**
     * Set whether to wrap at the image edges.
     * [MENTION=9956]PARAM[/MENTION] wrapEdges true if it should wrap.
     * [MENTION=288550]see[/MENTION] #getWrapEdges
     */
    public void setWrapEdges(boolean wrapEdges) {
        this.wrapEdges = wrapEdges;
    }

    /**
     * Get whether to wrap at the image edges.
     * @return true if it should wrap.
     * [MENTION=288550]see[/MENTION] #setWrapEdges
     */
    public boolean getWrapEdges() {
        return wrapEdges;
    }

    /**
     * Set whether to premultiply the alpha channel.
     * [MENTION=9956]PARAM[/MENTION] premultiplyAlpha true to premultiply the alpha
     * [MENTION=288550]see[/MENTION] #getPremultiplyAlpha
     */
    public void setPremultiplyAlpha( boolean premultiplyAlpha ) {
        this.premultiplyAlpha = premultiplyAlpha;
    }

    /**
     * Get whether to premultiply the alpha channel.
     * @return true to premultiply the alpha
     * [MENTION=288550]see[/MENTION] #setPremultiplyAlpha
     */
    public boolean getPremultiplyAlpha() {
        return premultiplyAlpha;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );

        int[] inPixels = new int[width*height];
        int[] outPixels = new int[width*height];
        getRGB( src, 0, 0, width, height, inPixels );

        float sinAngle = (float)Math.sin(angle);
        float cosAngle = (float)Math.cos(angle);

        float total;
        int cx = width/2;
        int cy = height/2;
        int index = 0;

        float imageRadius = (float)Math.sqrt( cx*cx + cy*cy );
        float translateX = (float)(distance * Math.cos( angle ));
        float translateY = (float)(distance * -Math.sin( angle ));
        float maxDistance = distance + Math.abs(rotation*imageRadius) + zoom*imageRadius;
        int repetitions = (int)maxDistance;
        AffineTransform t = new AffineTransform();
        Point2D.Float p = new Point2D.Float();

        if ( premultiplyAlpha )
            ImageMath.premultiply( inPixels, 0, inPixels.length );
        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                int a = 0, r = 0, g = 0, b = 0;
                int count = 0;
                for (int i = 0; i < repetitions; i++) {
                    int newX = x, newY = y;
                    float f = (float)i/repetitions;

                    p.x = x;
                    p.y = y;
                    t.setToIdentity();
                    t.translate( cx+f*translateX, cy+f*translateY );
                    float s = 1-zoom*f;
                    t.scale( s, s );
                    if ( rotation != 0 )
                        t.rotate( -rotation*f );
                    t.translate( -cx, -cy );
                    t.transform( p, p );
                    newX = (int)p.x;
                    newY = (int)p.y;

                    if (newX < 0 || newX >= width) {
                        if ( wrapEdges )
                            newX = ImageMath.mod( newX, width );
                        else
                            break;
                    }
                    if (newY < 0 || newY >= height) {
                        if ( wrapEdges )
                            newY = ImageMath.mod( newY, height );
                        else
                            break;
                    }

                    count++;
                    int rgb = inPixels[newY*width+newX];
                    a += (rgb >> 24) & 0xff;
                    r += (rgb >> 16) & 0xff;
                    g += (rgb >> 8) & 0xff;
                    b += rgb & 0xff;
                }
                if (count == 0) {
                    outPixels[index] = inPixels[index];
                } else {
                    a = PixelUtils.clamp((int)(a/count));
                    r = PixelUtils.clamp((int)(r/count));
                    g = PixelUtils.clamp((int)(g/count));
                    b = PixelUtils.clamp((int)(b/count));
                    outPixels[index] = (a << 24) | (r << 16) | (g << 8) | b;
                }
                index++;
            }
        }
        if ( premultiplyAlpha )
            ImageMath.unpremultiply( outPixels, 0, inPixels.length );

        setRGB( dst, 0, 0, width, height, outPixels );
        return dst;
    }

    public String toString() {
        return "Blur/Motion Blur...";
    }
}

*s27.postimg.org/9wlybqy4f/Motion_Blur.jpg

MotionBlurOp.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:57 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

/**
 * A filter which produces motion blur the faster, but lower-quality way.
 */
public class MotionBlurOp extends AbstractBufferedImageOp {

    private float centreX = 0.5f, centreY = 0.5f;
    private float distance;
    private float angle;
    private float rotation;
    private float zoom;

    /**
     * Construct a MotionBlurOp.
     */
    public MotionBlurOp() {
    }

    /**
     * Construct a MotionBlurOp.
     * [MENTION=9956]PARAM[/MENTION] distance the distance of blur.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of blur.
     * [MENTION=9956]PARAM[/MENTION] rotation the angle of rotation.
     * [MENTION=9956]PARAM[/MENTION] zoom the zoom factor.
     */
    public MotionBlurOp( float distance, float angle, float rotation, float zoom ) {
        this.distance = distance;
        this.angle = angle;
        this.rotation = rotation;
        this.zoom = zoom;
    }

    /**
     * Specifies the angle of blur.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of blur.
     * @angle
     * [MENTION=288550]see[/MENTION] #getAngle
     */
    public void setAngle( float angle ) {
        this.angle = angle;
    }

    /**
     * Returns the angle of blur.
     * @return the angle of blur.
     * [MENTION=288550]see[/MENTION] #setAngle
     */
    public float getAngle() {
        return angle;
    }

    /**
     * Set the distance of blur.
     * [MENTION=9956]PARAM[/MENTION] distance the distance of blur.
     * [MENTION=288550]see[/MENTION] #getDistance
     */
    public void setDistance( float distance ) {
        this.distance = distance;
    }

    /**
     * Get the distance of blur.
     * @return the distance of blur.
     * [MENTION=288550]see[/MENTION] #setDistance
     */
    public float getDistance() {
        return distance;
    }

    /**
     * Set the blur rotation.
     * [MENTION=9956]PARAM[/MENTION] rotation the angle of rotation.
     * [MENTION=288550]see[/MENTION] #getRotation
     */
    public void setRotation( float rotation ) {
        this.rotation = rotation;
    }

    /**
     * Get the blur rotation.
     * @return the angle of rotation.
     * [MENTION=288550]see[/MENTION] #setRotation
     */
    public float getRotation() {
        return rotation;
    }

    /**
     * Set the blur zoom.
     * [MENTION=9956]PARAM[/MENTION] zoom the zoom factor.
     * [MENTION=288550]see[/MENTION] #getZoom
     */
    public void setZoom( float zoom ) {
        this.zoom = zoom;
    }

    /**
     * Get the blur zoom.
     * @return the zoom factor.
     * [MENTION=288550]see[/MENTION] #setZoom
     */
    public float getZoom() {
        return zoom;
    }

    /**
     * Set the centre of the effect in the X direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreX the center
     * [MENTION=288550]see[/MENTION] #getCentreX
     */
    public void setCentreX( float centreX ) {
        this.centreX = centreX;
    }

    /**
     * Get the centre of the effect in the X direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreX
     */
    public float getCentreX() {
        return centreX;
    }

    /**
     * Set the centre of the effect in the Y direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreY the center
     * [MENTION=288550]see[/MENTION] #getCentreY
     */
    public void setCentreY( float centreY ) {
        this.centreY = centreY;
    }

    /**
     * Get the centre of the effect in the Y direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreY
     */
    public float getCentreY() {
        return centreY;
    }

    /**
     * Set the centre of the effect as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centre the center
     * [MENTION=288550]see[/MENTION] #getCentre
     */
    public void setCentre( Point2D centre ) {
        this.centreX = (float)centre.getX();
        this.centreY = (float)centre.getY();
    }

    /**
     * Get the centre of the effect as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentre
     */
    public Point2D getCentre() {
        return new Point2D.Float( centreX, centreY );
    }

    private int log2( int n ) {
        int m = 1;
        int log2n = 0;

        while (m < n) {
            m *= 2;
            log2n++;
        }
        return log2n;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        if ( dst == null )
            dst = createCompatibleDestImage( src, null );
        BufferedImage tsrc = src;
        float cx = (float)src.getWidth() * centreX;
        float cy = (float)src.getHeight() * centreY;
        float imageRadius = (float)Math.sqrt( cx*cx + cy*cy );
        float translateX = (float)(distance * Math.cos( angle ));
        float translateY = (float)(distance * -Math.sin( angle ));
        float scale = zoom;
        float rotate = rotation;
        float maxDistance = distance + Math.abs(rotation*imageRadius) + zoom*imageRadius;
        int steps = log2((int)maxDistance);

        translateX /= maxDistance;
        translateY /= maxDistance;
        scale /= maxDistance;
        rotate /= maxDistance;

        if ( steps == 0 ) {
            Graphics2D g = dst.createGraphics();
            g.drawRenderedImage( src, null );
            g.dispose();
            return dst;
        }

        BufferedImage tmp = createCompatibleDestImage( src, null );
        for ( int i = 0; i < steps; i++ ) {
            Graphics2D g = tmp.createGraphics();
            g.drawImage( tsrc, null, null );
            g.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON );
            g.setRenderingHint( RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR );
            g.setComposite( AlphaComposite.getInstance( AlphaComposite.SRC_OVER, 0.5f ) );

            g.translate( cx+translateX, cy+translateY );
            g.scale( 1.0001+scale, 1.0001+scale );  // The .0001 works round a bug on Windows where drawImage throws an ArrayIndexOutofBoundException
            if ( rotation != 0 )
                g.rotate( rotate );
            g.translate( -cx, -cy );

            g.drawImage( dst, null, null );
            g.dispose();
            BufferedImage ti = dst;
            dst = tmp;
            tmp = ti;
            tsrc = dst;

            translateX *= 2;
            translateY *= 2;
            scale *= 2;
            rotate *= 2;
        }
        return dst;
    }

    public String toString() {
        return "Blur/Faster Motion Blur...";
    }
}

NoiseFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:55 PM
 * To change this template use File | Settings | File Templates.
 */

import java.util.Random;

/**
 * A filter which adds random noise into an image.
 */
public class NoiseFilter extends PointFilter {

    /**
     * Gaussian distribution for the noise.
     */
    public final static int GAUSSIAN = 0;

    /**
     * Uniform distribution for the noise.
     */
    public final static int UNIFORM = 1;

    private int amount = 25;
    private int distribution = UNIFORM;
    private boolean monochrome = false;
    private float density = 1;
    private Random randomNumbers = new Random();

    public NoiseFilter() {
    }

    /**
     * Set the amount of effect.
     * [MENTION=9956]PARAM[/MENTION] amount the amount
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getAmount
     */
    public void setAmount(int amount) {
        this.amount = amount;
    }

    /**
     * Get the amount of noise.
     * @return the amount
     * [MENTION=288550]see[/MENTION] #setAmount
     */
    public int getAmount() {
        return amount;
    }

    /**
     * Set the distribution of the noise.
     * [MENTION=9956]PARAM[/MENTION] distribution the distribution
     * [MENTION=288550]see[/MENTION] #getDistribution
     */
    public void setDistribution( int distribution ) {
        this.distribution = distribution;
    }

    /**
     * Get the distribution of the noise.
     * @return the distribution
     * [MENTION=288550]see[/MENTION] #setDistribution
     */
    public int getDistribution() {
        return distribution;
    }

    /**
     * Set whether to use monochrome noise.
     * [MENTION=9956]PARAM[/MENTION] monochrome true for monochrome noise
     * [MENTION=288550]see[/MENTION] #getMonochrome
     */
    public void setMonochrome(boolean monochrome) {
        this.monochrome = monochrome;
    }

    /**
     * Get whether to use monochrome noise.
     * @return true for monochrome noise
     * [MENTION=288550]see[/MENTION] #setMonochrome
     */
    public boolean getMonochrome() {
        return monochrome;
    }

    /**
     * Set the density of the noise.
     * [MENTION=9956]PARAM[/MENTION] density the density
     * [MENTION=288550]see[/MENTION] #getDensity
     */
    public void setDensity( float density ) {
        this.density = density;
    }

    /**
     * Get the density of the noise.
     * @return the density
     * [MENTION=288550]see[/MENTION] #setDensity
     */
    public float getDensity() {
        return density;
    }

    private int random(int x) {
        x += (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount);
        if (x < 0)
            x = 0;
        else if (x > 0xff)
            x = 0xff;
        return x;
    }

    public int filterRGB(int x, int y, int rgb) {
        if ( randomNumbers.nextFloat() <= density ) {
            int a = rgb & 0xff000000;
            int r = (rgb >> 16) & 0xff;
            int g = (rgb >> 8) & 0xff;
            int b = rgb & 0xff;
            if (monochrome) {
                int n = (int)(((distribution == GAUSSIAN ? randomNumbers.nextGaussian() : 2*randomNumbers.nextFloat() - 1)) * amount);
                r = PixelUtils.clamp(r+n);
                g = PixelUtils.clamp(g+n);
                b = PixelUtils.clamp(b+n);
            } else {
                r = random(r);
                g = random(g);
                b = random(b);
            }
            return a | (r << 16) | (g << 8) | b;
        }
        return rgb;
    }

    public String toString() {
        return "Stylize/Add Noise...";
    }
}

*s29.postimg.org/yuw1ujlmr/Noise.jpg

OilFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:34 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;

/**
 * A filter which produces a "oil-painting" effect.
 */
public class OilFilter extends WholeImageFilter {

    private int range = 3;
    private int levels = 256;

    public OilFilter() {
    }

    /**
     * Set the range of the effect in pixels.
     * [MENTION=9956]PARAM[/MENTION] range the range
     * [MENTION=288550]see[/MENTION] #getRange
     */
    public void setRange( int range ) {
        this.range = range;
    }

    /**
     * Get the range of the effect in pixels.
     * @return the range
     * [MENTION=288550]see[/MENTION] #setRange
     */
    public int getRange() {
        return range;
    }

    /**
     * Set the number of levels for the effect.
     * [MENTION=9956]PARAM[/MENTION] levels the number of levels
     * [MENTION=288550]see[/MENTION] #getLevels
     */
    public void setLevels( int levels ) {
        this.levels = levels;
    }

    /**
     * Get the number of levels for the effect.
     * @return the number of levels
     * [MENTION=288550]see[/MENTION] #setLevels
     */
    public int getLevels() {
        return levels;
    }

    protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) {
        int index = 0;
        int[] rHistogram = new int[levels];
        int[] gHistogram = new int[levels];
        int[] bHistogram = new int[levels];
        int[] rTotal = new int[levels];
        int[] gTotal = new int[levels];
        int[] bTotal = new int[levels];
        int[] outPixels = new int[width * height];

        for (int y = 0; y < height; y++) {
            for (int x = 0; x < width; x++) {
                for (int i = 0; i < levels; i++)
                    rHistogram[i] = gHistogram[i] = bHistogram[i] = rTotal[i] = gTotal[i] = bTotal[i] = 0;

                for (int row = -range; row <= range; row++) {
                    int iy = y+row;
                    int ioffset;
                    if (0 <= iy && iy < height) {
                        ioffset = iy*width;
                        for (int col = -range; col <= range; col++) {
                            int ix = x+col;
                            if (0 <= ix && ix < width) {
                                int rgb = inPixels[ioffset+ix];
                                int r = (rgb >> 16) & 0xff;
                                int g = (rgb >> 8) & 0xff;
                                int b = rgb & 0xff;
                                int ri = r*levels/256;
                                int gi = g*levels/256;
                                int bi = b*levels/256;
                                rTotal[ri] += r;
                                gTotal[gi] += g;
                                bTotal[bi] += b;
                                rHistogram[ri]++;
                                gHistogram[gi]++;
                                bHistogram[bi]++;
                            }
                        }
                    }
                }

                int r = 0, g = 0, b = 0;
                for (int i = 1; i < levels; i++) {
                    if (rHistogram[i] > rHistogram[r])
                        r = i;
                    if (gHistogram[i] > gHistogram[g])
                        g = i;
                    if (bHistogram[i] > bHistogram[b])
                        b = i;
                }
                r = rTotal[r] / rHistogram[r];
                g = gTotal[g] / gHistogram[g];
                b = bTotal[b] / bHistogram[b];
                outPixels[index] = (inPixels[index] & 0xff000000) | ( r << 16 ) | ( g << 8 ) | b;
                index++;
            }
        }
        return outPixels;
    }

    public String toString() {
        return "Stylize/Oil...";
    }

}

*s11.postimg.org/ig1mh19a7/Oil.jpg

PixelUtils.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:34 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.util.Random;

/**
 * Some more useful math functions for image processing.
 * These are becoming obsolete as we move to Java2D. Use MiscComposite instead.
 */
public class PixelUtils {

    public final static int REPLACE = 0;
    public final static int NORMAL = 1;
    public final static int MIN = 2;
    public final static int MAX = 3;
    public final static int ADD = 4;
    public final static int SUBTRACT = 5;
    public final static int DIFFERENCE = 6;
    public final static int MULTIPLY = 7;
    public final static int HUE = 8;
    public final static int SATURATION = 9;
    public final static int VALUE = 10;
    public final static int COLOR = 11;
    public final static int SCREEN = 12;
    public final static int AVERAGE = 13;
    public final static int OVERLAY = 14;
    public final static int CLEAR = 15;
    public final static int EXCHANGE = 16;
    public final static int DISSOLVE = 17;
    public final static int DST_IN = 18;
    public final static int ALPHA = 19;
    public final static int ALPHA_TO_GRAY = 20;

    private static Random randomGenerator = new Random();

    /**
     * Clamp a value to the range 0..255
     */
    public static int clamp(int c) {
        if (c < 0)
            return 0;
        if (c > 255)
            return 255;
        return c;
    }

    public static int interpolate(int v1, int v2, float f) {
        return clamp((int)(v1+f*(v2-v1)));
    }

    public static int brightness(int rgb) {
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        return (r+g+b)/3;
    }

    public static boolean nearColors(int rgb1, int rgb2, int tolerance) {
        int r1 = (rgb1 >> 16) & 0xff;
        int g1 = (rgb1 >> 8) & 0xff;
        int b1 = rgb1 & 0xff;
        int r2 = (rgb2 >> 16) & 0xff;
        int g2 = (rgb2 >> 8) & 0xff;
        int b2 = rgb2 & 0xff;
        return Math.abs(r1-r2) <= tolerance && Math.abs(g1-g2) <= tolerance && Math.abs(b1-b2) <= tolerance;
    }

    private final static float hsb1[] = new float[3];//FIXME-not thread safe
    private final static float hsb2[] = new float[3];//FIXME-not thread safe

    // Return rgb1 painted onto rgb2
    public static int combinePixels(int rgb1, int rgb2, int op) {
        return combinePixels(rgb1, rgb2, op, 0xff);
    }

    public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha, int channelMask) {
        return (rgb2 & ~channelMask) | combinePixels(rgb1 & channelMask, rgb2, op, extraAlpha);
    }

    public static int combinePixels(int rgb1, int rgb2, int op, int extraAlpha) {
        if (op == REPLACE)
            return rgb1;
        int a1 = (rgb1 >> 24) & 0xff;
        int r1 = (rgb1 >> 16) & 0xff;
        int g1 = (rgb1 >> 8) & 0xff;
        int b1 = rgb1 & 0xff;
        int a2 = (rgb2 >> 24) & 0xff;
        int r2 = (rgb2 >> 16) & 0xff;
        int g2 = (rgb2 >> 8) & 0xff;
        int b2 = rgb2 & 0xff;

        switch (op) {
            case NORMAL:
                break;
            case MIN:
                r1 = Math.min(r1, r2);
                g1 = Math.min(g1, g2);
                b1 = Math.min(b1, b2);
                break;
            case MAX:
                r1 = Math.max(r1, r2);
                g1 = Math.max(g1, g2);
                b1 = Math.max(b1, b2);
                break;
            case ADD:
                r1 = clamp(r1+r2);
                g1 = clamp(g1+g2);
                b1 = clamp(b1+b2);
                break;
            case SUBTRACT:
                r1 = clamp(r2-r1);
                g1 = clamp(g2-g1);
                b1 = clamp(b2-b1);
                break;
            case DIFFERENCE:
                r1 = clamp(Math.abs(r1-r2));
                g1 = clamp(Math.abs(g1-g2));
                b1 = clamp(Math.abs(b1-b2));
                break;
            case MULTIPLY:
                r1 = clamp(r1*r2/255);
                g1 = clamp(g1*g2/255);
                b1 = clamp(b1*b2/255);
                break;
            case DISSOLVE:
                if ((randomGenerator.nextInt() & 0xff) <= a1) {
                    r1 = r2;
                    g1 = g2;
                    b1 = b2;
                }
                break;
            case AVERAGE:
                r1 = (r1+r2)/2;
                g1 = (g1+g2)/2;
                b1 = (b1+b2)/2;
                break;
            case HUE:
            case SATURATION:
            case VALUE:
            case COLOR:
                Color.RGBtoHSB(r1, g1, b1, hsb1);
                Color.RGBtoHSB(r2, g2, b2, hsb2);
                switch (op) {
                    case HUE:
                        hsb2[0] = hsb1[0];
                        break;
                    case SATURATION:
                        hsb2[1] = hsb1[1];
                        break;
                    case VALUE:
                        hsb2[2] = hsb1[2];
                        break;
                    case COLOR:
                        hsb2[0] = hsb1[0];
                        hsb2[1] = hsb1[1];
                        break;
                }
                rgb1 = Color.HSBtoRGB(hsb2[0], hsb2[1], hsb2[2]);
                r1 = (rgb1 >> 16) & 0xff;
                g1 = (rgb1 >> 8) & 0xff;
                b1 = rgb1 & 0xff;
                break;
            case SCREEN:
                r1 = 255 - ((255 - r1) * (255 - r2)) / 255;
                g1 = 255 - ((255 - g1) * (255 - g2)) / 255;
                b1 = 255 - ((255 - b1) * (255 - b2)) / 255;
                break;
            case OVERLAY:
                int m, s;
                s = 255 - ((255 - r1) * (255 - r2)) / 255;
                m = r1 * r2 / 255;
                r1 = (s * r1 + m * (255 - r1)) / 255;
                s = 255 - ((255 - g1) * (255 - g2)) / 255;
                m = g1 * g2 / 255;
                g1 = (s * g1 + m * (255 - g1)) / 255;
                s = 255 - ((255 - b1) * (255 - b2)) / 255;
                m = b1 * b2 / 255;
                b1 = (s * b1 + m * (255 - b1)) / 255;
                break;
            case CLEAR:
                r1 = g1 = b1 = 0xff;
                break;
            case DST_IN:
                r1 = clamp((r2*a1)/255);
                g1 = clamp((g2*a1)/255);
                b1 = clamp((b2*a1)/255);
                a1 = clamp((a2*a1)/255);
                return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
            case ALPHA:
                a1 = a1*a2/255;
                return (a1 << 24) | (r2 << 16) | (g2 << 8) | b2;
            case ALPHA_TO_GRAY:
                int na = 255-a1;
                return (a1 << 24) | (na << 16) | (na << 8) | na;
        }
        if (extraAlpha != 0xff || a1 != 0xff) {
            a1 = a1*extraAlpha/255;
            int a3 = (255-a1)*a2/255;
            r1 = clamp((r1*a1+r2*a3)/255);
            g1 = clamp((g1*a1+g2*a3)/255);
            b1 = clamp((b1*a1+b2*a3)/255);
            a1 = clamp(a1+a3);
        }
        return (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
    }

}

PointFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:35 PM
 * To change this template use File | Settings | File Templates.
 */


import java.awt.image.*;

/**
 * An abstract superclass for point filters. The interface is the same as the old RGBImageFilter.
 */
public abstract class PointFilter extends AbstractBufferedImageOp {

    protected boolean canFilterIndexColorModel = false;

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        int type = src.getType();
        WritableRaster srcRaster = src.getRaster();

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );
        WritableRaster dstRaster = dst.getRaster();

        setDimensions( width, height);

        int[] inPixels = new int[width];
        for ( int y = 0; y < height; y++ ) {
            // We try to avoid calling getRGB on images as it causes them to become unmanaged, causing horrible performance problems.
            if ( type == BufferedImage.TYPE_INT_ARGB ) {
                srcRaster.getDataElements( 0, y, width, 1, inPixels );
                for ( int x = 0; x < width; x++ )
                    inPixels[x] = filterRGB( x, y, inPixels[x] );
                dstRaster.setDataElements( 0, y, width, 1, inPixels );
            } else {
                src.getRGB( 0, y, width, 1, inPixels, 0, width );
                for ( int x = 0; x < width; x++ )
                    inPixels[x] = filterRGB( x, y, inPixels[x] );
                dst.setRGB( 0, y, width, 1, inPixels, 0, width );
            }
        }

        return dst;
    }

    public void setDimensions(int width, int height) {
    }

    public abstract int filterRGB(int x, int y, int rgb);
}

RaysFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:56 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import com.jhlabs.composite.*;

/**
 * A filter which produces the effect of light rays shining out of an image.
 */
public class RaysFilter extends MotionBlurOp {

    private float opacity = 1.0f;
    private float threshold = 0.0f;
    private float strength = 0.5f;
    private boolean raysOnly = false;
    private Colormap colormap;

    public RaysFilter() {
    }

    /**
     * Set the opacity of the rays.
     * [MENTION=9956]PARAM[/MENTION] opacity the opacity.
     * [MENTION=288550]see[/MENTION] #getOpacity
     */
    public void setOpacity(float opacity) {
        this.opacity = opacity;
    }

    /**
     * Get the opacity of the rays.
     * @return the opacity.
     * [MENTION=288550]see[/MENTION] #setOpacity
     */
    public float getOpacity() {
        return opacity;
    }

    /**
     * Set the threshold value.
     * [MENTION=9956]PARAM[/MENTION] threshold the threshold value
     * [MENTION=288550]see[/MENTION] #getThreshold
     */
    public void setThreshold( float threshold ) {
        this.threshold = threshold;
    }

    /**
     * Get the threshold value.
     * @return the threshold value
     * [MENTION=288550]see[/MENTION] #setThreshold
     */
    public float getThreshold() {
        return threshold;
    }

    /**
     * Set the strength of the rays.
     * [MENTION=9956]PARAM[/MENTION] strength the strength.
     * [MENTION=288550]see[/MENTION] #getStrength
     */
    public void setStrength( float strength ) {
        this.strength = strength;
    }

    /**
     * Get the strength of the rays.
     * @return the strength.
     * [MENTION=288550]see[/MENTION] #setStrength
     */
    public float getStrength() {
        return strength;
    }

    /**
     * Set whether to render only the rays.
     * [MENTION=9956]PARAM[/MENTION] raysOnly true to render rays only.
     * [MENTION=288550]see[/MENTION] #getRaysOnly
     */
    public void setRaysOnly(boolean raysOnly) {
        this.raysOnly = raysOnly;
    }

    /**
     * Get whether to render only the rays.
     * @return true to render rays only.
     * [MENTION=288550]see[/MENTION] #setRaysOnly
     */
    public boolean getRaysOnly() {
        return raysOnly;
    }

    /**
     * Set the colormap to be used for the filter.
     * [MENTION=9956]PARAM[/MENTION] colormap the colormap
     * [MENTION=288550]see[/MENTION] #getColormap
     */
    public void setColormap(Colormap colormap) {
        this.colormap = colormap;
    }

    /**
     * Get the colormap to be used for the filter.
     * @return the colormap
     * [MENTION=288550]see[/MENTION] #setColormap
     */
    public Colormap getColormap() {
        return colormap;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        int[] pixels = new int[width];
        int[] srcPixels = new int[width];

        BufferedImage rays = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);

        int threshold3 = (int)(threshold*3*255);
        for ( int y = 0; y < height; y++ ) {
            getRGB( src, 0, y, width, 1, pixels );
            for ( int x = 0; x < width; x++ ) {
                int rgb = pixels[x];
                int a = rgb & 0xff000000;
                int r = (rgb >> 16) & 0xff;
                int g = (rgb >> 8) & 0xff;
                int b = rgb & 0xff;
                int l = r + g + b;
                if (l < threshold3)
                    pixels[x] = 0xff000000;
                else {
                    l /= 3;
                    pixels[x] = a | (l << 16) | (l << 8) | l;
                }
            }
            setRGB( rays, 0, y, width, 1, pixels );
        }

        rays = super.filter( rays, null );

        for ( int y = 0; y < height; y++ ) {
            getRGB( rays, 0, y, width, 1, pixels );
            getRGB( src, 0, y, width, 1, srcPixels );
            for ( int x = 0; x < width; x++ ) {
                int rgb = pixels[x];
                int a = rgb & 0xff000000;
                int r = (rgb >> 16) & 0xff;
                int g = (rgb >> 8) & 0xff;
                int b = rgb & 0xff;

                if ( colormap != null ) {
                    int l = r + g + b;
                    rgb = colormap.getColor( l * strength * (1/3f) );
                } else {
                    r = PixelUtils.clamp((int)(r * strength));
                    g = PixelUtils.clamp((int)(g * strength));
                    b = PixelUtils.clamp((int)(b * strength));
                    rgb = a | (r << 16) | (g << 8) | b;
                }

                pixels[x] = rgb;
            }
            setRGB( rays, 0, y, width, 1, pixels );
        }

        if ( dst == null )
            dst = createCompatibleDestImage( src, null );

        Graphics2D g = dst.createGraphics();
        if ( !raysOnly ) {
            g.setComposite( AlphaComposite.SrcOver );
            g.drawRenderedImage( src, null );
        }
        g.setComposite( MiscComposite.getInstance( MiscComposite.ADD, opacity ) );
        g.drawRenderedImage( rays, null );
        g.dispose();

        return dst;
    }

    public String toString() {
        return "Stylize/Rays...";
    }
}

RGBAdjustFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:35 PM
 * To change this template use File | Settings | File Templates.
 */

public class RGBAdjustFilter extends PointFilter {

    public float rFactor, gFactor, bFactor;

    public RGBAdjustFilter() {
        this(0, 0, 0);
    }

    public RGBAdjustFilter(float r, float g, float b) {
        rFactor = 1+r;
        gFactor = 1+g;
        bFactor = 1+b;
        canFilterIndexColorModel = true;
    }

    public void setRFactor( float rFactor ) {
        this.rFactor = 1+rFactor;
    }

    public float getRFactor() {
        return rFactor-1;
    }

    public void setGFactor( float gFactor ) {
        this.gFactor = 1+gFactor;
    }

    public float getGFactor() {
        return gFactor-1;
    }

    public void setBFactor( float bFactor ) {
        this.bFactor = 1+bFactor;
    }

    public float getBFactor() {
        return bFactor-1;
    }

    public int[] getLUT() {
        int[] lut = new int[256];
        for ( int i = 0; i < 256; i++ ) {
            lut[i] = filterRGB( 0, 0, (i << 24) | (i << 16) | (i << 8) | i );
        }
        return lut;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        r = PixelUtils.clamp((int)(r * rFactor));
        g = PixelUtils.clamp((int)(g * gFactor));
        b = PixelUtils.clamp((int)(b * bFactor));
        return a | (r << 16) | (g << 8) | b;
    }

    public String toString() {
        return "Colors/Adjust RGB...";
    }
}

RippleFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:36 PM
 * To change this template use File | Settings | File Templates.
 */

import com.jhlabs.math.Noise;

import java.awt.*;

/**
 * A filter which distorts an image by rippling it in the X or Y directions.
 * The amplitude and wavelength of rippling can be specified as well as whether
 * pixels going off the edges are wrapped or not.
 */
public class RippleFilter extends TransformFilter {

    /**
     * Sine wave ripples.
     */
    public final static int SINE = 0;

    /**
     * Sawtooth wave ripples.
     */
    public final static int SAWTOOTH = 1;

    /**
     * Triangle wave ripples.
     */
    public final static int TRIANGLE = 2;

    /**
     * Noise ripples.
     */
    public final static int NOISE = 3;

    private float xAmplitude, yAmplitude;
    private float xWavelength, yWavelength;
    private int waveType;

    /**
     * Construct a RippleFilter.
     */
    public RippleFilter() {
        xAmplitude = 5.0f;
        yAmplitude = 0.0f;
        xWavelength = yWavelength = 16.0f;
    }

    /**
     * Set the amplitude of ripple in the X direction.
     * [MENTION=9956]PARAM[/MENTION] xAmplitude the amplitude (in pixels).
     * [MENTION=288550]see[/MENTION] #getXAmplitude
     */
    public void setXAmplitude(float xAmplitude) {
        this.xAmplitude = xAmplitude;
    }

    /**
     * Get the amplitude of ripple in the X direction.
     * @return the amplitude (in pixels).
     * [MENTION=288550]see[/MENTION] #setXAmplitude
     */
    public float getXAmplitude() {
        return xAmplitude;
    }

    /**
     * Set the wavelength of ripple in the X direction.
     * [MENTION=9956]PARAM[/MENTION] xWavelength the wavelength (in pixels).
     * [MENTION=288550]see[/MENTION] #getXWavelength
     */
    public void setXWavelength(float xWavelength) {
        this.xWavelength = xWavelength;
    }

    /**
     * Get the wavelength of ripple in the X direction.
     * @return the wavelength (in pixels).
     * [MENTION=288550]see[/MENTION] #setXWavelength
     */
    public float getXWavelength() {
        return xWavelength;
    }

    /**
     * Set the amplitude of ripple in the Y direction.
     * [MENTION=9956]PARAM[/MENTION] yAmplitude the amplitude (in pixels).
     * [MENTION=288550]see[/MENTION] #getYAmplitude
     */
    public void setYAmplitude(float yAmplitude) {
        this.yAmplitude = yAmplitude;
    }

    /**
     * Get the amplitude of ripple in the Y direction.
     * @return the amplitude (in pixels).
     * [MENTION=288550]see[/MENTION] #setYAmplitude
     */
    public float getYAmplitude() {
        return yAmplitude;
    }

    /**
     * Set the wavelength of ripple in the Y direction.
     * [MENTION=9956]PARAM[/MENTION] yWavelength the wavelength (in pixels).
     * [MENTION=288550]see[/MENTION] #getYWavelength
     */
    public void setYWavelength(float yWavelength) {
        this.yWavelength = yWavelength;
    }

    /**
     * Get the wavelength of ripple in the Y direction.
     * @return the wavelength (in pixels).
     * [MENTION=288550]see[/MENTION] #setYWavelength
     */
    public float getYWavelength() {
        return yWavelength;
    }


    /**
     * Set the wave type.
     * [MENTION=9956]PARAM[/MENTION] waveType the type.
     * [MENTION=288550]see[/MENTION] #getWaveType
     */
    public void setWaveType(int waveType) {
        this.waveType = waveType;
    }

    /**
     * Get the wave type.
     * @return the type.
     * [MENTION=288550]see[/MENTION] #setWaveType
     */
    public int getWaveType() {
        return waveType;
    }

    protected void transformSpace(Rectangle r) {
        if (edgeAction == ZERO) {
            r.x -= (int)xAmplitude;
            r.width += (int)(2*xAmplitude);
            r.y -= (int)yAmplitude;
            r.height += (int)(2*yAmplitude);
        }
    }

    protected void transformInverse(int x, int y, float[] out) {
        float nx = (float)y / xWavelength;
        float ny = (float)x / yWavelength;
        float fx, fy;
        switch (waveType) {
            case SINE:
            default:
                fx = (float)Math.sin(nx);
                fy = (float)Math.sin(ny);
                break;
            case SAWTOOTH:
                fx = ImageMath.mod(nx, 1);
                fy = ImageMath.mod(ny, 1);
                break;
            case TRIANGLE:
                fx = ImageMath.triangle(nx);
                fy = ImageMath.triangle(ny);
                break;
            case NOISE:
                fx = Noise.noise1(nx);
                fy = Noise.noise1(ny);
                break;
        }
        out[0] = x + xAmplitude * fx;
        out[1] = y + yAmplitude * fy;
    }

    public String toString() {
        return "Distort/Ripple...";
    }
}

*s16.postimg.org/5kfauocap/Ripple.jpg

SharpenFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:12 PM
 * To change this template use File | Settings | File Templates.
 */
/**
 * A filter which performs a simple 3x3 sharpening operation.
 */
public class SharpenFilter extends ConvolveFilter {

    private static float[] sharpenMatrix = {
            0.0f, -0.2f,  0.0f,
            -0.2f,  1.8f, -0.2f,
            0.0f, -0.2f,  0.0f
    };

    public SharpenFilter() {
        super(sharpenMatrix);
    }

    public String toString() {
        return "Blur/Sharpen";
    }
}

*s29.postimg.org/eqg9uavyb/Sharpen.jpg

SolarizeFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:10 PM
 * To change this template use File | Settings | File Templates.
 */
/**
 * A filter which solarizes an image.
 */
public class SolarizeFilter extends TransferFilter {

    protected float transferFunction( float v ) {
        return v > 0.5f ? 2*(v-0.5f) : 2*(0.5f-v);
    }

    public String toString() {
        return "Colors/Solarize";
    }
}

*s30.postimg.org/rrinyb371/Solarize.jpg

SparkleFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:37 PM
 * To change this template use File | Settings | File Templates.
 */

import java.util.Random;

public class SparkleFilter extends PointFilter {

    private int rays = 50;
    private int radius = 25;
    private int amount = 50;
    private int color = 0xffffffff;
    private int randomness = 25;
    private int width, height;
    private int centreX, centreY;
    private long seed = 371;
    private float[] rayLengths;
    private Random randomNumbers = new Random();

    public SparkleFilter() {
    }

    public void setColor(int color) {
        this.color = color;
    }

    public int getColor() {
        return color;
    }

    public void setRandomness(int randomness) {
        this.randomness = randomness;
    }

    public int getRandomness() {
        return randomness;
    }

    /**
     * Set the amount of sparkle.
     * [MENTION=9956]PARAM[/MENTION] amount the amount
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getAmount
     */
    public void setAmount(int amount) {
        this.amount = amount;
    }

    /**
     * Get the amount of sparkle.
     * @return the amount
     * [MENTION=288550]see[/MENTION] #setAmount
     */
    public int getAmount() {
        return amount;
    }

    public void setRays(int rays) {
        this.rays = rays;
    }

    public int getRays() {
        return rays;
    }

    /**
     * Set the radius of the effect.
     * [MENTION=9956]PARAM[/MENTION] radius the radius
     * @min-value 0
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(int radius) {
        this.radius = radius;
    }

    /**
     * Get the radius of the effect.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public int getRadius() {
        return radius;
    }

    public void setDimensions(int width, int height) {
        this.width = width;
        this.height = height;
        centreX = width/2;
        centreY = height/2;
        super.setDimensions(width, height);
        randomNumbers.setSeed(seed);
        rayLengths = new float[rays];
        for (int i = 0; i < rays; i++)
            rayLengths[i] = radius + randomness / 100.0f * radius * (float)randomNumbers.nextGaussian();
    }

    public int filterRGB(int x, int y, int rgb) {
        float dx = x-centreX;
        float dy = y-centreY;
        float distance = dx*dx+dy*dy;
        float angle = (float)Math.atan2(dy, dx);
        float d = (angle+ImageMath.PI) / (ImageMath.TWO_PI) * rays;
        int i = (int)d;
        float f = d - i;

        if (radius != 0) {
            float length = ImageMath.lerp(f, rayLengths[i % rays], rayLengths[(i+1) % rays]);
            float g = length*length / (distance+0.0001f);
            g = (float)Math.pow(g, (100-amount) / 50.0);
            f -= 0.5f;
//			f *= amount/50.0f;
            f = 1 - f*f;
            f *= g;
        }
        f = ImageMath.clamp(f, 0, 1);
        return ImageMath.mixColors(f, rgb, color);
    }

    public String toString() {
        return "Stylize/Sparkle...";
    }
}

*s30.postimg.org/5i9c5hx4d/Sparkle.jpg

SphereFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:13 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

/**
 * A filter which simulates a lens placed over an image.
 */
public class SphereFilter extends TransformFilter {

    private float a = 0;
    private float b = 0;
    private float a2 = 0;
    private float b2 = 0;
    private float centreX = 0.5f;
    private float centreY = 0.5f;
    private float refractionIndex = 1.5f;

    private float icentreX;
    private float icentreY;

    public SphereFilter() {
        setEdgeAction( CLAMP );
        setRadius( 100.0f );
    }

    /**
     * Set the index of refaction.
     * [MENTION=9956]PARAM[/MENTION] refractionIndex the index of refaction
     * [MENTION=288550]see[/MENTION] #getRefractionIndex
     */
    public void setRefractionIndex(float refractionIndex) {
        this.refractionIndex = refractionIndex;
    }

    /**
     * Get the index of refaction.
     * @return the index of refaction
     * [MENTION=288550]see[/MENTION] #setRefractionIndex
     */
    public float getRefractionIndex() {
        return refractionIndex;
    }

    /**
     * Set the radius of the effect.
     * [MENTION=9956]PARAM[/MENTION] r the radius
     * @min-value 0
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(float r) {
        this.a = r;
        this.b = r;
    }

    /**
     * Get the radius of the effect.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public float getRadius() {
        return a;
    }

    /**
     * Set the centre of the effect in the X direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreX the center
     * [MENTION=288550]see[/MENTION] #getCentreX
     */
    public void setCentreX( float centreX ) {
        this.centreX = centreX;
    }

    public float getCentreX() {
        return centreX;
    }

    /**
     * Set the centre of the effect in the Y direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreY the center
     * [MENTION=288550]see[/MENTION] #getCentreY
     */
    public void setCentreY( float centreY ) {
        this.centreY = centreY;
    }

    /**
     * Get the centre of the effect in the Y direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreY
     */
    public float getCentreY() {
        return centreY;
    }

    /**
     * Set the centre of the effect as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centre the center
     * [MENTION=288550]see[/MENTION] #getCentre
     */
    public void setCentre( Point2D centre ) {
        this.centreX = (float)centre.getX();
        this.centreY = (float)centre.getY();
    }

    /**
     * Get the centre of the effect as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentre
     */
    public Point2D getCentre() {
        return new Point2D.Float( centreX, centreY );
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        icentreX = width * centreX;
        icentreY = height * centreY;
        if (a == 0)
            a = width/2;
        if (b == 0)
            b = height/2;
        a2 = a*a;
        b2 = b*b;
        return super.filter( src, dst );
    }

    protected void transformInverse(int x, int y, float[] out) {
        float dx = x-icentreX;
        float dy = y-icentreY;
        float x2 = dx*dx;
        float y2 = dy*dy;
        if (y2 >= (b2 - (b2*x2)/a2)) {
            out[0] = x;
            out[1] = y;
        } else {
            float rRefraction = 1.0f / refractionIndex;

            float z = (float)Math.sqrt((1.0f - x2/a2 - y2/b2) * (a*b));
            float z2 = z*z;

            float xAngle = (float)Math.acos(dx / Math.sqrt(x2+z2));
            float angle1 = ImageMath.HALF_PI - xAngle;
            float angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction);
            angle2 = ImageMath.HALF_PI - xAngle - angle2;
            out[0] = x - (float)Math.tan(angle2)*z;

            float yAngle = (float)Math.acos(dy / Math.sqrt(y2+z2));
            angle1 = ImageMath.HALF_PI - yAngle;
            angle2 = (float)Math.asin(Math.sin(angle1)*rRefraction);
            angle2 = ImageMath.HALF_PI - yAngle - angle2;
            out[1] = y - (float)Math.tan(angle2)*z;
        }
    }

    public String toString() {
        return "Distort/Sphere...";
    }

}

*s27.postimg.org/ybc9d7kfz/Sphere.jpg

SwimFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:13 PM
 * To change this template use File | Settings | File Templates.
 */

import com.jhlabs.math.Noise;

/**
 * A filter which distorts an image as if it were underwater.
 */
public class SwimFilter extends TransformFilter {

    private float scale = 32;
    private float stretch = 1.0f;
    private float angle = 0.0f;
    private float amount = 1.0f;
    private float turbulence = 1.0f;
    private float time = 0.0f;
    private float m00 = 1.0f;
    private float m01 = 0.0f;
    private float m10 = 0.0f;
    private float m11 = 1.0f;

    public SwimFilter() {
    }

    /**
     * Set the amount of swim.
     * [MENTION=9956]PARAM[/MENTION] amount the amount of swim
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 100+
     * [MENTION=288550]see[/MENTION] #getAmount
     */
    public void setAmount(float amount) {
        this.amount = amount;
    }

    /**
     * Get the amount of swim.
     * @return the amount swim
     * [MENTION=288550]see[/MENTION] #setAmount
     */
    public float getAmount() {
        return amount;
    }

    /**
     * Specifies the scale of the distortion.
     * [MENTION=9956]PARAM[/MENTION] scale the scale of the distortion.
     * @min-value 1
     * [MENTION=56127]max[/MENTION]-value 300+
     * [MENTION=288550]see[/MENTION] #getScale
     */
    public void setScale(float scale) {
        this.scale = scale;
    }

    /**
     * Returns the scale of the distortion.
     * @return the scale of the distortion.
     * [MENTION=288550]see[/MENTION] #setScale
     */
    public float getScale() {
        return scale;
    }

    /**
     * Specifies the stretch factor of the distortion.
     * [MENTION=9956]PARAM[/MENTION] stretch the stretch factor of the distortion.
     * @min-value 1
     * [MENTION=56127]max[/MENTION]-value 50+
     * [MENTION=288550]see[/MENTION] #getStretch
     */
    public void setStretch(float stretch) {
        this.stretch = stretch;
    }

    /**
     * Returns the stretch factor of the distortion.
     * @return the stretch factor of the distortion.
     * [MENTION=288550]see[/MENTION] #setStretch
     */
    public float getStretch() {
        return stretch;
    }

    /**
     * Specifies the angle of the effect.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of the effect.
     * @angle
     * [MENTION=288550]see[/MENTION] #getAngle
     */
    public void setAngle(float angle) {
        this.angle = angle;
        float cos = (float)Math.cos(angle);
        float sin = (float)Math.sin(angle);
        m00 = cos;
        m01 = sin;
        m10 = -sin;
        m11 = cos;
    }

    /**
     * Returns the angle of the effect.
     * @return the angle of the effect.
     * [MENTION=288550]see[/MENTION] #setAngle
     */
    public float getAngle() {
        return angle;
    }

    /**
     * Specifies the turbulence of the texture.
     * [MENTION=9956]PARAM[/MENTION] turbulence the turbulence of the texture.
     * @min-value 0
     * [MENTION=56127]max[/MENTION]-value 1
     * [MENTION=288550]see[/MENTION] #getTurbulence
     */
    public void setTurbulence(float turbulence) {
        this.turbulence = turbulence;
    }

    /**
     * Returns the turbulence of the effect.
     * @return the turbulence of the effect.
     * [MENTION=288550]see[/MENTION] #setTurbulence
     */
    public float getTurbulence() {
        return turbulence;
    }

    /**
     * Specifies the time. Use this to animate the effect.
     * [MENTION=9956]PARAM[/MENTION] time the time.
     * @angle
     * [MENTION=288550]see[/MENTION] #getTime
     */
    public void setTime(float time) {
        this.time = time;
    }

    /**
     * Returns the time.
     * @return the time.
     * [MENTION=288550]see[/MENTION] #setTime
     */
    public float getTime() {
        return time;
    }

    protected void transformInverse(int x, int y, float[] out) {
        float nx = m00*x + m01*y;
        float ny = m10*x + m11*y;
        nx /= scale;
        ny /= scale * stretch;

        if ( turbulence == 1.0f ) {
            out[0] = x + amount * Noise.noise3(nx + 0.5f, ny, time);
            out[1] = y + amount * Noise.noise3(nx, ny+0.5f, time);
        } else {
            out[0] = x + amount * Noise.turbulence3(nx+0.5f, ny, turbulence, time);
            out[1] = y + amount * Noise.turbulence3(nx, ny+0.5f, turbulence, time);
        }
    }

    public String toString() {
        return "Distort/Swim...";
    }
}

ThresholdFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:14 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * A filter which performs a threshold operation on an image.
 */
public class ThresholdFilter extends PointFilter {

    private int lowerThreshold;
    private int upperThreshold;
    private int white = 0xffffff;
    private int black = 0x000000;

    /**
     * Construct a ThresholdFilter.
     */
    public ThresholdFilter() {
        this(127);
    }

    /**
     * Construct a ThresholdFilter.
     * [MENTION=9956]PARAM[/MENTION] t the threshold value
     */
    public ThresholdFilter(int t) {
        setLowerThreshold(t);
        setUpperThreshold(t);
    }

    /**
     * Set the lower threshold value.
     * [MENTION=9956]PARAM[/MENTION] lowerThreshold the threshold value
     * [MENTION=288550]see[/MENTION] #getLowerThreshold
     */
    public void setLowerThreshold(int lowerThreshold) {
        this.lowerThreshold = lowerThreshold;
    }

    /**
     * Get the lower threshold value.
     * @return the threshold value
     * [MENTION=288550]see[/MENTION] #setLowerThreshold
     */
    public int getLowerThreshold() {
        return lowerThreshold;
    }

    /**
     * Set the upper threshold value.
     * [MENTION=9956]PARAM[/MENTION] upperThreshold the threshold value
     * [MENTION=288550]see[/MENTION] #getUpperThreshold
     */
    public void setUpperThreshold(int upperThreshold) {
        this.upperThreshold = upperThreshold;
    }

    /**
     * Get the upper threshold value.
     * @return the threshold value
     * [MENTION=288550]see[/MENTION] #setUpperThreshold
     */
    public int getUpperThreshold() {
        return upperThreshold;
    }

    /**
     * Set the color to be used for pixels above the upper threshold.
     * [MENTION=9956]PARAM[/MENTION] white the color
     * [MENTION=288550]see[/MENTION] #getWhite
     */
    public void setWhite(int white) {
        this.white = white;
    }

    /**
     * Get the color to be used for pixels above the upper threshold.
     * @return the color
     * [MENTION=288550]see[/MENTION] #setWhite
     */
    public int getWhite() {
        return white;
    }

    /**
     * Set the color to be used for pixels below the lower threshold.
     * [MENTION=9956]PARAM[/MENTION] black the color
     * [MENTION=288550]see[/MENTION] #getBlack
     */
    public void setBlack(int black) {
        this.black = black;
    }

    /**
     * Set the color to be used for pixels below the lower threshold.
     * @return the color
     * [MENTION=288550]see[/MENTION] #setBlack
     */
    public int getBlack() {
        return black;
    }

    public int filterRGB(int x, int y, int rgb) {
        int v = PixelUtils.brightness( rgb );
        float f = ImageMath.smoothStep( lowerThreshold, upperThreshold, v );
        return (rgb & 0xff000000) | (ImageMath.mixColors( f, black, white ) & 0xffffff);
    }

    public String toString() {
        return "Stylize/Threshold...";
    }
}

*s30.postimg.org/f5cuf7q3x/Threshold.jpg

TileImageFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:15 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.image.*;

/**
 * A filter which tiles an image into a lerger one.
 */
public class TileImageFilter extends AbstractBufferedImageOp {

    private int width;
    private int height;
    private int tileWidth;
    private int tileHeight;

    /**
     * Construct a TileImageFilter.
     */
    public TileImageFilter() {
        this(32, 32);
    }

    /**
     * Construct a TileImageFilter.
     * [MENTION=9956]PARAM[/MENTION] width the output image width
     * [MENTION=9956]PARAM[/MENTION] height the output image height
     */
    public TileImageFilter(int width, int height) {
        this.width = width;
        this.height = height;
    }

    /**
     * Set the output image width.
     * [MENTION=9956]PARAM[/MENTION] width the width
     * [MENTION=288550]see[/MENTION] #getWidth
     */
    public void setWidth(int width) {
        this.width = width;
    }

    /**
     * Get the output image width.
     * @return the width
     * [MENTION=288550]see[/MENTION] #setWidth
     */
    public int getWidth() {
        return width;
    }

    /**
     * Set the output image height.
     * [MENTION=9956]PARAM[/MENTION] height the height
     * [MENTION=288550]see[/MENTION] #getHeight
     */
    public void setHeight(int height) {
        this.height = height;
    }

    /**
     * Get the output image height.
     * @return the height
     * [MENTION=288550]see[/MENTION] #setHeight
     */
    public int getHeight() {
        return height;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int tileWidth = src.getWidth();
        int tileHeight = src.getHeight();

        if ( dst == null ) {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(width, height), dstCM.isAlphaPremultiplied(), null);
        }

        Graphics2D g = dst.createGraphics();
        for ( int y = 0; y < height; y += tileHeight) {
            for ( int x = 0; x < width; x += tileWidth ) {
                g.drawImage( src, null, x, y );
            }
        }
        g.dispose();

        return dst;
    }

    public String toString() {
        return "Tile";
    }
}

*s30.postimg.org/6bv4plhwt/Tile.jpg

TransferFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:11 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;

public abstract class TransferFilter extends PointFilter {

    protected int[] rTable, gTable, bTable;
    protected boolean initialized = false;

    public TransferFilter() {
        canFilterIndexColorModel = true;
    }

    public int filterRGB(int x, int y, int rgb) {
        int a = rgb & 0xff000000;
        int r = (rgb >> 16) & 0xff;
        int g = (rgb >> 8) & 0xff;
        int b = rgb & 0xff;
        r = rTable[r];
        g = gTable[g];
        b = bTable[b];
        return a | (r << 16) | (g << 8) | b;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        if (!initialized)
            initialize();
        return super.filter( src, dst );
    }

    protected void initialize() {
        initialized = true;
        rTable = gTable = bTable = makeTable();
    }

    protected int[] makeTable() {
        int[] table = new int[256];
        for (int i = 0; i < 256; i++)
            table[i] = PixelUtils.clamp( (int)( 255 * transferFunction( i / 255.0f ) ) );
        return table;
    }

    protected float transferFunction( float v ) {
        return 0;
    }

    public int[] getLUT() {
        if (!initialized)
            initialize();
        int[] lut = new int[256];
        for ( int i = 0; i < 256; i++ ) {
            lut[i] = filterRGB( 0, 0, (i << 24) | (i << 16) | (i << 8) | i );
        }
        return lut;
    }

}

TransformFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:37 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.image.*;

/**
 * An abstract superclass for filters which distort images in some way. The subclass only needs to override
 * two methods to provide the mapping between source and destination pixels.
 */
public abstract class TransformFilter extends AbstractBufferedImageOp {

    /**
     * Treat pixels off the edge as zero.
     */
    public final static int ZERO = 0;

    /**
     * Clamp pixels to the image edges.
     */
    public final static int CLAMP = 1;

    /**
     * Wrap pixels off the edge onto the oppsoite edge.
     */
    public final static int WRAP = 2;

    /**
     * Clamp pixels RGB to the image edges, but zero the alpha. This prevents gray borders on your image.
     */
    public final static int RGB_CLAMP = 3;

    /**
     * Use nearest-neighbout interpolation.
     */
    public final static int NEAREST_NEIGHBOUR = 0;

    /**
     * Use bilinear interpolation.
     */
    public final static int BILINEAR = 1;

    /**
     * The action to take for pixels off the image edge.
     */
    protected int edgeAction = RGB_CLAMP;

    /**
     * The type of interpolation to use.
     */
    protected int interpolation = BILINEAR;

    /**
     * The output image rectangle.
     */
    protected Rectangle transformedSpace;

    /**
     * The input image rectangle.
     */
    protected Rectangle originalSpace;

    /**
     * Set the action to perform for pixels off the edge of the image.
     * [MENTION=9956]PARAM[/MENTION] edgeAction one of ZERO, CLAMP or WRAP
     * [MENTION=288550]see[/MENTION] #getEdgeAction
     */
    public void setEdgeAction(int edgeAction) {
        this.edgeAction = edgeAction;
    }

    /**
     * Get the action to perform for pixels off the edge of the image.
     * @return one of ZERO, CLAMP or WRAP
     * [MENTION=288550]see[/MENTION] #setEdgeAction
     */
    public int getEdgeAction() {
        return edgeAction;
    }

    /**
     * Set the type of interpolation to perform.
     * [MENTION=9956]PARAM[/MENTION] interpolation one of NEAREST_NEIGHBOUR or BILINEAR
     * [MENTION=288550]see[/MENTION] #getInterpolation
     */
    public void setInterpolation(int interpolation) {
        this.interpolation = interpolation;
    }

    /**
     * Get the type of interpolation to perform.
     * @return one of NEAREST_NEIGHBOUR or BILINEAR
     * [MENTION=288550]see[/MENTION] #setInterpolation
     */
    public int getInterpolation() {
        return interpolation;
    }

    /**
     * Inverse transform a point. This method needs to be overriden by all subclasses.
     * [MENTION=9956]PARAM[/MENTION] x the X position of the pixel in the output image
     * [MENTION=9956]PARAM[/MENTION] y the Y position of the pixel in the output image
     * [MENTION=9956]PARAM[/MENTION] out the position of the pixel in the input image
     */
    protected abstract void transformInverse(int x, int y, float[] out);

    /**
     * Forward transform a rectangle. Used to determine the size of the output image.
     * [MENTION=9956]PARAM[/MENTION] rect the rectangle to transform
     */
    protected void transformSpace(Rectangle rect) {
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        int type = src.getType();
        WritableRaster srcRaster = src.getRaster();

        originalSpace = new Rectangle(0, 0, width, height);
        transformedSpace = new Rectangle(0, 0, width, height);
        transformSpace(transformedSpace);

        if ( dst == null ) {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null);
        }
        WritableRaster dstRaster = dst.getRaster();

        int[] inPixels = getRGB( src, 0, 0, width, height, null );

        if ( interpolation == NEAREST_NEIGHBOUR )
            return filterPixelsNN( dst, width, height, inPixels, transformedSpace );

        int srcWidth = width;
        int srcHeight = height;
        int srcWidth1 = width-1;
        int srcHeight1 = height-1;
        int outWidth = transformedSpace.width;
        int outHeight = transformedSpace.height;
        int outX, outY;
        int index = 0;
        int[] outPixels = new int[outWidth];

        outX = transformedSpace.x;
        outY = transformedSpace.y;
        float[] out = new float[2];

        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(outX+x, outY+y, out);
                int srcX = (int)Math.floor( out[0] );
                int srcY = (int)Math.floor( out[1] );
                float xWeight = out[0]-srcX;
                float yWeight = out[1]-srcY;
                int nw, ne, sw, se;

                if ( srcX >= 0 && srcX < srcWidth1 && srcY >= 0 && srcY < srcHeight1) {
                    // Easy case, all corners are in the image
                    int i = srcWidth*srcY + srcX;
                    nw = inPixels[i];
                    ne = inPixels[i+1];
                    sw = inPixels[i+srcWidth];
                    se = inPixels[i+srcWidth+1];
                } else {
                    // Some of the corners are off the image
                    nw = getPixel( inPixels, srcX, srcY, srcWidth, srcHeight );
                    ne = getPixel( inPixels, srcX+1, srcY, srcWidth, srcHeight );
                    sw = getPixel( inPixels, srcX, srcY+1, srcWidth, srcHeight );
                    se = getPixel( inPixels, srcX+1, srcY+1, srcWidth, srcHeight );
                }
                outPixels[x] = ImageMath.bilinearInterpolate(xWeight, yWeight, nw, ne, sw, se);
            }
            setRGB( dst, 0, y, transformedSpace.width, 1, outPixels );
        }
        return dst;
    }

    final private int getPixel( int[] pixels, int x, int y, int width, int height ) {
        if (x < 0 || x >= width || y < 0 || y >= height) {
            switch (edgeAction) {
                case ZERO:
                default:
                    return 0;
                case WRAP:
                    return pixels[(ImageMath.mod(y, height) * width) + ImageMath.mod(x, width)];
                case CLAMP:
                    return pixels[(ImageMath.clamp(y, 0, height-1) * width) + ImageMath.clamp(x, 0, width-1)];
                case RGB_CLAMP:
                    return pixels[(ImageMath.clamp(y, 0, height-1) * width) + ImageMath.clamp(x, 0, width-1)] & 0x00ffffff;
            }
        }
        return pixels[ y*width+x ];
    }

    protected BufferedImage filterPixelsNN( BufferedImage dst, int width, int height, int[] inPixels, Rectangle transformedSpace ) {
        int srcWidth = width;
        int srcHeight = height;
        int outWidth = transformedSpace.width;
        int outHeight = transformedSpace.height;
        int outX, outY, srcX, srcY;
        int[] outPixels = new int[outWidth];

        outX = transformedSpace.x;
        outY = transformedSpace.y;
        int[] rgb = new int[4];
        float[] out = new float[2];

        for (int y = 0; y < outHeight; y++) {
            for (int x = 0; x < outWidth; x++) {
                transformInverse(outX+x, outY+y, out);
                srcX = (int)out[0];
                srcY = (int)out[1];
                // int casting rounds towards zero, so we check out[0] < 0, not srcX < 0
                if (out[0] < 0 || srcX >= srcWidth || out[1] < 0 || srcY >= srcHeight) {
                    int p;
                    switch (edgeAction) {
                        case ZERO:
                        default:
                            p = 0;
                            break;
                        case WRAP:
                            p = inPixels[(ImageMath.mod(srcY, srcHeight) * srcWidth) + ImageMath.mod(srcX, srcWidth)];
                            break;
                        case CLAMP:
                            p = inPixels[(ImageMath.clamp(srcY, 0, srcHeight-1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth-1)];
                            break;
                        case RGB_CLAMP:
                            p = inPixels[(ImageMath.clamp(srcY, 0, srcHeight-1) * srcWidth) + ImageMath.clamp(srcX, 0, srcWidth-1)] & 0x00ffffff;
                    }
                    outPixels[x] = p;
                } else {
                    int i = srcWidth*srcY + srcX;
                    rgb[0] = inPixels[i];
                    outPixels[x] = inPixels[i];
                }
            }
            setRGB( dst, 0, y, transformedSpace.width, 1, outPixels );
        }
        return dst;
    }

}

TwirlFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:38 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.geom.Point2D;
import java.awt.image.*;

/**
 * A Filter which distorts an image by twisting it from the centre out.
 * The twisting is centred at the centre of the image and extends out to the smallest of
 * the width and height. Pixels outside this radius are unaffected.
 */
public class TwirlFilter extends TransformFilter {

    private float angle = 0;
    private float centreX = 0.5f;
    private float centreY = 0.5f;
    private float radius = 100;

    private float radius2 = 0;
    private float icentreX;
    private float icentreY;

    /**
     * Construct a TwirlFilter with no distortion.
     */
    public TwirlFilter() {
        setEdgeAction( CLAMP );
    }

    /**
     * Set the angle of twirl in radians. 0 means no distortion.
     * [MENTION=9956]PARAM[/MENTION] angle the angle of twirl. This is the angle by which pixels at the nearest edge of the image will move.
     * [MENTION=288550]see[/MENTION] #getAngle
     */
    public void setAngle(float angle) {
        this.angle = angle;
    }

    /**
     * Get the angle of twist.
     * @return the angle in radians.
     * [MENTION=288550]see[/MENTION] #setAngle
     */
    public float getAngle() {
        return angle;
    }

    /**
     * Set the centre of the effect in the X direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreX the center
     * [MENTION=288550]see[/MENTION] #getCentreX
     */
    public void setCentreX( float centreX ) {
        this.centreX = centreX;
    }

    /**
     * Get the centre of the effect in the X direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreX
     */
    public float getCentreX() {
        return centreX;
    }

    /**
     * Set the centre of the effect in the Y direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreY the center
     * [MENTION=288550]see[/MENTION] #getCentreY
     */
    public void setCentreY( float centreY ) {
        this.centreY = centreY;
    }

    /**
     * Get the centre of the effect in the Y direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreY
     */
    public float getCentreY() {
        return centreY;
    }

    /**
     * Set the centre of the effect as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centre the center
     * [MENTION=288550]see[/MENTION] #getCentre
     */
    public void setCentre( Point2D centre ) {
        this.centreX = (float)centre.getX();
        this.centreY = (float)centre.getY();
    }

    /**
     * Get the centre of the effect as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentre
     */
    public Point2D getCentre() {
        return new Point2D.Float( centreX, centreY );
    }

    /**
     * Set the radius of the effect.
     * [MENTION=9956]PARAM[/MENTION] radius the radius
     * @min-value 0
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(float radius) {
        this.radius = radius;
    }

    /**
     * Get the radius of the effect.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public float getRadius() {
        return radius;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        icentreX = src.getWidth() * centreX;
        icentreY = src.getHeight() * centreY;
        if ( radius == 0 )
            radius = Math.min(icentreX, icentreY);
        radius2 = radius*radius;
        return super.filter( src, dst );
    }

    protected void transformInverse(int x, int y, float[] out) {
        float dx = x-icentreX;
        float dy = y-icentreY;
        float distance = dx*dx + dy*dy;
        if (distance > radius2) {
            out[0] = x;
            out[1] = y;
        } else {
            distance = (float)Math.sqrt(distance);
            float a = (float)Math.atan2(dy, dx) + angle * (radius-distance) / radius;
            out[0] = icentreX + distance*(float)Math.cos(a);
            out[1] = icentreY + distance*(float)Math.sin(a);
        }
    }

    public String toString() {
        return "Distort/Twirl...";
    }

}

*s17.postimg.org/6kokrciuj/Twirl.jpg

WaterFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:38 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;

/**
 * A filter which produces a water ripple distortion.
 */
public class WaterFilter extends TransformFilter {

    private float wavelength = 16;
    private float amplitude = 10;
    private float phase = 0;
    private float centreX = 0.5f;
    private float centreY = 0.5f;
    private float radius = 50;

    private float radius2 = 0;
    private float icentreX;
    private float icentreY;

    public WaterFilter() {
        setEdgeAction( CLAMP );
    }

    /**
     * Set the wavelength of the ripples.
     * [MENTION=9956]PARAM[/MENTION] wavelength the wavelength
     * [MENTION=288550]see[/MENTION] #getWavelength
     */
    public void setWavelength(float wavelength) {
        this.wavelength = wavelength;
    }

    /**
     * Get the wavelength of the ripples.
     * @return the wavelength
     * [MENTION=288550]see[/MENTION] #setWavelength
     */
    public float getWavelength() {
        return wavelength;
    }

    /**
     * Set the amplitude of the ripples.
     * [MENTION=9956]PARAM[/MENTION] amplitude the amplitude
     * [MENTION=288550]see[/MENTION] #getAmplitude
     */
    public void setAmplitude(float amplitude) {
        this.amplitude = amplitude;
    }

    /**
     * Get the amplitude of the ripples.
     * @return the amplitude
     * [MENTION=288550]see[/MENTION] #setAmplitude
     */
    public float getAmplitude() {
        return amplitude;
    }

    /**
     * Set the phase of the ripples.
     * [MENTION=9956]PARAM[/MENTION] phase the phase
     * [MENTION=288550]see[/MENTION] #getPhase
     */
    public void setPhase(float phase) {
        this.phase = phase;
    }

    /**
     * Get the phase of the ripples.
     * @return the phase
     * [MENTION=288550]see[/MENTION] #setPhase
     */
    public float getPhase() {
        return phase;
    }

    /**
     * Set the centre of the effect in the X direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreX the center
     * [MENTION=288550]see[/MENTION] #getCentreX
     */
    public void setCentreX( float centreX ) {
        this.centreX = centreX;
    }

    /**
     * Get the centre of the effect in the X direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreX
     */
    public float getCentreX() {
        return centreX;
    }

    /**
     * Set the centre of the effect in the Y direction as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centreY the center
     * [MENTION=288550]see[/MENTION] #getCentreY
     */
    public void setCentreY( float centreY ) {
        this.centreY = centreY;
    }

    /**
     * Get the centre of the effect in the Y direction as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentreY
     */
    public float getCentreY() {
        return centreY;
    }

    /**
     * Set the centre of the effect as a proportion of the image size.
     * [MENTION=9956]PARAM[/MENTION] centre the center
     * [MENTION=288550]see[/MENTION] #getCentre
     */
    public void setCentre( Point2D centre ) {
        this.centreX = (float)centre.getX();
        this.centreY = (float)centre.getY();
    }

    /**
     * Get the centre of the effect as a proportion of the image size.
     * @return the center
     * [MENTION=288550]see[/MENTION] #setCentre
     */
    public Point2D getCentre() {
        return new Point2D.Float( centreX, centreY );
    }

    /**
     * Set the radius of the effect.
     * [MENTION=9956]PARAM[/MENTION] radius the radius
     * @min-value 0
     * [MENTION=288550]see[/MENTION] #getRadius
     */
    public void setRadius(float radius) {
        this.radius = radius;
    }

    /**
     * Get the radius of the effect.
     * @return the radius
     * [MENTION=288550]see[/MENTION] #setRadius
     */
    public float getRadius() {
        return radius;
    }

    private boolean inside(int v, int a, int b) {
        return a <= v && v <= b;
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        icentreX = src.getWidth() * centreX;
        icentreY = src.getHeight() * centreY;
        if ( radius == 0 )
            radius = Math.min(icentreX, icentreY);
        radius2 = radius*radius;
        return super.filter( src, dst );
    }

    protected void transformInverse(int x, int y, float[] out) {
        float dx = x-icentreX;
        float dy = y-icentreY;
        float distance2 = dx*dx + dy*dy;
        if (distance2 > radius2) {
            out[0] = x;
            out[1] = y;
        } else {
            float distance = (float)Math.sqrt(distance2);
            float amount = amplitude * (float)Math.sin(distance / wavelength * ImageMath.TWO_PI - phase);
            amount *= (radius-distance)/radius;
            if ( distance != 0 )
                amount *= wavelength/distance;
            out[0] = x + dx*amount;
            out[1] = y + dy*amount;
        }
    }

    public String toString() {
        return "Distort/Water Ripples...";
    }
}

*s27.postimg.org/5jeol7rjz/Water_Ripples.jpg

WholeImageFilter.java

Code:
package com.jhlabs.image;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:39 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.image.BufferedImage;
import java.awt.*;
import java.awt.image.*;

/**
 * A filter which acts as a superclass for filters which need to have the whole image in memory
 * to do their stuff.
 */
public abstract class WholeImageFilter extends AbstractBufferedImageOp {

    /**
     * The output image bounds.
     */
    protected Rectangle transformedSpace;

    /**
     * The input image bounds.
     */
    protected Rectangle originalSpace;

    /**
     * Construct a WholeImageFilter.
     */
    public WholeImageFilter() {
    }

    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
        int width = src.getWidth();
        int height = src.getHeight();
        int type = src.getType();
        WritableRaster srcRaster = src.getRaster();

        originalSpace = new Rectangle(0, 0, width, height);
        transformedSpace = new Rectangle(0, 0, width, height);
        transformSpace(transformedSpace);

        if ( dst == null ) {
            ColorModel dstCM = src.getColorModel();
            dst = new BufferedImage(dstCM, dstCM.createCompatibleWritableRaster(transformedSpace.width, transformedSpace.height), dstCM.isAlphaPremultiplied(), null);
        }
        WritableRaster dstRaster = dst.getRaster();

        int[] inPixels = getRGB( src, 0, 0, width, height, null );
        inPixels = filterPixels( width, height, inPixels, transformedSpace );
        setRGB( dst, 0, 0, transformedSpace.width, transformedSpace.height, inPixels );

        return dst;
    }

    /**
     * Calculate output bounds for given input bounds.
     * [MENTION=9956]PARAM[/MENTION] rect input and output rectangle
     */
    protected void transformSpace(Rectangle rect) {
    }

    /**
     * Actually filter the pixels.
     * [MENTION=9956]PARAM[/MENTION] width the image width
     * [MENTION=9956]PARAM[/MENTION] height the image height
     * [MENTION=9956]PARAM[/MENTION] inPixels the image pixels
     * [MENTION=9956]PARAM[/MENTION] transformedSpace the output bounds
     * @return the output pixels
     */
    protected abstract int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace );
}

The package "com.jhlabs.math" contains the Math classes

FFT.java

Code:
package com.jhlabs.math;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:40 PM
 * To change this template use File | Settings | File Templates.
 */
public class FFT {

    // Weighting factors
    protected float[] w1;
    protected float[] w2;
    protected float[] w3;

    public FFT( int logN ) {
        // Prepare the weighting factors
        w1 = new float[logN];
        w2 = new float[logN];
        w3 = new float[logN];
        int N = 1;
        for ( int k = 0; k < logN; k++ ) {
            N <<= 1;
            double angle = -2.0 * Math.PI / N;
            w1[k] = (float)Math.sin(0.5 * angle);
            w2[k] = -2.0f * w1[k] * w1[k];
            w3[k] = (float)Math.sin(angle);
        }
    }

    private void scramble( int n, float[] real, float[] imag ) {
        int j = 0;

        for ( int i = 0; i < n; i++ ) {
            if ( i > j ) {
                float t;
                t = real[j];
                real[j] = real[i];
                real[i] = t;
                t = imag[j];
                imag[j] = imag[i];
                imag[i] = t;
            }
            int m = n >> 1;
            while (j >= m && m >= 2) {
                j -= m;
                m >>= 1;
            }
            j += m;
        }
    }

    private void butterflies( int n, int logN, int direction, float[] real, float[] imag ) {
        int N = 1;

        for ( int k = 0; k < logN; k++ ) {
            float w_re, w_im, wp_re, wp_im, temp_re, temp_im, wt;
            int half_N = N;
            N <<= 1;
            wt = direction * w1[k];
            wp_re = w2[k];
            wp_im = direction * w3[k];
            w_re = 1.0f;
            w_im = 0.0f;
            for ( int offset = 0; offset < half_N; offset++ ) {
                for( int i = offset; i < n; i += N ) {
                    int j = i + half_N;
                    float re = real[j];
                    float im = imag[j];
                    temp_re = (w_re * re) - (w_im * im);
                    temp_im = (w_im * re) + (w_re * im);
                    real[j] = real[i] - temp_re;
                    real[i] += temp_re;
                    imag[j] = imag[i] - temp_im;
                    imag[i] += temp_im;
                }
                wt = w_re;
                w_re = wt * wp_re - w_im * wp_im + w_re;
                w_im = w_im * wp_re + wt * wp_im + w_im;
            }
        }
        if ( direction == -1 ) {
            float nr = 1.0f / n;
            for ( int i = 0; i < n; i++ ) {
                real[i] *= nr;
                imag[i] *= nr;
            }
        }
    }

    public void transform1D( float[] real, float[] imag, int logN, int n, boolean forward ) {
        scramble( n, real, imag );
        butterflies( n, logN, forward ? 1 : -1, real, imag );
    }

    public void transform2D( float[] real, float[] imag, int cols, int rows, boolean forward ) {
        int log2cols = log2(cols);
        int log2rows = log2(rows);
        int n = Math.max(rows, cols);
        float[] rtemp = new float[n];
        float[] itemp = new float[n];

        // FFT the rows
        for ( int y = 0; y < rows; y++ ) {
            int offset = y*cols;
            System.arraycopy( real, offset, rtemp, 0, cols );
            System.arraycopy( imag, offset, itemp, 0, cols );
            transform1D(rtemp, itemp, log2cols, cols, forward);
            System.arraycopy( rtemp, 0, real, offset, cols );
            System.arraycopy( itemp, 0, imag, offset, cols );
        }

        // FFT the columns
        for ( int x = 0; x < cols; x++ ) {
            int index = x;
            for ( int y = 0; y < rows; y++ ) {
                rtemp[y] = real[index];
                itemp[y] = imag[index];
                index += cols;
            }
            transform1D(rtemp, itemp, log2rows, rows, forward);
            index = x;
            for ( int y = 0; y < rows; y++ ) {
                real[index] = rtemp[y];
                imag[index] = itemp[y];
                index += cols;
            }
        }
    }

    private int log2( int n ) {
        int m = 1;
        int log2n = 0;

        while (m < n) {
            m *= 2;
            log2n++;
        }
        return m == n ? log2n : -1;
    }

}

Function1D.java

Code:
package com.jhlabs.math;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:41 PM
 * To change this template use File | Settings | File Templates.
 */

public interface Function1D {
    public float evaluate(float v);
}

Function2D.java

Code:
package com.jhlabs.math;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:41 PM
 * To change this template use File | Settings | File Templates.
 */
public interface Function2D {
    public float evaluate(float x, float y);
}

Function3D.java

Code:
package com.jhlabs.math;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:42 PM
 * To change this template use File | Settings | File Templates.
 */
public interface Function3D {
    public float evaluate(float x, float y, float z);
}

ImageFunction2D.java

Code:
package com.jhlabs.math;

import java.awt.*;
import java.awt.image.*;
import com.jhlabs.image.*;

public class ImageFunction2D implements Function2D {

	public final static int ZERO = 0;
	public final static int CLAMP = 1;
	public final static int WRAP = 2;

	protected int[] pixels;
	protected int width;
	protected int height;
	protected int edgeAction = ZERO;
	protected boolean alpha = false;

	public ImageFunction2D(BufferedImage image) {
		this(image, false);
	}

	public ImageFunction2D(BufferedImage image, boolean alpha) {
		this(image, ZERO, alpha);
	}

	public ImageFunction2D(BufferedImage image, int edgeAction, boolean alpha) {
		init( getRGB( image, 0, 0, image.getWidth(), image.getHeight(), null), image.getWidth(), image.getHeight(), edgeAction, alpha);
	}

	public ImageFunction2D(int[] pixels, int width, int height, int edgeAction, boolean alpha) {
		init(pixels, width, height, edgeAction, alpha);
	}

 	public ImageFunction2D(Image image) {
		this( image, ZERO, false );
 	}

	public ImageFunction2D(Image image, int edgeAction, boolean alpha) {
 		PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, null, 0, -1);
 		try {
 			pg.grabPixels();
 		} catch (InterruptedException e) {
 			throw new RuntimeException("interrupted waiting for pixels!");
 		}
 		if ((pg.status() & ImageObserver.ABORT) != 0) {
 			throw new RuntimeException("image fetch aborted");
 		}
 		init((int[])pg.getPixels(), pg.getWidth(), pg.getHeight(), edgeAction, alpha);
  	}

	/**
	 * A convenience method for getting ARGB pixels from an image. This tries to avoid the performance
	 * penalty of BufferedImage.getRGB unmanaging the image.
	 */
	public int[] getRGB( BufferedImage image, int x, int y, int width, int height, int[] pixels ) {
		int type = image.getType();
		if ( type == BufferedImage.TYPE_INT_ARGB || type == BufferedImage.TYPE_INT_RGB )
			return (int [])image.getRaster().getDataElements( x, y, width, height, pixels );
		return image.getRGB( x, y, width, height, pixels, 0, width );
    }

	public void init(int[] pixels, int width, int height, int edgeAction, boolean alpha) {
		this.pixels = pixels;
		this.width = width;
		this.height = height;
		this.edgeAction = edgeAction;
		this.alpha = alpha;
	}

	public float evaluate(float x, float y) {
		int ix = (int)x;
		int iy = (int)y;
		if (edgeAction == WRAP) {
			ix = ImageMath.mod(ix, width);
			iy = ImageMath.mod(iy, height);
		} else if (ix < 0 || iy < 0 || ix >= width || iy >= height) {
			if (edgeAction == ZERO)
				return 0;
			if (ix < 0)
				ix = 0;
			else if (ix >= width)
				ix = width-1;
			if (iy < 0)
				iy = 0;
			else if (iy >= height)
				iy = height-1;
		}
		return alpha ? ((pixels[iy*width+ix] >> 24) & 0xff) / 255.0f : PixelUtils.brightness(pixels[iy*width+ix]) / 255.0f;
	}

	public void setEdgeAction(int edgeAction) {
		this.edgeAction = edgeAction;
	}

	public int getEdgeAction() {
		return edgeAction;
	}

	public int getWidth() {
		return width;
	}

	public int getHeight() {
		return height;
	}

	public int[] getPixels() {
		return pixels;
	}
}

Noise.java

Code:
package com.jhlabs.math;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:42 PM
 * To change this template use File | Settings | File Templates.
 */

import java.util.Random;
/**
 * Perlin Noise functions
 */
public class Noise implements Function1D, Function2D, Function3D {

    private static Random randomGenerator = new Random();

    public float evaluate(float x) {
        return noise1(x);
    }

    public float evaluate(float x, float y) {
        return noise2(x, y);
    }

    public float evaluate(float x, float y, float z) {
        return noise3(x, y, z);
    }

    /**
     * Compute turbulence using Perlin noise.
     * [MENTION=9956]PARAM[/MENTION] x the x value
     * [MENTION=9956]PARAM[/MENTION] y the y value
     * [MENTION=9956]PARAM[/MENTION] octaves number of octaves of turbulence
     * @return turbulence value at (x,y)
     */
    public static float turbulence2(float x, float y, float octaves) {
        float t = 0.0f;

        for (float f = 1.0f; f <= octaves; f *= 2)
            t += Math.abs(noise2(f * x, f * y)) / f;
        return t;
    }

    /**
     * Compute turbulence using Perlin noise.
     * [MENTION=9956]PARAM[/MENTION] x the x value
     * [MENTION=9956]PARAM[/MENTION] y the y value
     * [MENTION=9956]PARAM[/MENTION] octaves number of octaves of turbulence
     * @return turbulence value at (x,y)
     */
    public static float turbulence3(float x, float y, float z, float octaves) {
        float t = 0.0f;

        for (float f = 1.0f; f <= octaves; f *= 2)
            t += Math.abs(noise3(f * x, f * y, f * z)) / f;
        return t;
    }

    private final static int B = 0x100;
    private final static int BM = 0xff;
    private final static int N = 0x1000;

    static int[] p = new int[B + B + 2];
    static float[][] g3 = new float[B + B + 2][3];
    static float[][] g2 = new float[B + B + 2][2];
    static float[] g1 = new float[B + B + 2];
    static boolean start = true;

    private static float sCurve(float t) {
        return t * t * (3.0f - 2.0f * t);
    }

    /**
     * Compute 1-dimensional Perlin noise.
     * [MENTION=9956]PARAM[/MENTION] x the x value
     * @return noise value at x in the range -1..1
     */
    public static float noise1(float x) {
        int bx0, bx1;
        float rx0, rx1, sx, t, u, v;

        if (start) {
            start = false;
            init();
        }

        t = x + N;
        bx0 = ((int)t) & BM;
        bx1 = (bx0+1) & BM;
        rx0 = t - (int)t;
        rx1 = rx0 - 1.0f;

        sx = sCurve(rx0);

        u = rx0 * g1[p[bx0]];
        v = rx1 * g1[p[bx1]];
        return 2.3f*lerp(sx, u, v);
    }

    /**
     * Compute 2-dimensional Perlin noise.
     * [MENTION=9956]PARAM[/MENTION] x the x coordinate
     * [MENTION=9956]PARAM[/MENTION] y the y coordinate
     * @return noise value at (x,y)
     */
    public static float noise2(float x, float y) {
        int bx0, bx1, by0, by1, b00, b10, b01, b11;
        float rx0, rx1, ry0, ry1, q[], sx, sy, a, b, t, u, v;
        int i, j;

        if (start) {
            start = false;
            init();
        }

        t = x + N;
        bx0 = ((int)t) & BM;
        bx1 = (bx0+1) & BM;
        rx0 = t - (int)t;
        rx1 = rx0 - 1.0f;

        t = y + N;
        by0 = ((int)t) & BM;
        by1 = (by0+1) & BM;
        ry0 = t - (int)t;
        ry1 = ry0 - 1.0f;

        i = p[bx0];
        j = p[bx1];

        b00 = p[i + by0];
        b10 = p[j + by0];
        b01 = p[i + by1];
        b11 = p[j + by1];

        sx = sCurve(rx0);
        sy = sCurve(ry0);

        q = g2[b00]; u = rx0 * q[0] + ry0 * q[1];
        q = g2[b10]; v = rx1 * q[0] + ry0 * q[1];
        a = lerp(sx, u, v);

        q = g2[b01]; u = rx0 * q[0] + ry1 * q[1];
        q = g2[b11]; v = rx1 * q[0] + ry1 * q[1];
        b = lerp(sx, u, v);

        return 1.5f*lerp(sy, a, b);
    }

    /**
     * Compute 3-dimensional Perlin noise.
     * [MENTION=9956]PARAM[/MENTION] x the x coordinate
     * [MENTION=9956]PARAM[/MENTION] y the y coordinate
     * [MENTION=9956]PARAM[/MENTION] y the y coordinate
     * @return noise value at (x,y,z)
     */
    public static float noise3(float x, float y, float z) {
        int bx0, bx1, by0, by1, bz0, bz1, b00, b10, b01, b11;
        float rx0, rx1, ry0, ry1, rz0, rz1, q[], sy, sz, a, b, c, d, t, u, v;
        int i, j;

        if (start) {
            start = false;
            init();
        }

        t = x + N;
        bx0 = ((int)t) & BM;
        bx1 = (bx0+1) & BM;
        rx0 = t - (int)t;
        rx1 = rx0 - 1.0f;

        t = y + N;
        by0 = ((int)t) & BM;
        by1 = (by0+1) & BM;
        ry0 = t - (int)t;
        ry1 = ry0 - 1.0f;

        t = z + N;
        bz0 = ((int)t) & BM;
        bz1 = (bz0+1) & BM;
        rz0 = t - (int)t;
        rz1 = rz0 - 1.0f;

        i = p[bx0];
        j = p[bx1];

        b00 = p[i + by0];
        b10 = p[j + by0];
        b01 = p[i + by1];
        b11 = p[j + by1];

        t  = sCurve(rx0);
        sy = sCurve(ry0);
        sz = sCurve(rz0);

        q = g3[b00 + bz0]; u = rx0 * q[0] + ry0 * q[1] + rz0 * q[2];
        q = g3[b10 + bz0]; v = rx1 * q[0] + ry0 * q[1] + rz0 * q[2];
        a = lerp(t, u, v);

        q = g3[b01 + bz0]; u = rx0 * q[0] + ry1 * q[1] + rz0 * q[2];
        q = g3[b11 + bz0]; v = rx1 * q[0] + ry1 * q[1] + rz0 * q[2];
        b = lerp(t, u, v);

        c = lerp(sy, a, b);

        q = g3[b00 + bz1]; u = rx0 * q[0] + ry0 * q[1] + rz1 * q[2];
        q = g3[b10 + bz1]; v = rx1 * q[0] + ry0 * q[1] + rz1 * q[2];
        a = lerp(t, u, v);

        q = g3[b01 + bz1]; u = rx0 * q[0] + ry1 * q[1] + rz1 * q[2];
        q = g3[b11 + bz1]; v = rx1 * q[0] + ry1 * q[1] + rz1 * q[2];
        b = lerp(t, u, v);

        d = lerp(sy, a, b);

        return 1.5f*lerp(sz, c, d);
    }

    public static float lerp(float t, float a, float b) {
        return a + t * (b - a);
    }

    private static void normalize2(float v[]) {
        float s = (float)Math.sqrt(v[0] * v[0] + v[1] * v[1]);
        v[0] = v[0] / s;
        v[1] = v[1] / s;
    }

    static void normalize3(float v[]) {
        float s = (float)Math.sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
        v[0] = v[0] / s;
        v[1] = v[1] / s;
        v[2] = v[2] / s;
    }

    private static int random() {
        return randomGenerator.nextInt() & 0x7fffffff;
    }

    private static void init() {
        int i, j, k;

        for (i = 0; i < B; i++) {
            p[i] = i;

            g1[i] = (float)((random() % (B + B)) - B) / B;

            for (j = 0; j < 2; j++)
                g2[i][j] = (float)((random() % (B + B)) - B) / B;
            normalize2(g2[i]);

            for (j = 0; j < 3; j++)
                g3[i][j] = (float)((random() % (B + B)) - B) / B;
            normalize3(g3[i]);
        }

        for (i = B-1; i >= 0; i--) {
            k = p[i];
            p[i] = p[j = random() % B];
            p[j] = k;
        }

        for (i = 0; i < B + 2; i++) {
            p[B + i] = p[i];
            g1[B + i] = g1[i];
            for (j = 0; j < 2; j++)
                g2[B + i][j] = g2[i][j];
            for (j = 0; j < 3; j++)
                g3[B + i][j] = g3[i][j];
        }
    }

    /**
     * Returns the minimum and maximum of a number of random values
     * of the given function. This is useful for making some stab at
     * normalising the function.
     */
    public static float[] findRange(Function1D f, float[] minmax) {
        if (minmax == null)
            minmax = new float[2];
        float min = 0, max = 0;
        // Some random numbers here...
        for (float x = -100; x < 100; x += 1.27139) {
            float n = f.evaluate(x);
            min = Math.min(min, n);
            max = Math.max(max, n);
        }
        minmax[0] = min;
        minmax[1] = max;
        return minmax;
    }

    /**
     * Returns the minimum and maximum of a number of random values
     * of the given function. This is useful for making some stab at
     * normalising the function.
     */
    public static float[] findRange(Function2D f, float[] minmax) {
        if (minmax == null)
            minmax = new float[2];
        float min = 0, max = 0;
        // Some random numbers here...
        for (float y = -100; y < 100; y += 10.35173) {
            for (float x = -100; x < 100; x += 10.77139) {
                float n = f.evaluate(x, y);
                min = Math.min(min, n);
                max = Math.max(max, n);
            }
        }
        minmax[0] = min;
        minmax[1] = max;
        return minmax;
    }

}

The package "com.jhlabs.vecmath" contains the Vecmath classes & functions

AxisAngle4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class AxisAngle4f {
	public float x, y, z, angle;

	public AxisAngle4f() {
		this( 0, 0, 0, 0 );
	}
	
	public AxisAngle4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.angle = x[2];
	}

	public AxisAngle4f( float x, float y, float z, float angle ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.angle = angle;
	}

	public AxisAngle4f( AxisAngle4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.angle = t.angle;
	}

	public AxisAngle4f( Vector3f v, float angle ) {
		this.x = v.x;
		this.y = v.y;
		this.z = v.z;
		this.angle = angle;
	}

	public void set( float x, float y, float z, float angle ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.angle = angle;
	}

	public void set( AxisAngle4f t ) {
		x = t.x;
		y = t.y;
		z = t.z;
		angle = t.angle;
	}

	public void get( AxisAngle4f t ) {
		t.x = x;
		t.y = y;
		t.z = z;
		t.angle = angle;
	}

	public void get( float[] t ) {
		t[0] = x;
		t[1] = y;
		t[2] = z;
		t[3] = angle;
	}

	public String toString() {
		return "["+x+", "+y+", "+z+", "+angle+"]";
	}
	
}

Color4f.java

Code:
package com.jhlabs.vecmath;

import java.awt.*;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Color4f extends Tuple4f {

	public Color4f() {
		this( 0, 0, 0, 0 );
	}
	
	public Color4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[3];
	}

	public Color4f( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public Color4f( Color4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public Color4f( Tuple4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public Color4f( Color c ) {
		set( c );
	}

	public void set( Color c ) {
		set( c.getRGBComponents( null ) );
	}

	public Color get() {
		return new Color( x, y, z, w );
	}
}

Matrix4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Matrix4f {
	public float m00, m01, m02, m03;
	public float m10, m11, m12, m13;
	public float m20, m21, m22, m23;
	public float m30, m31, m32, m33;

	public Matrix4f() {
		setIdentity();
	}

	public Matrix4f( Matrix4f m ) {
		set( m );
	}

	public Matrix4f(float[] m) {
		set( m );
	}

	public void set( Matrix4f m) {
		m00 = m.m00;
		m01 = m.m01;
		m02 = m.m02;
		m03 = m.m03;
		m10 = m.m10;
		m11 = m.m11;
		m12 = m.m12;
		m13 = m.m13;
		m20 = m.m20;
		m21 = m.m21;
		m22 = m.m22;
		m23 = m.m23;
		m30 = m.m30;
		m31 = m.m31;
		m32 = m.m32;
		m33 = m.m33;
	}

	public void set(float[] m) {
		m00 = m[0];
		m01 = m[1];
		m02 = m[2];
		m03 = m[3];
		m10 = m[4];
		m11 = m[5];
		m12 = m[6];
		m13 = m[7];
		m20 = m[8];
		m21 = m[9];
		m22 = m[10];
		m23 = m[11];
		m30 = m[12];
		m31 = m[13];
		m32 = m[14];
		m33 = m[15];
	}

	public void get( Matrix4f m) {
		m.m00 = m00;
		m.m01 = m01;
		m.m02 = m02;
		m.m03 = m03;
		m.m10 = m10;
		m.m11 = m11;
		m.m12 = m12;
		m.m13 = m13;
		m.m20 = m20;
		m.m21 = m21;
		m.m22 = m22;
		m.m23 = m23;
		m.m30 = m30;
		m.m31 = m31;
		m.m32 = m32;
		m.m33 = m33;
	}

	public void get(float[] m) {
		m[0] = m00;
		m[1] = m01;
		m[2] = m02;
		m[3] = m03;
		m[4] = m10;
		m[5] = m11;
		m[6] = m12;
		m[7] = m13;
		m[8] = m20;
		m[9] = m21;
		m[10] = m22;
		m[11] = m23;
		m[12] = m30;
		m[13] = m31;
		m[14] = m32;
		m[15] = m33;
	}

	public void setIdentity() {
		m00 = 1.0f;
		m01 = 0.0f;
		m02 = 0.0f;
		m03 = 0.0f;

		m10 = 0.0f;
		m11 = 1.0f;
		m12 = 0.0f;
		m13 = 0.0f;

		m20 = 0.0f;
		m21 = 0.0f;
		m22 = 1.0f;
		m23 = 0.0f;

		m30 = 0.0f;
		m31 = 0.0f;
		m32 = 0.0f;
		m33 = 1.0f;
	}

	public void mul( Matrix4f m ) {
		float tm00 = m00;
		float tm01 = m01;
		float tm02 = m02;
		float tm03 = m03;
		float tm10 = m10;
		float tm11 = m11;
		float tm12 = m12;
		float tm13 = m13;
		float tm20 = m20;
		float tm21 = m21;
		float tm22 = m22;
		float tm23 = m23;
		float tm30 = m30;
		float tm31 = m31;
		float tm32 = m32;
		float tm33 = m33;

		m00 = tm00*m.m00 + tm10*m.m01 + tm20*m.m02 + tm30*m.m03;
		m01 = tm01*m.m00 + tm11*m.m01 + tm21*m.m02 + tm31*m.m03;
		m02 = tm02*m.m00 + tm12*m.m01 + tm22*m.m02 + tm32*m.m03;
		m03 = tm03*m.m00 + tm13*m.m01 + tm23*m.m02 + tm33*m.m03;
		m10 = tm00*m.m10 + tm10*m.m11 + tm20*m.m12 + tm30*m.m13;
		m11 = tm01*m.m10 + tm11*m.m11 + tm21*m.m12 + tm31*m.m13;
		m12 = tm02*m.m10 + tm12*m.m11 + tm22*m.m12 + tm32*m.m13;
		m13 = tm03*m.m10 + tm13*m.m11 + tm23*m.m12 + tm33*m.m13;
		m20 = tm00*m.m20 + tm10*m.m21 + tm20*m.m22 + tm30*m.m23;
		m21 = tm01*m.m20 + tm11*m.m21 + tm21*m.m22 + tm31*m.m23;
		m22 = tm02*m.m20 + tm12*m.m21 + tm22*m.m22 + tm32*m.m23;
		m23 = tm03*m.m20 + tm13*m.m21 + tm23*m.m22 + tm33*m.m23;
		m30 = tm00*m.m30 + tm10*m.m31 + tm20*m.m32 + tm30*m.m33;
		m31 = tm01*m.m30 + tm11*m.m31 + tm21*m.m32 + tm31*m.m33;
		m32 = tm02*m.m30 + tm12*m.m31 + tm22*m.m32 + tm32*m.m33;
		m33 = tm03*m.m30 + tm13*m.m31 + tm23*m.m32 + tm33*m.m33;
	}

	public void invert() {
		Matrix4f t = new Matrix4f( this );
		invert( t );
	}

	public void invert( Matrix4f t ) {
		m00 = t.m00;
		m01 = t.m10;
		m02 = t.m20;
		m03 = t.m03;

		m10 = t.m01;
		m11 = t.m11;
		m12 = t.m21;
		m13 = t.m13;

		m20 = t.m02;
		m21 = t.m12;
		m22 = t.m22;
		m23 = t.m23;

		m30 *= -1.0f;
		m31 *= -1.0f;
		m32 *= -1.0f;
		m33 = t.m33;
	}

	public void set( AxisAngle4f a ) {
		float halfTheta = a.angle * 0.5f;
		float cosHalfTheta = (float)Math.cos(halfTheta);
		float sinHalfTheta = (float)Math.sin(halfTheta);
		set( new Quat4f( a.x * sinHalfTheta, a.y * sinHalfTheta, a.z * sinHalfTheta, cosHalfTheta ) );
	}

	public void set( Quat4f q ) {
		float wx, wy, wz, xx, yy, yz, xy, xz, zz, x2, y2, z2;
		x2 = q.x + q.x;
		y2 = q.y + q.y;
		z2 = q.z + q.z;
		xx = q.x * x2;
		xy = q.x * y2;
		xz = q.x * z2;
		yy = q.y * y2;
		yz = q.y * z2;
		zz = q.z * z2;
		wx = q.w * x2;
		wy = q.w * y2;
		wz = q.w * z2;
		m00 = 1.0f - (yy + zz);
		m01 = xy - wz;
		m02 = xz + wy;
		m03 = 0.0f;
		m10 = xy + wz;
		m11 = 1.0f - (xx + zz);
		m12 = yz - wx;
		m13 = 0.0f;
		m20 = xz - wy;
		m21 = yz + wx;
		m22 = 1.0f - (xx + yy);
		m23 = 0.0f;
		m30 = 0;
		m31 = 0;
		m32 = 0;
		m33 = 1;
	}

	public void transform( Point3f v ) {
		float x = v.x * m00 + v.y * m10 + v.z * m20 + m30;
		float y = v.x * m01 + v.y * m11 + v.z * m21 + m31;
		float z = v.x * m02 + v.y * m12 + v.z * m22 + m32;
		v.x = x;
		v.y = y;
		v.z = z;
	}

	public void transform( Vector3f v ) {
		float x = v.x * m00 + v.y * m10 + v.z * m20;
		float y = v.x * m01 + v.y * m11 + v.z * m21;
		float z = v.x * m02 + v.y * m12 + v.z * m22;
		v.x = x;
		v.y = y;
		v.z = z;
	}

	public void setTranslation( Vector3f v ) {
		m30 = v.x;
		m31 = v.y;
		m32 = v.z;
	}

	public void set( float scale ) {
		m00 = scale;
		m11 = scale;
		m22 = scale;
	}

	public void rotX( float angle ) {
		float s = (float)Math.sin( angle );
		float c = (float)Math.cos( angle );
		m00 = 1.0f;
		m01 = 0.0f;
		m02 = 0.0f;
		m03 = 0.0f;

		m10 = 0.0f;
		m11 = c;
		m12 = s;
		m13 = 0.0f;

		m20 = 0.0f;
		m21 = -s;
		m22 = c;
		m23 = 0.0f;

		m30 = 0.0f;
		m31 = 0.0f;
		m32 = 0.0f;
		m33 = 1.0f;
	}

	public void rotY( float angle ) {
		float s = (float)Math.sin( angle );
		float c = (float)Math.cos( angle );
		m00 = c;
		m01 = 0.0f;
		m02 = -s;
		m03 = 0.0f;

		m10 = 0.0f;
		m11 = 1.0f;
		m12 = 0.0f;
		m13 = 0.0f;

		m20 = s;
		m21 = 0.0f;
		m22 = c;
		m23 = 0.0f;

		m30 = 0.0f;
		m31 = 0.0f;
		m32 = 0.0f;
		m33 = 1.0f;
	}

	public void rotZ( float angle ) {
		float s = (float)Math.sin( angle );
		float c = (float)Math.cos( angle );
		m00 = c;
		m01 = s;
		m02 = 0.0f;
		m03 = 0.0f;

		m10 = -s;
		m11 = c;
		m12 = 0.0f;
		m13 = 0.0f;

		m20 = 0.0f;
		m21 = 0.0f;
		m22 = 1.0f;
		m23 = 0.0f;

		m30 = 0.0f;
		m31 = 0.0f;
		m32 = 0.0f;
		m33 = 1.0f;
	}
/*
	void rotate(float angle, float x, float y, float z) {
		Matrix4f m = new Matrix4f();//FIXME
		m.MatrixFromAxisAngle(Vector3f(x, y, z), angle);
		Multiply(m);
	}
*/
}

Point3f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Point3f extends Tuple3f {

	public Point3f() {
		this( 0, 0, 0 );
	}
	
	public Point3f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
	}

	public Point3f( float x, float y, float z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public Point3f( Point3f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
	}

	public Point3f( Tuple3f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
	}

	public float distanceL1( Point3f p ) {
		return Math.abs(x-p.x) + Math.abs(y-p.y) + Math.abs(z-p.z);
	}

	public float distanceSquared( Point3f p ) {
		float dx = x-p.x;
		float dy = y-p.y;
		float dz = z-p.z;
		return dx*dx+dy*dy+dz*dz;
	}

	public float distance( Point3f p ) {
		float dx = x-p.x;
		float dy = y-p.y;
		float dz = z-p.z;
		return (float)Math.sqrt( dx*dx+dy*dy+dz*dz );
	}

}

Point4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Point4f extends Tuple4f {

	public Point4f() {
		this( 0, 0, 0, 0 );
	}
	
	public Point4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[3];
	}

	public Point4f( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public Point4f( Point4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public Point4f( Tuple4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public float distanceL1( Point4f p ) {
		return Math.abs(x-p.x) + Math.abs(y-p.y) + Math.abs(z-p.z) + Math.abs(w-p.w);
	}

	public float distanceSquared( Point4f p ) {
		float dx = x-p.x;
		float dy = y-p.y;
		float dz = z-p.z;
		float dw = w-p.w;
		return dx*dx+dy*dy+dz*dz+dw*dw;
	}

	public float distance( Point4f p ) {
		float dx = x-p.x;
		float dy = y-p.y;
		float dz = z-p.z;
		float dw = w-p.w;
		return (float)Math.sqrt( dx*dx+dy*dy+dz*dz+dw*dw );
	}

}

Quat4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Quat4f extends Tuple4f {

	public Quat4f() {
		this( 0, 0, 0, 0 );
	}
	
	public Quat4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[3];
	}

	public Quat4f( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public Quat4f( Quat4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public Quat4f( Tuple4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public void set( AxisAngle4f a ) {
		float halfTheta = a.angle * 0.5f;
		float cosHalfTheta = (float)Math.cos(halfTheta);
		float sinHalfTheta = (float)Math.sin(halfTheta);
		x = a.x * sinHalfTheta;
		y = a.y * sinHalfTheta;
		z = a.z * sinHalfTheta;
		w = cosHalfTheta;
	}

/*
	public void EulerToQuaternion(float roll, float pitch, float yaw)
	{
		float cr, cp, cy, sr, sp, sy, cpcy, spsy;
		cr = cos(roll/2);
		cp = cos(pitch/2);
		cy = cos(yaw/2);
		sr = sin(roll/2);
		sp = sin(pitch/2);
		sy = sin(yaw/2);
		cpcy = cp * cy;
		spsy = sp * sy;
		w = cr * cpcy + sr * spsy;
		x = sr * cpcy - cr * spsy;
		y = cr * sp * cy + sr * cp * sy;
		z = cr * cp * sy - sr * sp * cy;
	}
*/

	public void normalize() {
		float d = 1.0f/( x*x+y*y+z*z+w*w );
		x *= d;
		y *= d;
		z *= d;
		w *= d;
	}

/*
	public void mul( Quat4f q ) {
		Quat4f q3 = new Quat4f();
		Vector3f vectorq1 = new Vector3f( x, y, z );
		Vector3f vectorq2 = new Vector3f( q.x, q.y, q.z );

		Vector3f tempvec1 = new Vector3f( vectorq1 );
		Vector3f tempvec2;
		Vector3f tempvec3;
		q3.w = (w*q.w) - tempvec1.dot(vectorq2);
		tempvec1.cross(vectorq2);
		tempvec2.x = w * q.x;
		tempvec2.y = w * q.y;
		tempvec2.z = w * q.z;
		tempvec3.x = q.w * x;
		tempvec3.y = q.w * y;
		tempvec3.z = q.w * z;
		q3.x = tempvec1.x + tempvec2.x + tempvec3.x;
		q3.y = tempvec1.y + tempvec2.y + tempvec3.y;
		q3.z = tempvec1.z + tempvec2.z + tempvec3.z;
		set(q3);
	}
*/

	public void set( Matrix4f m ) {
		float s;
		int i;

		float tr = m.m00 + m.m11 + m.m22;

		if (tr > 0.0) {
			s = (float)Math.sqrt(tr + 1.0f);
			w = s / 2.0f;
			s = 0.5f / s;
			x = (m.m12 - m.m21) * s;
			y = (m.m20 - m.m02) * s;
			z = (m.m01 - m.m10) * s;
		} else {		
			i = 0;
			if ( m.m11 > m.m00 ) {
				i = 1;
				if ( m.m22 > m.m11 ) {
					i = 2;
				} else {
				}
			} else {
				if ( m.m22 > m.m00 ) {
					i = 2;
				} else {
				}
			}

			switch ( i ) {
			case 0:
				s = (float)Math.sqrt ((m.m00 - (m.m11 + m.m22)) + 1.0f);
				x = s * 0.5f;
				if (s != 0.0)
					s = 0.5f / s;
				w = (m.m12 - m.m21) * s;
				y = (m.m01 + m.m10) * s;
				z = (m.m02 + m.m20) * s;
				break;
			case 1:
				s = (float)Math.sqrt ((m.m11 - (m.m22 + m.m00)) + 1.0f);
				y = s * 0.5f;
				if (s != 0.0)
					s = 0.5f / s;
				w = (m.m20 - m.m02) * s;
				z = (m.m12 + m.m21) * s;
				x = (m.m10 + m.m01) * s;
				break;
			case 2:
				s = (float)Math.sqrt ((m.m00 - (m.m11 + m.m22)) + 1.0f);
				z = s * 0.5f;
				if (s != 0.0)
					s = 0.5f / s;
				w = (m.m01 - m.m10) * s;
				x = (m.m20 + m.m02) * s;
				y = (m.m21 + m.m12) * s;
				break;
			}

		}
	}

}

Tuple3f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Tuple3f {
	public float x, y, z;

	public Tuple3f() {
		this( 0, 0, 0 );
	}
	
	public Tuple3f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
	}

	public Tuple3f( float x, float y, float z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public Tuple3f( Tuple3f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
	}

	public void absolute() {
		x = Math.abs(x);
		y = Math.abs(y);
		z = Math.abs(z);
	}

	public void absolute( Tuple3f t ) {
		x = Math.abs(t.x);
		y = Math.abs(t.y);
		z = Math.abs(t.z);
	}

	public void clamp( float min, float max ) {
		if ( x < min )
			x = min;
		else if ( x > max )
			x = max;
		if ( y < min )
			y = min;
		else if ( y > max )
			y = max;
		if ( z < min )
			z = min;
		else if ( z > max )
			z = max;
	}

	public void set( float x, float y, float z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public void set( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
	}

	public void set( Tuple3f t ) {
		x = t.x;
		y = t.y;
		z = t.z;
	}

	public void get( Tuple3f t ) {
		t.x = x;
		t.y = y;
		t.z = z;
	}

	public void get( float[] t ) {
		t[0] = x;
		t[1] = y;
		t[2] = z;
	}

	public void negate() {
		x = -x;
		y = -y;
		z = -z;
	}

	public void negate( Tuple3f t ) {
		x = -t.x;
		y = -t.y;
		z = -t.z;
	}

	public void interpolate( Tuple3f t, float alpha ) {
		float a = 1-alpha;
		x = a*x + alpha*t.x;
		y = a*y + alpha*t.y;
		z = a*z + alpha*t.z;
	}

	public void scale( float s ) {
		x *= s;
		y *= s;
		z *= s;
	}

	public void add( Tuple3f t ) {
		x += t.x;
		y += t.y;
		z += t.z;
	}

	public void add( Tuple3f t1, Tuple3f t2 ) {
		x = t1.x+t2.x;
		y = t1.y+t2.y;
		z = t1.z+t2.z;
	}

	public void sub( Tuple3f t ) {
		x -= t.x;
		y -= t.y;
		z -= t.z;
	}

	public void sub( Tuple3f t1, Tuple3f t2 ) {
		x = t1.x-t2.x;
		y = t1.y-t2.y;
		z = t1.z-t2.z;
	}

	public void scaleAdd( float s, Tuple3f t ) {
		x += s*t.x;
		y += s*t.y;
		z += s*t.z;
	}
	
	public void scaleAdd( float s, Tuple3f t1, Tuple3f t2 ) {
		x = s*t1.x + t2.x;
		y = s*t1.y + t2.y;
		z = s*t1.z + t2.z;
	}
	
	public String toString() {
		return "["+x+", "+y+", "+z+"]";
	}
	
}

Tuple4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Tuple4f {
	public float x, y, z, w;

	public Tuple4f() {
		this( 0, 0, 0, 0 );
	}
	
	public Tuple4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[2];
	}

	public Tuple4f( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public Tuple4f( Tuple4f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
		this.w = t.w;
	}

	public void absolute() {
		x = Math.abs(x);
		y = Math.abs(y);
		z = Math.abs(z);
		w = Math.abs(w);
	}

	public void absolute( Tuple4f t ) {
		x = Math.abs(t.x);
		y = Math.abs(t.y);
		z = Math.abs(t.z);
		w = Math.abs(t.w);
	}

	public void clamp( float min, float max ) {
		if ( x < min )
			x = min;
		else if ( x > max )
			x = max;
		if ( y < min )
			y = min;
		else if ( y > max )
			y = max;
		if ( z < min )
			z = min;
		else if ( z > max )
			z = max;
		if ( w < min )
			w = min;
		else if ( w > max )
			w = max;
	}

	public void set( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public void set( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[2];
	}

	public void set( Tuple4f t ) {
		x = t.x;
		y = t.y;
		z = t.z;
		w = t.w;
	}

	public void get( Tuple4f t ) {
		t.x = x;
		t.y = y;
		t.z = z;
		t.w = w;
	}

	public void get( float[] t ) {
		t[0] = x;
		t[1] = y;
		t[2] = z;
		t[3] = w;
	}

	public void negate() {
		x = -x;
		y = -y;
		z = -z;
		w = -w;
	}

	public void negate( Tuple4f t ) {
		x = -t.x;
		y = -t.y;
		z = -t.z;
		w = -t.w;
	}

	public void interpolate( Tuple4f t, float alpha ) {
		float a = 1-alpha;
		x = a*x + alpha*t.x;
		y = a*y + alpha*t.y;
		z = a*z + alpha*t.z;
		w = a*w + alpha*t.w;
	}

	public void scale( float s ) {
		x *= s;
		y *= s;
		z *= s;
		w *= s;
	}

	public void add( Tuple4f t ) {
		x += t.x;
		y += t.y;
		z += t.z;
		w += t.w;
	}

	public void add( Tuple4f t1, Tuple4f t2 ) {
		x = t1.x+t2.x;
		y = t1.y+t2.y;
		z = t1.z+t2.z;
		w = t1.w+t2.w;
	}

	public void sub( Tuple4f t ) {
		x -= t.x;
		y -= t.y;
		z -= t.z;
		w -= t.w;
	}

	public void sub( Tuple4f t1, Tuple4f t2 ) {
		x = t1.x-t2.x;
		y = t1.y-t2.y;
		z = t1.z-t2.z;
		w = t1.w-t2.w;
	}

	public String toString() {
		return "["+x+", "+y+", "+z+", "+w+"]";
	}
	
}

Vector3f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Vector3f extends Tuple3f {

	public Vector3f() {
		this( 0, 0, 0 );
	}
	
	public Vector3f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
	}

	public Vector3f( float x, float y, float z ) {
		this.x = x;
		this.y = y;
		this.z = z;
	}

	public Vector3f( Vector3f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
	}

	public Vector3f( Tuple3f t ) {
		this.x = t.x;
		this.y = t.y;
		this.z = t.z;
	}

	public float angle( Vector3f v ) {
		return (float)Math.acos( dot(v) / (length()*v.length()) );
	}

	public float dot( Vector3f v ) {
		return v.x * x + v.y * y + v.z * z;
	}

	public void cross( Vector3f v1, Vector3f v2 ) {
		x = v1.y * v2.z - v1.z * v2.y;
		y = v1.z * v2.x - v1.x * v2.z;
		z = v1.x * v2.y - v1.y * v2.x;
	}

	public float length() {
		return (float)Math.sqrt( x*x+y*y+z*z );
	}

	public void normalize() {
		float d = 1.0f/(float)Math.sqrt( x*x+y*y+z*z );
		x *= d;
		y *= d;
		z *= d;
	}

}

Vector4f.java

Code:
package com.jhlabs.vecmath;

/**
 * Vector math package, converted to look similar to javax.vecmath.
 */
public class Vector4f extends Tuple4f {

	public Vector4f() {
		this( 0, 0, 0, 0 );
	}
	
	public Vector4f( float[] x ) {
		this.x = x[0];
		this.y = x[1];
		this.z = x[2];
		this.w = x[2];
	}

	public Vector4f( float x, float y, float z, float w ) {
		this.x = x;
		this.y = y;
		this.z = z;
		this.w = w;
	}

	public Vector4f( Vector4f t ) {
		x = t.x;
		y = t.y;
		z = t.z;
		w = t.w;
	}

	public Vector4f( Tuple4f t ) {
		x = t.x;
		y = t.y;
		z = t.z;
		w = t.w;
	}

	public float dot( Vector4f v ) {
		return v.x * x + v.y * y + v.z * z + v.w * w;
	}

	public float length() {
		return (float)Math.sqrt( x*x+y*y+z*z+w*w );
	}

	public void normalize() {
		float d = 1.0f/( x*x+y*y+z*z+w*w );
		x *= d;
		y *= d;
		z *= d;
		w *= d;
	}

}

The package "com.jhlabs.composite" contains the Composite utility Classes.

AddComposite.java

Code:
package com.jhlabs.composite;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:00 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.*;
import java.awt.image.*;

public final class AddComposite extends RGBComposite {

    public AddComposite( float alpha ) {
        super( alpha );
    }

    public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
        return new Context( extraAlpha, srcColorModel, dstColorModel );
    }

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir + sr;
                if ( dor > 255 )
                    dor = 255;
                dog = dig + sg;
                if ( dog > 255 )
                    dog = 255;
                dob = dib + sb;
                if ( dob > 255 )
                    dob = 255;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

AverageComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class AverageComposite extends RGBComposite {

	public AverageComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = (dir + sr) / 2;
                dog = (dig + sg) / 2;
                dob = (dib + sb) / 2;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

BurnComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class BurnComposite extends RGBComposite {

	public BurnComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                if (dir != 255)
                    dor = clamp(255-(((int)(255-sr) << 8) / (dir+1)));
                else
                    dor = sr;
                if (dig != 255)
                    dog = clamp(255-(((int)(255-sg) << 8) / (dig+1)));
                else
                    dog = sg;
                if (dib != 255)
                    dob = clamp(255-(((int)(255-sb) << 8) / (dib+1)));
                else
                    dob = sb;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ColorBurnComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ColorBurnComposite extends RGBComposite {

	public ColorBurnComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                if (sr != 0)
                    dor = Math.max(255 - (((int)(255-dir) << 8) / sr), 0);
                else
                    dor = sr;
                if (sg != 0)
                    dog = Math.max(255 - (((int)(255-dig) << 8) / sg), 0);
                else
                    dog = sg;
                if (sb != 0)
                    dob = Math.max(255 - (((int)(255-dib) << 8) / sb), 0);
                else
                    dob = sb;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ColorComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ColorComposite extends RGBComposite {

	public ColorComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
		private float[] sHSB = new float[3];
        private float[] dHSB = new float[3];

        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                Color.RGBtoHSB( sr, sg, sb, sHSB );
                Color.RGBtoHSB( dir, dig, dib, dHSB );

                dHSB[0] = sHSB[0];
                dHSB[1] = sHSB[1];

                int doRGB = Color.HSBtoRGB( dHSB[0], dHSB[1], dHSB[2] );
                dor = (doRGB & 0xff0000) >> 16;
                dog = (doRGB & 0xff00) >> 8;
                dob = (doRGB & 0xff);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ColorDodgeComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ColorDodgeComposite extends RGBComposite {

	public ColorDodgeComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                if (sr != 255)
                    dor = Math.min((dir << 8) / (255-sr), 255);
                else
                    dor = sr;
                if (sg != 255)
                    dog = Math.min((dig << 8) / (255-sg), 255);
                else
                    dog = sg;
                if (sb != 255)
                    dob = Math.min((dib << 8) / (255-sb), 255);
                else
                    dob = sb;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

DarkenComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class DarkenComposite extends RGBComposite {

	public DarkenComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir < sr ? dir : sr;
                dog = dig < sg ? dig : sg;
                dob = dib < sb ? dib : sb;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

DifferenceComposite.java

Code:
package com.jhlabs.composite;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:02 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.image.ColorModel;

public final class DifferenceComposite extends RGBComposite {

    public DifferenceComposite( float alpha ) {
        super( alpha );
    }

    public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
        return new Context( extraAlpha, srcColorModel, dstColorModel );
    }

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir - sr;
                if ( dor < 0 )
                    dor = -dor;
                dog = dig - sg;
                if ( dog < 0 )
                    dog = -dog;
                dob = dib - sb;
                if ( dob < 0 )
                    dob = -dob;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

DodgeComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class DodgeComposite extends RGBComposite {

	public DodgeComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = clamp((sr << 8) / (256-dir));
                dog = clamp((sg << 8) / (256-dig));
                dob = clamp((sb << 8) / (256-dib));

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ExclusionComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ExclusionComposite extends RGBComposite {

	public ExclusionComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir+multiply255(sr, (255-dir-dir));
                dog = dig+multiply255(sg, (255-dig-dig));
                dob = dib+multiply255(sb, (255-dib-dib));

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

HardLightComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class HardLightComposite extends RGBComposite {

	public HardLightComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                if (sr > 127)
                    dor = 255 - 2*multiply255(255 - sr, 255 - dir);
                else
                    dor = 2*multiply255(sr, dir);
                if (sg > 127)
                    dog = 255 - 2*multiply255(255 - sg, 255 - dig);
                else
                    dog = 2*multiply255(sg, dig);
                if (sb > 127)
                    dob = 255 - 2*multiply255(255 - sb, 255 - dib);
                else
                    dob = 2*multiply255(sb, dib);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

HueComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class HueComposite extends RGBComposite {

	public HueComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
		private float[] sHSB = new float[3];
        private float[] dHSB = new float[3];

        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                Color.RGBtoHSB( sr, sg, sb, sHSB );
                Color.RGBtoHSB( dir, dig, dib, dHSB );

                dHSB[0] = sHSB[0];

                int doRGB = Color.HSBtoRGB( dHSB[0], dHSB[1], dHSB[2] );
                dor = (doRGB & 0xff0000) >> 16;
                dog = (doRGB & 0xff00) >> 8;
                dob = (doRGB & 0xff);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

LightenComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class LightenComposite extends RGBComposite {

	public LightenComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir > sr ? dir : sr;
                dog = dig > sg ? dig : sg;
                dob = dib > sb ? dib : sb;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

MiscComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class MiscComposite implements Composite {

	public final static int BLEND = 0;
	public final static int ADD = 1;
	public final static int SUBTRACT = 2;
	public final static int DIFFERENCE = 3;

	public final static int MULTIPLY = 4;
	public final static int DARKEN = 5;
	public final static int BURN = 6;
	public final static int COLOR_BURN = 7;

	public final static int SCREEN = 8;
	public final static int LIGHTEN = 9;
	public final static int DODGE = 10;
	public final static int COLOR_DODGE = 11;

	public final static int HUE = 12;
	public final static int SATURATION = 13;
	public final static int VALUE = 14;
	public final static int COLOR = 15;

	public final static int OVERLAY = 16;
	public final static int SOFT_LIGHT = 17;
	public final static int HARD_LIGHT = 18;
	public final static int PIN_LIGHT = 19;

	public final static int EXCLUSION = 20;
	public final static int NEGATION = 21;
	public final static int AVERAGE = 22;

	public final static int STENCIL = 23;
	public final static int SILHOUETTE = 24;

	private static final int MIN_RULE = BLEND;
	private static final int MAX_RULE = SILHOUETTE;

	public static String[] RULE_NAMES = {
		"Normal",
		"Add",
		"Subtract",
		"Difference",

		"Multiply",
		"Darken",
		"Burn",
		"Color Burn",

		"Screen",
		"Lighten",
		"Dodge",
		"Color Dodge",

		"Hue",
		"Saturation",
		"Brightness",
		"Color",

		"Overlay",
		"Soft Light",
		"Hard Light",
		"Pin Light",

		"Exclusion",
		"Negation",
		"Average",

		"Stencil",
		"Silhouette",
	};

	protected float extraAlpha;
	protected int rule;

	private MiscComposite(int rule) {
		this(rule, 1.0f);
	}

	private MiscComposite(int rule, float alpha) {
		if (alpha < 0.0f || alpha > 1.0f)
			throw new IllegalArgumentException("alpha value out of range");
		if (rule < MIN_RULE || rule > MAX_RULE)
			throw new IllegalArgumentException("unknown composite rule");
		this.rule = rule;
		this.extraAlpha = alpha;
	}

	public static Composite getInstance(int rule, float alpha) {
		switch ( rule ) {
		case MiscComposite.BLEND:
			return AlphaComposite.getInstance( AlphaComposite.SRC_OVER, alpha );
		case MiscComposite.ADD:
			return new AddComposite( alpha );
		case MiscComposite.SUBTRACT:
			return new SubtractComposite( alpha );
		case MiscComposite.DIFFERENCE:
			return new DifferenceComposite( alpha );
		case MiscComposite.MULTIPLY:
			return new MultiplyComposite( alpha );
		case MiscComposite.DARKEN:
			return new DarkenComposite( alpha );
		case MiscComposite.BURN:
			return new BurnComposite( alpha );
		case MiscComposite.COLOR_BURN:
			return new ColorBurnComposite( alpha );
		case MiscComposite.SCREEN:
			return new ScreenComposite( alpha );
		case MiscComposite.LIGHTEN:
			return new LightenComposite( alpha );
		case MiscComposite.DODGE:
			return new DodgeComposite( alpha );
		case MiscComposite.COLOR_DODGE:
			return new ColorDodgeComposite( alpha );
		case MiscComposite.HUE:
			return new HueComposite( alpha );
		case MiscComposite.SATURATION:
			return new SaturationComposite( alpha );
		case MiscComposite.VALUE:
			return new ValueComposite( alpha );
		case MiscComposite.COLOR:
			return new ColorComposite( alpha );
		case MiscComposite.OVERLAY:
			return new OverlayComposite( alpha );
		case MiscComposite.SOFT_LIGHT:
			return new SoftLightComposite( alpha );
		case MiscComposite.HARD_LIGHT:
			return new HardLightComposite( alpha );
		case MiscComposite.PIN_LIGHT:
			return new PinLightComposite( alpha );
		case MiscComposite.EXCLUSION:
			return new ExclusionComposite( alpha );
		case MiscComposite.NEGATION:
			return new NegationComposite( alpha );
		case MiscComposite.AVERAGE:
			return new AverageComposite( alpha );
		case MiscComposite.STENCIL:
			return AlphaComposite.getInstance( AlphaComposite.DST_IN, alpha );
		case MiscComposite.SILHOUETTE:
			return AlphaComposite.getInstance( AlphaComposite.DST_OUT, alpha );
		}
		return new MiscComposite(rule, alpha);
	}

	public CompositeContext createContext(ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints) {
		return new MiscCompositeContext( rule, extraAlpha, srcColorModel, dstColorModel );
	}

	public float getAlpha() {
		return extraAlpha;
	}

	public int getRule() {
		return rule;
	}

	public int hashCode() {
		return (Float.floatToIntBits(extraAlpha) * 31 + rule);
	}

	public boolean equals(Object o) {
		if (!(o instanceof MiscComposite))
			return false;
		MiscComposite c = (MiscComposite)o;

		if (rule != c.rule)
			return false;
		if (extraAlpha != c.extraAlpha)
			return false;
		return true;
	}

}

MiscCompositeContext.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.awt.color.*;
import java.net.*;
import java.io.*;

public class MiscCompositeContext implements CompositeContext {

	private int rule;
	private float alpha;
	private ColorModel srcColorModel;
	private ColorModel dstColorModel;
	private ColorSpace srcColorSpace;
	private ColorSpace dstColorSpace;
	private boolean srcNeedsConverting;
	private boolean dstNeedsConverting;

	public MiscCompositeContext(int rule,
						 float alpha,
						 ColorModel srcColorModel,
						 ColorModel dstColorModel) {
		this.rule = rule;
		this.alpha = alpha;
		this.srcColorModel = srcColorModel;
		this.dstColorModel = dstColorModel;
		this.srcColorSpace = srcColorModel.getColorSpace();
		this.dstColorSpace = dstColorModel.getColorSpace();
		ColorModel srgbCM = ColorModel.getRGBdefault();
//		srcNeedsConverting = !srcColorModel.equals(srgbCM);
//		dstNeedsConverting = !dstColorModel.equals(srgbCM);
	}

	public void dispose() {
	}

	// Multiply two numbers in the range 0..255 such that 255*255=255
	static int multiply255( int a, int b ) {
		int t = a * b + 0x80;
		return ((t >> 8) + t) >> 8;
	}

	static int clamp( int a ) {
		return a < 0 ? 0 : a > 255 ? 255 : a;
	}

	public void compose(Raster src, Raster dstIn, WritableRaster dstOut) {
		float a=0, ac=0;
		float alpha = this.alpha;
		int t;

		float[] sHsv = null, diHsv = null, doHsv = null;
		switch ( rule ) {
		case MiscComposite.HUE:
		case MiscComposite.SATURATION:
		case MiscComposite.VALUE:
		case MiscComposite.COLOR:
			sHsv = new float[3];
			diHsv = new float[3];
			doHsv = new float[3];
			break;
		}

		int[] srcPix = null;
		int[] dstPix = null;

		int x = dstOut.getMinX();
		int w = dstOut.getWidth();

		int y0 = dstOut.getMinY();
		int y1 = y0 + dstOut.getHeight();

		for ( int y = y0; y < y1; y++ ) {
			srcPix = src.getPixels(x, y, w, 1, srcPix);
			dstPix = dstIn.getPixels(x, y, w, 1, dstPix);
			int i = 0;
			int end = w*4;

			while ( i < end ) {
				int sr = srcPix[i];
				int dir = dstPix[i];
				int sg = srcPix[i+1];
				int dig = dstPix[i+1];
				int sb = srcPix[i+2];
				int dib = dstPix[i+2];
				int sa = srcPix[i+3];
				int dia = dstPix[i+3];
				int dor, dog, dob, doa;

				switch ( rule ) {
				case MiscComposite.ADD:
				default:
					dor = dir + sr;
					if ( dor > 255 )
						dor = 255;
					dog = dig + sg;
					if ( dog > 255 )
						dog = 255;
					dob = dib + sb;
					if ( dob > 255 )
						dob = 255;
					break;

				case MiscComposite.SUBTRACT:
					dor = dir - sr;
					if ( dor < 0 )
						dor = 0;
					dog = dig - sg;
					if ( dog < 0 )
						dog = 0;
					dob = dib - sb;
					if ( dob < 0 )
						dob = 0;
					break;

				case MiscComposite.DIFFERENCE:
					dor = dir - sr;
					if ( dor < 0 )
						dor = -dor;
					dog = dig - sg;
					if ( dog < 0 )
						dog = -dog;
					dob = dib - sb;
					if ( dob < 0 )
						dob = -dob;
					break;

				case MiscComposite.MULTIPLY:
					t = dir * sr + 0x80;
					dor = ((t >> 8) + t) >> 8;
					t = dig * sg + 0x80;
					dog = ((t >> 8) + t) >> 8;
					t = dib * sb + 0x80;
					dob = ((t >> 8) + t) >> 8;
					break;

				case MiscComposite.SCREEN:
					t = (255-dir) * (255-sr) + 0x80;
					dor = 255 - ( ((t >> 8) + t) >> 8 );
					t = (255-dig) * (255-sg) + 0x80;
					dog = 255 - ( ((t >> 8) + t) >> 8 );
					t = (255-dib) * (255-sb) + 0x80;
					dob = 255 - ( ((t >> 8) + t) >> 8 );
					break;

				case MiscComposite.OVERLAY:
					if ( dir < 128 ) {
						t = dir * sr + 0x80;
						dor = 2 * (((t >> 8) + t) >> 8);
					} else {
						t = (255-dir) * (255-sr) + 0x80;
						dor = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
					}
					if ( dig < 128 ) {
						t = dig * sg + 0x80;
						dog = 2 * (((t >> 8) + t) >> 8);
					} else {
						t = (255-dig) * (255-sg) + 0x80;
						dog = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
					}
					if ( dib < 128 ) {
						t = dib * sb + 0x80;
						dob = 2 * (((t >> 8) + t) >> 8);
					} else {
						t = (255-dib) * (255-sb) + 0x80;
						dob = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
					}
					break;

				case MiscComposite.DARKEN:
					dor = dir < sr ? dir : sr;
					dog = dig < sg ? dig : sg;
					dob = dib < sb ? dib : sb;
					break;

				case MiscComposite.LIGHTEN:
					dor = dir > sr ? dir : sr;
					dog = dig > sg ? dig : sg;
					dob = dib > sb ? dib : sb;
					break;

				case MiscComposite.AVERAGE:
					dor = (dir + sr) / 2;
					dog = (dig + sg) / 2;
					dob = (dib + sb) / 2;
					break;

				case MiscComposite.HUE:
				case MiscComposite.SATURATION:
				case MiscComposite.VALUE:
				case MiscComposite.COLOR:
					Color.RGBtoHSB(sr, sg, sb, sHsv);
					Color.RGBtoHSB(dir, dig, dib, diHsv);

					switch(rule) {
					case MiscComposite.HUE:
						doHsv[0] = sHsv[0];
						doHsv[1] = diHsv[1];
						doHsv[2] = diHsv[2];
						break;
					case MiscComposite.SATURATION:
						doHsv[0] = diHsv[0];
						doHsv[1] = sHsv[1];
						doHsv[2] = diHsv[2];
						break;
					case MiscComposite.VALUE:
						doHsv[0] = diHsv[0];
						doHsv[1] = diHsv[1];
						doHsv[2] = sHsv[2];
						break;
					case MiscComposite.COLOR:
						doHsv[0] = sHsv[0];
						doHsv[1] = sHsv[1];
						doHsv[2] = diHsv[2];
						break;
					}

					int doRGB = Color.HSBtoRGB(doHsv[0], doHsv[1], doHsv[2]);
					dor = (doRGB&0xff0000)>>16;
					dog = (doRGB&0xff00)>>8;
					dob = (doRGB&0xff);
					break;

				case MiscComposite.BURN:
					if (dir != 255)
						dor = clamp(255-(((int)(255-sr) << 8) / (dir+1)));
					else
						dor = sr;
					if (dig != 255)
						dog = clamp(255-(((int)(255-sg) << 8) / (dig+1)));
					else
						dog = sg;
					if (dib != 255)
						dob = clamp(255-(((int)(255-sb) << 8) / (dib+1)));
					else
						dob = sb;
					break;

				case MiscComposite.COLOR_BURN:
					if (sr != 0)
						dor = Math.max(255 - (((int)(255-dir) << 8) / sr), 0);
					else
						dor = sr;
					if (sg != 0)
						dog = Math.max(255 - (((int)(255-dig) << 8) / sg), 0);
					else
						dog = sg;
					if (sb != 0)
						dob = Math.max(255 - (((int)(255-dib) << 8) / sb), 0);
					else
						dob = sb;
					break;

				case MiscComposite.DODGE:
					dor = clamp((sr << 8) / (256-dir));
					dog = clamp((sg << 8) / (256-dig));
					dob = clamp((sb << 8) / (256-dib));
					break;

				case MiscComposite.COLOR_DODGE:
					if (sr != 255)
						dor = Math.min((dir << 8) / (255-sr), 255);
					else
						dor = sr;
					if (sg != 255)
						dog = Math.min((dig << 8) / (255-sg), 255);
					else
						dog = sg;
					if (sb != 255)
						dob = Math.min((dib << 8) / (255-sb), 255);
					else
						dob = sb;
					break;

				case MiscComposite.SOFT_LIGHT:
					int d;
					d = multiply255(sr, dir);
					dor = d + multiply255(dir, 255 - multiply255(255-dir, 255-sr)-d);
					d = multiply255(sg, dig);
					dog = d + multiply255(dig, 255 - multiply255(255-dig, 255-sg)-d);
					d = multiply255(sb, dib);
					dob = d + multiply255(dib, 255 - multiply255(255-dib, 255-sb)-d);
					break;

				case MiscComposite.HARD_LIGHT:
					if (sr > 127)
						dor = 255 - 2*multiply255(255 - sr, 255 - dir);
					else
						dor = 2*multiply255(sr, dir);
					if (sg > 127)
						dog = 255 - 2*multiply255(255 - sg, 255 - dig);
					else
						dog = 2*multiply255(sg, dig);
					if (sb > 127)
						dob = 255 - 2*multiply255(255 - sb, 255 - dib);
					else
						dob = 2*multiply255(sb, dib);
					break;

				case MiscComposite.PIN_LIGHT:
					dor = sr > 127 ? Math.max(sr, dir) : Math.min(sr, dir);
					dog = sg > 127 ? Math.max(sg, dig) : Math.min(sg, dig);
					dob = sb > 127 ? Math.max(sb, dib) : Math.min(sb, dib);
					break;

				case MiscComposite.EXCLUSION:
					dor = dir+multiply255(sr, (255-dir-dir));
					dog = dig+multiply255(sg, (255-dig-dig));
					dob = dib+multiply255(sb, (255-dib-dib));
					break;

				case MiscComposite.NEGATION:
					dor = 255 - Math.abs(255-sr-dir);
					dog = 255 - Math.abs(255-sg-dig);
					dob = 255 - Math.abs(255-sb-dib);
					break;
				}

				a = alpha*sa/255f;
				ac = 1-a;

				dstPix[i] = (int)(a*dor + ac*dir);
				dstPix[i+1] = (int)(a*dog + ac*dig);
				dstPix[i+2] = (int)(a*dob + ac*dib);
				dstPix[i+3] = (int)(sa*alpha + dia*ac);
				i += 4;
			}
			dstOut.setPixels(x, y, w, 1, dstPix);
		}
	}

}

MultiplyComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class MultiplyComposite extends RGBComposite {

	public MultiplyComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                int t = dir * sr + 0x80;
                dor = ((t >> 8) + t) >> 8;
                t = dig * sg + 0x80;
                dog = ((t >> 8) + t) >> 8;
                t = dib * sb + 0x80;
                dob = ((t >> 8) + t) >> 8;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

NegationComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class NegationComposite extends RGBComposite {

	public NegationComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = 255 - Math.abs(255-sr-dir);
                dog = 255 - Math.abs(255-sg-dig);
                dob = 255 - Math.abs(255-sb-dib);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

OverlayComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class OverlayComposite extends RGBComposite {

	public OverlayComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                int t;
                if ( dir < 128 ) {
                    t = dir * sr + 0x80;
                    dor = 2 * (((t >> 8) + t) >> 8);
                } else {
                    t = (255-dir) * (255-sr) + 0x80;
                    dor = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
                }
                if ( dig < 128 ) {
                    t = dig * sg + 0x80;
                    dog = 2 * (((t >> 8) + t) >> 8);
                } else {
                    t = (255-dig) * (255-sg) + 0x80;
                    dog = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
                }
                if ( dib < 128 ) {
                    t = dib * sb + 0x80;
                    dob = 2 * (((t >> 8) + t) >> 8);
                } else {
                    t = (255-dib) * (255-sb) + 0x80;
                    dob = 2 * (255 - ( ((t >> 8) + t) >> 8 ));
                }

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

PinLightComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class PinLightComposite extends RGBComposite {

	public PinLightComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = sr > 127 ? Math.max(sr, dir) : Math.min(sr, dir);
                dog = sg > 127 ? Math.max(sg, dig) : Math.min(sg, dig);
                dob = sb > 127 ? Math.max(sb, dib) : Math.min(sb, dib);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

RGBComposite.java

Code:
package com.jhlabs.composite;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:02 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.image.ColorModel;
import java.awt.image.Raster;
import java.awt.image.WritableRaster;

public abstract class RGBComposite implements Composite {

    protected float extraAlpha;

    public RGBComposite() {
        this( 1.0f );
    }

    public RGBComposite( float alpha ) {
        if ( alpha < 0.0f || alpha > 1.0f )
            throw new IllegalArgumentException("RGBComposite: alpha must be between 0 and 1");
        this.extraAlpha = alpha;
    }

    public float getAlpha() {
        return extraAlpha;
    }

    public int hashCode() {
        return Float.floatToIntBits(extraAlpha);
    }

    public boolean equals(Object o) {
        if (!(o instanceof RGBComposite))
            return false;
        RGBComposite c = (RGBComposite)o;

        if ( extraAlpha != c.extraAlpha )
            return false;
        return true;
    }

    public abstract static class RGBCompositeContext implements CompositeContext {

        private float alpha;
        private ColorModel srcColorModel;
        private ColorModel dstColorModel;

        public RGBCompositeContext( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            this.alpha = alpha;
            this.srcColorModel = srcColorModel;
            this.dstColorModel = dstColorModel;
        }

        public void dispose() {
        }

        // Multiply two numbers in the range 0..255 such that 255*255=255
        static int multiply255( int a, int b ) {
            int t = a * b + 0x80;
            return ((t >> 8) + t) >> 8;
        }

        static int clamp( int a ) {
            return a < 0 ? 0 : a > 255 ? 255 : a;
        }

        public abstract void composeRGB( int[] src, int[] dst, float alpha );

        public void compose( Raster src, Raster dstIn, WritableRaster dstOut ) {
            float alpha = this.alpha;

            int[] srcPix = null;
            int[] dstPix = null;

            int x = dstOut.getMinX();
            int w = dstOut.getWidth();
            int y0 = dstOut.getMinY();
            int y1 = y0 + dstOut.getHeight();

            for ( int y = y0; y < y1; y++ ) {
                srcPix = src.getPixels( x, y, w, 1, srcPix );
                dstPix = dstIn.getPixels( x, y, w, 1, dstPix );
                composeRGB( srcPix, dstPix, alpha );
                dstOut.setPixels( x, y, w, 1, dstPix );
            }
        }

    }
}

SaturationComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class SaturationComposite extends RGBComposite {

	public SaturationComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
		private float[] sHSB = new float[3];
        private float[] dHSB = new float[3];

        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                Color.RGBtoHSB( sr, sg, sb, sHSB );
                Color.RGBtoHSB( dir, dig, dib, dHSB );

                dHSB[1] = sHSB[1];

                int doRGB = Color.HSBtoRGB( dHSB[0], dHSB[1], dHSB[2] );
                dor = (doRGB & 0xff0000) >> 16;
                dog = (doRGB & 0xff00) >> 8;
                dob = (doRGB & 0xff);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ScreenComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ScreenComposite extends RGBComposite {

	public ScreenComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                int t = (255-dir) * (255-sr) + 0x80;
                dor = 255 - ( ((t >> 8) + t) >> 8 );
                t = (255-dig) * (255-sg) + 0x80;
                dog = 255 - ( ((t >> 8) + t) >> 8 );
                t = (255-dib) * (255-sb) + 0x80;
                dob = 255 - ( ((t >> 8) + t) >> 8 );

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

SoftLightComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class SoftLightComposite extends RGBComposite {

	public SoftLightComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                int d;
                d = multiply255(sr, dir);
                dor = d + multiply255(dir, 255 - multiply255(255-dir, 255-sr)-d);
                d = multiply255(sg, dig);
                dog = d + multiply255(dig, 255 - multiply255(255-dig, 255-sg)-d);
                d = multiply255(sb, dib);
                dob = d + multiply255(dib, 255 - multiply255(255-dib, 255-sb)-d);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

SubtractComposite.java

Code:
package com.jhlabs.composite;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 9:01 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.*;
import java.awt.image.*;

public final class SubtractComposite extends RGBComposite {

    public SubtractComposite( float alpha ) {
        super( alpha );
    }

    public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
        return new Context( extraAlpha, srcColorModel, dstColorModel );
    }

    static class Context extends RGBCompositeContext {
        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                dor = dir - sr;
                if ( dor < 0 )
                    dor = 0;
                dog = dig - sg;
                if ( dog < 0 )
                    dog = 0;
                dob = dib - sb;
                if ( dob < 0 )
                    dob = 0;

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

ValueComposite.java

Code:
package com.jhlabs.composite;

import java.awt.*;
import java.awt.image.*;

public final class ValueComposite extends RGBComposite {

	public ValueComposite( float alpha ) {
        super( alpha );
	}

	public CompositeContext createContext( ColorModel srcColorModel, ColorModel dstColorModel, RenderingHints hints ) {
		return new Context( extraAlpha, srcColorModel, dstColorModel );
	}

    static class Context extends RGBCompositeContext {
		private float[] sHSB = new float[3];
        private float[] dHSB = new float[3];

        public Context( float alpha, ColorModel srcColorModel, ColorModel dstColorModel ) {
            super( alpha, srcColorModel, dstColorModel );
        }

        public void composeRGB( int[] src, int[] dst, float alpha ) {
            int w = src.length;

            for ( int i = 0; i < w; i += 4 ) {
                int sr = src[i];
                int dir = dst[i];
                int sg = src[i+1];
                int dig = dst[i+1];
                int sb = src[i+2];
                int dib = dst[i+2];
                int sa = src[i+3];
                int dia = dst[i+3];
                int dor, dog, dob;

                Color.RGBtoHSB( sr, sg, sb, sHSB );
                Color.RGBtoHSB( dir, dig, dib, dHSB );

                dHSB[2] = sHSB[2];

                int doRGB = Color.HSBtoRGB( dHSB[0], dHSB[1], dHSB[2] );
                dor = (doRGB & 0xff0000) >> 16;
                dog = (doRGB & 0xff00) >> 8;
                dob = (doRGB & 0xff);

                float a = alpha*sa/255f;
                float ac = 1-a;

                dst[i] = (int)(a*dor + ac*dir);
                dst[i+1] = (int)(a*dog + ac*dig);
                dst[i+2] = (int)(a*dob + ac*dib);
                dst[i+3] = (int)(sa*alpha + dia*ac);
            }
        }
    }

}

The package "com.jhlabs.util" contains the utility classes

ImagePreview.java - Shows the Image Preview

Code:
package com.jhlabs.util;

/**
 * Created with IntelliJ IDEA.
 * User: JGuru
 * Date: 8/2/14
 * Time: 8:45 PM
 * To change this template use File | Settings | File Templates.
 */

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.border.BevelBorder;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.io.IOException;

/**
 *
 * @author Sowndar
 */
public class ImagePreview extends JComponent implements PropertyChangeListener {

    ImageIcon thumbnail = null;
    int width = 180;

    public ImagePreview(JFileChooser fc) {
        setPreferredSize(new Dimension(width, 50));
        fc.addPropertyChangeListener(this);
        setBorder(new BevelBorder(BevelBorder.LOWERED));
    }

    public void loadImage(File f) {
        if (f == null) {
            thumbnail = null;
        } else {
            ImageIcon tmpIcon = new ImageIcon(getImage(f.getPath()));
            if (tmpIcon.getIconWidth() > width) {
                thumbnail = new ImageIcon(
                        tmpIcon.getImage().getScaledInstance(width, -1, Image.SCALE_SMOOTH));
            } else {
                thumbnail = tmpIcon;
            }
        }
    }

    public BufferedImage getImage(String fileName) {
        try {
            return ImageIO.read(new File(fileName));
        } catch (IOException ioe) {
            System.err.println("Error loading Image!!");
        }
        return null;
    }

    @Override
    public void propertyChange(PropertyChangeEvent e) {
        String prop = e.getPropertyName();
        if (prop == JFileChooser.SELECTED_FILE_CHANGED_PROPERTY) {
            if (isShowing()) {
                loadImage((File) e.getNewValue());
                repaint();
            }
        }
    }

    @Override
    public void paintComponent(Graphics g) {
        super.paintComponent(g);
        if (thumbnail != null) {
            int x = getWidth() / 2 - thumbnail.getIconWidth() / 2;
            int y = getHeight() / 2 - thumbnail.getIconHeight() / 2;
            if (y < 0) {
                y = 0;
            }

            if (x < 5) {
                x = 5;
            }
            thumbnail.paintIcon(this, g, x, y);
        }
    }
}

Code:
package com.jhlabs.util;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 9/19/14
 * Time: 4:23 PM
 * To change this template use File | Settings | File Templates.
 */

/**
 * An image histogram.
 */
public class Histogram {

    public static final int RED = 0;
    public static final int GREEN = 1;
    public static final int BLUE = 2;
    public static final int GRAY = 3;

    protected int[][] histogram;
    protected int numSamples;
    protected int[] minValue;
    protected int[] maxValue;
    protected int[] minFrequency;
    protected int[] maxFrequency;
    protected float[] mean;
    protected boolean isGray;

    public Histogram() {
        histogram = null;
        numSamples = 0;
        isGray = true;
        minValue = null;
        maxValue = null;
        minFrequency = null;
        maxFrequency = null;
        mean = null;
    }

    public Histogram(int[] pixels, int w, int h, int offset, int stride) {
        histogram = new int[3][256];
        minValue = new int[4];
        maxValue = new int[4];
        minFrequency = new int[3];
        maxFrequency = new int[3];
        mean = new float[3];

        numSamples = w * h;
        isGray = true;

        int index = 0;
        for (int y = 0; y < h; y++) {
            index = offset + y * stride;
            for (int x = 0; x < w; x++) {
                int rgb = pixels[index++];
                int r = (rgb >> 16) & 0xff;
                int g = (rgb >> 8) & 0xff;
                int b = rgb & 0xff;
                histogram[RED][r]++;
                histogram[GREEN][g]++;
                histogram[BLUE][b]++;
            }
        }

        for (int i = 0; i < 256; i++) {
            if (histogram[RED][i] != histogram[GREEN][i] || histogram[GREEN][i] != histogram[BLUE][i]) {
                isGray = false;
                break;
            }
        }

        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 256; j++) {
                if (histogram[i][j] > 0) {
                    minValue[i] = j;
                    break;
                }
            }

            for (int j = 255; j >= 0; j--) {
                if (histogram[i][j] > 0) {
                    maxValue[i] = j;
                    break;
                }
            }

            minFrequency[i] = Integer.MAX_VALUE;
            maxFrequency[i] = 0;
            for (int j = 0; j < 256; j++) {
                minFrequency[i] = Math.min(minFrequency[i], histogram[i][j]);
                maxFrequency[i] = Math.max(maxFrequency[i], histogram[i][j]);
                mean[i] += (float) (j * histogram[i][j]);
            }
            mean[i] /= (float) numSamples;
        }
        minValue[GRAY] = Math.min(Math.min(minValue[RED], minValue[GREEN]), minValue[BLUE]);
        maxValue[GRAY] = Math.max(Math.max(maxValue[RED], maxValue[GREEN]), maxValue[BLUE]);
    }

    public boolean isGray() {
        return isGray;
    }

    public int getNumSamples() {
        return numSamples;
    }

    public int getFrequency(int value) {
        if (numSamples > 0 && isGray && value >= 0 && value <= 255)
            return histogram[0][value];
        return -1;
    }

    public int getFrequency(int channel, int value) {
        if (numSamples < 1 || channel < 0 || channel > 2 ||
                value < 0 || value > 255)
            return -1;
        return histogram[channel][value];
    }

    public int getMinFrequency() {
        if (numSamples > 0 && isGray)
            return minFrequency[0];
        return -1;
    }

    public int getMinFrequency(int channel) {
        if (numSamples < 1 || channel < 0 || channel > 2)
            return -1;
        return minFrequency[channel];
    }


    public int getMaxFrequency() {
        if (numSamples > 0 && isGray)
            return maxFrequency[0];
        return -1;
    }

    public int getMaxFrequency(int channel) {
        if (numSamples < 1 || channel < 0 || channel > 2)
            return -1;
        return maxFrequency[channel];
    }


    public int getMinValue() {
        if (numSamples > 0 && isGray)
            return minValue[0];
        return -1;
    }

    public int getMinValue(int channel) {
        return minValue[channel];
    }

    public int getMaxValue() {
        if (numSamples > 0 && isGray)
            return maxValue[0];
        return -1;
    }

    public int getMaxValue(int channel) {
        return maxValue[channel];
    }

    public float getMeanValue() {
        if (numSamples > 0 && isGray)
            return mean[0];
        return -1.0F;
    }

    public float getMeanValue(int channel) {
        if (numSamples > 0 && RED <= channel && channel <= BLUE)
            return mean[channel];
        return -1.0F;
    }
}

Code:
package com.jhlabs.util;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 9/19/14
 * Time: 4:24 PM
 * To change this template use File | Settings | File Templates.
 */

import java.awt.*;
import java.awt.image.BufferedImage;
import java.awt.image.PixelGrabber;

public class HistogramDisplay {
    private static final int MARGIN = 10;
    private static final int INPUT_Y = 36;
    private static final int OUTPUT_Y = 10;
    private boolean displayRGB = true;
    protected Histogram histogram;
    private String path = "Images/";
    private String fileName;
    private BufferedImage image;

    public HistogramDisplay(BufferedImage imgName) {
        image = imgName;
        setImage(image);
    }

    public Dimension getMinimumSize() {
        return new Dimension(276, 66);
    }

    public void setImage(BufferedImage image) {
        if (image != null) {
            PixelGrabber pg = new PixelGrabber(image, 0, 0, -1, -1, null, 0, -1);
            try {
                pg.grabPixels();
            } catch (InterruptedException e) {
                throw new RuntimeException("interrupted waiting for pixels!");
            }
            if ((pg.status() & 0x80) != 0) {
                throw new RuntimeException("image fetch aborted");
            }
            histogram = new Histogram((int[]) pg.getPixels(), pg.getWidth(), pg.getHeight(), 0, pg.getWidth());
        }
    }

    public Dimension getPreferredSize() {
        return new Dimension(276, 200);
    }

    public BufferedImage getHistogram() {
        BufferedImage buff = new BufferedImage(276, 220, BufferedImage.TRANSLUCENT);
        Graphics2D g2d = (Graphics2D) buff.getGraphics();

        // Set the rendering hints
        g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
        g2d.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_COLOR_RENDERING, RenderingHints.VALUE_COLOR_RENDER_QUALITY);
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BICUBIC);

        int width = 276;
        int height = 220;
        int b = height - 36;
        width -= 20;
        g2d.setColor(Color.white);
        g2d.fillRect(11, 1, width, b);
        g2d.setColor(Color.black);
        g2d.drawRect(10, 0, width - 1, b);
        // Draw the Histogram
        if (histogram != null) {

            if (displayRGB) {
                int max = 0;
                for (int channel = 0; channel <= 2; channel++)
                    max = Math.max(histogram.getMaxFrequency(channel), 0);
                g2d.setComposite(AlphaComposite.getInstance(3, 0.6F));
                for (int channel = 0; channel <= 2; channel++) {
                    g2d.setColor(channel == 1 ? Color.green : channel == 0 ? Color.red : Color.blue);
                    for (int x = 0; x < 256; x++) {
                        int y = histogram.getFrequency(channel, x) * height / max;
                        g2d.drawLine(x + 10, b, x + 10, b - y);
                    }
                }
            } else {

                g2d.setColor(Color.black);
                int channel = 0;
                int max = histogram.getMaxFrequency(channel);
                for (int x = 0; x < 256; x++) {
                    int y = histogram.getFrequency(channel, x) * height / max;
                    g2d.drawLine(x + 10, b, x + 10, b - y);
                }
            }
        }
        return buff;
    }
}

Here is how to use various filters :

Code:
// We import various Image filters ...
import com.jhlabs.image.*;
...
// Rest of the classes

// To apply the emboss filter , we use the following code

// Emboss the Image (like in the back side of a Rupee coin)
    EmbossFilter eFilter = new EmbossFilter();
    eFilter.setAzimuth(5f);
    eFilter.setElevation(0.5f);
    eFilter.setBumpHeight(1.8f);
    if (image != null) {
         setImage(eFilter.filter(image, null), "Embossed - Azimuth = 5f , Elevation = 0.5f , BumpHeight = 1.8f");
    }

To use this software , launch it from the IDE .
From the menu select File -> Open .
select a valid Image file , select OK.

From the menu select Filter -> Emboss

(this applies the Emboss filter to the Image)

Click on the Print menuitem (File -> Print ) to print the Image

Click on the Save menuitem , to save the Image, this overwrites the original Image!!

Click on the Revert menuitem ( File -> Revert) to revert to the original Image

ImageProcessor.java - The main class contains the code to apply the various filters

Code:
package com.jhlabs.util;

/**
 * Created with IntelliJ IDEA.
 * User: Sowndar
 * Date: 8/2/14
 * Time: 8:43 PM
 * To change this template use File | Settings | File Templates.
 */
// ImageProcessor - Do some filters like lens Blur, crystallize, Emboss, Ripple . motion blur etc.,

import com.jhlabs.image.*;

import javax.imageio.ImageIO;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.IOException;
import java.util.HashSet;
import java.util.Set;

public class ImageProcessor extends JFrame implements ActionListener, Printable {

    private JLabel label = new JLabel();
    private JFileChooser fc = new JFileChooser(".");
    private JLabel message = new JLabel("Ready", JLabel.LEFT);
    private BufferedImage buffImg, image;
    // MenuItems ...
    private JMenuItem open = new JMenuItem("Open...");
    private JMenuItem revert = new JMenuItem("Revert");
    private JMenuItem lensBlur = new JMenuItem("Lens Blur");
    private JMenuItem blur = new JMenuItem("Blur");
    private JMenuItem crystallize = new JMenuItem("Crystallize");
    private JMenuItem emboss = new JMenuItem("Emboss");
    private JMenuItem grayScale = new JMenuItem("GrayScale");
    private JMenuItem invert = new JMenuItem("Invert");
    private JMenuItem sharpen = new JMenuItem("Sharpen");
    private JMenuItem light = new JMenuItem("Light");
    private JMenuItem solarize = new JMenuItem("Solarize");
    private JMenuItem sphere = new JMenuItem("Sphere");
    private JMenuItem threshold = new JMenuItem("Threshold");
    private JMenuItem edge = new JMenuItem("Edge");
    private JMenuItem motionBlur = new JMenuItem("Motion Blur");
    private JMenuItem marble = new JMenuItem("Marble");
    private JMenuItem noise = new JMenuItem("Noise");
    private JMenuItem oil = new JMenuItem("Oil");
    private JMenuItem ripple = new JMenuItem("Ripple");
    private JMenuItem sparkle = new JMenuItem("Sparkle");
    private JMenuItem twirl = new JMenuItem("Twirl");
    private JMenuItem water = new JMenuItem("Water Ripples");
    private JMenuItem tile = new JMenuItem("Tile");
    private JMenuItem histograph = new JMenuItem("Histogram");
    private JMenuItem print = new JMenuItem("Print");
    private JMenuItem save = new JMenuItem("Save");
    private JMenuItem exit = new JMenuItem("Exit");
    private int imgWidth = -1;
    private int imgHeight = -1;
    private Dimension scrDim;
    private String fileName;
    private JFrame frame = new JFrame("Histogram");
    private HistogramDisplay histogramDisplay;
    private JLabel histLabel = new JLabel();

    // Get supported Image formats (remove duplicate entries)
    public String[] getReaderFormats() {
        String[] rFormat = ImageIO.getReaderFormatNames();
        Set<String> set = new HashSet<String>();
        String imgformat = "";
        // Remove duplicate entries
        for (String aRFormat : rFormat) {
            imgformat = aRFormat;
            imgformat = imgformat.toLowerCase();
            set.add(imgformat);
        }
        String[] frmt = new String[set.size()];
        return set.toArray(frmt);
    }

    // Update the UI
    public void updateUI() {
        open.updateUI();
        revert.updateUI();
        blur.updateUI();
        edge.updateUI();
        lensBlur.updateUI();
        crystallize.updateUI();
        emboss.updateUI();
        invert.updateUI();
        light.updateUI();
        solarize.updateUI();
        sphere.updateUI();
        threshold.updateUI();
        sharpen.updateUI();
        marble.updateUI();
        noise.updateUI();
        grayScale.updateUI();
        motionBlur.updateUI();
        oil.updateUI();
        ripple.updateUI();
        sparkle.updateUI();
        twirl.updateUI();
        histograph.updateUI();
        exit.updateUI();
        fc.updateUI();
        water.updateUI();
        tile.updateUI();
        print.updateUI();
        save.updateUI();
    }

    // Enable or disable Components
    @Override
    public void setEnabled(boolean condition) {
        revert.setEnabled(condition);
        edge.setEnabled(condition);
        blur.setEnabled(condition);
        lensBlur.setEnabled(condition);
        crystallize.setEnabled(condition);
        emboss.setEnabled(condition);
        invert.setEnabled(condition);
        light.setEnabled(condition);
        solarize.setEnabled(condition);
        sphere.setEnabled(condition);
        threshold.setEnabled(condition);
        sharpen.setEnabled(condition);
        marble.setEnabled(condition);
        noise.setEnabled(condition);
        grayScale.setEnabled(condition);
        motionBlur.setEnabled(condition);
        oil.setEnabled(condition);
        ripple.setEnabled(condition);
        sparkle.setEnabled(condition);
        twirl.setEnabled(condition);
        water.setEnabled(condition);
        tile.setEnabled(condition);
        histograph.setEnabled(condition);
        print.setEnabled(condition);
        save.setEnabled(condition);
    }

    // Constructor
    public ImageProcessor(String title) {
        super(title);
        try {
            UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
        } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException e) {
            System.err.println("Error loading look'n feel!!");
        }
        updateUI();
        scrDim = Toolkit.getDefaultToolkit().getScreenSize();
        label.setHorizontalAlignment(SwingConstants.CENTER);
        label.setVerticalAlignment(SwingConstants.CENTER);
        // Add the action listeners
        open.addActionListener(this);
        revert.addActionListener(this);
        blur.addActionListener(this);
        lensBlur.addActionListener(this);
        crystallize.addActionListener(this);
        emboss.addActionListener(this);
        grayScale.addActionListener(this);
        invert.addActionListener(this);
        light.addActionListener(this);
        solarize.addActionListener(this);
        sphere.addActionListener(this);
        threshold.addActionListener(this);
        sharpen.addActionListener(this);
        marble.addActionListener(this);
        noise.addActionListener(this);
        edge.addActionListener(this);
        motionBlur.addActionListener(this);
        oil.addActionListener(this);
        ripple.addActionListener(this);
        sparkle.addActionListener(this);
        twirl.addActionListener(this);
        water.addActionListener(this);
        tile.addActionListener(this);
        histograph.addActionListener(this);
        print.addActionListener(this);
        save.addActionListener(this);
        exit.addActionListener(this);
        JMenuBar mBar = new JMenuBar();

        JMenu menu = new JMenu("File");
        menu.addActionListener(this);

        //Disable menuitems other than 'Open' & 'Exit"!
        // Since there is no Image to process!!
        setEnabled(false);
        menu.add(open);
        menu.addSeparator();
        menu.add(revert);
        menu.addSeparator();
        menu.add(print);
        menu.add(save);
        menu.add(exit);

        mBar.add(menu);

        menu = new JMenu("Filter");
        menu.addActionListener(this);

        menu.add(blur);
        menu.add(lensBlur);
        menu.add(crystallize);
        menu.add(emboss);
        menu.add(grayScale);
        menu.add(edge);
        menu.add(invert);
        menu.add(light);
        menu.add(solarize);
        menu.add(sphere);
        menu.add(threshold);
        menu.add(sharpen);
        menu.add(marble);
        menu.add(noise);
        menu.add(ripple);
        menu.add(motionBlur);
        menu.add(oil);
        menu.add(sparkle);
        menu.add(twirl);
        menu.add(water);
        menu.add(tile);
        menu.add(histograph);

        mBar.add(menu);
        setJMenuBar(mBar);

        frame.add(histLabel);
        add(new JScrollPane(label), BorderLayout.CENTER);
        add(message, BorderLayout.SOUTH);
        setSize(scrDim.width / 2, scrDim.height);
        setVisible(true);
        setDefaultCloseOperation(EXIT_ON_CLOSE);
    }

    // Print the Image
    @Override
    public int print(Graphics g, PageFormat pf, int page) throws
            PrinterException {

        if (page > 0) { /* We have only one page, and 'page' is zero-based */

            return NO_SUCH_PAGE;
        }

        /* User (0,0) is typically outside the imageable area, so we must
         * translate by the X and Y values in the PageFormat to avoid clipping
         */
        Graphics2D g2d = (Graphics2D) g;
        g2d.translate(pf.getImageableX(), pf.getImageableY());

        if (buffImg != null) {
            g2d.drawImage(buffImg, 0, 0, this);
        }

        /* tell the caller that this page is part of the printed document */
        return PAGE_EXISTS;
    }

    // Update the Image in the label & the message
    public void setImage(BufferedImage buff, String msg) {
        if (buff != null) {
            if (label != null) {
                label.setIcon(new ImageIcon(buff));
                buffImg = buff;
                message.setText(msg);
            }
        }
    }

    // Get the Image from the disk
    public BufferedImage getImage(String fileName) {
        //Fetch the Image for processing
        try {
            return ImageIO.read(new File(fileName));
        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(null, "Not a valid Image!!!", "Error", JOptionPane.ERROR_MESSAGE);
            //Disable menuitems other than 'Open' & 'Exit"!
            // Since there is no Image to process!!
            setEnabled(false);
        }
        // In case of error
        return null;
    }

    // Save Image to the disk
    public void saveImage() {
        try {
            String format = fileName.substring(fileName.lastIndexOf(".") + 1);
            ImageIO.write(buffImg, format, new File(fileName));

        } catch (IOException ioe) {
            JOptionPane.showMessageDialog(null, "The Image can't be saved!!", "Message", JOptionPane.ERROR_MESSAGE);
        }
    }

    @Override
    public void actionPerformed(ActionEvent ae) {
        Object source = ae.getSource();
        if (source == exit) {
            System.exit(0);
        } else if (source == save) {
            saveImage();
        } else if (source == print) {
            if (image != null) {
                // Print the Image
                PrinterJob job = PrinterJob.getPrinterJob();
                job.setPrintable(this);
                boolean ok = job.printDialog();
                if (ok) {
                    try {
                        job.print();
                    } catch (PrinterException ex) {
                        /* The job did not successfully complete */
                    }
                }
            }
        } else if (source == revert) {
            // Restore the original Image
            label.setIcon(new ImageIcon(image));
            message.setText("Image Reverted");
        } else if (source == open) {
            //Open the FileChooser dialog
            fc.setAccessory(new ImagePreview(fc));
            fc.setPreferredSize(new Dimension(800, 550));
            fc.setAcceptAllFileFilterUsed(false);
            fc.setCurrentDirectory(new File("Samples"));
            final String[] format = getReaderFormats();
            fc.addChoosableFileFilter(new FileFilter() {

                @Override
                public boolean accept(File file) {
                    String fileName = file.getName();
                    for (String aFormat : format) {
                        // Show directory & images files only
                        if (fileName.endsWith(aFormat) || file.isDirectory()) {
                            return true;
                        }
                    }
                    return false;
                }

                // Show something like "*.jpg,*.jpeg,*.bmp,*.tiff,*.gif,*.jpeg2000" etc.,
                @Override
                public String getDescription() {
                    String str = "";
                    for (String aFormat : format) {
                        str += "*." + aFormat + ",";
                    }
                    return str;
                }
            });
            int result = fc.showOpenDialog(this);

            if (result != 0) {
                return;
            }

            File file = fc.getSelectedFile();
            fileName = file.toString();
            if (file == null) {
                return;
            } else {
                //Fetch the Image for processing
                image = getImage(fileName);
                if (image != null) {
                    buffImg = image;
                    imgWidth = image.getWidth(null);
                    imgHeight = image.getHeight(null);
                    //Enable the MenuItems now!
                    setEnabled(true);
                    // Update the label
                    label.setIcon(new ImageIcon(buffImg));
                    histogramDisplay = new HistogramDisplay(buffImg);
                    if(frame.isShowing()) {
                        frame.setVisible(false);
                    }
                    message.setText("Ready");
                    pack();
                } else {
                    setEnabled(false);
                    // Update the label
                    label.setIcon(null);
                    message.setText("Ready");
                }
            }
        } else if (source == blur) {
            BlurFilter blurFilter = new BlurFilter();
            if (image != null) {
                setImage(blurFilter.filter(image, null), "Blur Filter");
            }
        } else if (source == lensBlur) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    setEnabled(false);
                    LensBlurFilter lFilter = new LensBlurFilter();
                    lFilter.setBloom(1f);
                    lFilter.setBloomThreshold(5f);
                    lFilter.setRadius(15);
                    if (image != null) {
                        setImage(lFilter.filter(image, null), "Lens Blur - Bloom = 1f, BloomThreshold = 5f, Radius = 15");
                    }
                    setEnabled(true);
                }
            }).start();

        } else if (source == crystallize) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    setEnabled(false);
                    CrystallizeFilter cFilter = new CrystallizeFilter();
                    cFilter.setAmount(40f);
                    cFilter.setGridType(CrystallizeFilter.HEXAGONAL);
                    cFilter.setScale(20);
                    if (image != null) {
                        setImage(cFilter.filter(image, null), "Crystallized - Amount = 40f , Scale = 20");
                    }
                    setEnabled(true);
                }
            }).start();

        } else if (source == oil) {
            // This takes a bit longer to process
            new Thread(new Runnable() {

                @Override
                public void run() {
                    setEnabled(false);
                    OilFilter oFilter = new OilFilter();
                    if (image != null) {
                        setImage(oFilter.filter(image, null), "Image Oil Filter");
                    }
                    setEnabled(true);
                }
            }).start();

        } else if (source == ripple) {
            try {
                setEnabled(false);
                RippleFilter rFilter = new RippleFilter();
                // WaveType - SINE, SAWTOOTH, TRIANGLE, NOISE
                rFilter.setWaveType(RippleFilter.SINE);
                rFilter.setXAmplitude(5f);
                rFilter.setYAmplitude(5f);
                rFilter.setXWavelength(6f);
                if (image != null) {
                    setImage(rFilter.filter(image, null), "Ripples - WaveType = SINE, XAmplitude = 5f, YAmplitude = 5f, XWaveLength = 6f");
                }
                setEnabled(true);
            } catch (Exception e) {
            }
        } else if (source == sparkle) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    setEnabled(false);
                    SparkleFilter spFilter = new SparkleFilter();
                    spFilter.setAmount(40);
                    spFilter.setRadius(50);
                    spFilter.setRandomness(10 * 2);
                    spFilter.setRays(55);
                    if (image != null) {
                        setImage(spFilter.filter(image, null), "Sparkle");
                    }
                    setEnabled(true);
                }
            }).start();

        } else if (source == emboss) {
            setEnabled(false);
            // Emboss the Image (like in the back side of a Rupee coin)
            EmbossFilter eFilter = new EmbossFilter();
            eFilter.setAzimuth(5f);
            eFilter.setElevation(0.5f);
            eFilter.setBumpHeight(1.8f);
            if (image != null) {
                setImage(eFilter.filter(image, null), "Embossed - Azimuth = 5f , Elevation = 0.5f , BumpHeight = 1.8f");
            }
            setEnabled(true);

        } else if (source == grayScale) {
            GrayscaleFilter grayscaleFilter = new GrayscaleFilter();
            if (image != null) {
                setImage(grayscaleFilter.filter(image, null), "GrayScale");
            }
        } else if (source == invert) {
            InvertFilter invertFilter = new InvertFilter();
            if (image != null) {
                setImage(invertFilter.filter(image, null), "Invert Filter");
            }
        } else if (source == light) {
            LightFilter lightFilter = new LightFilter();
            lightFilter.setDiffuseColor(15);
            lightFilter.setBumpSource(LightFilter.BUMPS_FROM_BEVEL);
            lightFilter.setViewDistance(60f);
            if (image != null) {
                setImage(lightFilter.filter(image, null), "Light Filter");
            }
        } else if (source == solarize) {
            SolarizeFilter solarizeFilter = new SolarizeFilter();
            if (image != null) {
                setImage(solarizeFilter.filter(image, null), "Solarize");
            }
        } else if (source == sphere) {
            SphereFilter sphereFilter = new SphereFilter();
            sphereFilter.setRefractionIndex(1.5f);
            sphereFilter.setRadius(200f);
            if (image != null) {
                setImage(sphereFilter.filter(image, null), "Sphere Filter");
            }
        } else if (source == threshold) {
            ThresholdFilter thresholdFilter = new ThresholdFilter();
            if (image != null) {
                setImage(thresholdFilter.filter(image, null), "Threshold Filter");
            }
        } else if (source == sharpen) {
            SharpenFilter sharpenFilter = new SharpenFilter();
            if (image != null) {
                setImage(sharpenFilter.filter(image, null), "Sharpen Filter");
            }
        } else if (source == marble) {
            MarbleFilter marbleFilter = new MarbleFilter();
            if (image != null) {
                setImage(marbleFilter.filter(image, null), "Marble Filter");
            }
        } else if (source == noise) {
            NoiseFilter noiseFilter = new NoiseFilter();
            noiseFilter.setAmount(50);
            noiseFilter.setDensity(25f);
            noiseFilter.setDistribution(35);
            if (image != null) {
                setImage(noiseFilter.filter(image, null), "Noise Filter");
            }
        } else if (source == edge) {
            EdgeFilter edgeFilter = new EdgeFilter();
            edgeFilter.setHEdgeMatrix(EdgeFilter.ROBERTS_H);
            edgeFilter.setVEdgeMatrix(EdgeFilter.FREI_CHEN_V);
            if (image != null) {
                setImage(edgeFilter.filter(image, null), "Edge Filter");
            }
        } else if (source == motionBlur) {
            new Thread(new Runnable() {

                @Override
                public void run() {
                    // Motion blur takes a lot of time!!, For faster Motion blur use MotionBlurOp
                    setEnabled(false);
                    MotionBlurFilter mFilter = new MotionBlurFilter();
                    mFilter.setDistance(120);
                    mFilter.setAngle(20);
                    if (image != null) {
                        setImage(mFilter.filter(image, null), "Motion Blur - Angle = 120f");
                    }
                    setEnabled(true);
                }
            }).start();

        } else if (source == twirl) {
            setEnabled(false);
            TwirlFilter tFilter = new TwirlFilter();
            tFilter.setAngle(3);
            tFilter.setRadius(250f);
            if (image != null) {
                setImage(tFilter.filter(image, null), "Twirl - Angle = 3 radians");
            }
            setEnabled(true);
        } else if (source == histograph) {

            // Display the Histogram
            histLabel.setIcon(new ImageIcon(histogramDisplay.getHistogram()));
            frame.pack();
            frame.setResizable(false);
            frame.validate();
            frame.setVisible(true);
            frame.setDefaultCloseOperation(JFrame.HIDE_ON_CLOSE);

        } else if (source == tile) {
            TileImageFilter tileImageFilter = new TileImageFilter();
            tileImageFilter.setWidth(imgWidth * 3);
            tileImageFilter.setHeight(imgHeight * 3);
            if (image != null) {
                setImage(tileImageFilter.filter(image, null), "Tile Image");
            }
        } else {
            setEnabled(false);
            // Water ripple effect
            WaterFilter wFilter = new WaterFilter();
            wFilter.setAmplitude(20);
            wFilter.setPhase(8f);
            wFilter.setWavelength(120f);
            wFilter.setRadius(250f);
            if (image != null) {
                setImage(wFilter.filter(image, null), "Water Ripples - Amplitude = 20, Phase = 8f, WaveLength = 120f, Radius = 250f");
            }
            setEnabled(true);
        }
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                new ImageProcessor("Image Processor");
            }
        });
    }
}

Bigger programs must be organised into several packages for the sake of simplicity & readability.

A package is a namespace that organizes a set of related classes and interfaces. Conceptually you can think of packages as being similar to different folders
on your computer. You might keep HTML pages in one folder, images in another, and scripts or applications in yet another. Because software written in the Java
programming language can be composed of hundreds or thousands of individual classes, it makes sense to keep things organized by placing related classes and interfaces into packages.

Also you must use a IDE like NetBeans , Eclipse, or IntelliJ IDEA to create & run these programs. The IDE integrates compiler, profiler, debugger , code analyser + others into a single
application. It makes the job of a Java Developer a lot easier!!

This wraps up the Image processing guide!!
 
Last edited:
Top Bottom