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
17
18package android.filterpacks.imageproc;
19
20import android.filterfw.core.Filter;
21import android.filterfw.core.FilterContext;
22import android.filterfw.core.Frame;
23import android.filterfw.core.FrameFormat;
24import android.filterfw.core.GenerateFieldPort;
25import android.filterfw.core.MutableFrameFormat;
26import android.filterfw.core.Program;
27import android.filterfw.core.ShaderProgram;
28import android.filterfw.geometry.Quad;
29import android.filterfw.format.ImageFormat;
30import android.filterfw.format.ObjectFormat;
31
32/**
33 * @hide
34 */
35public class CropFilter extends Filter {
36
37    private Program mProgram;
38    private FrameFormat mLastFormat = null;
39
40    @GenerateFieldPort(name = "owidth")
41    private int mOutputWidth = -1;
42
43    @GenerateFieldPort(name = "oheight")
44    private int mOutputHeight = -1;
45
46    @GenerateFieldPort(name = "fillblack")
47    private boolean mFillBlack = false;
48
49    public CropFilter(String name) {
50        super(name);
51    }
52
53    private final String mFragShader =
54      "precision mediump float;\n" +
55      "uniform sampler2D tex_sampler_0;\n" +
56      "varying vec2 v_texcoord;\n" +
57      "void main() {\n" +
58      "  const vec2 lo = vec2(0.0, 0.0);\n" +
59      "  const vec2 hi = vec2(1.0, 1.0);\n" +
60      "  const vec4 black = vec4(0.0, 0.0, 0.0, 1.0);\n" +
61      "  bool out_of_bounds =\n" +
62      "    any(lessThan(v_texcoord, lo)) ||\n" +
63      "    any(greaterThan(v_texcoord, hi));\n" +
64      "  if (out_of_bounds) {\n" +
65      "    gl_FragColor = black;\n" +
66      "  } else {\n" +
67      "    gl_FragColor = texture2D(tex_sampler_0, v_texcoord);\n" +
68      "  }\n" +
69      "}\n";
70
71    @Override
72    public void setupPorts() {
73        addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA));
74        addMaskedInputPort("box", ObjectFormat.fromClass(Quad.class, FrameFormat.TARGET_SIMPLE));
75        addOutputBasedOnInput("image", "image");
76    }
77
78    @Override
79    public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) {
80        // Make sure output size is set to unspecified, as we do not know what we will be resizing
81        // to.
82        MutableFrameFormat outputFormat = inputFormat.mutableCopy();
83        outputFormat.setDimensions(FrameFormat.SIZE_UNSPECIFIED, FrameFormat.SIZE_UNSPECIFIED);
84        return outputFormat;
85    }
86
87    protected void createProgram(FilterContext context, FrameFormat format) {
88        // TODO: Add CPU version
89        if (mLastFormat != null && mLastFormat.getTarget() == format.getTarget()) return;
90        mLastFormat = format;
91        mProgram = null;
92        switch (format.getTarget()) {
93            case FrameFormat.TARGET_GPU:
94              if(mFillBlack)
95                mProgram = new ShaderProgram(context, mFragShader);
96              else
97                mProgram = ShaderProgram.createIdentity(context);
98
99                break;
100        }
101        if (mProgram == null) {
102            throw new RuntimeException("Could not create a program for crop filter " + this + "!");
103        }
104    }
105
106    @Override
107    public void process(FilterContext env) {
108        // Get input frame
109        Frame imageFrame = pullInput("image");
110        Frame boxFrame = pullInput("box");
111
112        createProgram(env, imageFrame.getFormat());
113
114        // Get the box
115        Quad box = (Quad)boxFrame.getObjectValue();
116
117        // Create output format
118        MutableFrameFormat outputFormat = imageFrame.getFormat().mutableCopy();
119        outputFormat.setDimensions(mOutputWidth == -1 ? outputFormat.getWidth() : mOutputWidth,
120                                   mOutputHeight == -1 ? outputFormat.getHeight() : mOutputHeight);
121
122        // Create output frame
123        Frame output = env.getFrameManager().newFrame(outputFormat);
124
125        // Set the program parameters
126        if (mProgram instanceof ShaderProgram) {
127            ShaderProgram shaderProgram = (ShaderProgram)mProgram;
128            shaderProgram.setSourceRegion(box);
129        }
130
131        mProgram.process(imageFrame, output);
132
133        // Push output
134        pushOutput("image", output);
135
136        // Release pushed frame
137        output.release();
138    }
139
140
141}
142