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.MutableFrameFormat; 25import android.filterfw.core.Program; 26import android.filterfw.core.ShaderProgram; 27import android.filterfw.format.ImageFormat; 28 29public class ImageStitcher extends Filter { 30 31 @GenerateFieldPort(name = "xSlices") 32 private int mXSlices; 33 34 @GenerateFieldPort(name = "ySlices") 35 private int mYSlices; 36 37 @GenerateFieldPort(name = "padSize") 38 private int mPadSize; 39 40 private Program mProgram; 41 private Frame mOutputFrame; 42 43 private int mInputWidth; 44 private int mInputHeight; 45 46 private int mImageWidth; 47 private int mImageHeight; 48 49 private int mSliceWidth; 50 private int mSliceHeight; 51 52 private int mSliceIndex; 53 54 public ImageStitcher(String name) { 55 super(name); 56 mSliceIndex = 0; 57 } 58 59 @Override 60 public void setupPorts() { 61 addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA, 62 FrameFormat.TARGET_GPU)); 63 addOutputBasedOnInput("image", "image"); 64 } 65 66 @Override 67 public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { 68 return inputFormat; 69 } 70 71 private FrameFormat calcOutputFormatForInput(FrameFormat format) { 72 MutableFrameFormat outputFormat = format.mutableCopy(); 73 74 mInputWidth = format.getWidth(); 75 mInputHeight = format.getHeight(); 76 77 mSliceWidth = mInputWidth - 2 * mPadSize; 78 mSliceHeight = mInputHeight - 2 * mPadSize; 79 80 mImageWidth = mSliceWidth * mXSlices; 81 mImageHeight = mSliceHeight * mYSlices; 82 83 outputFormat.setDimensions(mImageWidth, mImageHeight); 84 return outputFormat; 85 } 86 87 @Override 88 public void process(FilterContext context) { 89 // Get input frame 90 Frame input = pullInput("image"); 91 FrameFormat format = input.getFormat(); 92 93 // Create output frame 94 if (mSliceIndex == 0) { 95 mOutputFrame = context.getFrameManager().newFrame(calcOutputFormatForInput(format)); 96 } else { 97 if ((format.getWidth() != mInputWidth) || 98 (format.getHeight() != mInputHeight)) { 99 // CHECK input format here 100 throw new RuntimeException("Image size should not change."); 101 } 102 } 103 104 // Create the program if not created already 105 if (mProgram == null) { 106 mProgram = ShaderProgram.createIdentity(context); 107 } 108 109 // TODO(rslin) : not sure shifting by 0.5 is needed. 110 float x0 = ((float) mPadSize) / mInputWidth; 111 float y0 = ((float) mPadSize) / mInputHeight; 112 113 int outputOffsetX = (mSliceIndex % mXSlices) * mSliceWidth; 114 int outputOffsetY = (mSliceIndex / mXSlices) * mSliceHeight; 115 116 float outputWidth = (float) Math.min(mSliceWidth, mImageWidth - outputOffsetX); 117 float outputHeight = (float) Math.min(mSliceHeight, mImageHeight - outputOffsetY); 118 119 // We need to set the source rect as well because the input are padded images. 120 ((ShaderProgram) mProgram).setSourceRect(x0, y0, 121 outputWidth / mInputWidth, 122 outputHeight / mInputHeight); 123 124 ((ShaderProgram) mProgram).setTargetRect(((float) outputOffsetX)/ mImageWidth, 125 ((float) outputOffsetY) / mImageHeight, 126 outputWidth / mImageWidth, 127 outputHeight / mImageHeight); 128 129 // Process this tile 130 mProgram.process(input, mOutputFrame); 131 mSliceIndex++; 132 133 // Push output 134 if (mSliceIndex == mXSlices * mYSlices) { 135 pushOutput("image", mOutputFrame); 136 mOutputFrame.release(); 137 mSliceIndex = 0; 138 } 139 } 140} 141