From 6570ec1c3edb8071446791001872d8ba87659200 Mon Sep 17 00:00:00 2001 From: Ruei-sung Lin Date: Thu, 18 Aug 2011 17:47:38 -0700 Subject: [PATCH] Moving photo editor effects to imageproc Change-Id: Idb11915f9e70aa40a228532ed998563227b4c5ff --- .../java/android/media/effect/EffectFactory.java | 168 ++++++++++- .../android/media/effect/SizeChangeEffect.java | 66 +++++ .../media/effect/effects/AutoFixEffect.java | 31 +++ .../media/effect/effects/BlackWhiteEffect.java | 31 +++ .../effect/effects/ColorTemperatureEffect.java | 31 +++ .../android/media/effect/effects/CropEffect.java | 33 +++ .../media/effect/effects/CrossProcessEffect.java | 31 +++ .../media/effect/effects/DocumentaryEffect.java | 64 +++++ .../android/media/effect/effects/DoodleEffect.java | 32 +++ .../media/effect/effects/DuotoneEffect.java | 31 +++ .../media/effect/effects/FillLightEffect.java | 31 +++ .../android/media/effect/effects/FlipEffect.java | 31 +++ .../android/media/effect/effects/GrainEffect.java | 31 +++ .../media/effect/effects/GrayscaleEffect.java | 31 +++ .../media/effect/effects/LomoishEffect.java | 70 +++++ .../media/effect/effects/NegativeEffect.java | 31 +++ .../media/effect/effects/PosterizeEffect.java | 31 +++ .../android/media/effect/effects/RedEyeEffect.java | 32 +++ .../android/media/effect/effects/RotateEffect.java | 31 +++ .../media/effect/effects/SaturateEffect.java | 31 +++ .../android/media/effect/effects/SepiaEffect.java | 31 +++ .../media/effect/effects/SharpenEffect.java | 31 +++ .../media/effect/effects/StraightenEffect.java | 31 +++ .../android/media/effect/effects/TintEffect.java | 31 +++ .../media/effect/effects/VignetteEffect.java | 31 +++ mca/filterpacks/imageproc/java/AutoFixFilter.java | 307 +++++++++++++++++++++ .../imageproc/java/BlackWhiteFilter.java | 175 ++++++++++++ .../imageproc/java/ColorTemperatureFilter.java | 128 +++++++++ mca/filterpacks/imageproc/java/CropRectFilter.java | 141 ++++++++++ .../imageproc/java/CrossProcessFilter.java | 116 ++++++++ mca/filterpacks/imageproc/java/DoodleFilter.java | 156 +++++++++++ mca/filterpacks/imageproc/java/DuotoneFilter.java | 122 ++++++++ .../imageproc/java/FillLightFilter.java | 140 ++++++++++ mca/filterpacks/imageproc/java/FisheyeFilter.java | 5 +- mca/filterpacks/imageproc/java/FlipFilter.java | 121 ++++++++ mca/filterpacks/imageproc/java/GrainFilter.java | 185 +++++++++++++ mca/filterpacks/imageproc/java/NegativeFilter.java | 103 +++++++ .../imageproc/java/PosterizeFilter.java | 108 ++++++++ mca/filterpacks/imageproc/java/RedEyeFilter.java | 166 +++++++++++ mca/filterpacks/imageproc/java/RotateFilter.java | 156 +++++++++++ mca/filterpacks/imageproc/java/SaturateFilter.java | 170 ++++++++++++ mca/filterpacks/imageproc/java/SepiaFilter.java | 111 ++++++++ mca/filterpacks/imageproc/java/SharpenFilter.java | 153 ++++++++++ .../imageproc/java/StraightenFilter.java | 154 +++++++++++ mca/filterpacks/imageproc/java/TintFilter.java | 134 +++++++++ mca/filterpacks/imageproc/java/ToGrayFilter.java | 4 + mca/filterpacks/imageproc/java/VignetteFilter.java | 151 ++++++++++ 47 files changed, 4024 insertions(+), 5 deletions(-) create mode 100644 mca/effect/java/android/media/effect/SizeChangeEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/AutoFixEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/BlackWhiteEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/ColorTemperatureEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/CropEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/CrossProcessEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/DocumentaryEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/DoodleEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/DuotoneEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/FillLightEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/FlipEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/GrainEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/GrayscaleEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/LomoishEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/NegativeEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/PosterizeEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/RedEyeEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/RotateEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/SaturateEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/SepiaEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/SharpenEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/StraightenEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/TintEffect.java create mode 100644 mca/effect/java/android/media/effect/effects/VignetteEffect.java create mode 100644 mca/filterpacks/imageproc/java/AutoFixFilter.java create mode 100644 mca/filterpacks/imageproc/java/BlackWhiteFilter.java create mode 100644 mca/filterpacks/imageproc/java/ColorTemperatureFilter.java create mode 100644 mca/filterpacks/imageproc/java/CropRectFilter.java create mode 100644 mca/filterpacks/imageproc/java/CrossProcessFilter.java create mode 100644 mca/filterpacks/imageproc/java/DoodleFilter.java create mode 100644 mca/filterpacks/imageproc/java/DuotoneFilter.java create mode 100644 mca/filterpacks/imageproc/java/FillLightFilter.java create mode 100644 mca/filterpacks/imageproc/java/FlipFilter.java create mode 100644 mca/filterpacks/imageproc/java/GrainFilter.java create mode 100644 mca/filterpacks/imageproc/java/NegativeFilter.java create mode 100644 mca/filterpacks/imageproc/java/PosterizeFilter.java create mode 100644 mca/filterpacks/imageproc/java/RedEyeFilter.java create mode 100644 mca/filterpacks/imageproc/java/RotateFilter.java create mode 100644 mca/filterpacks/imageproc/java/SaturateFilter.java create mode 100644 mca/filterpacks/imageproc/java/SepiaFilter.java create mode 100644 mca/filterpacks/imageproc/java/SharpenFilter.java create mode 100644 mca/filterpacks/imageproc/java/StraightenFilter.java create mode 100644 mca/filterpacks/imageproc/java/TintFilter.java create mode 100644 mca/filterpacks/imageproc/java/VignetteFilter.java diff --git a/mca/effect/java/android/media/effect/EffectFactory.java b/mca/effect/java/android/media/effect/EffectFactory.java index 0612051f..140532dd 100644 --- a/mca/effect/java/android/media/effect/EffectFactory.java +++ b/mca/effect/java/android/media/effect/EffectFactory.java @@ -17,10 +17,6 @@ package android.media.effect; -import android.media.effect.effects.BrightnessEffect; -import android.media.effect.effects.ContrastEffect; -import android.media.effect.effects.FisheyeEffect; - import java.lang.reflect.Constructor; import java.util.HashMap; @@ -40,6 +36,7 @@ public class EffectFactory { }; /** List of Effects */ + /** *

Adjusts the brightness of the image.

*

Available parameters:

@@ -107,6 +104,169 @@ public class EffectFactory { */ public final static String EFFECT_BACKDROPPER = "BackDropperEffect"; + /** + * Applies histogram equalization on the image.
+ * Parameters: scale (float): the scale of histogram equalization. + * @hide + */ + public final static String EFFECT_AUTOFIX = "AutoFixEffect"; + + /** + * Adjusts the range of minimal and maximal values of color pixels.
+ * Parameters: black (float): the value of the minimal pixel. + * Parameters: white (float): the value of the maximal pixel. + * @hide + */ + public final static String EFFECT_BLACKWHITE = "BlackWhiteEffect"; + + /** + * Crops an upright rectangular area from the image.
+ * Parameters: xorigin (int): xorigin. + * yorigin (int): yorigin. + * width (int): rectangle width. + * height (int): rectangle height. + * @hide + */ + public final static String EFFECT_CROP = "CropEffect"; + + /** + * Applies cross process effect on image.
+ * Parameters: contrast (float): The strength of the color contrast. + * @hide + */ + public final static String EFFECT_CROSSPROCESS = "CrossProcessEffect"; + + /** + * Applies documentary effect on image.
+ * Parameters: contrast (float): The strength of the color contrast. + * @hide + */ + public final static String EFFECT_DOCUMENTARY = "DocumentaryEffect"; + + /** + * Attaches doodles to image.
+ * Parameters: contrast (float): The strength of the color contrast. + * @hide + */ + public final static String EFFECT_DOODLE = "DoodleEffect"; + + /** + * Applies duotone effect on image.
+ * Parameters: first_color (float): first color in duotone. + * Parameters: second_color (float): second color in duotone. + * @hide + */ + public final static String EFFECT_DUOTONE = "DuotoneEffect"; + + /** + * Adds backlight to the image.
+ * Parameters: backlight (float): The scale of the distortion. + * @hide + */ + public final static String EFFECT_FILLLIGHT = "FillLightEffect"; + + /** + * Flips image vertically and/or horizontally.
+ * Parameters: vertical (boolean): flip image vertically. + * Parameters: horizontal (boolean): flip image horizontally. + * @hide + */ + public final static String EFFECT_FLIP = "FlipEffect"; + + /** + * Applies film grain effect on image.
+ * @hide + */ + public final static String EFFECT_GRAIN = "GrainEffect"; + + /** + * Converts image to grayscale.
+ * @hide + */ + public final static String EFFECT_GRAYSCALE = "GrayscaleEffect"; + + /** + * Applies lomoish effect on image.
+ * @hide + */ + public final static String EFFECT_LOMOISH = "LomoishEffect"; + + /** + * Applies negative film effect on image.
+ * Parameters: scale (float): the degree of film grain. + * @hide + */ + public final static String EFFECT_NEGATIVE = "NegativeEffect"; + + /** + * Applied posterized effect on image.
+ * @hide + */ + public final static String EFFECT_POSTERIZE = "PosterizeEffect"; + + /** + * Removes red eyes on specified region.
+ * Parameters: intensity (float): threshold used to indentify red eyes. + * redeye (Bitmap): bitmap specifies red eye regions. + * @hide + */ + public final static String EFFECT_REDEYE = "RedEyeEffect"; + + /** + * Rotates the image.
+ * Parameters: degree (float): the degree of rotation. shoule be a multiple of 90. + * @hide + */ + public final static String EFFECT_ROTATE = "RotateEffect"; + + /** + * Adjusts color saturation on image.
+ * Parameters: scale (float): The scale of color saturation. + * @hide + */ + public final static String EFFECT_SATURATE = "SaturateEffect"; + + /** + * Converts image to sepia tone.
+ * @hide + */ + public final static String EFFECT_SEPIA = "SepiaEffect"; + + /** + * Sharpens the image.
+ * Parameters: scale (float): The degree of sharpening. + * @hide + */ + public final static String EFFECT_SHARPEN = "SharpenEffect"; + + /** + * Rotates and resizes the image accroding to specified angle.
+ * Parameters: scale (angle): the angle of rotation. + * @hide + */ + public final static String EFFECT_STRAIGHTEN = "StraightenEffect"; + + /** + * Adjusts color temperature in the image.
+ * Parameters: scale (float): the value of color temperature. + * @hide + */ + public final static String EFFECT_TEMPERATURE = "ColorTemperatureEffect"; + + /** + * Applies tine effect on image.
+ * @hide + */ + public final static String EFFECT_TINT = "TintEffect"; + + /** + * Appliies vignette effect on image.
+ * Parameters: range (float): The range of vignetting. + * @hide + */ + public final static String EFFECT_VIGNETTE = "VignetteEffect"; + + /** ...Many more effects to follow ... */ EffectFactory(EffectContext effectContext) { diff --git a/mca/effect/java/android/media/effect/SizeChangeEffect.java b/mca/effect/java/android/media/effect/SizeChangeEffect.java new file mode 100644 index 00000000..4d3a4bd8 --- /dev/null +++ b/mca/effect/java/android/media/effect/SizeChangeEffect.java @@ -0,0 +1,66 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.effect; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterFactory; +import android.filterfw.core.FilterFunction; +import android.filterfw.core.Frame; +import android.media.effect.Effect; +import android.media.effect.EffectContext; + +import android.util.Log; + +/** + * Effect subclass for effects based on a single Filter with output size differnet + * from input. Subclasses need only invoke the constructor with the correct arguments + * to obtain an Effect implementation. + * + * @hide + */ +public class SizeChangeEffect extends SingleFilterEffect { + + public SizeChangeEffect(EffectContext context, + String name, + Class filterClass, + String inputName, + String outputName, + Object... finalParameters) { + super(context, name, filterClass, inputName, outputName, finalParameters); + } + + @Override + public void apply(int inputTexId, int width, int height, int outputTexId) { + mEffectContext.assertValidGLState(); + mEffectContext.saveGLState(); + + Frame inputFrame = frameFromTexture(inputTexId, width, height); + Frame resultFrame = mFunction.executeWithArgList(mInputName, inputFrame); + + int outputWidth = resultFrame.getFormat().getWidth(); + int outputHeight = resultFrame.getFormat().getHeight(); + + Frame outputFrame = frameFromTexture(outputTexId, outputWidth, outputHeight); + outputFrame.setDataFromFrame(resultFrame); + + inputFrame.release(); + outputFrame.release(); + resultFrame.release(); + + mEffectContext.restoreGLState(); + } +} diff --git a/mca/effect/java/android/media/effect/effects/AutoFixEffect.java b/mca/effect/java/android/media/effect/effects/AutoFixEffect.java new file mode 100644 index 00000000..44a141b6 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/AutoFixEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.AutoFixFilter; + +/** + * @hide + */ +public class AutoFixEffect extends SingleFilterEffect { + public AutoFixEffect(EffectContext context, String name) { + super(context, name, AutoFixFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/BlackWhiteEffect.java b/mca/effect/java/android/media/effect/effects/BlackWhiteEffect.java new file mode 100644 index 00000000..771afff8 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/BlackWhiteEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.BlackWhiteFilter; + +/** + * @hide + */ +public class BlackWhiteEffect extends SingleFilterEffect { + public BlackWhiteEffect(EffectContext context, String name) { + super(context, name, BlackWhiteFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/ColorTemperatureEffect.java b/mca/effect/java/android/media/effect/effects/ColorTemperatureEffect.java new file mode 100644 index 00000000..62d98ced --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/ColorTemperatureEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.ColorTemperatureFilter; + +/** + * @hide + */ +public class ColorTemperatureEffect extends SingleFilterEffect { + public ColorTemperatureEffect(EffectContext context, String name) { + super(context, name, ColorTemperatureFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/CropEffect.java b/mca/effect/java/android/media/effect/effects/CropEffect.java new file mode 100644 index 00000000..3e8d78a3 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/CropEffect.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SizeChangeEffect; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.CropRectFilter; + +/** + * @hide + */ +//public class CropEffect extends SingleFilterEffect { +public class CropEffect extends SizeChangeEffect { + public CropEffect(EffectContext context, String name) { + super(context, name, CropRectFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/CrossProcessEffect.java b/mca/effect/java/android/media/effect/effects/CrossProcessEffect.java new file mode 100644 index 00000000..d7a7df58 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/CrossProcessEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.CrossProcessFilter; + +/** + * @hide + */ +public class CrossProcessEffect extends SingleFilterEffect { + public CrossProcessEffect(EffectContext context, String name) { + super(context, name, CrossProcessFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/DocumentaryEffect.java b/mca/effect/java/android/media/effect/effects/DocumentaryEffect.java new file mode 100644 index 00000000..ea9690de --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/DocumentaryEffect.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.effect.effects; + +import android.filterfw.core.Filter; +import android.filterfw.core.OneShotScheduler; +import android.media.effect.EffectContext; +import android.media.effect.FilterGraphEffect; + +/** + * @hide + */ +public class DocumentaryEffect extends FilterGraphEffect { + private static final String mGraphDefinition = + "@import android.filterpacks.base;\n" + + "@import android.filterpacks.imageproc;\n" + + "\n" + + "@filter GLTextureSource input {\n" + + " texId = 0;\n" + // Will be set by base class + " width = 0;\n" + + " height = 0;\n" + + " repeatFrame = true;\n" + + "}\n" + + "\n" + + "@filter BlackWhiteFilter blackwhite {\n" + + " white = 0.5;\n" + + " black = 0.0;\n" + + "}\n" + + "\n" + + "@filter ToGrayFilter grayscale {\n" + + "}\n" + + "\n" + + "@filter VignetteFilter vignette {\n" + + " range = 0.83;\n" + + "}\n" + + "\n" + + "@filter GLTextureTarget output {\n" + + " texId = 0;\n" + + "}\n" + + "\n" + + "@connect input[frame] => blackwhite[image];\n" + + "@connect blackwhite[image] => grayscale[image];\n" + + "@connect grayscale[image] => vignette[image];\n" + + "@connect vignette[image] => output[frame];\n"; + + + public DocumentaryEffect(EffectContext context, String name) { + super(context, name, mGraphDefinition, "input", "output", OneShotScheduler.class); + } +} diff --git a/mca/effect/java/android/media/effect/effects/DoodleEffect.java b/mca/effect/java/android/media/effect/effects/DoodleEffect.java new file mode 100644 index 00000000..53cf6232 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/DoodleEffect.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.DoodleFilter; + +/** + * @hide + */ +public class DoodleEffect extends SingleFilterEffect { + public DoodleEffect(EffectContext context, String name) { + super(context, name, DoodleFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/DuotoneEffect.java b/mca/effect/java/android/media/effect/effects/DuotoneEffect.java new file mode 100644 index 00000000..1391b1f2 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/DuotoneEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.DuotoneFilter; + +/** + * @hide + */ +public class DuotoneEffect extends SingleFilterEffect { + public DuotoneEffect(EffectContext context, String name) { + super(context, name, DuotoneFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/FillLightEffect.java b/mca/effect/java/android/media/effect/effects/FillLightEffect.java new file mode 100644 index 00000000..5260de34 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/FillLightEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.FillLightFilter; + +/** + * @hide + */ +public class FillLightEffect extends SingleFilterEffect { + public FillLightEffect(EffectContext context, String name) { + super(context, name, FillLightFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/FlipEffect.java b/mca/effect/java/android/media/effect/effects/FlipEffect.java new file mode 100644 index 00000000..0f5c4212 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/FlipEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.FlipFilter; + +/** + * @hide + */ +public class FlipEffect extends SingleFilterEffect { + public FlipEffect(EffectContext context, String name) { + super(context, name, FlipFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/GrainEffect.java b/mca/effect/java/android/media/effect/effects/GrainEffect.java new file mode 100644 index 00000000..2fda7e90 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/GrainEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.GrainFilter; + +/** + * @hide + */ +public class GrainEffect extends SingleFilterEffect { + public GrainEffect(EffectContext context, String name) { + super(context, name, GrainFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/GrayscaleEffect.java b/mca/effect/java/android/media/effect/effects/GrayscaleEffect.java new file mode 100644 index 00000000..26ca081f --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/GrayscaleEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.ToGrayFilter; + +/** + * @hide + */ +public class GrayscaleEffect extends SingleFilterEffect { + public GrayscaleEffect(EffectContext context, String name) { + super(context, name, ToGrayFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/LomoishEffect.java b/mca/effect/java/android/media/effect/effects/LomoishEffect.java new file mode 100644 index 00000000..8e17e07b --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/LomoishEffect.java @@ -0,0 +1,70 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.media.effect.effects; + +import android.filterfw.core.Filter; +import android.filterfw.core.OneShotScheduler; +import android.media.effect.EffectContext; +import android.media.effect.FilterGraphEffect; + +/** + * @hide + */ +public class LomoishEffect extends FilterGraphEffect { + private static final String mGraphDefinition = + "@import android.filterpacks.base;\n" + + "@import android.filterpacks.imageproc;\n" + + "\n" + + "@filter GLTextureSource input {\n" + + " texId = 0;\n" + // Will be set by base class + " width = 0;\n" + + " height = 0;\n" + + " repeatFrame = true;\n" + + "}\n" + + "\n" + + "@filter SharpenFilter sharpen {\n" + + // TODO: scale should be -0.15 + " scale = 0.15;\n" + + "}\n" + + "\n" + + "@filter CrossProcessFilter crossProcess {\n" + + "}\n" + + "\n" + + "@filter BlackWhiteFilter blackWhite {\n" + + " white = 0.8;\n" + + " black = 0.15;\n" + + "}\n" + + "\n" + + "@filter VignetteFilter vignette {\n" + + " range = 0.73;\n" + + "}\n" + + "\n" + + "@filter GLTextureTarget output {\n" + + " texId = 0;\n" + + "}\n" + + "\n" + + "@connect input[frame] => sharpen[image];\n" + + "@connect sharpen[image] => crossProcess[image];\n" + + "@connect crossProcess[image] => blackWhite[image];\n" + + "@connect blackWhite[image] => vignette[image];\n" + + "@connect vignette[image] => output[frame];\n"; + + + public LomoishEffect(EffectContext context, String name) { + super(context, name, mGraphDefinition, "input", "output", OneShotScheduler.class); + } +} diff --git a/mca/effect/java/android/media/effect/effects/NegativeEffect.java b/mca/effect/java/android/media/effect/effects/NegativeEffect.java new file mode 100644 index 00000000..29fc94a1 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/NegativeEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.NegativeFilter; + +/** + * @hide + */ +public class NegativeEffect extends SingleFilterEffect { + public NegativeEffect(EffectContext context, String name) { + super(context, name, NegativeFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/PosterizeEffect.java b/mca/effect/java/android/media/effect/effects/PosterizeEffect.java new file mode 100644 index 00000000..20a8a37b --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/PosterizeEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.PosterizeFilter; + +/** + * @hide + */ +public class PosterizeEffect extends SingleFilterEffect { + public PosterizeEffect(EffectContext context, String name) { + super(context, name, PosterizeFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/RedEyeEffect.java b/mca/effect/java/android/media/effect/effects/RedEyeEffect.java new file mode 100644 index 00000000..8ed9909c --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/RedEyeEffect.java @@ -0,0 +1,32 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.RedEyeFilter; + +/** + * @hide + */ +public class RedEyeEffect extends SingleFilterEffect { + public RedEyeEffect(EffectContext context, String name) { + super(context, name, RedEyeFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/RotateEffect.java b/mca/effect/java/android/media/effect/effects/RotateEffect.java new file mode 100644 index 00000000..23400152 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/RotateEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SizeChangeEffect; +import android.filterpacks.imageproc.RotateFilter; + +/** + * @hide + */ +public class RotateEffect extends SizeChangeEffect { + public RotateEffect(EffectContext context, String name) { + super(context, name, RotateFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/SaturateEffect.java b/mca/effect/java/android/media/effect/effects/SaturateEffect.java new file mode 100644 index 00000000..fe9250a7 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/SaturateEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.SaturateFilter; + +/** + * @hide + */ +public class SaturateEffect extends SingleFilterEffect { + public SaturateEffect(EffectContext context, String name) { + super(context, name, SaturateFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/SepiaEffect.java b/mca/effect/java/android/media/effect/effects/SepiaEffect.java new file mode 100644 index 00000000..de85b2d4 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/SepiaEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.SepiaFilter; + +/** + * @hide + */ +public class SepiaEffect extends SingleFilterEffect { + public SepiaEffect(EffectContext context, String name) { + super(context, name, SepiaFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/SharpenEffect.java b/mca/effect/java/android/media/effect/effects/SharpenEffect.java new file mode 100644 index 00000000..46776ebf --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/SharpenEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.SharpenFilter; + +/** + * @hide + */ +public class SharpenEffect extends SingleFilterEffect { + public SharpenEffect(EffectContext context, String name) { + super(context, name, SharpenFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/StraightenEffect.java b/mca/effect/java/android/media/effect/effects/StraightenEffect.java new file mode 100644 index 00000000..49253a00 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/StraightenEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.StraightenFilter; + +/** + * @hide + */ +public class StraightenEffect extends SingleFilterEffect { + public StraightenEffect(EffectContext context, String name) { + super(context, name, StraightenFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/TintEffect.java b/mca/effect/java/android/media/effect/effects/TintEffect.java new file mode 100644 index 00000000..6de9ea8f --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/TintEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.TintFilter; + +/** + * @hide + */ +public class TintEffect extends SingleFilterEffect { + public TintEffect(EffectContext context, String name) { + super(context, name, TintFilter.class, "image", "image"); + } +} diff --git a/mca/effect/java/android/media/effect/effects/VignetteEffect.java b/mca/effect/java/android/media/effect/effects/VignetteEffect.java new file mode 100644 index 00000000..b143d775 --- /dev/null +++ b/mca/effect/java/android/media/effect/effects/VignetteEffect.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.media.effect.effects; + +import android.media.effect.EffectContext; +import android.media.effect.SingleFilterEffect; +import android.filterpacks.imageproc.VignetteFilter; + +/** + * @hide + */ +public class VignetteEffect extends SingleFilterEffect { + public VignetteEffect(EffectContext context, String name) { + super(context, name, VignetteFilter.class, "image", "image"); + } +} diff --git a/mca/filterpacks/imageproc/java/AutoFixFilter.java b/mca/filterpacks/imageproc/java/AutoFixFilter.java new file mode 100644 index 00000000..97e86158 --- /dev/null +++ b/mca/filterpacks/imageproc/java/AutoFixFilter.java @@ -0,0 +1,307 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import android.util.Log; + +public class AutoFixFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + @GenerateFieldPort(name = "scale") + private float mScale; + + private static final int normal_cdf[] = { + 9, 33, 50, 64, 75, 84, 92, 99, 106, 112, 117, 122, 126, 130, 134, 138, 142, + 145, 148, 150, 154, 157, 159, 162, 164, 166, 169, 170, 173, 175, 177, 179, + 180, 182, 184, 186, 188, 189, 190, 192, 194, 195, 197, 198, 199, 200, 202, + 203, 205, 206, 207, 208, 209, 210, 212, 213, 214, 215, 216, 217, 218, 219, + 220, 221, 222, 223, 224, 225, 226, 227, 228, 229, 229, 230, 231, 232, 233, + 234, 235, 236, 236, 237, 238, 239, 239, 240, 240, 242, 242, 243, 244, 245, + 245, 246, 247, 247, 248, 249, 249, 250, 250, 251, 252, 253, 253, 254, 255, + 255, 256, 256, 257, 258, 258, 259, 259, 259, 260, 261, 262, 262, 263, 263, + 264, 264, 265, 265, 266, 267, 267, 268, 268, 269, 269, 269, 270, 270, 271, + 272, 272, 273, 273, 274, 274, 275, 275, 276, 276, 277, 277, 277, 278, 278, + 279, 279, 279, 280, 280, 281, 282, 282, 282, 283, 283, 284, 284, 285, 285, + 285, 286, 286, 287, 287, 288, 288, 288, 289, 289, 289, 290, 290, 290, 291, + 292, 292, 292, 293, 293, 294, 294, 294, 295, 295, 296, 296, 296, 297, 297, + 297, 298, 298, 298, 299, 299, 299, 299, 300, 300, 301, 301, 302, 302, 302, + 303, 303, 304, 304, 304, 305, 305, 305, 306, 306, 306, 307, 307, 307, 308, + 308, 308, 309, 309, 309, 309, 310, 310, 310, 310, 311, 312, 312, 312, 313, + 313, 313, 314, 314, 314, 315, 315, 315, 315, 316, 316, 316, 317, 317, 317, + 318, 318, 318, 319, 319, 319, 319, 319, 320, 320, 320, 321, 321, 322, 322, + 322, 323, 323, 323, 323, 324, 324, 324, 325, 325, 325, 325, 326, 326, 326, + 327, 327, 327, 327, 328, 328, 328, 329, 329, 329, 329, 329, 330, 330, 330, + 330, 331, 331, 332, 332, 332, 333, 333, 333, 333, 334, 334, 334, 334, 335, + 335, 335, 336, 336, 336, 336, 337, 337, 337, 337, 338, 338, 338, 339, 339, + 339, 339, 339, 339, 340, 340, 340, 340, 341, 341, 342, 342, 342, 342, 343, + 343, 343, 344, 344, 344, 344, 345, 345, 345, 345, 346, 346, 346, 346, 347, + 347, 347, 347, 348, 348, 348, 348, 349, 349, 349, 349, 349, 349, 350, 350, + 350, 350, 351, 351, 352, 352, 352, 352, 353, 353, 353, 353, 354, 354, 354, + 354, 355, 355, 355, 355, 356, 356, 356, 356, 357, 357, 357, 357, 358, 358, + 358, 358, 359, 359, 359, 359, 359, 359, 359, 360, 360, 360, 360, 361, 361, + 362, 362, 362, 362, 363, 363, 363, 363, 364, 364, 364, 364, 365, 365, 365, + 365, 366, 366, 366, 366, 366, 367, 367, 367, 367, 368, 368, 368, 368, 369, + 369, 369, 369, 369, 369, 370, 370, 370, 370, 370, 371, 371, 372, 372, 372, + 372, 373, 373, 373, 373, 374, 374, 374, 374, 374, 375, 375, 375, 375, 376, + 376, 376, 376, 377, 377, 377, 377, 378, 378, 378, 378, 378, 379, 379, 379, + 379, 379, 379, 380, 380, 380, 380, 381, 381, 381, 382, 382, 382, 382, 383, + 383, 383, 383, 384, 384, 384, 384, 385, 385, 385, 385, 385, 386, 386, 386, + 386, 387, 387, 387, 387, 388, 388, 388, 388, 388, 389, 389, 389, 389, 389, + 389, 390, 390, 390, 390, 391, 391, 392, 392, 392, 392, 392, 393, 393, 393, + 393, 394, 394, 394, 394, 395, 395, 395, 395, 396, 396, 396, 396, 396, 397, + 397, 397, 397, 398, 398, 398, 398, 399, 399, 399, 399, 399, 399, 400, 400, + 400, 400, 400, 401, 401, 402, 402, 402, 402, 403, 403, 403, 403, 404, 404, + 404, 404, 405, 405, 405, 405, 406, 406, 406, 406, 406, 407, 407, 407, 407, + 408, 408, 408, 408, 409, 409, 409, 409, 409, 409, 410, 410, 410, 410, 411, + 411, 412, 412, 412, 412, 413, 413, 413, 413, 414, 414, 414, 414, 415, 415, + 415, 415, 416, 416, 416, 416, 417, 417, 417, 417, 418, 418, 418, 418, 419, + 419, 419, 419, 419, 419, 420, 420, 420, 420, 421, 421, 422, 422, 422, 422, + 423, 423, 423, 423, 424, 424, 424, 425, 425, 425, 425, 426, 426, 426, 426, + 427, 427, 427, 427, 428, 428, 428, 429, 429, 429, 429, 429, 429, 430, 430, + 430, 430, 431, 431, 432, 432, 432, 433, 433, 433, 433, 434, 434, 434, 435, + 435, 435, 435, 436, 436, 436, 436, 437, 437, 437, 438, 438, 438, 438, 439, + 439, 439, 439, 439, 440, 440, 440, 441, 441, 442, 442, 442, 443, 443, 443, + 443, 444, 444, 444, 445, 445, 445, 446, 446, 446, 446, 447, 447, 447, 448, + 448, 448, 449, 449, 449, 449, 449, 450, 450, 450, 451, 451, 452, 452, 452, + 453, 453, 453, 454, 454, 454, 455, 455, 455, 456, 456, 456, 457, 457, 457, + 458, 458, 458, 459, 459, 459, 459, 460, 460, 460, 461, 461, 462, 462, 462, + 463, 463, 463, 464, 464, 465, 465, 465, 466, 466, 466, 467, 467, 467, 468, + 468, 469, 469, 469, 469, 470, 470, 470, 471, 472, 472, 472, 473, 473, 474, + 474, 474, 475, 475, 476, 476, 476, 477, 477, 478, 478, 478, 479, 479, 479, + 480, 480, 480, 481, 482, 482, 483, 483, 484, 484, 484, 485, 485, 486, 486, + 487, 487, 488, 488, 488, 489, 489, 489, 490, 490, 491, 492, 492, 493, 493, + 494, 494, 495, 495, 496, 496, 497, 497, 498, 498, 499, 499, 499, 500, 501, + 502, 502, 503, 503, 504, 504, 505, 505, 506, 507, 507, 508, 508, 509, 509, + 510, 510, 511, 512, 513, 513, 514, 515, 515, 516, 517, 517, 518, 519, 519, + 519, 520, 521, 522, 523, 524, 524, 525, 526, 526, 527, 528, 529, 529, 530, + 531, 532, 533, 534, 535, 535, 536, 537, 538, 539, 539, 540, 542, 543, 544, + 545, 546, 547, 548, 549, 549, 550, 552, 553, 554, 555, 556, 558, 559, 559, + 561, 562, 564, 565, 566, 568, 569, 570, 572, 574, 575, 577, 578, 579, 582, + 583, 585, 587, 589, 590, 593, 595, 597, 599, 602, 604, 607, 609, 612, 615, + 618, 620, 624, 628, 631, 635, 639, 644, 649, 654, 659, 666, 673, 680, 690, + 700, 714 }; + + private final String mAutoFixShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform sampler2D tex_sampler_1;\n" + + "uniform sampler2D tex_sampler_2;\n" + + "uniform float scale;\n" + + "uniform float shift_scale;\n" + + "uniform float hist_offset;\n" + + "uniform float hist_scale;\n" + + "uniform float density_offset;\n" + + "uniform float density_scale;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " const vec3 weights = vec3(0.33333, 0.33333, 0.33333);\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float energy = dot(color.rgb, weights);\n" + + " float mask_value = energy - 0.5;\n" + + " float alpha;\n" + + " if (mask_value > 0.0) {\n" + + " alpha = (pow(2.0 * mask_value, 1.5) - 1.0) * scale + 1.0;\n" + + " } else { \n" + + " alpha = (pow(2.0 * mask_value, 2.0) - 1.0) * scale + 1.0;\n" + + " }\n" + + " float index = energy * hist_scale + hist_offset;\n" + + " vec4 temp = texture2D(tex_sampler_1, vec2(index, 0.5));\n" + + " float value = temp.g + temp.r * shift_scale;\n" + + " index = value * density_scale + density_offset;\n" + + " temp = texture2D(tex_sampler_2, vec2(index, 0.5));\n" + + " value = temp.g + temp.r * shift_scale;\n" + + " float dst_energy = energy * alpha + value * (1.0 - alpha);\n" + + " float max_energy = energy / max(color.r, max(color.g, color.b));\n" + + " if (dst_energy > max_energy) {\n" + + " dst_energy = max_energy;\n" + + " }\n" + + " if (energy == 0.0) {\n" + + " gl_FragColor = color;\n" + + " } else {\n" + + " gl_FragColor = vec4(color.rgb * dst_energy / energy, color.a);\n" + + " }\n" + + "}\n"; + + private Program mShaderProgram; + private Program mNativeProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private Frame mHistFrame; + private Frame mDensityFrame; + + public AutoFixFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mAutoFixShader); + shaderProgram.setMaximumTileSize(mTileSize); + mShaderProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + private void initParameters() { + mShaderProgram.setHostValue("shift_scale", 1.0f / 256f); + mShaderProgram.setHostValue("hist_offset", 0.5f / 766f); + mShaderProgram.setHostValue("hist_scale", 765f / 766f); + mShaderProgram.setHostValue("density_offset", 0.5f / 1024f); + mShaderProgram.setHostValue("density_scale", 1023f / 1024f); + mShaderProgram.setHostValue("scale", mScale); + } + + @Override + protected void prepare(FilterContext context) { + int densityDim = 1024; + int histDim = 255 * 3 + 1; + long precision = (256l * 256l - 1l); + + int[] densityTable = new int[densityDim]; + for (int i = 0; i < densityDim; ++i) { + long temp = normal_cdf[i] * precision / histDim; + densityTable[i] = (int) temp; + } + + FrameFormat densityFormat = ImageFormat.create(densityDim, 1, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + mDensityFrame = context.getFrameManager().newFrame(densityFormat); + mDensityFrame.setInts(densityTable); + } + + @Override + public void tearDown(FilterContext context) { + mDensityFrame.release(); + mDensityFrame = null; + + if (mHistFrame != null) { + mHistFrame.release(); + mHistFrame = null; + } + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mShaderProgram != null) { + mShaderProgram.setHostValue("scale", mScale); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mShaderProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + initParameters(); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + createHistogramFrame(context, mWidth, mHeight, input.getInts()); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + Frame[] inputs = {input, mHistFrame, mDensityFrame}; + mShaderProgram.process(inputs, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void createHistogramFrame(FilterContext context, int width, int height, int[] data) { + int histDims = 255 * 3 + 1; + int[] histArray = new int[histDims]; + + float border_thickness_ratio = 0.05f; + int y_border_thickness = (int) (height * border_thickness_ratio); + int x_border_thickness = (int) (width * border_thickness_ratio); + int pixels = (width - 2 * x_border_thickness) * (height - 2 * y_border_thickness); + + float count = 0f; + for (int y = y_border_thickness; y < height - y_border_thickness; ++y) { + for (int x = x_border_thickness; x < width - x_border_thickness; ++x) { + int index = y * width + x; + int energy = (data[index] & 0xFF) + ((data[index] >> 8) & 0xFF) + + ((data[index] >> 16) & 0xFF); + histArray[energy] ++; + } + } + + for (int i = 1; i < histDims; i++) { + histArray[i] += histArray[i-1]; + } + + for (int i = 0; i < histDims; i++) { + long temp = (256 * 256 - 1l) * histArray[i] / pixels; + histArray[i] = (int) temp; + } + + FrameFormat shaderHistFormat = ImageFormat.create(histDims, 1, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + if (mHistFrame != null) + mHistFrame.release(); + + mHistFrame = context.getFrameManager().newFrame(shaderHistFormat); + mHistFrame.setInts(histArray); + } +} diff --git a/mca/filterpacks/imageproc/java/BlackWhiteFilter.java b/mca/filterpacks/imageproc/java/BlackWhiteFilter.java new file mode 100644 index 00000000..6fcd0d9d --- /dev/null +++ b/mca/filterpacks/imageproc/java/BlackWhiteFilter.java @@ -0,0 +1,175 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import java.util.Random; + +public class BlackWhiteFilter extends Filter { + + @GenerateFieldPort(name = "black") + private float mBlack; + + @GenerateFieldPort(name = "white") + private float mWhite; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private Frame mNoiseFrame; + private Random mRandom; + + private final String mBlackWhiteShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform sampler2D tex_sampler_1;\n" + + "uniform float black;\n" + + "uniform float scale;\n" + + "uniform float stepsize;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float dither = texture2D(tex_sampler_1, v_texcoord).r;\n" + + " vec3 xform = clamp((color.rgb - black) * scale, 0.0, 1.0);\n" + + " vec3 temp = clamp((color.rgb + stepsize - black) * scale, 0.0, 1.0);\n" + + " vec3 new_color = clamp(xform + (temp - xform) * (dither - 0.5), 0.0, 1.0);\n" + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; + + public BlackWhiteFilter(String name) { + super(name); + + mRandom = new Random(); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + @Override + public void tearDown(FilterContext context) { + if (mNoiseFrame != null) { + mNoiseFrame.release(); + mNoiseFrame = null; + } + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mBlackWhiteShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + updateParameters(); + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + private void updateParameters() { + float scale = (mBlack != mWhite) ? 1.0f / (mWhite - mBlack) : 2000f; + float stepsize = 1.0f / 255.0f; + + mProgram.setHostValue("black", mBlack); + mProgram.setHostValue("scale", scale); + mProgram.setHostValue("stepsize", stepsize); + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + + if (mNoiseFrame != null) + mNoiseFrame.release(); + + int[] buffer = new int[mWidth * mHeight]; + for (int i = 0; i < mWidth * mHeight; ++i) { + buffer[i] = mRandom.nextInt(255); + } + FrameFormat format = ImageFormat.create(mWidth, mHeight, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + mNoiseFrame = context.getFrameManager().newFrame(format); + mNoiseFrame.setInts(buffer); + } + + if (mNoiseFrame != null && (mNoiseFrame.getFormat().getWidth() != mWidth || + mNoiseFrame.getFormat().getHeight() != mHeight)) { + throw new RuntimeException("Random map and imput image size mismatch!"); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + Frame[] inputs = {input, mNoiseFrame}; + mProgram.process(inputs, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } +} diff --git a/mca/filterpacks/imageproc/java/ColorTemperatureFilter.java b/mca/filterpacks/imageproc/java/ColorTemperatureFilter.java new file mode 100644 index 00000000..5447d242 --- /dev/null +++ b/mca/filterpacks/imageproc/java/ColorTemperatureFilter.java @@ -0,0 +1,128 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.util.Log; + +public class ColorTemperatureFilter extends Filter { + + @GenerateFieldPort(name = "scale") + private float mScale; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mColorTemperatureShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform float scale;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec3 new_color = color.rgb;\n" + + " new_color.r = color.r + color.r * ( 1.0 - color.r) * scale;\n" + + " new_color.b = color.b - color.b * ( 1.0 - color.b) * scale;\n" + + " if (scale > 0.0) { \n" + + " color.g = color.g + color.g * ( 1.0 - color.g) * scale * 0.25;\n" + + " }\n" + + " float max_value = max(new_color.r, max(new_color.g, new_color.b));\n" + + " if (max_value > 1.0) { \n" + + " new_color /= max_value;\n" + + " } \n" + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; + + public ColorTemperatureFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mColorTemperatureShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + updateParameters(); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateParameters() { + mProgram.setHostValue("scale", 2.0f * mScale - 1.0f); + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } +} diff --git a/mca/filterpacks/imageproc/java/CropRectFilter.java b/mca/filterpacks/imageproc/java/CropRectFilter.java new file mode 100644 index 00000000..d423d060 --- /dev/null +++ b/mca/filterpacks/imageproc/java/CropRectFilter.java @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.MutableFrameFormat; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.util.Log; + +/** + * @hide + */ +public class CropRectFilter extends Filter { + + @GenerateFieldPort(name = "xorigin") + private int mXorigin; + + @GenerateFieldPort(name = "yorigin") + private int mYorigin; + + @GenerateFieldPort(name = "width") + private int mOutputWidth; + + @GenerateFieldPort(name = "height") + private int mOutputHeight; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + public CropRectFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateSourceRect(mWidth, mHeight); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + FrameFormat outputFormat = ImageFormat.create(mOutputWidth, mOutputHeight, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + Frame output = context.getFrameManager().newFrame(outputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + updateSourceRect(inputFormat.getWidth(), inputFormat.getHeight()); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + void updateSourceRect(int width, int height) { + mWidth = width; + mHeight = height; + + /* + Log.e("CropFilter", mWidth + ", " + mHeight + ", " + + (float) mXorigin / mWidth + ", " + + (float) mYorigin / mHeight + ", " + + (float) mOutputWidth / mWidth + ", " + + (float) mOutputHeight / mHeight); + */ + + ((ShaderProgram) mProgram).setSourceRect((float) mXorigin / mWidth, + (float) mYorigin / mHeight, + (float) mOutputWidth / mWidth, + (float) mOutputHeight / mHeight); + } +} diff --git a/mca/filterpacks/imageproc/java/CrossProcessFilter.java b/mca/filterpacks/imageproc/java/CrossProcessFilter.java new file mode 100644 index 00000000..9615eb9b --- /dev/null +++ b/mca/filterpacks/imageproc/java/CrossProcessFilter.java @@ -0,0 +1,116 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import android.util.Log; + +public class CrossProcessFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mCrossProcessShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec3 ncolor = vec3(0.0, 0.0, 0.0);\n" + + " if (color.r < 0.5) {\n" + + " ncolor.r = 4.0 * pow(color.r, 3.0);\n" + + " } else {\n" + + " ncolor.r = 1.0 - 4.0 * pow(1.0 - color.r, 3.0);\n" + + " }\n" + + " if (color.g < 0.5) {\n" + + " ncolor.g = 2.0 * pow(color.g, 2.0);\n" + + " } else {\n" + + " ncolor.g = 1.0 - 2.0 * pow(1.0 - color.g, 2.0);\n" + + " }\n" + + " ncolor.b = color.b * 0.5 + 0.25;\n" + + " gl_FragColor = vec4(ncolor.rgb, color.a);\n" + + "}\n"; + + public CrossProcessFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mCrossProcessShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter CrossProcess does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } +} diff --git a/mca/filterpacks/imageproc/java/DoodleFilter.java b/mca/filterpacks/imageproc/java/DoodleFilter.java new file mode 100644 index 00000000..5284bcae --- /dev/null +++ b/mca/filterpacks/imageproc/java/DoodleFilter.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.filterpacks.imageproc.ImageCombineFilter; +import android.graphics.Bitmap; + +import android.util.Log; + +/** + * @hide + */ +public class DoodleFilter extends Filter { + + @GenerateFieldPort(name = "doodle") + private Bitmap mDoodleBitmap; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private Frame mDoodleFrame; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mDoodleShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform sampler2D tex_sampler_1;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 original = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec4 mask = texture2D(tex_sampler_1, v_texcoord);\n" + + " gl_FragColor = vec4(original.rgb * (1.0 - mask.a) + mask.rgb, 1.0);\n" + + "}\n"; + + public DoodleFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mDoodleShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter FisheyeFilter does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void tearDown(FilterContext context) { + if (mDoodleFrame != null) { + mDoodleFrame.release(); + mDoodleFrame = null; + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + + createDoodleFrame(context); + } + + // Process + Frame[] inputs = {input, mDoodleFrame}; + mProgram.process(inputs, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void createDoodleFrame(FilterContext context) { + if (mDoodleBitmap != null) { + Log.e("DoodleFilter", "create doodle frame " + + mDoodleBitmap.getWidth() + " " + mDoodleBitmap.getHeight()); + + FrameFormat format = ImageFormat.create(mDoodleBitmap.getWidth(), + mDoodleBitmap.getHeight(), + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + + if (mDoodleFrame != null) { + mDoodleFrame.release(); + } + + mDoodleFrame = context.getFrameManager().newFrame(format); + mDoodleFrame.setBitmap(mDoodleBitmap); + + mDoodleBitmap.recycle(); + mDoodleBitmap = null; + } + } +} diff --git a/mca/filterpacks/imageproc/java/DuotoneFilter.java b/mca/filterpacks/imageproc/java/DuotoneFilter.java new file mode 100644 index 00000000..65821f45 --- /dev/null +++ b/mca/filterpacks/imageproc/java/DuotoneFilter.java @@ -0,0 +1,122 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + + +public class DuotoneFilter extends Filter { + + // TODO(rslin): extract rgb values from 4 byte integer + @GenerateFieldPort(name = "first_color") + private int mFirstColor; + + @GenerateFieldPort(name = "second_color") + private int mSecondColor; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mDuotoneShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform vec3 first;\n" + + "uniform vec3 second;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float energy = (color.r + color.g + color.b) * 0.3333;\n" + + " vec3 new_color = (1.0 - energy) * first + energy * second;\n" + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; + + public DuotoneFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mDuotoneShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Duotone does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + initParameters(); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void initParameters() { + float first[] = { 0f / 255f, 68f / 255f, 136f / 255f}; + float second[] = { 1.0f, 1.0f, 0.0f}; + + mProgram.setHostValue("first", first); + mProgram.setHostValue("second", second); + } +} diff --git a/mca/filterpacks/imageproc/java/FillLightFilter.java b/mca/filterpacks/imageproc/java/FillLightFilter.java new file mode 100644 index 00000000..5d9c8623 --- /dev/null +++ b/mca/filterpacks/imageproc/java/FillLightFilter.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.GenerateFinalPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import android.util.Log; + +public class FillLightFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + @GenerateFieldPort(name = "backlight") + private float mBacklight; + + private Program mProgram; + + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mFillLightShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform float mult;\n" + + "uniform float igamma;\n" + + "varying vec2 v_texcoord;\n" + + "void main()\n" + + "{\n" + + " const vec3 color_weights = vec3(0.25, 0.5, 0.25);\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float lightmask = dot(color.rgb, color_weights);\n" + + " float backmask = (1.0 - lightmask);\n" + + " vec3 ones = vec3(1.0, 1.0, 1.0);\n" + + " vec3 diff = pow(mult * color.rgb, igamma * ones) - color.rgb;\n" + + " diff = min(diff, 1.0);\n" + + " vec3 new_color = min(color.rgb + diff * backmask, 1.0);\n" + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; + + public FillLightFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mFillLightShader); + Log.e("FillLight", "tile size: " + mTileSize); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter FillLight does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + updateParameters(); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + private void updateParameters() { + float fade_gamma = 0.3f; + float amt = 1.0f - mBacklight; + float mult = 1.0f / (amt * 0.7f + 0.3f); + float faded = fade_gamma + (1.0f -fade_gamma) *mult; + float igamma = 1.0f / faded; + + mProgram.setHostValue("mult", mult); + mProgram.setHostValue("igamma", igamma); + } +} diff --git a/mca/filterpacks/imageproc/java/FisheyeFilter.java b/mca/filterpacks/imageproc/java/FisheyeFilter.java index 8599822a..7ad7a54f 100644 --- a/mca/filterpacks/imageproc/java/FisheyeFilter.java +++ b/mca/filterpacks/imageproc/java/FisheyeFilter.java @@ -46,6 +46,9 @@ public class FisheyeFilter extends Filter { @GenerateFieldPort(name = "scale") private float mScale; + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + private Program mProgram; private int mWidth = 0; @@ -94,7 +97,7 @@ public class FisheyeFilter extends Filter { switch (target) { case FrameFormat.TARGET_GPU: ShaderProgram shaderProgram = new ShaderProgram(context, mFisheyeShader); - shaderProgram.setMaximumTileSize(512); + shaderProgram.setMaximumTileSize(mTileSize); mProgram = shaderProgram; break; diff --git a/mca/filterpacks/imageproc/java/FlipFilter.java b/mca/filterpacks/imageproc/java/FlipFilter.java new file mode 100644 index 00000000..58f0913b --- /dev/null +++ b/mca/filterpacks/imageproc/java/FlipFilter.java @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.MutableFrameFormat; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import android.util.Log; + +/** + * @hide + */ +public class FlipFilter extends Filter { + + @GenerateFieldPort(name = "vertical") + private boolean mVertical; + + @GenerateFieldPort(name = "horizontal") + private boolean mHorizontal; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + public FlipFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + updateParameters(); + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateParameters() { + float x_origin = (mVertical) ? 1.0f : 0.0f; + float y_origin = (mHorizontal) ? 1.0f : 0.0f; + float width = (mVertical) ? -1.0f : 1.0f; + float height = (mHorizontal) ? -1.0f : 1.0f; + ((ShaderProgram) mProgram).setSourceRect(x_origin, y_origin, width, height); + } +} diff --git a/mca/filterpacks/imageproc/java/GrainFilter.java b/mca/filterpacks/imageproc/java/GrainFilter.java new file mode 100644 index 00000000..6b172eb6 --- /dev/null +++ b/mca/filterpacks/imageproc/java/GrainFilter.java @@ -0,0 +1,185 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.filterfw.geometry.Quad; +import android.filterfw.geometry.Point; + +import java.util.Random; + +public class GrainFilter extends Filter { + + @GenerateFieldPort(name = "scale") + private float mScale; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private Frame mNoiseFrame = null; + private Random mRandom; + + private final String mGrainShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform sampler2D tex_sampler_1;\n" + + "uniform float scale;\n" + + "uniform float stepX;\n" + + "uniform float stepY;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " float noise = texture2D(tex_sampler_1, v_texcoord + vec2(-stepX, -stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, v_texcoord + vec2(-stepX, stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, v_texcoord + vec2(stepX, -stepY)).r * 0.224;\n" + + " noise += texture2D(tex_sampler_1, v_texcoord + vec2(stepX, stepY)).r * 0.224;\n" + + " noise += 0.4448;\n" + + " noise *= scale;\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float energy = color.r + color.g + color.b;\n" + + " float mask = 1.733 - sqrt(energy);\n" + + " float weight = 1.0 - mask * noise;\n" + + " gl_FragColor = vec4(color.rgb * weight, color.a);\n" + + "}\n"; + + + public GrainFilter(String name) { + super(name); + + mRandom = new Random(); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mGrainShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + private void updateParameters() { + mProgram.setHostValue("scale", mScale); + } + + private void updateFrameSize(int width, int height) { + mWidth = width; + mHeight = height; + + if (mProgram != null) { + mProgram.setHostValue("stepX", 0.5f / mWidth); + mProgram.setHostValue("stepY", 0.5f / mHeight); + updateParameters(); + } + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void tearDown(FilterContext context) { + if (mNoiseFrame != null) { + mNoiseFrame.release(); + mNoiseFrame = null; + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + updateParameters(); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + updateFrameSize(inputFormat.getWidth(), inputFormat.getHeight()); + + if (mNoiseFrame != null) + mNoiseFrame.release(); + + int[] buffer = new int[mWidth * mHeight]; + for (int i = 0; i < mWidth * mHeight; ++i) { + buffer[i] = mRandom.nextInt(255); + } + FrameFormat format = ImageFormat.create(mWidth, mHeight, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + mNoiseFrame = context.getFrameManager().newFrame(format); + mNoiseFrame.setInts(buffer); + } + + if (mNoiseFrame.getFormat().getWidth() != mWidth || + mNoiseFrame.getFormat().getHeight() != mHeight) { + throw new RuntimeException("Random map and imput image size mismatch!"); + } + + // Process + Frame[] inputs = {input, mNoiseFrame}; + mProgram.process(inputs, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } +} diff --git a/mca/filterpacks/imageproc/java/NegativeFilter.java b/mca/filterpacks/imageproc/java/NegativeFilter.java new file mode 100644 index 00000000..440d6a64 --- /dev/null +++ b/mca/filterpacks/imageproc/java/NegativeFilter.java @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + + +public class NegativeFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mNegativeShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " gl_FragColor = vec4(1.0 - color.rgb, color.a);\n" + + "}\n"; + + public NegativeFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mNegativeShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + +} diff --git a/mca/filterpacks/imageproc/java/PosterizeFilter.java b/mca/filterpacks/imageproc/java/PosterizeFilter.java new file mode 100644 index 00000000..f7aaab63 --- /dev/null +++ b/mca/filterpacks/imageproc/java/PosterizeFilter.java @@ -0,0 +1,108 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +public class PosterizeFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mPosterizeShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec3 pcolor;\n" + + // TODO(rslin): step function doesn't work properly in IMG devices. + // " vec3 pcolor = 0.5 * step(0.5, color.rgb) + 0.25;\n" + + " pcolor.r = (color.r >= 0.5) ? 0.75 : 0.25;\n" + + " pcolor.g = (color.g >= 0.5) ? 0.75 : 0.25;\n" + + " pcolor.b = (color.b >= 0.5) ? 0.75 : 0.25;\n" + + " gl_FragColor = vec4(pcolor, color.a);\n" + + "}\n"; + + public PosterizeFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mPosterizeShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + +} diff --git a/mca/filterpacks/imageproc/java/RedEyeFilter.java b/mca/filterpacks/imageproc/java/RedEyeFilter.java new file mode 100644 index 00000000..7c1d0641 --- /dev/null +++ b/mca/filterpacks/imageproc/java/RedEyeFilter.java @@ -0,0 +1,166 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.graphics.Bitmap; + +import java.util.Set; + +import android.util.Log; + +/** + * @hide + */ +public class RedEyeFilter extends Filter { + + @GenerateFieldPort(name = "intensity") + private float mIntensity; + + @GenerateFieldPort(name = "redeye") + private Bitmap mRedEyeBitmap = null; + + @GenerateFieldPort(name = "update") + private boolean mUpdate; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Frame mRedEyeFrame; + + private int mWidth = 0; + private int mHeight = 0; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mRedEyeShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform sampler2D tex_sampler_1;\n" + + "uniform float intensity;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec4 mask = texture2D(tex_sampler_1, v_texcoord);\n" + + " gl_FragColor = vec4(mask.a, mask.a, mask.a, 1.0) * intensity + color * (1.0 - intensity);\n" + + " if (mask.a > 0.0) {\n" + + " gl_FragColor.r = 0.0;\n" + + " float green_blue = color.g + color.b;\n" + + " float red_intensity = color.r / green_blue;\n" + + " if (red_intensity > intensity) {\n" + + " color.r = 0.5 * green_blue;\n" + + " }\n" + + " }\n" + + " gl_FragColor = color;\n" + + "}\n"; + + public RedEyeFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mRedEyeShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter RedEye does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void tearDown(FilterContext context) { + if (mRedEyeFrame != null) { + mRedEyeFrame.release(); + mRedEyeFrame = null; + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + if (mUpdate) + updateProgramParams(context); + + // Process + Frame[] inputs = {input, mRedEyeFrame}; + mProgram.process(inputs, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateProgramParams(FilterContext context) { + mProgram.setHostValue("intensity", mIntensity); + + if (mRedEyeBitmap != null) { + + // TODO(rslin): Can I reuse the existing frame instead of creating + // a new frame each time? + FrameFormat format = ImageFormat.create(mRedEyeBitmap.getWidth(), + mRedEyeBitmap.getHeight(), + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + if (mRedEyeFrame != null) { + mRedEyeFrame.release(); + } + mRedEyeFrame = context.getFrameManager().newFrame(format); + mRedEyeFrame.setBitmap(mRedEyeBitmap); + } + } +} diff --git a/mca/filterpacks/imageproc/java/RotateFilter.java b/mca/filterpacks/imageproc/java/RotateFilter.java new file mode 100644 index 00000000..df1b558b --- /dev/null +++ b/mca/filterpacks/imageproc/java/RotateFilter.java @@ -0,0 +1,156 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.MutableFrameFormat; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.filterfw.geometry.Quad; +import android.filterfw.geometry.Point; +import android.util.Log; + +/** + * @hide + */ +public class RotateFilter extends Filter { + + @GenerateFieldPort(name = "degree") + private float mAngle; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private int mOutputWidth; + private int mOutputHeight; + + public RotateFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); + shaderProgram.setMaximumTileSize(mTileSize); + shaderProgram.setClearsOutput(true); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + mOutputWidth = mWidth; + mOutputHeight = mHeight; + + updateParameters(); + } + + // Create output frame + FrameFormat outputFormat = ImageFormat.create(mOutputWidth, mOutputHeight, + ImageFormat.COLORSPACE_RGBA, + FrameFormat.TARGET_GPU); + + Frame output = context.getFrameManager().newFrame(outputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateParameters() { + float sinTheta; + float cosTheta; + + if (mAngle % 90 == 0) { + if (mAngle % 180 == 0) { + sinTheta = 0f; + cosTheta = (mAngle % 360 == 0) ? 1f:-1f; + } else { + cosTheta = 0f; + sinTheta = ((mAngle + 90f) % 360 == 0) ? -1f:1f; + + mOutputWidth = mHeight; + mOutputHeight = mWidth; + } + } else { + throw new RuntimeException("degree has to be multiply of 90."); + } + + Point x0 = new Point(0.5f * (-cosTheta + sinTheta + 1f), + 0.5f * (-sinTheta - cosTheta + 1f)); + Point x1 = new Point(0.5f * (cosTheta + sinTheta + 1f), + 0.5f * (sinTheta - cosTheta + 1f)); + Point x2 = new Point(0.5f * (-cosTheta - sinTheta + 1f), + 0.5f * (-sinTheta + cosTheta + 1f)); + Point x3 = new Point(0.5f * (cosTheta - sinTheta + 1f), + 0.5f * (sinTheta + cosTheta + 1f)); + Quad quad = new Quad(x0, x1, x2, x3); + ((ShaderProgram) mProgram).setTargetRegion(quad); + } +} diff --git a/mca/filterpacks/imageproc/java/SaturateFilter.java b/mca/filterpacks/imageproc/java/SaturateFilter.java new file mode 100644 index 00000000..5b924c08 --- /dev/null +++ b/mca/filterpacks/imageproc/java/SaturateFilter.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +public class SaturateFilter extends Filter { + + @GenerateFieldPort(name = "scale") + private float mScale; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mBenProgram; + private Program mHerfProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mBenSaturateShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform float scale;\n" + + "uniform float shift;\n" + + "uniform vec3 weights;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float kv = dot(color.rgb, weights) + shift;\n" + + " vec3 new_color = scale * color.rgb + (1.0 - scale) * kv;\n" + + " gl_FragColor = vec4(new_color, color.a);\n" + + "}\n"; + + private final String mHerfSaturateShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform vec3 weights;\n" + + "uniform vec3 exponents;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float de = dot(color.rgb, weights);\n" + + " float inv_de = 1.0 / de;\n" + + " vec3 new_color = de * pow(color.rgb * inv_de, exponents);\n" + + " float max_color = max(max(max(new_color.r, new_color.g), new_color.b), 1.0);\n" + + " gl_FragColor = vec4(new_color / max_color, color.a);\n" + + "}\n"; + + + public SaturateFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mBenSaturateShader); + shaderProgram.setMaximumTileSize(mTileSize); + mBenProgram = shaderProgram; + + shaderProgram = new ShaderProgram(context, mHerfSaturateShader); + shaderProgram.setMaximumTileSize(mTileSize); + mHerfProgram = shaderProgram; + + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mBenProgram != null && mHerfProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mBenProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + initParameters(); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + if (mScale > 0.0f) { + mHerfProgram.process(input, output); + } else { + mBenProgram.process(input, output); + } + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void initParameters() { + float shift = 1.0f / 255.0f; + float weights[] = { 2f/8f, 5f/8f, 1f/8f}; + + mBenProgram.setHostValue("weights", weights); + mBenProgram.setHostValue("shift", shift); + + mHerfProgram.setHostValue("weights", weights); + + updateParameters(); + } + + private void updateParameters() { + + if (mScale > 0.0f) { + float exponents[] = new float[3]; + + exponents[0] = (0.9f * mScale) + 1.0f; + exponents[1] = (2.1f * mScale) + 1.0f; + exponents[2] = (2.7f * mScale) + 1.0f; + + mHerfProgram.setHostValue("exponents", exponents); + } else { + mBenProgram.setHostValue("scale", 1.0f + mScale); + } + } + +} diff --git a/mca/filterpacks/imageproc/java/SepiaFilter.java b/mca/filterpacks/imageproc/java/SepiaFilter.java new file mode 100644 index 00000000..7a83fdf7 --- /dev/null +++ b/mca/filterpacks/imageproc/java/SepiaFilter.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +public class SepiaFilter extends Filter { + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mSepiaShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform mat3 matrix;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " vec3 new_color = min(matrix * color.rgb, 1.0);\n" + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; + + public SepiaFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mSepiaShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + initParameters(); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void initParameters() { + float weights[] = { 805.0f / 2048.0f, 715.0f / 2048.0f, 557.0f / 2048.0f, + 1575.0f / 2048.0f, 1405.0f / 2048.0f, 1097.0f / 2048.0f, + 387.0f / 2048.0f, 344.0f / 2048.0f, 268.0f / 2048.0f }; + mProgram.setHostValue("matrix", weights); + } +} diff --git a/mca/filterpacks/imageproc/java/SharpenFilter.java b/mca/filterpacks/imageproc/java/SharpenFilter.java new file mode 100644 index 00000000..86a9bc1f --- /dev/null +++ b/mca/filterpacks/imageproc/java/SharpenFilter.java @@ -0,0 +1,153 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +import java.util.Set; + +public class SharpenFilter extends Filter { + + @GenerateFieldPort(name = "scale") + private float mScale; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mSharpenShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform float scale;\n" + + "uniform float stepsizeX;\n" + + "uniform float stepsizeY;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec3 nbr_color = vec3(0.0, 0.0, 0.0);\n" + + " vec2 coord;\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " coord.x = v_texcoord.x - 0.5 * stepsizeX;\n" + + " coord.y = v_texcoord.y - stepsizeY;\n" + + " nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" + + " coord.x = v_texcoord.x - stepsizeX;\n" + + " coord.y = v_texcoord.y + 0.5 * stepsizeY;\n" + + " nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" + + " coord.x = v_texcoord.x + stepsizeX;\n" + + " coord.y = v_texcoord.y - 0.5 * stepsizeY;\n" + + " nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" + + " coord.x = v_texcoord.x + stepsizeX;\n" + + " coord.y = v_texcoord.y + 0.5 * stepsizeY;\n" + + " nbr_color += texture2D(tex_sampler_0, coord).rgb - color.rgb;\n" + + " gl_FragColor = vec4(color.rgb - 2.0 * scale * nbr_color, color.a);\n" + + "}\n"; + + public SharpenFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mSharpenShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + updateFrameSize(inputFormat.getWidth(), inputFormat.getHeight()); + } + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateFrameSize(int width, int height) { + mWidth = width; + mHeight = height; + + if (mProgram != null) { + mProgram.setHostValue("stepsizeX", 1.0f / mWidth); + mProgram.setHostValue("stepsizeY", 1.0f / mHeight); + updateParameters(); + } + } + + private void updateParameters() { + mProgram.setHostValue("scale", mScale); + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } +} diff --git a/mca/filterpacks/imageproc/java/StraightenFilter.java b/mca/filterpacks/imageproc/java/StraightenFilter.java new file mode 100644 index 00000000..f1548acb --- /dev/null +++ b/mca/filterpacks/imageproc/java/StraightenFilter.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.MutableFrameFormat; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; +import android.filterfw.geometry.Quad; +import android.filterfw.geometry.Point; +import android.util.Log; + +/** + * @hide + */ +public class StraightenFilter extends Filter { + + @GenerateFieldPort(name = "angle") + private float mAngle; + + @GenerateFieldPort(name = "maxAngle") + private float mMaxAngle; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private static final float DEGREE_TO_RADIAN = (float) Math.PI / 180.0f; + + public StraightenFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = ShaderProgram.createIdentity(context); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Create output frame + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + updateParameters(); + } + + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void updateParameters() { + float cosTheta = (float) Math.cos(mAngle * DEGREE_TO_RADIAN); + float sinTheta = (float) Math.sin(mAngle * DEGREE_TO_RADIAN); + + if (mMaxAngle <= 0) + throw new RuntimeException("Max angle is out of range (0-180)."); + mMaxAngle = (mMaxAngle > 90) ? 90 : mMaxAngle; + + Point p0 = new Point(-cosTheta * mWidth + sinTheta * mHeight, + -sinTheta * mWidth - cosTheta * mHeight); + + Point p1 = new Point(cosTheta * mWidth + sinTheta * mHeight, + sinTheta * mWidth - cosTheta * mHeight); + + Point p2 = new Point(-cosTheta * mWidth - sinTheta * mHeight, + -sinTheta * mWidth + cosTheta * mHeight); + + Point p3 = new Point(cosTheta * mWidth - sinTheta * mHeight, + sinTheta * mWidth + cosTheta * mHeight); + + float maxWidth = (float) Math.max(Math.abs(p0.x), Math.abs(p1.x)); + float maxHeight = (float) Math.max(Math.abs(p0.y), Math.abs(p1.y)); + + float scale = 0.5f * Math.min( mWidth / maxWidth, + mHeight / maxHeight); + + p0.set(scale * p0.x / mWidth + 0.5f, scale * p0.y / mHeight + 0.5f); + p1.set(scale * p1.x / mWidth + 0.5f, scale * p1.y / mHeight + 0.5f); + p2.set(scale * p2.x / mWidth + 0.5f, scale * p2.y / mHeight + 0.5f); + p3.set(scale * p3.x / mWidth + 0.5f, scale * p3.y / mHeight + 0.5f); + + Quad quad = new Quad(p0, p1, p2, p3); + ((ShaderProgram) mProgram).setSourceRegion(quad); + } +} diff --git a/mca/filterpacks/imageproc/java/TintFilter.java b/mca/filterpacks/imageproc/java/TintFilter.java new file mode 100644 index 00000000..a946b0ca --- /dev/null +++ b/mca/filterpacks/imageproc/java/TintFilter.java @@ -0,0 +1,134 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + + +public class TintFilter extends Filter { + + // TODO(rslin): extract rgb values from 4 byte integer + @GenerateFieldPort(name = "tint") + private int mTint; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final String mTintShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform vec3 tint;\n" + + "uniform vec3 color_ratio;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " float avg_color = dot(color_ratio, color.rgb);\n" + + " vec3 new_color = min(0.8 * avg_color + 0.2 * tint, 1.0);\n" + + " gl_FragColor = vec4(new_color.rgb, color.a);\n" + + "}\n"; + + public TintFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mTintShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + initParameters(); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } + + private void initParameters() { + float color_ratio[] = {0.21f, 0.71f, 0.07f}; + mProgram.setHostValue("color_ratio", color_ratio); + + updateParameters(); + } + + private void updateParameters() { + float tint_color[] = {(float) ((mTint >> 16) & 0xff) / 256f, + (float) ((mTint >> 8) & 0xff) / 256f, + (float) (mTint & 0xff) / 256f }; + + mProgram.setHostValue("tint", tint_color); + } + +} diff --git a/mca/filterpacks/imageproc/java/ToGrayFilter.java b/mca/filterpacks/imageproc/java/ToGrayFilter.java index ac58db21..00e7bf47 100644 --- a/mca/filterpacks/imageproc/java/ToGrayFilter.java +++ b/mca/filterpacks/imageproc/java/ToGrayFilter.java @@ -42,6 +42,9 @@ public class ToGrayFilter extends SimpleImageFilter { @GenerateFieldPort(name = "invertSource", hasDefault = true) private boolean mInvertSource = false; + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + private MutableFrameFormat mOutputFormat; private static final String mColorToGray4Shader = @@ -78,6 +81,7 @@ public class ToGrayFilter extends SimpleImageFilter { inputChannels + "! Channels must be 4!"); } ShaderProgram program = new ShaderProgram(context, mColorToGray4Shader); + program.setMaximumTileSize(mTileSize); if (mInvertSource) program.setSourceRect(0.0f, 1.0f, 1.0f, -1.0f); return program; diff --git a/mca/filterpacks/imageproc/java/VignetteFilter.java b/mca/filterpacks/imageproc/java/VignetteFilter.java new file mode 100644 index 00000000..855ffd8d --- /dev/null +++ b/mca/filterpacks/imageproc/java/VignetteFilter.java @@ -0,0 +1,151 @@ +/* + * Copyright (C) 2011 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.filterpacks.imageproc; + +import android.filterfw.core.Filter; +import android.filterfw.core.FilterContext; +import android.filterfw.core.Frame; +import android.filterfw.core.FrameFormat; +import android.filterfw.core.GenerateFieldPort; +import android.filterfw.core.KeyValueMap; +import android.filterfw.core.NativeProgram; +import android.filterfw.core.NativeFrame; +import android.filterfw.core.Program; +import android.filterfw.core.ShaderProgram; +import android.filterfw.format.ImageFormat; + +public class VignetteFilter extends Filter { + + @GenerateFieldPort(name = "range") + private float mRange; + + @GenerateFieldPort(name = "tile_size", hasDefault = true) + private int mTileSize = 640; + + private Program mProgram; + + private int mWidth = 0; + private int mHeight = 0; + private int mTarget = FrameFormat.TARGET_UNSPECIFIED; + + private final float mSlope = 20.0f; + private final float mShade = 0.85f; + + private final String mVignetteShader = + "precision mediump float;\n" + + "uniform sampler2D tex_sampler_0;\n" + + "uniform float range;\n" + + "uniform float inv_max_dist;\n" + + "uniform float shade;\n" + + "uniform vec2 center;\n" + + "varying vec2 v_texcoord;\n" + + "void main() {\n" + + " const float slope = 20.0;\n" + + " float dist = distance(gl_FragCoord.xy, center);\n" + + " float lumen = shade / (1.0 + exp((dist * inv_max_dist - range) * slope)) + (1.0 - shade);\n" + + " vec4 color = texture2D(tex_sampler_0, v_texcoord);\n" + + " gl_FragColor = vec4(color.rgb * lumen, color.a);\n" + + "}\n"; + + public VignetteFilter(String name) { + super(name); + } + + @Override + public void setupPorts() { + addMaskedInputPort("image", ImageFormat.create(ImageFormat.COLORSPACE_RGBA)); + addOutputBasedOnInput("image", "image"); + } + + @Override + public FrameFormat getOutputFormat(String portName, FrameFormat inputFormat) { + return inputFormat; + } + + public void initProgram(FilterContext context, int target) { + switch (target) { + case FrameFormat.TARGET_GPU: + ShaderProgram shaderProgram = new ShaderProgram(context, mVignetteShader); + shaderProgram.setMaximumTileSize(mTileSize); + mProgram = shaderProgram; + break; + + default: + throw new RuntimeException("Filter Sharpen does not support frames of " + + "target " + target + "!"); + } + mTarget = target; + } + + private void initParameters() { + if (mProgram != null) { + float centerX = (float) (0.5 * mWidth); + float centerY = (float) (0.5 * mHeight); + float center[] = {centerX, centerY}; + float max_dist = (float) Math.sqrt(centerX * centerX + centerY * centerY); + + mProgram.setHostValue("center", center); + mProgram.setHostValue("inv_max_dist", 1.0f / max_dist); + mProgram.setHostValue("shade", mShade); + + updateParameters(); + } + } + + private void updateParameters() { + mProgram.setHostValue("range", mRange); + } + + + @Override + public void fieldPortValueUpdated(String name, FilterContext context) { + if (mProgram != null) { + updateParameters(); + } + } + + @Override + public void process(FilterContext context) { + // Get input frame + Frame input = pullInput("image"); + FrameFormat inputFormat = input.getFormat(); + + // Create program if not created already + if (mProgram == null || inputFormat.getTarget() != mTarget) { + initProgram(context, inputFormat.getTarget()); + } + + // Check if the frame size has changed + if (inputFormat.getWidth() != mWidth || inputFormat.getHeight() != mHeight) { + mWidth = inputFormat.getWidth(); + mHeight = inputFormat.getHeight(); + initParameters(); + } + + // Create output frame + Frame output = context.getFrameManager().newFrame(inputFormat); + + // Process + mProgram.process(input, output); + + // Push output + pushOutput("image", output); + + // Release pushed frame + output.release(); + } +} -- 2.11.0