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.*; 020import java.awt.image.*; 021import com.jhlabs.math.*; 022 023/** 024 * A filter which simulates the appearance of looking through glass. A separate grayscale displacement image is provided and 025 * pixels in the source image are displaced according to the gradient of the displacement map. 026 */ 027public class DisplaceFilter extends TransformFilter { 028 029 private float amount = 1; 030 private BufferedImage displacementMap = null; 031 private int[] xmap, ymap; 032 private int dw, dh; 033 034 public DisplaceFilter() { 035 } 036 037 /** 038 * Set the displacement map. 039 * @param displacementMap an image representing the displacment at each point 040 * @see #getDisplacementMap 041 */ 042 public void setDisplacementMap(BufferedImage displacementMap) { 043 this.displacementMap = displacementMap; 044 } 045 046 /** 047 * Get the displacement map. 048 * @return an image representing the displacment at each point 049 * @see #setDisplacementMap 050 */ 051 public BufferedImage getDisplacementMap() { 052 return displacementMap; 053 } 054 055 /** 056 * Set the amount of distortion. 057 * @param amount the amount 058 * @min-value 0 059 * @max-value 1 060 * @see #getAmount 061 */ 062 public void setAmount(float amount) { 063 this.amount = amount; 064 } 065 066 /** 067 * Get the amount of distortion. 068 * @return the amount 069 * @see #setAmount 070 */ 071 public float getAmount() { 072 return amount; 073 } 074 075 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 076 int w = src.getWidth(); 077 int h = src.getHeight(); 078 079 BufferedImage dm = displacementMap != null ? displacementMap : src; 080 081 dw = dm.getWidth(); 082 dh = dm.getHeight(); 083 084 int[] mapPixels = new int[dw*dh]; 085 getRGB( dm, 0, 0, dw, dh, mapPixels ); 086 xmap = new int[dw*dh]; 087 ymap = new int[dw*dh]; 088 089 int i = 0; 090 for ( int y = 0; y < dh; y++ ) { 091 for ( int x = 0; x < dw; x++ ) { 092 int rgb = mapPixels[i]; 093 int r = (rgb >> 16) & 0xff; 094 int g = (rgb >> 8) & 0xff; 095 int b = rgb & 0xff; 096 mapPixels[i] = (r+g+b) / 8; // An arbitrary scaling factor which gives a good range for "amount" 097 i++; 098 } 099 } 100 101 i = 0; 102 for ( int y = 0; y < dh; y++ ) { 103 int j1 = ((y+dh-1) % dh) * dw; 104 int j2 = y*dw; 105 int j3 = ((y+1) % dh) * dw; 106 for ( int x = 0; x < dw; x++ ) { 107 int k1 = (x+dw-1) % dw; 108 int k2 = x; 109 int k3 = (x+1) % dw; 110 xmap[i] = mapPixels[k1+j1] + mapPixels[k1+j2] + mapPixels[k1+j3] - mapPixels[k3+j1] - mapPixels[k3+j2] - mapPixels[k3+j3]; 111 ymap[i] = mapPixels[k1+j3] + mapPixels[k2+j3] + mapPixels[k3+j3] - mapPixels[k1+j1] - mapPixels[k2+j1] - mapPixels[k3+j1]; 112 i++; 113 } 114 } 115 mapPixels = null; 116 dst = super.filter( src, dst ); 117 xmap = ymap = null; 118 return dst; 119 } 120 121 protected void transformInverse(int x, int y, float[] out) { 122 float xDisplacement, yDisplacement; 123 float nx = x; 124 float ny = y; 125 int i = (y % dh)*dw + x % dw; 126 out[0] = x + amount * xmap[i]; 127 out[1] = y + amount * ymap[i]; 128 } 129 130 public String toString() { 131 return "Distort/Displace..."; 132 } 133}