001/*
002Copyright 2006 Jerry Huxtable
003
004Licensed under the Apache License, Version 2.0 (the "License");
005you may not use this file except in compliance with the License.
006You may obtain a copy of the License at
007
008   http://www.apache.org/licenses/LICENSE-2.0
009
010Unless required by applicable law or agreed to in writing, software
011distributed under the License is distributed on an "AS IS" BASIS,
012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013See the License for the specific language governing permissions and
014limitations under the License.
015*/
016
017package com.jhlabs.image;
018
019import java.awt.image.*;
020
021/**
022 * A filter which subtracts Gaussian blur from an image, sharpening it.
023 * @author Jerry Huxtable
024 */
025public class UnsharpFilter extends GaussianFilter {
026
027        private float amount = 0.5f;
028        private int threshold = 1;
029        
030        public UnsharpFilter() {
031                radius = 2;
032        }
033        
034        /**
035     * Set the threshold value.
036     * @param threshold the threshold value
037     * @see #getThreshold
038     */
039        public void setThreshold( int threshold ) {
040                this.threshold = threshold;
041        }
042        
043        /**
044     * Get the threshold value.
045     * @return the threshold value
046     * @see #setThreshold
047     */
048        public int getThreshold() {
049                return threshold;
050        }
051        
052        /**
053         * Set the amount of sharpening.
054         * @param amount the amount
055     * @min-value 0
056     * @max-value 1
057     * @see #getAmount
058         */
059        public void setAmount( float amount ) {
060                this.amount = amount;
061        }
062        
063        /**
064         * Get the amount of sharpening.
065         * @return the amount
066     * @see #setAmount
067         */
068        public float getAmount() {
069                return amount;
070        }
071        
072    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
073        int width = src.getWidth();
074        int height = src.getHeight();
075
076        if ( dst == null )
077            dst = createCompatibleDestImage( src, null );
078
079        int[] inPixels = new int[width*height];
080        int[] outPixels = new int[width*height];
081        src.getRGB( 0, 0, width, height, inPixels, 0, width );
082
083                if ( radius > 0 ) {
084                        convolveAndTranspose(kernel, inPixels, outPixels, width, height, alpha, alpha && premultiplyAlpha, false, CLAMP_EDGES);
085                        convolveAndTranspose(kernel, outPixels, inPixels, height, width, alpha, false, alpha && premultiplyAlpha, CLAMP_EDGES);
086                }
087
088        src.getRGB( 0, 0, width, height, outPixels, 0, width );
089
090                float a = 4*amount;
091
092                int index = 0;
093                for ( int y = 0; y < height; y++ ) {
094                        for ( int x = 0; x < width; x++ ) {
095                                int rgb1 = outPixels[index];
096                                int r1 = (rgb1 >> 16) & 0xff;
097                                int g1 = (rgb1 >> 8) & 0xff;
098                                int b1 = rgb1 & 0xff;
099
100                                int rgb2 = inPixels[index];
101                                int r2 = (rgb2 >> 16) & 0xff;
102                                int g2 = (rgb2 >> 8) & 0xff;
103                                int b2 = rgb2 & 0xff;
104
105                                if ( Math.abs( r1 -  r2 ) >= threshold )
106                                        r1 = PixelUtils.clamp( (int)((a+1) * (r1-r2) + r2) );
107                                if ( Math.abs( g1 -  g2 ) >= threshold )
108                                        g1 = PixelUtils.clamp( (int)((a+1) * (g1-g2) + g2) );
109                                if ( Math.abs( b1 -  b2 ) >= threshold )
110                                        b1 = PixelUtils.clamp( (int)((a+1) * (b1-b2) + b2) );
111
112                                inPixels[index] = (rgb1 & 0xff000000) | (r1 << 16) | (g1 << 8) | b1;
113                                index++;
114                        }
115                }
116
117        dst.setRGB( 0, 0, width, height, inPixels, 0, width );
118        return dst;
119    }
120
121        public String toString() {
122                return "Blur/Unsharp Mask...";
123        }
124}