VignetteFilter.java revision 65953da4636fbf5f0a24b8f5f2b5fa7d76ff13d9
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.filterpacks.imageproc;
18
19import android.filterfw.core.Filter;
20import android.filterfw.core.FilterContext;
21import android.filterfw.core.Frame;
22import android.filterfw.core.FrameFormat;
23import android.filterfw.core.GenerateFieldPort;
24import android.filterfw.core.KeyValueMap;
25import android.filterfw.core.NativeProgram;
26import android.filterfw.core.NativeFrame;
27import android.filterfw.core.Program;
28import android.filterfw.core.ShaderProgram;
29import android.filterfw.format.ImageFormat;
30
31public class VignetteFilter extends Filter {
32
33    @GenerateFieldPort(name = "scale", hasDefault = true)
34    private float mScale = 0f;
35
36    @GenerateFieldPort(name = "tile_size", hasDefault = true)
37    private int mTileSize = 640;
38
39    private Program mProgram;
40
41    private int mWidth = 0;
42    private int mHeight = 0;
43    private int mTarget = FrameFormat.TARGET_UNSPECIFIED;
44
45    private final float mSlope = 20.0f;
46    private final float mShade = 0.85f;
47
48    private final String mVignetteShader =
49            "precision mediump float;\n" +
50            "uniform sampler2D tex_sampler_0;\n" +
51            "uniform float range;\n" +
52            "uniform float inv_max_dist;\n" +
53            "uniform float shade;\n" +
54            "uniform vec2 center;\n" +
55            "varying vec2 v_texcoord;\n" +
56            "void main() {\n" +
57            "  const float slope = 20.0;\n" +
58            "  float dist = distance(gl_FragCoord.xy, center);\n" +
59            "  float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n" +
60            "  vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" +
61            "  gl_FragColor = vec4(color.rgb * lumen, color.a);\n" +
62            "}\n";
63
64    public VignetteFilter(String name) {
65        super(name);
66    }
67
68    @Override
69    public void setupPorts() {
70        addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
71        addOutputBasedOnInput("image", "image");
72    }
73
74    @Override
75    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
76        return inputFormat;
77    }
78
79    public void initProgram(FilterContext context, int target) {
80        switch (target) {
81            case FrameFormat.TARGET_GPU:
82                ShaderProgram shaderProgram = new ShaderProgram(context, mVignetteShader);
83                shaderProgram.setMaximumTileSize(mTileSize);
84                mProgram = shaderProgram;
85                break;
86
87            default:
88                throw new RuntimeException("Filter Sharpen does not support frames of " +
89                    "target " + target + "!");
90        }
91        mTarget = target;
92    }
93
94    private void initParameters() {
95        if (mProgram != null) {
96            float centerX = (float) (0.5 * mWidth);
97            float centerY = (float) (0.5 * mHeight);
98            float center[] = {centerX, centerY};
99            float max_dist = (float) Math.sqrt(centerX * centerX + centerY * centerY);
100
101            mProgram.setHostValue("center", center);
102            mProgram.setHostValue("inv_max_dist", 1.0f / max_dist);
103            mProgram.setHostValue("shade", mShade);
104
105            updateParameters();
106        }
107    }
108
109    private void updateParameters() {
110        // The 'range' is between 1.3 to 0.6. When scale is zero then range is 1.3
111        // which means no vignette at all because the luminousity difference is
112        // less than 1/256 and will cause nothing.
113        mProgram.setHostValue("range", 1.30f - (float) Math.sqrt(mScale) * 0.7f);
114    }
115
116    @Override
117    public void fieldPortValueUpdated(String name, FilterContext context) {
118        if (mProgram != null) {
119            updateParameters();
120        }
121    }
122
123    @Override
124    public void process(FilterContext context) {
125        // Get input frame
126        Frame input = pullInput("image");
127        FrameFormat inputFormat = input.getFormat();
128
129        // Create program if not created already
130        if (mProgram == null || inputFormat.getTarget() != mTarget) {
131            initProgram(context, inputFormat.getTarget());
132        }
133
134        // Check if the frame size has changed
135        if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) {
136            mWidth = inputFormat.getWidth();
137            mHeight = inputFormat.getHeight();
138            initParameters();
139        }
140
141        // Create output frame
142        Frame output = context.getFrameManager().newFrame(inputFormat);
143
144        // Process
145        mProgram.process(input, output);
146
147        // Push output
148        pushOutput("image", output);
149
150        // Release pushed frame
151        output.release();
152    }
153}
154