DocumentaryFilter.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 31import java.util.Random; 32 33public class DocumentaryFilter extends Filter { 34 35 @GenerateFieldPort(name = "tile_size", hasDefault = true) 36 private int mTileSize = 640; 37 38 private Program mProgram; 39 40 private int mWidth = 0; 41 private int mHeight = 0; 42 private int mTarget = FrameFormat.TARGET_UNSPECIFIED; 43 44 private Frame mNoiseFrame; 45 private Random mRandom; 46 47 private final String mDocumentaryShader = 48 "precision mediump float;\n" + 49 "uniform sampler2D tex_sampler_0;\n" + 50 "uniform sampler2D tex_sampler_1;\n" + 51 "uniform float stepsize;\n" + 52 "uniform float inv_max_dist;\n" + 53 "uniform vec2 center;\n" + 54 "varying vec2 v_texcoord;\n" + 55 "void main() {\n" + 56 // black white 57 " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + 58 " float dither = texture2D(tex_sampler_1, v_texcoord).r;\n" + 59 " vec3 xform = clamp(2.0 * color.rgb, 0.0, 1.0);\n" + 60 " vec3 temp = clamp(2.0 * (color.rgb + stepsize), 0.0, 1.0);\n" + 61 " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" + 62 // grayscale 63 " float gray = dot(new_color, vec3(0.299, 0.587, 0.114));\n" + 64 " new_color = vec3(gray, gray, gray);\n" + 65 // vignette 66 " float dist = distance(gl_FragCoord.xy, center);\n" + 67 " float lumen = 0.85 / (1.0 + exp((dist * inv_max_dist - 0.83) * 20.0)) + 0.15;\n" + 68 " gl_FragColor = vec4(new_color * lumen, color.a);\n" + 69 "}\n"; 70 71 public DocumentaryFilter(String name) { 72 super(name); 73 74 mRandom = new Random(); 75 } 76 77 @Override 78 public void setupPorts() { 79 addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); 80 addOutputBasedOnInput("image", "image"); 81 } 82 83 @Override 84 public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 85 return inputFormat; 86 } 87 88 @Override 89 public void tearDown(FilterContext context) { 90 if (mNoiseFrame != null) { 91 mNoiseFrame.release(); 92 mNoiseFrame = null; 93 } 94 } 95 96 public void initProgram(FilterContext context, int target) { 97 switch (target) { 98 case FrameFormat.TARGET_GPU: 99 ShaderProgram shaderProgram = new ShaderProgram(context, mDocumentaryShader); 100 shaderProgram.setMaximumTileSize(mTileSize); 101 mProgram = shaderProgram; 102 break; 103 104 default: 105 throw new RuntimeException("Filter Sharpen does not support frames of " + 106 "target " + target + "!"); 107 } 108 mTarget = target; 109 } 110 111 @Override 112 public void process(FilterContext context) { 113 // Get input frame 114 Frame input = pullInput("image"); 115 FrameFormat inputFormat = input.getFormat(); 116 117 // Create program if not created already 118 if (mProgram == null || inputFormat.getTarget() != mTarget) { 119 initProgram(context, inputFormat.getTarget()); 120 } 121 122 // Check if the frame size has changed 123 if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { 124 mWidth = inputFormat.getWidth(); 125 mHeight = inputFormat.getHeight(); 126 127 int[] buffer = new int[mWidth * mHeight]; 128 for (int i = 0; i < mWidth * mHeight; ++i) { 129 buffer[i] = mRandom.nextInt(255); 130 } 131 FrameFormat format = ImageFormat.create(mWidth, mHeight, 132 ImageFormat.COLORSPACE_RGBA, 133 FrameFormat.TARGET_GPU); 134 if (mNoiseFrame != null) { 135 mNoiseFrame.release(); 136 } 137 mNoiseFrame = context.getFrameManager().newFrame(format); 138 mNoiseFrame.setInts(buffer); 139 140 initParameters(); 141 } 142 143 if (mNoiseFrame != null && (mNoiseFrame.getFormat().getWidth() != mWidth || 144 mNoiseFrame.getFormat().getHeight() != mHeight)) { 145 throw new RuntimeException("Random map and imput image size mismatch!"); 146 } 147 148 // Create output frame 149 Frame output = context.getFrameManager().newFrame(inputFormat); 150 151 // Process 152 Frame[] inputs = {input, mNoiseFrame}; 153 mProgram.process(inputs, output); 154 155 // Push output 156 pushOutput("image", output); 157 158 // Release pushed frame 159 output.release(); 160 } 161 162 private void initParameters() { 163 if (mProgram != null) { 164 float centerX = (float) (0.5 * mWidth); 165 float centerY = (float) (0.5 * mHeight); 166 float center[] = {centerX, centerY}; 167 float max_dist = (float) Math.sqrt(centerX * centerX + centerY * centerY); 168 169 mProgram.setHostValue("center", center); 170 mProgram.setHostValue("inv_max_dist", 1.0f / max_dist); 171 mProgram.setHostValue("stepsize", 1.0f / 255.0f); 172 } 173 } 174 175} 176