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.util.*;
021import com.jhlabs.math.*;
022
023/**
024 * A filter which applies a crystallizing effect to an image, by producing Voronoi cells filled with colours from the image.
025 */
026public class CrystallizeFilter extends CellularFilter {
027
028        private float edgeThickness = 0.4f;
029        private boolean fadeEdges = false;
030        private int edgeColor = 0xff000000;
031
032        public CrystallizeFilter() {
033                setScale(16);
034                setRandomness(0.0f);
035        }
036        
037        public void setEdgeThickness(float edgeThickness) {
038                this.edgeThickness = edgeThickness;
039        }
040
041        public float getEdgeThickness() {
042                return edgeThickness;
043        }
044
045        public void setFadeEdges(boolean fadeEdges) {
046                this.fadeEdges = fadeEdges;
047        }
048
049        public boolean getFadeEdges() {
050                return fadeEdges;
051        }
052
053        public void setEdgeColor(int edgeColor) {
054                this.edgeColor = edgeColor;
055        }
056
057        public int getEdgeColor() {
058                return edgeColor;
059        }
060
061        public int getPixel(int x, int y, int[] inPixels, int width, int height) {
062                float nx = m00*x + m01*y;
063                float ny = m10*x + m11*y;
064                nx /= scale;
065                ny /= scale * stretch;
066                nx += 1000;
067                ny += 1000;     // Reduce artifacts around 0,0
068                float f = evaluate(nx, ny);
069
070                float f1 = results[0].distance;
071                float f2 = results[1].distance;
072                int srcx = ImageMath.clamp((int)((results[0].x-1000)*scale), 0, width-1);
073                int srcy = ImageMath.clamp((int)((results[0].y-1000)*scale), 0, height-1);
074                int v = inPixels[srcy * width + srcx];
075                f = (f2 - f1) / edgeThickness;
076                f = ImageMath.smoothStep(0, edgeThickness, f);
077                if (fadeEdges) {
078                        srcx = ImageMath.clamp((int)((results[1].x-1000)*scale), 0, width-1);
079                        srcy = ImageMath.clamp((int)((results[1].y-1000)*scale), 0, height-1);
080                        int v2 = inPixels[srcy * width + srcx];
081                        v2 = ImageMath.mixColors(0.5f, v2, v);
082                        v = ImageMath.mixColors(f, v2, v);
083                } else
084                        v = ImageMath.mixColors(f, edgeColor, v);
085                return v;
086        }
087
088        public String toString() {
089                return "Pixellate/Crystallize...";
090        }
091        
092}