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.*; 021 022/** 023 * A class to emboss an image. 024 */ 025public class EmbossFilter extends WholeImageFilter { 026 027 private final static float pixelScale = 255.9f; 028 029 private float azimuth = 135.0f * ImageMath.PI / 180.0f, elevation = 30.0f * ImageMath.PI / 180f; 030 private boolean emboss = false; 031 private float width45 = 3.0f; 032 033 public EmbossFilter() { 034 } 035 036 public void setAzimuth(float azimuth) { 037 this.azimuth = azimuth; 038 } 039 040 public float getAzimuth() { 041 return azimuth; 042 } 043 044 public void setElevation(float elevation) { 045 this.elevation = elevation; 046 } 047 048 public float getElevation() { 049 return elevation; 050 } 051 052 public void setBumpHeight(float bumpHeight) { 053 this.width45 = 3 * bumpHeight; 054 } 055 056 public float getBumpHeight() { 057 return width45 / 3; 058 } 059 060 public void setEmboss(boolean emboss) { 061 this.emboss = emboss; 062 } 063 064 public boolean getEmboss() { 065 return emboss; 066 } 067 068 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 069 int index = 0; 070 int[] outPixels = new int[width * height]; 071 072 int[] bumpPixels; 073 int bumpMapWidth, bumpMapHeight; 074 075 bumpMapWidth = width; 076 bumpMapHeight = height; 077 bumpPixels = new int[bumpMapWidth * bumpMapHeight]; 078 for (int i = 0; i < inPixels.length; i++) 079 bumpPixels[i] = PixelUtils.brightness(inPixels[i]); 080 081 int Nx, Ny, Nz, Lx, Ly, Lz, Nz2, NzLz, NdotL; 082 int shade, background; 083 084 Lx = (int)(Math.cos(azimuth) * Math.cos(elevation) * pixelScale); 085 Ly = (int)(Math.sin(azimuth) * Math.cos(elevation) * pixelScale); 086 Lz = (int)(Math.sin(elevation) * pixelScale); 087 088 Nz = (int)(6 * 255 / width45); 089 Nz2 = Nz * Nz; 090 NzLz = Nz * Lz; 091 092 background = Lz; 093 094 int bumpIndex = 0; 095 096 for (int y = 0; y < height; y++, bumpIndex += bumpMapWidth) { 097 int s1 = bumpIndex; 098 int s2 = s1 + bumpMapWidth; 099 int s3 = s2 + bumpMapWidth; 100 101 for (int x = 0; x < width; x++, s1++, s2++, s3++) { 102 if (y != 0 && y < height-2 && x != 0 && x < width-2) { 103 Nx = bumpPixels[s1-1] + bumpPixels[s2-1] + bumpPixels[s3-1] - bumpPixels[s1+1] - bumpPixels[s2+1] - bumpPixels[s3+1]; 104 Ny = bumpPixels[s3-1] + bumpPixels[s3] + bumpPixels[s3+1] - bumpPixels[s1-1] - bumpPixels[s1] - bumpPixels[s1+1]; 105 106 if (Nx == 0 && Ny == 0) 107 shade = background; 108 else if ((NdotL = Nx*Lx + Ny*Ly + NzLz) < 0) 109 shade = 0; 110 else 111 shade = (int)(NdotL / Math.sqrt(Nx*Nx + Ny*Ny + Nz2)); 112 } else 113 shade = background; 114 115 if (emboss) { 116 int rgb = inPixels[index]; 117 int a = rgb & 0xff000000; 118 int r = (rgb >> 16) & 0xff; 119 int g = (rgb >> 8) & 0xff; 120 int b = rgb & 0xff; 121 r = (r*shade) >> 8; 122 g = (g*shade) >> 8; 123 b = (b*shade) >> 8; 124 outPixels[index++] = a | (r << 16) | (g << 8) | b; 125 } else 126 outPixels[index++] = 0xff000000 | (shade << 16) | (shade << 8) | shade; 127 } 128 } 129 130 return outPixels; 131 } 132 133 public String toString() { 134 return "Stylize/Emboss..."; 135 } 136 137}