001/**
002 *
003 * Copyright (c) 2014, the Railo Company Ltd. All rights reserved.
004 *
005 * This library is free software; you can redistribute it and/or
006 * modify it under the terms of the GNU Lesser General Public
007 * License as published by the Free Software Foundation; either 
008 * version 2.1 of the License, or (at your option) any later version.
009 * 
010 * This library is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
013 * Lesser General Public License for more details.
014 * 
015 * You should have received a copy of the GNU Lesser General Public 
016 * License along with this library.  If not, see <http://www.gnu.org/licenses/>.
017 * 
018 **/
019/*
020*
021
022Licensed under the Apache License, Version 2.0 (the "License");
023you may not use this file except in compliance with the License.
024You may obtain a copy of the License at
025
026   http://www.apache.org/licenses/LICENSE-2.0
027
028Unless required by applicable law or agreed to in writing, software
029distributed under the License is distributed on an "AS IS" BASIS,
030WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
031See the License for the specific language governing permissions and
032limitations under the License.
033*/
034
035package lucee.runtime.img.filter;import java.awt.image.BufferedImage;
036
037import lucee.runtime.engine.ThreadLocalPageContext;
038import lucee.runtime.exp.FunctionException;
039import lucee.runtime.exp.PageException;
040import lucee.runtime.img.ImageUtil;
041import lucee.runtime.type.KeyImpl;
042import lucee.runtime.type.Struct;
043import lucee.runtime.type.util.CollectionUtil;
044
045/**
046 * A filter which interpolates between two images. You can set the interpolation factor outside the range 0 to 1
047 * to extrapolate images.
048 */
049public class InterpolateFilter extends AbstractBufferedImageOp  implements DynFiltering {
050        
051        private BufferedImage destination;
052        private float interpolation;
053
054        public InterpolateFilter() {
055        }
056
057    /**
058     * Set the destination image.
059     * @param destination the destination image
060     * @see #getDestination
061     */
062        public void setDestination( BufferedImage destination ) {
063                this.destination = destination;
064        }
065        
066    /**
067     * Get the destination image.
068     * @return the destination image
069     * @see #setDestination
070     */
071        public BufferedImage getDestination() {
072                return destination;
073        }
074        
075    /**
076     * Set the interpolation factor.
077     * @param interpolation the interpolation factor
078     * @see #getInterpolation
079     */
080        public void setInterpolation( float interpolation ) {
081                this.interpolation = interpolation;
082        }
083        
084    /**
085     * Get the interpolation factor.
086     * @return the interpolation factor
087     * @see #setInterpolation
088     */
089        public float getInterpolation() {
090                return interpolation;
091        }
092        
093    public BufferedImage filter( BufferedImage src, BufferedImage dst ) {
094        int width = src.getWidth();
095        int height = src.getHeight();
096                src.getType();
097                src.getRaster();
098
099        if ( dst == null )
100            dst = createCompatibleDestImage( src, null );
101                dst.getRaster();
102
103        if ( destination != null ) {
104                        width = Math.min( width, destination.getWidth() );
105                        height = Math.min( height, destination.getWidth() );
106                        int[] pixels1 = null;
107                        int[] pixels2 = null;
108
109                        for (int y = 0; y < height; y++) {
110                                pixels1 = getRGB( src, 0, y, width, 1, pixels1 );
111                                pixels2 = getRGB( destination, 0, y, width, 1, pixels2 );
112                                for (int x = 0; x < width; x++) {
113                                        int rgb1 = pixels1[x];
114                                        int rgb2 = pixels2[x];
115                                        int a1 = (rgb1 >> 24) & 0xff;
116                                        int r1 = (rgb1 >> 16) & 0xff;
117                                        int g1 = (rgb1 >> 8) & 0xff;
118                                        int b1 = rgb1 & 0xff;
119                                        //int a2 = (rgb2 >> 24) & 0xff;
120                                        int r2 = (rgb2 >> 16) & 0xff;
121                                        int g2 = (rgb2 >> 8) & 0xff;
122                                        int b2 = rgb2 & 0xff;
123                                        r1 = PixelUtils.clamp( ImageMath.lerp( interpolation, r1, r2 ) );
124                                        g1 = PixelUtils.clamp( ImageMath.lerp( interpolation, g1, g2 ) );
125                                        b1 = PixelUtils.clamp( ImageMath.lerp( interpolation, b1, b2 ) );
126                                        pixels1[x] = (a1 << 24) | (r1 << 16) | (g1 << 8) | b1;
127                                }
128                                setRGB( dst, 0, y, width, 1, pixels1 );
129                        }
130        }
131
132        return dst;
133    }
134
135        public String toString() {
136                return "Effects/Interpolate...";
137        }
138        public BufferedImage filter(BufferedImage src, Struct parameters) throws PageException {BufferedImage dst=ImageUtil.createBufferedImage(src);
139                Object o;
140                if((o=parameters.removeEL(KeyImpl.init("Interpolation")))!=null)setInterpolation(ImageFilterUtil.toFloatValue(o,"Interpolation"));
141                if((o=parameters.removeEL(KeyImpl.init("destination")))!=null)setDestination(ImageFilterUtil.toBufferedImage(o,"destination"));
142
143                // check for arguments not supported
144                if(parameters.size()>0) {
145                        throw new FunctionException(ThreadLocalPageContext.get(), "ImageFilter", 3, "parameters", "the parameter"+(parameters.size()>1?"s":"")+" ["+CollectionUtil.getKeyList(parameters,", ")+"] "+(parameters.size()>1?"are":"is")+" not allowed, only the following parameters are supported [Interpolation]");
146                }
147
148                return filter(src, dst);
149        }
150}