diff options
Diffstat (limited to 'src/com/android/gallery3d/filtershow/filters')
57 files changed, 6960 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java new file mode 100644 index 000000000..3fa91916d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -0,0 +1,296 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.content.Context; +import android.content.res.Resources; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorCrop; +import com.android.gallery3d.filtershow.editors.EditorMirror; +import com.android.gallery3d.filtershow.editors.EditorRotate; +import com.android.gallery3d.filtershow.editors.EditorStraighten; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Vector; + +public abstract class BaseFiltersManager implements FiltersManagerInterface { + protected HashMap<Class, ImageFilter> mFilters = null; + protected HashMap<String, FilterRepresentation> mRepresentationLookup = null; + private static final String LOGTAG = "BaseFiltersManager"; + + protected ArrayList<FilterRepresentation> mLooks = new ArrayList<FilterRepresentation>(); + protected ArrayList<FilterRepresentation> mBorders = new ArrayList<FilterRepresentation>(); + protected ArrayList<FilterRepresentation> mTools = new ArrayList<FilterRepresentation>(); + protected ArrayList<FilterRepresentation> mEffects = new ArrayList<FilterRepresentation>(); + + protected void init() { + mFilters = new HashMap<Class, ImageFilter>(); + mRepresentationLookup = new HashMap<String, FilterRepresentation>(); + Vector<Class> filters = new Vector<Class>(); + addFilterClasses(filters); + for (Class filterClass : filters) { + try { + Object filterInstance = filterClass.newInstance(); + if (filterInstance instanceof ImageFilter) { + mFilters.put(filterClass, (ImageFilter) filterInstance); + + FilterRepresentation rep = + ((ImageFilter) filterInstance).getDefaultRepresentation(); + if (rep != null) { + addRepresentation(rep); + } + } + } catch (InstantiationException e) { + e.printStackTrace(); + } catch (IllegalAccessException e) { + e.printStackTrace(); + } + } + } + + public void addRepresentation(FilterRepresentation rep) { + mRepresentationLookup.put(rep.getSerializationName(), rep); + } + + public FilterRepresentation createFilterFromName(String name) { + try { + return mRepresentationLookup.get(name).copy(); + } catch (Exception e) { + Log.v(LOGTAG, "unable to generate a filter representation for \"" + name + "\""); + e.printStackTrace(); + } + return null; + } + + public ImageFilter getFilter(Class c) { + return mFilters.get(c); + } + + @Override + public ImageFilter getFilterForRepresentation(FilterRepresentation representation) { + return mFilters.get(representation.getFilterClass()); + } + + public FilterRepresentation getRepresentation(Class c) { + ImageFilter filter = mFilters.get(c); + if (filter != null) { + return filter.getDefaultRepresentation(); + } + return null; + } + + public void freeFilterResources(ImagePreset preset) { + if (preset == null) { + return; + } + Vector<ImageFilter> usedFilters = preset.getUsedFilters(this); + for (Class c : mFilters.keySet()) { + ImageFilter filter = mFilters.get(c); + if (!usedFilters.contains(filter)) { + filter.freeResources(); + } + } + } + + public void freeRSFilterScripts() { + for (Class c : mFilters.keySet()) { + ImageFilter filter = mFilters.get(c); + if (filter != null && filter instanceof ImageFilterRS) { + ((ImageFilterRS) filter).resetScripts(); + } + } + } + + protected void addFilterClasses(Vector<Class> filters) { + filters.add(ImageFilterTinyPlanet.class); + filters.add(ImageFilterRedEye.class); + filters.add(ImageFilterWBalance.class); + filters.add(ImageFilterExposure.class); + filters.add(ImageFilterVignette.class); + filters.add(ImageFilterGrad.class); + filters.add(ImageFilterContrast.class); + filters.add(ImageFilterShadows.class); + filters.add(ImageFilterHighlights.class); + filters.add(ImageFilterVibrance.class); + filters.add(ImageFilterSharpen.class); + filters.add(ImageFilterCurves.class); + filters.add(ImageFilterDraw.class); + filters.add(ImageFilterHue.class); + filters.add(ImageFilterChanSat.class); + filters.add(ImageFilterSaturated.class); + filters.add(ImageFilterBwFilter.class); + filters.add(ImageFilterNegative.class); + filters.add(ImageFilterEdge.class); + filters.add(ImageFilterKMeans.class); + filters.add(ImageFilterFx.class); + filters.add(ImageFilterBorder.class); + filters.add(ImageFilterParametricBorder.class); + } + + public ArrayList<FilterRepresentation> getLooks() { + return mLooks; + } + + public ArrayList<FilterRepresentation> getBorders() { + return mBorders; + } + + public ArrayList<FilterRepresentation> getTools() { + return mTools; + } + + public ArrayList<FilterRepresentation> getEffects() { + return mEffects; + } + + public void addBorders(Context context) { + + } + + public void addLooks(Context context) { + int[] drawid = { + R.drawable.filtershow_fx_0005_punch, + R.drawable.filtershow_fx_0000_vintage, + R.drawable.filtershow_fx_0004_bw_contrast, + R.drawable.filtershow_fx_0002_bleach, + R.drawable.filtershow_fx_0001_instant, + R.drawable.filtershow_fx_0007_washout, + R.drawable.filtershow_fx_0003_blue_crush, + R.drawable.filtershow_fx_0008_washout_color, + R.drawable.filtershow_fx_0006_x_process + }; + + int[] fxNameid = { + R.string.ffx_punch, + R.string.ffx_vintage, + R.string.ffx_bw_contrast, + R.string.ffx_bleach, + R.string.ffx_instant, + R.string.ffx_washout, + R.string.ffx_blue_crush, + R.string.ffx_washout_color, + R.string.ffx_x_process + }; + + // Do not localize. + String[] serializationNames = { + "LUT3D_PUNCH", + "LUT3D_VINTAGE", + "LUT3D_BW", + "LUT3D_BLEACH", + "LUT3D_INSTANT", + "LUT3D_WASHOUT", + "LUT3D_BLUECRUSH", + "LUT3D_WASHOUT", + "LUT3D_XPROCESS" + }; + + FilterFxRepresentation nullFx = + new FilterFxRepresentation(context.getString(R.string.none), + 0, R.string.none); + mLooks.add(nullFx); + + for (int i = 0; i < drawid.length; i++) { + FilterFxRepresentation fx = new FilterFxRepresentation( + context.getString(fxNameid[i]), drawid[i], fxNameid[i]); + fx.setSerializationName(serializationNames[i]); + ImagePreset preset = new ImagePreset(); + preset.addFilter(fx); + FilterUserPresetRepresentation rep = new FilterUserPresetRepresentation( + context.getString(fxNameid[i]), preset, -1); + mLooks.add(rep); + addRepresentation(fx); + } + } + + public void addEffects() { + mEffects.add(getRepresentation(ImageFilterTinyPlanet.class)); + mEffects.add(getRepresentation(ImageFilterWBalance.class)); + mEffects.add(getRepresentation(ImageFilterExposure.class)); + mEffects.add(getRepresentation(ImageFilterVignette.class)); + mEffects.add(getRepresentation(ImageFilterGrad.class)); + mEffects.add(getRepresentation(ImageFilterContrast.class)); + mEffects.add(getRepresentation(ImageFilterShadows.class)); + mEffects.add(getRepresentation(ImageFilterHighlights.class)); + mEffects.add(getRepresentation(ImageFilterVibrance.class)); + mEffects.add(getRepresentation(ImageFilterSharpen.class)); + mEffects.add(getRepresentation(ImageFilterCurves.class)); + mEffects.add(getRepresentation(ImageFilterHue.class)); + mEffects.add(getRepresentation(ImageFilterChanSat.class)); + mEffects.add(getRepresentation(ImageFilterBwFilter.class)); + mEffects.add(getRepresentation(ImageFilterNegative.class)); + mEffects.add(getRepresentation(ImageFilterEdge.class)); + mEffects.add(getRepresentation(ImageFilterKMeans.class)); + } + + public void addTools(Context context) { + + int[] editorsId = { + EditorCrop.ID, + EditorStraighten.ID, + EditorRotate.ID, + EditorMirror.ID + }; + + int[] textId = { + R.string.crop, + R.string.straighten, + R.string.rotate, + R.string.mirror + }; + + int[] overlayId = { + R.drawable.filtershow_button_geometry_crop, + R.drawable.filtershow_button_geometry_straighten, + R.drawable.filtershow_button_geometry_rotate, + R.drawable.filtershow_button_geometry_flip + }; + + FilterRepresentation[] geometryFilters = { + new FilterCropRepresentation(), + new FilterStraightenRepresentation(), + new FilterRotateRepresentation(), + new FilterMirrorRepresentation() + }; + + for (int i = 0; i < editorsId.length; i++) { + int editorId = editorsId[i]; + FilterRepresentation geometry = geometryFilters[i]; + geometry.setEditorId(editorId); + geometry.setTextId(textId[i]); + geometry.setOverlayId(overlayId[i]); + geometry.setOverlayOnly(true); + if (geometry.getTextId() != 0) { + geometry.setName(context.getString(geometry.getTextId())); + } + mTools.add(geometry); + } + + mTools.add(getRepresentation(ImageFilterRedEye.class)); + mTools.add(getRepresentation(ImageFilterDraw.class)); + } + + public void setFilterResources(Resources resources) { + ImageFilterBorder filterBorder = (ImageFilterBorder) getFilter(ImageFilterBorder.class); + filterBorder.setResources(resources); + ImageFilterFx filterFx = (ImageFilterFx) getFilter(ImageFilterFx.class); + filterFx.setResources(resources); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ColorSpaceMatrix.java b/src/com/android/gallery3d/filtershow/filters/ColorSpaceMatrix.java new file mode 100644 index 000000000..7c307a9e7 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ColorSpaceMatrix.java @@ -0,0 +1,225 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import java.util.Arrays; + +public class ColorSpaceMatrix { + private final float[] mMatrix = new float[16]; + private static final float RLUM = 0.3086f; + private static final float GLUM = 0.6094f; + private static final float BLUM = 0.0820f; + + public ColorSpaceMatrix() { + identity(); + } + + /** + * Copy constructor + * + * @param matrix + */ + public ColorSpaceMatrix(ColorSpaceMatrix matrix) { + System.arraycopy(matrix.mMatrix, 0, mMatrix, 0, matrix.mMatrix.length); + } + + /** + * get the matrix + * + * @return the internal matrix + */ + public float[] getMatrix() { + return mMatrix; + } + + /** + * set matrix to identity + */ + public void identity() { + Arrays.fill(mMatrix, 0); + mMatrix[0] = mMatrix[5] = mMatrix[10] = mMatrix[15] = 1; + } + + public void convertToLuminance() { + mMatrix[0] = mMatrix[1] = mMatrix[2] = 0.3086f; + mMatrix[4] = mMatrix[5] = mMatrix[6] = 0.6094f; + mMatrix[8] = mMatrix[9] = mMatrix[10] = 0.0820f; + } + + private void multiply(float[] a) + { + int x, y; + float[] temp = new float[16]; + + for (y = 0; y < 4; y++) { + int y4 = y * 4; + for (x = 0; x < 4; x++) { + temp[y4 + x] = mMatrix[y4 + 0] * a[x] + + mMatrix[y4 + 1] * a[4 + x] + + mMatrix[y4 + 2] * a[8 + x] + + mMatrix[y4 + 3] * a[12 + x]; + } + } + for (int i = 0; i < 16; i++) + mMatrix[i] = temp[i]; + } + + private void xRotateMatrix(float rs, float rc) + { + ColorSpaceMatrix c = new ColorSpaceMatrix(); + float[] tmp = c.mMatrix; + + tmp[5] = rc; + tmp[6] = rs; + tmp[9] = -rs; + tmp[10] = rc; + + multiply(tmp); + } + + private void yRotateMatrix(float rs, float rc) + { + ColorSpaceMatrix c = new ColorSpaceMatrix(); + float[] tmp = c.mMatrix; + + tmp[0] = rc; + tmp[2] = -rs; + tmp[8] = rs; + tmp[10] = rc; + + multiply(tmp); + } + + private void zRotateMatrix(float rs, float rc) + { + ColorSpaceMatrix c = new ColorSpaceMatrix(); + float[] tmp = c.mMatrix; + + tmp[0] = rc; + tmp[1] = rs; + tmp[4] = -rs; + tmp[5] = rc; + multiply(tmp); + } + + private void zShearMatrix(float dx, float dy) + { + ColorSpaceMatrix c = new ColorSpaceMatrix(); + float[] tmp = c.mMatrix; + + tmp[2] = dx; + tmp[6] = dy; + multiply(tmp); + } + + /** + * sets the transform to a shift in Hue + * + * @param rot rotation in degrees + */ + public void setHue(float rot) + { + float mag = (float) Math.sqrt(2.0); + float xrs = 1 / mag; + float xrc = 1 / mag; + xRotateMatrix(xrs, xrc); + mag = (float) Math.sqrt(3.0); + float yrs = -1 / mag; + float yrc = (float) Math.sqrt(2.0) / mag; + yRotateMatrix(yrs, yrc); + + float lx = getRedf(RLUM, GLUM, BLUM); + float ly = getGreenf(RLUM, GLUM, BLUM); + float lz = getBluef(RLUM, GLUM, BLUM); + float zsx = lx / lz; + float zsy = ly / lz; + zShearMatrix(zsx, zsy); + + float zrs = (float) Math.sin(rot * Math.PI / 180.0); + float zrc = (float) Math.cos(rot * Math.PI / 180.0); + zRotateMatrix(zrs, zrc); + zShearMatrix(-zsx, -zsy); + yRotateMatrix(-yrs, yrc); + xRotateMatrix(-xrs, xrc); + } + + /** + * set it to a saturation matrix + * + * @param s + */ + public void changeSaturation(float s) { + mMatrix[0] = (1 - s) * RLUM + s; + mMatrix[1] = (1 - s) * RLUM; + mMatrix[2] = (1 - s) * RLUM; + mMatrix[4] = (1 - s) * GLUM; + mMatrix[5] = (1 - s) * GLUM + s; + mMatrix[6] = (1 - s) * GLUM; + mMatrix[8] = (1 - s) * BLUM; + mMatrix[9] = (1 - s) * BLUM; + mMatrix[10] = (1 - s) * BLUM + s; + } + + /** + * Transform RGB value + * + * @param r red pixel value + * @param g green pixel value + * @param b blue pixel value + * @return computed red pixel value + */ + public float getRed(int r, int g, int b) { + return r * mMatrix[0] + g * mMatrix[4] + b * mMatrix[8] + mMatrix[12]; + } + + /** + * Transform RGB value + * + * @param r red pixel value + * @param g green pixel value + * @param b blue pixel value + * @return computed green pixel value + */ + public float getGreen(int r, int g, int b) { + return r * mMatrix[1] + g * mMatrix[5] + b * mMatrix[9] + mMatrix[13]; + } + + /** + * Transform RGB value + * + * @param r red pixel value + * @param g green pixel value + * @param b blue pixel value + * @return computed blue pixel value + */ + public float getBlue(int r, int g, int b) { + return r * mMatrix[2] + g * mMatrix[6] + b * mMatrix[10] + mMatrix[14]; + } + + private float getRedf(float r, float g, float b) { + return r * mMatrix[0] + g * mMatrix[4] + b * mMatrix[8] + mMatrix[12]; + } + + private float getGreenf(float r, float g, float b) { + return r * mMatrix[1] + g * mMatrix[5] + b * mMatrix[9] + mMatrix[13]; + } + + private float getBluef(float r, float g, float b) { + return r * mMatrix[2] + g * mMatrix[6] + b * mMatrix[10] + mMatrix[14]; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java new file mode 100644 index 000000000..1eebdb571 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterBasicRepresentation.java @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + + +import android.util.Log; + +import com.android.gallery3d.filtershow.controller.Control; +import com.android.gallery3d.filtershow.controller.FilterView; +import com.android.gallery3d.filtershow.controller.Parameter; +import com.android.gallery3d.filtershow.controller.ParameterInteger; + +public class FilterBasicRepresentation extends FilterRepresentation implements ParameterInteger { + private static final String LOGTAG = "FilterBasicRep"; + private int mMinimum; + private int mValue; + private int mMaximum; + private int mDefaultValue; + private int mPreviewValue; + public static final String SERIAL_NAME = "Name"; + public static final String SERIAL_VALUE = "Value"; + private boolean mLogVerbose = Log.isLoggable(LOGTAG, Log.VERBOSE); + + public FilterBasicRepresentation(String name, int minimum, int value, int maximum) { + super(name); + mMinimum = minimum; + mMaximum = maximum; + setValue(value); + } + + @Override + public String toString() { + return getName() + " : " + mMinimum + " < " + mValue + " < " + mMaximum; + } + + @Override + public FilterRepresentation copy() { + FilterBasicRepresentation representation = new FilterBasicRepresentation(getName(),0,0,0); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterBasicRepresentation) { + FilterBasicRepresentation representation = (FilterBasicRepresentation) a; + setMinimum(representation.getMinimum()); + setMaximum(representation.getMaximum()); + setValue(representation.getValue()); + setDefaultValue(representation.getDefaultValue()); + setPreviewValue(representation.getPreviewValue()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterBasicRepresentation) { + FilterBasicRepresentation basic = (FilterBasicRepresentation) representation; + if (basic.mMinimum == mMinimum + && basic.mMaximum == mMaximum + && basic.mValue == mValue + && basic.mDefaultValue == mDefaultValue + && basic.mPreviewValue == mPreviewValue) { + return true; + } + } + return false; + } + + @Override + public int getMinimum() { + return mMinimum; + } + + public void setMinimum(int minimum) { + mMinimum = minimum; + } + + @Override + public int getValue() { + return mValue; + } + + @Override + public void setValue(int value) { + mValue = value; + if (mValue < mMinimum) { + mValue = mMinimum; + } + if (mValue > mMaximum) { + mValue = mMaximum; + } + } + + @Override + public int getMaximum() { + return mMaximum; + } + + public void setMaximum(int maximum) { + mMaximum = maximum; + } + + public void setDefaultValue(int defaultValue) { + mDefaultValue = defaultValue; + } + + @Override + public int getDefaultValue() { + return mDefaultValue; + } + + public int getPreviewValue() { + return mPreviewValue; + } + + public void setPreviewValue(int previewValue) { + mPreviewValue = previewValue; + } + + @Override + public String getStateRepresentation() { + int val = getValue(); + return ((val > 0) ? "+" : "") + val; + } + + @Override + public String getParameterType(){ + return sParameterType; + } + + @Override + public void setController(Control control) { + } + + @Override + public String getValueString() { + return getStateRepresentation(); + } + + @Override + public String getParameterName() { + return getName(); + } + + @Override + public void setFilterView(FilterView editor) { + } + + @Override + public void copyFrom(Parameter src) { + useParametersFrom((FilterBasicRepresentation) src); + } + + @Override + public String[][] serializeRepresentation() { + String[][] ret = { + {SERIAL_NAME , getName() }, + {SERIAL_VALUE , Integer.toString(mValue)}}; + return ret; + } + + @Override + public void deSerializeRepresentation(String[][] rep) { + super.deSerializeRepresentation(rep); + for (int i = 0; i < rep.length; i++) { + if (SERIAL_VALUE.equals(rep[i][0])) { + mValue = Integer.parseInt(rep[i][1]); + break; + } + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterChanSatRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterChanSatRepresentation.java new file mode 100644 index 000000000..7ce67dd96 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterChanSatRepresentation.java @@ -0,0 +1,211 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.controller.BasicParameterInt; +import com.android.gallery3d.filtershow.controller.Parameter; +import com.android.gallery3d.filtershow.controller.ParameterSet; +import com.android.gallery3d.filtershow.editors.EditorChanSat; +import com.android.gallery3d.filtershow.imageshow.ControlPoint; +import com.android.gallery3d.filtershow.imageshow.Spline; + +import java.io.IOException; +import java.util.Vector; + +/** + * Representation for a filter that has per channel & Master saturation + */ +public class FilterChanSatRepresentation extends FilterRepresentation implements ParameterSet { + private static final String LOGTAG = "FilterChanSatRepresentation"; + private static final String ARGS = "ARGS"; + private static final String SERIALIZATION_NAME = "channelsaturation"; + + public static final int MODE_MASTER = 0; + public static final int MODE_RED = 1; + public static final int MODE_YELLOW = 2; + public static final int MODE_GREEN = 3; + public static final int MODE_CYAN = 4; + public static final int MODE_BLUE = 5; + public static final int MODE_MAGENTA = 6; + private int mParameterMode = MODE_MASTER; + + private static int MINSAT = -100; + private static int MAXSAT = 100; + private BasicParameterInt mParamMaster = new BasicParameterInt(MODE_MASTER, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamRed = new BasicParameterInt(MODE_RED, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamYellow = new BasicParameterInt(MODE_YELLOW, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamGreen = new BasicParameterInt(MODE_GREEN, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamCyan = new BasicParameterInt(MODE_CYAN, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamBlue = new BasicParameterInt(MODE_BLUE, 0, MINSAT, MAXSAT); + private BasicParameterInt mParamMagenta = new BasicParameterInt(MODE_MAGENTA, 0, MINSAT, MAXSAT); + + private BasicParameterInt[] mAllParam = { + mParamMaster, + mParamRed, + mParamYellow, + mParamGreen, + mParamCyan, + mParamBlue, + mParamMagenta}; + + public FilterChanSatRepresentation() { + super("ChannelSaturation"); + setTextId(R.string.saturation); + setFilterType(FilterRepresentation.TYPE_NORMAL); + setSerializationName(SERIALIZATION_NAME); + setFilterClass(ImageFilterChanSat.class); + setEditorId(EditorChanSat.ID); + } + + public String toString() { + return getName() + " : " + mParamRed + ", " + mParamCyan + ", " + mParamRed + + ", " + mParamGreen + ", " + mParamMaster + ", " + mParamYellow; + } + + @Override + public FilterRepresentation copy() { + FilterChanSatRepresentation representation = new FilterChanSatRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterChanSatRepresentation) { + FilterChanSatRepresentation representation = (FilterChanSatRepresentation) a; + + for (int i = 0; i < mAllParam.length; i++) { + mAllParam[i].copyFrom(representation.mAllParam[i]); + } + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterChanSatRepresentation) { + FilterChanSatRepresentation rep = (FilterChanSatRepresentation) representation; + for (int i = 0; i < mAllParam.length; i++) { + if (rep.getValue(i) != getValue(i)) + return false; + } + return true; + } + return false; + } + + public int getValue(int mode) { + return mAllParam[mode].getValue(); + } + + public void setValue(int mode, int value) { + mAllParam[mode].setValue(value); + } + + public int getMinimum() { + return mParamMaster.getMinimum(); + } + + public int getMaximum() { + return mParamMaster.getMaximum(); + } + + public int getParameterMode() { + return mParameterMode; + } + + public void setParameterMode(int parameterMode) { + mParameterMode = parameterMode; + } + + public int getCurrentParameter() { + return getValue(mParameterMode); + } + + public void setCurrentParameter(int value) { + setValue(mParameterMode, value); + } + + @Override + public int getNumberOfParameters() { + return 6; + } + + @Override + public Parameter getFilterParameter(int index) { + return mAllParam[index]; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + + writer.name(ARGS); + writer.beginArray(); + writer.value(getValue(MODE_MASTER)); + writer.value(getValue(MODE_RED)); + writer.value(getValue(MODE_YELLOW)); + writer.value(getValue(MODE_GREEN)); + writer.value(getValue(MODE_CYAN)); + writer.value(getValue(MODE_BLUE)); + writer.value(getValue(MODE_MAGENTA)); + writer.endArray(); + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader sreader) throws IOException { + sreader.beginObject(); + + while (sreader.hasNext()) { + String name = sreader.nextName(); + if (name.startsWith(ARGS)) { + sreader.beginArray(); + sreader.hasNext(); + setValue(MODE_MASTER, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_RED, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_YELLOW, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_GREEN, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_CYAN, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_BLUE, sreader.nextInt()); + sreader.hasNext(); + setValue(MODE_MAGENTA, sreader.nextInt()); + sreader.hasNext(); + sreader.endArray(); + } else { + sreader.skipValue(); + } + } + sreader.endObject(); + } +}
\ No newline at end of file diff --git a/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java new file mode 100644 index 000000000..94eb20631 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterColorBorderRepresentation.java @@ -0,0 +1,113 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; + +public class FilterColorBorderRepresentation extends FilterRepresentation { + private int mColor; + private int mBorderSize; + private int mBorderRadius; + + public FilterColorBorderRepresentation(int color, int size, int radius) { + super("ColorBorder"); + mColor = color; + mBorderSize = size; + mBorderRadius = radius; + setFilterType(FilterRepresentation.TYPE_BORDER); + setTextId(R.string.borders); + setEditorId(ImageOnlyEditor.ID); + setShowParameterValue(false); + } + + public String toString() { + return "FilterBorder: " + getName(); + } + + @Override + public FilterRepresentation copy() { + FilterColorBorderRepresentation representation = new FilterColorBorderRepresentation(0,0,0); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterColorBorderRepresentation) { + FilterColorBorderRepresentation representation = (FilterColorBorderRepresentation) a; + setName(representation.getName()); + setColor(representation.getColor()); + setBorderSize(representation.getBorderSize()); + setBorderRadius(representation.getBorderRadius()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterColorBorderRepresentation) { + FilterColorBorderRepresentation border = (FilterColorBorderRepresentation) representation; + if (border.mColor == mColor + && border.mBorderSize == mBorderSize + && border.mBorderRadius == mBorderRadius) { + return true; + } + } + return false; + } + + public boolean allowsSingleInstanceOnly() { + return true; + } + + @Override + public int getTextId() { + return R.string.borders; + } + + public int getColor() { + return mColor; + } + + public void setColor(int color) { + mColor = color; + } + + public int getBorderSize() { + return mBorderSize; + } + + public void setBorderSize(int borderSize) { + mBorderSize = borderSize; + } + + public int getBorderRadius() { + return mBorderRadius; + } + + public void setBorderRadius(int borderRadius) { + mBorderRadius = borderRadius; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java new file mode 100644 index 000000000..c1bd7b3bb --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterCropRepresentation.java @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.RectF; +import android.util.JsonReader; +import android.util.JsonWriter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorCrop; + +import java.io.IOException; + +public class FilterCropRepresentation extends FilterRepresentation { + public static final String SERIALIZATION_NAME = "CROP"; + public static final String[] BOUNDS = { + "C0", "C1", "C2", "C3" + }; + private static final String TAG = FilterCropRepresentation.class.getSimpleName(); + + RectF mCrop = getNil(); + + public FilterCropRepresentation(RectF crop) { + super(FilterCropRepresentation.class.getSimpleName()); + setSerializationName(SERIALIZATION_NAME); + setShowParameterValue(true); + setFilterClass(FilterCropRepresentation.class); + setFilterType(FilterRepresentation.TYPE_GEOMETRY); + setTextId(R.string.crop); + setEditorId(EditorCrop.ID); + setCrop(crop); + } + + public FilterCropRepresentation(FilterCropRepresentation m) { + this(m.mCrop); + } + + public FilterCropRepresentation() { + this(sNilRect); + } + + public void set(FilterCropRepresentation r) { + mCrop.set(r.mCrop); + } + + @Override + public boolean equals(FilterRepresentation rep) { + if (!(rep instanceof FilterCropRepresentation)) { + return false; + } + FilterCropRepresentation crop = (FilterCropRepresentation) rep; + if (mCrop.bottom != crop.mCrop.bottom + || mCrop.left != crop.mCrop.left + || mCrop.right != crop.mCrop.right + || mCrop.top != crop.mCrop.top) { + return false; + } + return true; + } + + public RectF getCrop() { + return new RectF(mCrop); + } + + public void getCrop(RectF r) { + r.set(mCrop); + } + + public void setCrop(RectF crop) { + if (crop == null) { + throw new IllegalArgumentException("Argument to setCrop is null"); + } + mCrop.set(crop); + } + + /** + * Takes a crop rect contained by [0, 0, 1, 1] and scales it by the height + * and width of the image rect. + */ + public static void findScaledCrop(RectF crop, int bitmapWidth, int bitmapHeight) { + crop.left *= bitmapWidth; + crop.top *= bitmapHeight; + crop.right *= bitmapWidth; + crop.bottom *= bitmapHeight; + } + + /** + * Takes crop rect and normalizes it by scaling down by the height and width + * of the image rect. + */ + public static void findNormalizedCrop(RectF crop, int bitmapWidth, int bitmapHeight) { + crop.left /= bitmapWidth; + crop.top /= bitmapHeight; + crop.right /= bitmapWidth; + crop.bottom /= bitmapHeight; + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } + + @Override + public FilterRepresentation copy() { + return new FilterCropRepresentation(this); + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + if (!(representation instanceof FilterCropRepresentation)) { + throw new IllegalArgumentException("calling copyAllParameters with incompatible types!"); + } + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (!(a instanceof FilterCropRepresentation)) { + throw new IllegalArgumentException("calling useParametersFrom with incompatible types!"); + } + setCrop(((FilterCropRepresentation) a).mCrop); + } + + private static final RectF sNilRect = new RectF(0, 0, 1, 1); + + @Override + public boolean isNil() { + return mCrop.equals(sNilRect); + } + + public static RectF getNil() { + return new RectF(sNilRect); + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + writer.name(BOUNDS[0]).value(mCrop.left); + writer.name(BOUNDS[1]).value(mCrop.top); + writer.name(BOUNDS[2]).value(mCrop.right); + writer.name(BOUNDS[3]).value(mCrop.bottom); + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader reader) throws IOException { + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + if (BOUNDS[0].equals(name)) { + mCrop.left = (float) reader.nextDouble(); + } else if (BOUNDS[1].equals(name)) { + mCrop.top = (float) reader.nextDouble(); + } else if (BOUNDS[2].equals(name)) { + mCrop.right = (float) reader.nextDouble(); + } else if (BOUNDS[3].equals(name)) { + mCrop.bottom = (float) reader.nextDouble(); + } else { + reader.skipValue(); + } + } + reader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java new file mode 100644 index 000000000..edab2a08d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java @@ -0,0 +1,170 @@ +package com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.imageshow.ControlPoint; +import com.android.gallery3d.filtershow.imageshow.Spline; + +import java.io.IOException; + +/** + * TODO: Insert description here. (generated by hoford) + */ +public class FilterCurvesRepresentation extends FilterRepresentation { + private static final String LOGTAG = "FilterCurvesRepresentation"; + public static final String SERIALIZATION_NAME = "Curve"; + private static final int MAX_SPLINE_NUMBER = 4; + + private Spline[] mSplines = new Spline[MAX_SPLINE_NUMBER]; + + public FilterCurvesRepresentation() { + super("Curves"); + setSerializationName("CURVES"); + setFilterClass(ImageFilterCurves.class); + setTextId(R.string.curvesRGB); + setOverlayId(R.drawable.filtershow_button_colors_curve); + setEditorId(R.id.imageCurves); + setShowParameterValue(false); + setSupportsPartialRendering(true); + reset(); + } + + @Override + public FilterRepresentation copy() { + FilterCurvesRepresentation representation = new FilterCurvesRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (!(a instanceof FilterCurvesRepresentation)) { + Log.v(LOGTAG, "cannot use parameters from " + a); + return; + } + FilterCurvesRepresentation representation = (FilterCurvesRepresentation) a; + Spline[] spline = new Spline[MAX_SPLINE_NUMBER]; + for (int i = 0; i < spline.length; i++) { + Spline sp = representation.mSplines[i]; + if (sp != null) { + spline[i] = new Spline(sp); + } else { + spline[i] = new Spline(); + } + } + mSplines = spline; + } + + @Override + public boolean isNil() { + for (int i = 0; i < MAX_SPLINE_NUMBER; i++) { + if (getSpline(i) != null && !getSpline(i).isOriginal()) { + return false; + } + } + return true; + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + + if (!(representation instanceof FilterCurvesRepresentation)) { + return false; + } else { + FilterCurvesRepresentation curve = + (FilterCurvesRepresentation) representation; + for (int i = 0; i < MAX_SPLINE_NUMBER; i++) { + if (!getSpline(i).sameValues(curve.getSpline(i))) { + return false; + } + } + } + // Every spline matches, therefore they are the same. + return true; + } + + public void reset() { + Spline spline = new Spline(); + + spline.addPoint(0.0f, 1.0f); + spline.addPoint(1.0f, 0.0f); + + for (int i = 0; i < MAX_SPLINE_NUMBER; i++) { + mSplines[i] = new Spline(spline); + } + } + + public void setSpline(int splineIndex, Spline s) { + mSplines[splineIndex] = s; + } + + public Spline getSpline(int splineIndex) { + return mSplines[splineIndex]; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + { + writer.name(NAME_TAG); + writer.value(getName()); + for (int i = 0; i < mSplines.length; i++) { + writer.name(SERIALIZATION_NAME + i); + writer.beginArray(); + int nop = mSplines[i].getNbPoints(); + for (int j = 0; j < nop; j++) { + ControlPoint p = mSplines[i].getPoint(j); + writer.beginArray(); + writer.value(p.x); + writer.value(p.y); + writer.endArray(); + } + writer.endArray(); + } + + } + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader sreader) throws IOException { + sreader.beginObject(); + Spline[] spline = new Spline[MAX_SPLINE_NUMBER]; + while (sreader.hasNext()) { + String name = sreader.nextName(); + if (NAME_TAG.equals(name)) { + setName(sreader.nextString()); + } else if (name.startsWith(SERIALIZATION_NAME)) { + int curveNo = Integer.parseInt(name.substring(SERIALIZATION_NAME.length())); + spline[curveNo] = new Spline(); + sreader.beginArray(); + while (sreader.hasNext()) { + sreader.beginArray(); + sreader.hasNext(); + float x = (float) sreader.nextDouble(); + sreader.hasNext(); + float y = (float) sreader.nextDouble(); + sreader.endArray(); + spline[curveNo].addPoint(x, y); + } + sreader.endArray(); + + } + } + mSplines = spline; + sreader.endObject(); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java new file mode 100644 index 000000000..ac0cb7492 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterDirectRepresentation.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +public class FilterDirectRepresentation extends FilterRepresentation { + + @Override + public FilterRepresentation copy() { + FilterDirectRepresentation representation = new FilterDirectRepresentation(getName()); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public FilterDirectRepresentation(String name) { + super(name); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java new file mode 100644 index 000000000..977dbeac5 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterDrawRepresentation.java @@ -0,0 +1,171 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Path; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorDraw; + +import java.util.Vector; + +public class FilterDrawRepresentation extends FilterRepresentation { + private static final String LOGTAG = "FilterDrawRepresentation"; + + public static class StrokeData implements Cloneable { + public byte mType; + public Path mPath; + public float mRadius; + public int mColor; + public int noPoints = 0; + @Override + public String toString() { + return "stroke(" + mType + ", path(" + (mPath) + "), " + mRadius + " , " + + Integer.toHexString(mColor) + ")"; + } + @Override + public StrokeData clone() throws CloneNotSupportedException { + return (StrokeData) super.clone(); + } + } + + private Vector<StrokeData> mDrawing = new Vector<StrokeData>(); + private StrokeData mCurrent; // used in the currently drawing style + + public FilterDrawRepresentation() { + super("Draw"); + setFilterClass(ImageFilterDraw.class); + setSerializationName("DRAW"); + setFilterType(FilterRepresentation.TYPE_VIGNETTE); + setTextId(R.string.imageDraw); + setEditorId(EditorDraw.ID); + setOverlayId(R.drawable.filtershow_drawing); + setOverlayOnly(true); + } + + @Override + public String toString() { + return getName() + " : strokes=" + mDrawing.size() + + ((mCurrent == null) ? " no current " + : ("draw=" + mCurrent.mType + " " + mCurrent.noPoints)); + } + + public Vector<StrokeData> getDrawing() { + return mDrawing; + } + + public StrokeData getCurrentDrawing() { + return mCurrent; + } + + @Override + public FilterRepresentation copy() { + FilterDrawRepresentation representation = new FilterDrawRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public boolean isNil() { + return getDrawing().isEmpty(); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterDrawRepresentation) { + FilterDrawRepresentation representation = (FilterDrawRepresentation) a; + try { + if (representation.mCurrent != null) { + mCurrent = (StrokeData) representation.mCurrent.clone(); + } else { + mCurrent = null; + } + if (representation.mDrawing != null) { + mDrawing = (Vector<StrokeData>) representation.mDrawing.clone(); + } else { + mDrawing = null; + } + + } catch (CloneNotSupportedException e) { + e.printStackTrace(); + } + } else { + Log.v(LOGTAG, "cannot use parameters from " + a); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterDrawRepresentation) { + FilterDrawRepresentation fdRep = (FilterDrawRepresentation) representation; + if (fdRep.mDrawing.size() != mDrawing.size()) + return false; + if (fdRep.mCurrent == null && mCurrent.mPath == null) { + return true; + } + if (fdRep.mCurrent != null && mCurrent.mPath != null) { + if (fdRep.mCurrent.noPoints == mCurrent.noPoints) { + return true; + } + return false; + } + } + return false; + } + + public void startNewSection(byte type, int color, float size, float x, float y) { + mCurrent = new StrokeData(); + mCurrent.mColor = color; + mCurrent.mRadius = size; + mCurrent.mType = type; + mCurrent.mPath = new Path(); + mCurrent.mPath.moveTo(x, y); + mCurrent.noPoints = 0; + } + + public void addPoint(float x, float y) { + mCurrent.noPoints++; + mCurrent.mPath.lineTo(x, y); + } + + public void endSection(float x, float y) { + mCurrent.mPath.lineTo(x, y); + mCurrent.noPoints++; + mDrawing.add(mCurrent); + mCurrent = null; + } + + public void clearCurrentSection() { + mCurrent = null; + } + + public void clear() { + mCurrent = null; + mDrawing.clear(); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java new file mode 100644 index 000000000..e5a6fdd23 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; + +public class FilterFxRepresentation extends FilterRepresentation { + private static final String LOGTAG = "FilterFxRepresentation"; + // TODO: When implementing serialization, we should find a unique way of + // specifying bitmaps / names (the resource IDs being random) + private int mBitmapResource = 0; + private int mNameResource = 0; + + public FilterFxRepresentation(String name, int bitmapResource, int nameResource) { + super(name); + setFilterClass(ImageFilterFx.class); + mBitmapResource = bitmapResource; + mNameResource = nameResource; + setFilterType(FilterRepresentation.TYPE_FX); + setTextId(nameResource); + setEditorId(ImageOnlyEditor.ID); + setShowParameterValue(false); + setSupportsPartialRendering(true); + } + + @Override + public String toString() { + return "FilterFx: " + hashCode() + " : " + getName() + " bitmap rsc: " + mBitmapResource; + } + + @Override + public FilterRepresentation copy() { + FilterFxRepresentation representation = new FilterFxRepresentation(getName(),0,0); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public synchronized void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterFxRepresentation) { + FilterFxRepresentation representation = (FilterFxRepresentation) a; + setName(representation.getName()); + setSerializationName(representation.getSerializationName()); + setBitmapResource(representation.getBitmapResource()); + setNameResource(representation.getNameResource()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterFxRepresentation) { + FilterFxRepresentation fx = (FilterFxRepresentation) representation; + if (fx.mNameResource == mNameResource + && fx.mBitmapResource == mBitmapResource) { + return true; + } + } + return false; + } + + @Override + public boolean same(FilterRepresentation representation) { + if (!super.same(representation)) { + return false; + } + return equals(representation); + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } + + public int getNameResource() { + return mNameResource; + } + + public void setNameResource(int nameResource) { + mNameResource = nameResource; + } + + public int getBitmapResource() { + return mBitmapResource; + } + + public void setBitmapResource(int bitmapResource) { + mBitmapResource = bitmapResource; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java new file mode 100644 index 000000000..0c272d48a --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java @@ -0,0 +1,497 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Rect; +import android.util.JsonReader; +import android.util.JsonWriter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorGrad; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.imageshow.Line; + +import java.io.IOException; +import java.util.Vector; + +public class FilterGradRepresentation extends FilterRepresentation + implements Line { + private static final String LOGTAG = "FilterGradRepresentation"; + public static final int MAX_POINTS = 16; + public static final int PARAM_BRIGHTNESS = 0; + public static final int PARAM_SATURATION = 1; + public static final int PARAM_CONTRAST = 2; + private static final double ADD_MIN_DIST = .05; + private static String LINE_NAME = "Point"; + private static final String SERIALIZATION_NAME = "grad"; + + public FilterGradRepresentation() { + super("Grad"); + setSerializationName(SERIALIZATION_NAME); + creatExample(); + setOverlayId(R.drawable.filtershow_button_grad); + setFilterClass(ImageFilterGrad.class); + setTextId(R.string.grad); + setEditorId(EditorGrad.ID); + } + + public void trimVector(){ + int n = mBands.size(); + for (int i = n; i < MAX_POINTS; i++) { + mBands.add(new Band()); + } + for (int i = MAX_POINTS; i < n; i++) { + mBands.remove(i); + } + } + + Vector<Band> mBands = new Vector<Band>(); + Band mCurrentBand; + + static class Band { + private boolean mask = true; + + private int xPos1 = -1; + private int yPos1 = 100; + private int xPos2 = -1; + private int yPos2 = 100; + private int brightness = 40; + private int contrast = 0; + private int saturation = 0; + + + public Band() { + } + + public Band(int x, int y) { + xPos1 = x; + yPos1 = y+30; + xPos2 = x; + yPos2 = y-30; + } + + public Band(Band copy) { + mask = copy.mask; + xPos1 = copy.xPos1; + yPos1 = copy.yPos1; + xPos2 = copy.xPos2; + yPos2 = copy.yPos2; + brightness = copy.brightness; + contrast = copy.contrast; + saturation = copy.saturation; + } + + } + + @Override + public String toString() { + int count = 0; + for (Band point : mBands) { + if (!point.mask) { + count++; + } + } + return "c=" + mBands.indexOf(mBands) + "[" + mBands.size() + "]" + count; + } + + private void creatExample() { + Band p = new Band(); + p.mask = false; + p.xPos1 = -1; + p.yPos1 = 100; + p.xPos2 = -1; + p.yPos2 = 100; + p.brightness = 40; + p.contrast = 0; + p.saturation = 0; + mBands.add(0, p); + mCurrentBand = p; + trimVector(); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + FilterGradRepresentation rep = (FilterGradRepresentation) a; + Vector<Band> tmpBands = new Vector<Band>(); + int n = (rep.mCurrentBand == null) ? 0 : rep.mBands.indexOf(rep.mCurrentBand); + for (Band band : rep.mBands) { + tmpBands.add(new Band(band)); + } + mCurrentBand = null; + mBands = tmpBands; + mCurrentBand = mBands.elementAt(n); + } + + @Override + public FilterRepresentation copy() { + FilterGradRepresentation representation = new FilterGradRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (representation instanceof FilterGradRepresentation) { + FilterGradRepresentation rep = (FilterGradRepresentation) representation; + int n = getNumberOfBands(); + if (rep.getNumberOfBands() != n) { + return false; + } + for (int i = 0; i < mBands.size(); i++) { + Band b1 = mBands.get(i); + Band b2 = rep.mBands.get(i); + if (b1.mask != b2.mask + || b1.brightness != b2.brightness + || b1.contrast != b2.contrast + || b1.saturation != b2.saturation + || b1.xPos1 != b2.xPos1 + || b1.xPos2 != b2.xPos2 + || b1.yPos1 != b2.yPos1 + || b1.yPos2 != b2.yPos2) { + return false; + } + } + return true; + } + return false; + } + + public int getNumberOfBands() { + int count = 0; + for (Band point : mBands) { + if (!point.mask) { + count++; + } + } + return count; + } + + public int addBand(Rect rect) { + mBands.add(0, mCurrentBand = new Band(rect.centerX(), rect.centerY())); + mCurrentBand.mask = false; + int x = (mCurrentBand.xPos1 + mCurrentBand.xPos2)/2; + int y = (mCurrentBand.yPos1 + mCurrentBand.yPos2)/2; + double addDelta = ADD_MIN_DIST * Math.max(rect.width(), rect.height()); + boolean moved = true; + int count = 0; + int toMove = mBands.indexOf(mCurrentBand); + + while (moved) { + moved = false; + count++; + if (count > 14) { + break; + } + + for (Band point : mBands) { + if (point.mask) { + break; + } + } + + for (Band point : mBands) { + if (point.mask) { + break; + } + int index = mBands.indexOf(point); + + if (toMove != index) { + double dist = Math.hypot(point.xPos1 - x, point.yPos1 - y); + if (dist < addDelta) { + moved = true; + mCurrentBand.xPos1 += addDelta; + mCurrentBand.yPos1 += addDelta; + mCurrentBand.xPos2 += addDelta; + mCurrentBand.yPos2 += addDelta; + x = (mCurrentBand.xPos1 + mCurrentBand.xPos2)/2; + y = (mCurrentBand.yPos1 + mCurrentBand.yPos2)/2; + + if (mCurrentBand.yPos1 > rect.bottom) { + mCurrentBand.yPos1 = (int) (rect.top + addDelta); + } + if (mCurrentBand.xPos1 > rect.right) { + mCurrentBand.xPos1 = (int) (rect.left + addDelta); + } + } + } + } + } + trimVector(); + return 0; + } + + public void deleteCurrentBand() { + int index = mBands.indexOf(mCurrentBand); + mBands.remove(mCurrentBand); + trimVector(); + if (getNumberOfBands() == 0) { + addBand(MasterImage.getImage().getOriginalBounds()); + } + mCurrentBand = mBands.get(0); + } + + public void nextPoint(){ + int index = mBands.indexOf(mCurrentBand); + int tmp = index; + Band point; + int k = 0; + do { + index = (index+1)% mBands.size(); + point = mBands.get(index); + if (k++ >= mBands.size()) { + break; + } + } + while (point.mask == true); + mCurrentBand = mBands.get(index); + } + + public void setSelectedPoint(int pos) { + mCurrentBand = mBands.get(pos); + } + + public int getSelectedPoint() { + return mBands.indexOf(mCurrentBand); + } + + public boolean[] getMask() { + boolean[] ret = new boolean[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = !point.mask; + } + return ret; + } + + public int[] getXPos1() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.xPos1; + } + return ret; + } + + public int[] getYPos1() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.yPos1; + } + return ret; + } + + public int[] getXPos2() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.xPos2; + } + return ret; + } + + public int[] getYPos2() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.yPos2; + } + return ret; + } + + public int[] getBrightness() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.brightness; + } + return ret; + } + + public int[] getContrast() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.contrast; + } + return ret; + } + + public int[] getSaturation() { + int[] ret = new int[mBands.size()]; + int i = 0; + for (Band point : mBands) { + ret[i++] = point.saturation; + } + return ret; + } + + public int getParameter(int type) { + switch (type){ + case PARAM_BRIGHTNESS: + return mCurrentBand.brightness; + case PARAM_SATURATION: + return mCurrentBand.saturation; + case PARAM_CONTRAST: + return mCurrentBand.contrast; + } + throw new IllegalArgumentException("no such type " + type); + } + + public int getParameterMax(int type) { + switch (type) { + case PARAM_BRIGHTNESS: + return 100; + case PARAM_SATURATION: + return 100; + case PARAM_CONTRAST: + return 100; + } + throw new IllegalArgumentException("no such type " + type); + } + + public int getParameterMin(int type) { + switch (type) { + case PARAM_BRIGHTNESS: + return -100; + case PARAM_SATURATION: + return -100; + case PARAM_CONTRAST: + return -100; + } + throw new IllegalArgumentException("no such type " + type); + } + + public void setParameter(int type, int value) { + mCurrentBand.mask = false; + switch (type) { + case PARAM_BRIGHTNESS: + mCurrentBand.brightness = value; + break; + case PARAM_SATURATION: + mCurrentBand.saturation = value; + break; + case PARAM_CONTRAST: + mCurrentBand.contrast = value; + break; + default: + throw new IllegalArgumentException("no such type " + type); + } + } + + @Override + public void setPoint1(float x, float y) { + mCurrentBand.xPos1 = (int)x; + mCurrentBand.yPos1 = (int)y; + } + + @Override + public void setPoint2(float x, float y) { + mCurrentBand.xPos2 = (int)x; + mCurrentBand.yPos2 = (int)y; + } + + @Override + public float getPoint1X() { + return mCurrentBand.xPos1; + } + + @Override + public float getPoint1Y() { + return mCurrentBand.yPos1; + } + @Override + public float getPoint2X() { + return mCurrentBand.xPos2; + } + + @Override + public float getPoint2Y() { + return mCurrentBand.yPos2; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + int len = mBands.size(); + int count = 0; + + for (int i = 0; i < len; i++) { + Band point = mBands.get(i); + if (point.mask) { + continue; + } + writer.name(LINE_NAME + count); + count++; + writer.beginArray(); + writer.value(point.xPos1); + writer.value(point.yPos1); + writer.value(point.xPos2); + writer.value(point.yPos2); + writer.value(point.brightness); + writer.value(point.contrast); + writer.value(point.saturation); + writer.endArray(); + } + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader sreader) throws IOException { + sreader.beginObject(); + Vector<Band> points = new Vector<Band>(); + + while (sreader.hasNext()) { + String name = sreader.nextName(); + if (name.startsWith(LINE_NAME)) { + int pointNo = Integer.parseInt(name.substring(LINE_NAME.length())); + sreader.beginArray(); + Band p = new Band(); + p.mask = false; + sreader.hasNext(); + p.xPos1 = sreader.nextInt(); + sreader.hasNext(); + p.yPos1 = sreader.nextInt(); + sreader.hasNext(); + p.xPos2 = sreader.nextInt(); + sreader.hasNext(); + p.yPos2 = sreader.nextInt(); + sreader.hasNext(); + p.brightness = sreader.nextInt(); + sreader.hasNext(); + p.contrast = sreader.nextInt(); + sreader.hasNext(); + p.saturation = sreader.nextInt(); + sreader.hasNext(); + sreader.endArray(); + points.add(p); + + } else { + sreader.skipValue(); + } + } + mBands = points; + trimVector(); + mCurrentBand = mBands.get(0); + sreader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java new file mode 100644 index 000000000..f310a2be1 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterImageBorderRepresentation.java @@ -0,0 +1,91 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; + +public class FilterImageBorderRepresentation extends FilterRepresentation { + private int mDrawableResource = 0; + + public FilterImageBorderRepresentation(int drawableResource) { + super("ImageBorder"); + setFilterClass(ImageFilterBorder.class); + mDrawableResource = drawableResource; + setFilterType(FilterRepresentation.TYPE_BORDER); + setTextId(R.string.borders); + setEditorId(ImageOnlyEditor.ID); + setShowParameterValue(false); + } + + public String toString() { + return "FilterBorder: " + getName(); + } + + @Override + public FilterRepresentation copy() { + FilterImageBorderRepresentation representation = + new FilterImageBorderRepresentation(mDrawableResource); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterImageBorderRepresentation) { + FilterImageBorderRepresentation representation = (FilterImageBorderRepresentation) a; + setName(representation.getName()); + setDrawableResource(representation.getDrawableResource()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterImageBorderRepresentation) { + FilterImageBorderRepresentation border = (FilterImageBorderRepresentation) representation; + if (border.mDrawableResource == mDrawableResource) { + return true; + } + } + return false; + } + + @Override + public int getTextId() { + return R.string.none; + } + + public boolean allowsSingleInstanceOnly() { + return true; + } + + public int getDrawableResource() { + return mDrawableResource; + } + + public void setDrawableResource(int drawableResource) { + mDrawableResource = drawableResource; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java new file mode 100644 index 000000000..8dcff0d16 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterMirrorRepresentation.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorMirror; + +import java.io.IOException; + +public class FilterMirrorRepresentation extends FilterRepresentation { + public static final String SERIALIZATION_NAME = "MIRROR"; + private static final String SERIALIZATION_MIRROR_VALUE = "value"; + private static final String TAG = FilterMirrorRepresentation.class.getSimpleName(); + + Mirror mMirror; + + public enum Mirror { + NONE('N'), VERTICAL('V'), HORIZONTAL('H'), BOTH('B'); + char mValue; + + private Mirror(char value) { + mValue = value; + } + + public char value() { + return mValue; + } + + public static Mirror fromValue(char value) { + switch (value) { + case 'N': + return NONE; + case 'V': + return VERTICAL; + case 'H': + return HORIZONTAL; + case 'B': + return BOTH; + default: + return null; + } + } + } + + public FilterMirrorRepresentation(Mirror mirror) { + super(FilterMirrorRepresentation.class.getSimpleName()); + setSerializationName(SERIALIZATION_NAME); + setShowParameterValue(true); + setFilterClass(FilterMirrorRepresentation.class); + setFilterType(FilterRepresentation.TYPE_GEOMETRY); + setTextId(R.string.mirror); + setEditorId(EditorMirror.ID); + setMirror(mirror); + } + + public FilterMirrorRepresentation(FilterMirrorRepresentation m) { + this(m.getMirror()); + } + + public FilterMirrorRepresentation() { + this(getNil()); + } + + @Override + public boolean equals(FilterRepresentation rep) { + if (!(rep instanceof FilterMirrorRepresentation)) { + return false; + } + FilterMirrorRepresentation mirror = (FilterMirrorRepresentation) rep; + if (mMirror != mirror.mMirror) { + return false; + } + return true; + } + + public Mirror getMirror() { + return mMirror; + } + + public void set(FilterMirrorRepresentation r) { + mMirror = r.mMirror; + } + + public void setMirror(Mirror mirror) { + if (mirror == null) { + throw new IllegalArgumentException("Argument to setMirror is null"); + } + mMirror = mirror; + } + + public void cycle() { + switch (mMirror) { + case NONE: + mMirror = Mirror.HORIZONTAL; + break; + case HORIZONTAL: + mMirror = Mirror.VERTICAL; + break; + case VERTICAL: + mMirror = Mirror.BOTH; + break; + case BOTH: + mMirror = Mirror.NONE; + break; + } + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } + + @Override + public FilterRepresentation copy() { + return new FilterMirrorRepresentation(this); + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + if (!(representation instanceof FilterMirrorRepresentation)) { + throw new IllegalArgumentException("calling copyAllParameters with incompatible types!"); + } + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (!(a instanceof FilterMirrorRepresentation)) { + throw new IllegalArgumentException("calling useParametersFrom with incompatible types!"); + } + setMirror(((FilterMirrorRepresentation) a).getMirror()); + } + + @Override + public boolean isNil() { + return mMirror == getNil(); + } + + public static Mirror getNil() { + return Mirror.NONE; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + writer.name(SERIALIZATION_MIRROR_VALUE).value(mMirror.value()); + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader reader) throws IOException { + boolean unset = true; + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + if (SERIALIZATION_MIRROR_VALUE.equals(name)) { + Mirror r = Mirror.fromValue((char) reader.nextInt()); + if (r != null) { + setMirror(r); + unset = false; + } + } else { + reader.skipValue(); + } + } + if (unset) { + Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME); + } + reader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterPoint.java b/src/com/android/gallery3d/filtershow/filters/FilterPoint.java new file mode 100644 index 000000000..4520717a1 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterPoint.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +public interface FilterPoint { + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java new file mode 100644 index 000000000..9bd1699d9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterPointRepresentation.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import java.util.Vector; + +public abstract class FilterPointRepresentation extends FilterRepresentation { + private static final String LOGTAG = "FilterPointRepresentation"; + private Vector<FilterPoint> mCandidates = new Vector<FilterPoint>(); + + public FilterPointRepresentation(String type, int textid, int editorID) { + super(type); + setFilterClass(ImageFilterRedEye.class); + setFilterType(FilterRepresentation.TYPE_NORMAL); + setTextId(textid); + setEditorId(editorID); + } + + @Override + public abstract FilterRepresentation copy(); + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public boolean hasCandidates() { + return mCandidates != null; + } + + public Vector<FilterPoint> getCandidates() { + return mCandidates; + } + + @Override + public boolean isNil() { + if (getCandidates() != null && getCandidates().size() > 0) { + return false; + } + return true; + } + + public Object getCandidate(int index) { + return this.mCandidates.get(index); + } + + public void addCandidate(FilterPoint c) { + this.mCandidates.add(c); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (a instanceof FilterPointRepresentation) { + FilterPointRepresentation representation = (FilterPointRepresentation) a; + mCandidates.clear(); + for (FilterPoint redEyeCandidate : representation.mCandidates) { + mCandidates.add(redEyeCandidate); + } + } + } + + public void removeCandidate(RedEyeCandidate c) { + this.mCandidates.remove(c); + } + + public void clearCandidates() { + this.mCandidates.clear(); + } + + public int getNumberOfCandidates() { + return mCandidates.size(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java new file mode 100644 index 000000000..dd06a9760 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterRedEyeRepresentation.java @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.RectF; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorRedEye; + +import java.util.Vector; + +public class FilterRedEyeRepresentation extends FilterPointRepresentation { + private static final String LOGTAG = "FilterRedEyeRepresentation"; + + public FilterRedEyeRepresentation() { + super("RedEye",R.string.redeye,EditorRedEye.ID); + setSerializationName("REDEYE"); + setFilterClass(ImageFilterRedEye.class); + setOverlayId(R.drawable.photoeditor_effect_redeye); + setOverlayOnly(true); + } + + @Override + public FilterRepresentation copy() { + FilterRedEyeRepresentation representation = new FilterRedEyeRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + public void addRect(RectF rect, RectF bounds) { + Vector<RedEyeCandidate> intersects = new Vector<RedEyeCandidate>(); + for (int i = 0; i < getCandidates().size(); i++) { + RedEyeCandidate r = (RedEyeCandidate) getCandidate(i); + if (r.intersect(rect)) { + intersects.add(r); + } + } + for (int i = 0; i < intersects.size(); i++) { + RedEyeCandidate r = intersects.elementAt(i); + rect.union(r.mRect); + bounds.union(r.mBounds); + removeCandidate(r); + } + addCandidate(new RedEyeCandidate(rect, bounds)); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java new file mode 100644 index 000000000..5b33ffba5 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java @@ -0,0 +1,262 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.filtershow.editors.BasicEditor; + +import java.io.IOException; +import java.util.ArrayList; + +public class FilterRepresentation { + private static final String LOGTAG = "FilterRepresentation"; + private static final boolean DEBUG = false; + private String mName; + private int mPriority = TYPE_NORMAL; + private Class<?> mFilterClass; + private boolean mSupportsPartialRendering = false; + private int mTextId = 0; + private int mEditorId = BasicEditor.ID; + private int mButtonId = 0; + private int mOverlayId = 0; + private boolean mOverlayOnly = false; + private boolean mShowParameterValue = true; + private String mSerializationName; + public static final byte TYPE_BORDER = 1; + public static final byte TYPE_FX = 2; + public static final byte TYPE_WBALANCE = 3; + public static final byte TYPE_VIGNETTE = 4; + public static final byte TYPE_NORMAL = 5; + public static final byte TYPE_TINYPLANET = 6; + public static final byte TYPE_GEOMETRY = 7; + protected static final String NAME_TAG = "Name"; + + public FilterRepresentation(String name) { + mName = name; + } + + public FilterRepresentation copy(){ + FilterRepresentation representation = new FilterRepresentation(mName); + representation.useParametersFrom(this); + return representation; + } + + protected void copyAllParameters(FilterRepresentation representation) { + representation.setName(getName()); + representation.setFilterClass(getFilterClass()); + representation.setFilterType(getFilterType()); + representation.setSupportsPartialRendering(supportsPartialRendering()); + representation.setTextId(getTextId()); + representation.setEditorId(getEditorId()); + representation.setOverlayId(getOverlayId()); + representation.setOverlayOnly(getOverlayOnly()); + representation.setShowParameterValue(showParameterValue()); + representation.mSerializationName = mSerializationName; + + } + + public boolean equals(FilterRepresentation representation) { + if (representation == null) { + return false; + } + if (representation.mFilterClass == mFilterClass + && representation.mName.equalsIgnoreCase(mName) + && representation.mPriority == mPriority + // TODO: After we enable partial rendering, we can switch back + // to use member variable here. + && representation.supportsPartialRendering() == supportsPartialRendering() + && representation.mTextId == mTextId + && representation.mEditorId == mEditorId + && representation.mButtonId == mButtonId + && representation.mOverlayId == mOverlayId + && representation.mOverlayOnly == mOverlayOnly + && representation.mShowParameterValue == mShowParameterValue) { + return true; + } + return false; + } + + @Override + public String toString() { + return mName; + } + + public void setName(String name) { + mName = name; + } + + public String getName() { + return mName; + } + + public void setSerializationName(String sname) { + mSerializationName = sname; + } + + public String getSerializationName() { + return mSerializationName; + } + + public void setFilterType(int priority) { + mPriority = priority; + } + + public int getFilterType() { + return mPriority; + } + + public boolean isNil() { + return false; + } + + public boolean supportsPartialRendering() { + return false && mSupportsPartialRendering; // disable for now + } + + public void setSupportsPartialRendering(boolean value) { + mSupportsPartialRendering = value; + } + + public void useParametersFrom(FilterRepresentation a) { + } + + public boolean allowsSingleInstanceOnly() { + return false; + } + + public Class<?> getFilterClass() { + return mFilterClass; + } + + public void setFilterClass(Class<?> filterClass) { + mFilterClass = filterClass; + } + + // This same() function is different from equals(), basically it checks + // whether 2 FilterRepresentations are the same type. It doesn't care about + // the values. + public boolean same(FilterRepresentation b) { + if (b == null) { + return false; + } + return getFilterClass() == b.getFilterClass(); + } + + public int getTextId() { + return mTextId; + } + + public void setTextId(int textId) { + mTextId = textId; + } + + public int getOverlayId() { + return mOverlayId; + } + + public void setOverlayId(int overlayId) { + mOverlayId = overlayId; + } + + public boolean getOverlayOnly() { + return mOverlayOnly; + } + + public void setOverlayOnly(boolean value) { + mOverlayOnly = value; + } + + final public int getEditorId() { + return mEditorId; + } + + public int[] getEditorIds() { + return new int[] { + mEditorId }; + } + + public void setEditorId(int editorId) { + mEditorId = editorId; + } + + public boolean showParameterValue() { + return mShowParameterValue; + } + + public void setShowParameterValue(boolean showParameterValue) { + mShowParameterValue = showParameterValue; + } + + public String getStateRepresentation() { + return ""; + } + + /** + * Method must "beginObject()" add its info and "endObject()" + * @param writer + * @throws IOException + */ + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + { + String[][] rep = serializeRepresentation(); + for (int k = 0; k < rep.length; k++) { + writer.name(rep[k][0]); + writer.value(rep[k][1]); + } + } + writer.endObject(); + } + + // this is the old way of doing this and will be removed soon + public String[][] serializeRepresentation() { + String[][] ret = {{NAME_TAG, getName()}}; + return ret; + } + + public void deSerializeRepresentation(JsonReader reader) throws IOException { + ArrayList<String[]> al = new ArrayList<String[]>(); + reader.beginObject(); + while (reader.hasNext()) { + String[] kv = {reader.nextName(), reader.nextString()}; + al.add(kv); + + } + reader.endObject(); + String[][] oldFormat = al.toArray(new String[al.size()][]); + + deSerializeRepresentation(oldFormat); + } + + // this is the old way of doing this and will be removed soon + public void deSerializeRepresentation(String[][] rep) { + for (int i = 0; i < rep.length; i++) { + if (NAME_TAG.equals(rep[i][0])) { + mName = rep[i][1]; + break; + } + } + } + + // Override this in subclasses + public int getStyle() { + return -1; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java new file mode 100644 index 000000000..eb89de036 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterRotateRepresentation.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorRotate; + +import java.io.IOException; + +public class FilterRotateRepresentation extends FilterRepresentation { + public static final String SERIALIZATION_NAME = "ROTATION"; + public static final String SERIALIZATION_ROTATE_VALUE = "value"; + private static final String TAG = FilterRotateRepresentation.class.getSimpleName(); + + Rotation mRotation; + + public enum Rotation { + ZERO(0), NINETY(90), ONE_EIGHTY(180), TWO_SEVENTY(270); + private final int mValue; + + private Rotation(int value) { + mValue = value; + } + + public int value() { + return mValue; + } + + public static Rotation fromValue(int value) { + switch (value) { + case 0: + return ZERO; + case 90: + return NINETY; + case 180: + return ONE_EIGHTY; + case 270: + return TWO_SEVENTY; + default: + return null; + } + } + } + + public FilterRotateRepresentation(Rotation rotation) { + super(FilterRotateRepresentation.class.getSimpleName()); + setSerializationName(SERIALIZATION_NAME); + setShowParameterValue(true); + setFilterClass(FilterRotateRepresentation.class); + setFilterType(FilterRepresentation.TYPE_GEOMETRY); + setTextId(R.string.rotate); + setEditorId(EditorRotate.ID); + setRotation(rotation); + } + + public FilterRotateRepresentation(FilterRotateRepresentation r) { + this(r.getRotation()); + } + + public FilterRotateRepresentation() { + this(getNil()); + } + + public Rotation getRotation() { + return mRotation; + } + + public void rotateCW() { + switch(mRotation) { + case ZERO: + mRotation = Rotation.NINETY; + break; + case NINETY: + mRotation = Rotation.ONE_EIGHTY; + break; + case ONE_EIGHTY: + mRotation = Rotation.TWO_SEVENTY; + break; + case TWO_SEVENTY: + mRotation = Rotation.ZERO; + break; + } + } + + public void set(FilterRotateRepresentation r) { + mRotation = r.mRotation; + } + + public void setRotation(Rotation rotation) { + if (rotation == null) { + throw new IllegalArgumentException("Argument to setRotation is null"); + } + mRotation = rotation; + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } + + @Override + public FilterRepresentation copy() { + return new FilterRotateRepresentation(this); + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + if (!(representation instanceof FilterRotateRepresentation)) { + throw new IllegalArgumentException("calling copyAllParameters with incompatible types!"); + } + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (!(a instanceof FilterRotateRepresentation)) { + throw new IllegalArgumentException("calling useParametersFrom with incompatible types!"); + } + setRotation(((FilterRotateRepresentation) a).getRotation()); + } + + @Override + public boolean isNil() { + return mRotation == getNil(); + } + + public static Rotation getNil() { + return Rotation.ZERO; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + writer.name(SERIALIZATION_ROTATE_VALUE).value(mRotation.value()); + writer.endObject(); + } + + @Override + public boolean equals(FilterRepresentation rep) { + if (!(rep instanceof FilterRotateRepresentation)) { + return false; + } + FilterRotateRepresentation rotate = (FilterRotateRepresentation) rep; + if (rotate.mRotation.value() != mRotation.value()) { + return false; + } + return true; + } + + @Override + public void deSerializeRepresentation(JsonReader reader) throws IOException { + boolean unset = true; + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + if (SERIALIZATION_ROTATE_VALUE.equals(name)) { + Rotation r = Rotation.fromValue(reader.nextInt()); + if (r != null) { + setRotation(r); + unset = false; + } + } else { + reader.skipValue(); + } + } + if (unset) { + Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME); + } + reader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java new file mode 100644 index 000000000..94c9497fc --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterStraightenRepresentation.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorStraighten; + +import java.io.IOException; + +public class FilterStraightenRepresentation extends FilterRepresentation { + public static final String SERIALIZATION_NAME = "STRAIGHTEN"; + public static final String SERIALIZATION_STRAIGHTEN_VALUE = "value"; + private static final String TAG = FilterStraightenRepresentation.class.getSimpleName(); + public static final int MAX_STRAIGHTEN_ANGLE = 45; + public static final int MIN_STRAIGHTEN_ANGLE = -45; + + float mStraighten; + + public FilterStraightenRepresentation(float straighten) { + super(FilterStraightenRepresentation.class.getSimpleName()); + setSerializationName(SERIALIZATION_NAME); + setShowParameterValue(true); + setFilterClass(FilterStraightenRepresentation.class); + setFilterType(FilterRepresentation.TYPE_GEOMETRY); + setTextId(R.string.straighten); + setEditorId(EditorStraighten.ID); + setStraighten(straighten); + } + + public FilterStraightenRepresentation(FilterStraightenRepresentation s) { + this(s.getStraighten()); + } + + public FilterStraightenRepresentation() { + this(getNil()); + } + + public void set(FilterStraightenRepresentation r) { + mStraighten = r.mStraighten; + } + + @Override + public boolean equals(FilterRepresentation rep) { + if (!(rep instanceof FilterStraightenRepresentation)) { + return false; + } + FilterStraightenRepresentation straighten = (FilterStraightenRepresentation) rep; + if (straighten.mStraighten != mStraighten) { + return false; + } + return true; + } + + public float getStraighten() { + return mStraighten; + } + + public void setStraighten(float straighten) { + if (!rangeCheck(straighten)) { + straighten = Math.min(Math.max(straighten, MIN_STRAIGHTEN_ANGLE), MAX_STRAIGHTEN_ANGLE); + } + mStraighten = straighten; + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } + + @Override + public FilterRepresentation copy() { + return new FilterStraightenRepresentation(this); + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + if (!(representation instanceof FilterStraightenRepresentation)) { + throw new IllegalArgumentException("calling copyAllParameters with incompatible types!"); + } + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + if (!(a instanceof FilterStraightenRepresentation)) { + throw new IllegalArgumentException("calling useParametersFrom with incompatible types!"); + } + setStraighten(((FilterStraightenRepresentation) a).getStraighten()); + } + + @Override + public boolean isNil() { + return mStraighten == getNil(); + } + + public static float getNil() { + return 0; + } + + @Override + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + writer.name(SERIALIZATION_STRAIGHTEN_VALUE).value(mStraighten); + writer.endObject(); + } + + @Override + public void deSerializeRepresentation(JsonReader reader) throws IOException { + boolean unset = true; + reader.beginObject(); + while (reader.hasNext()) { + String name = reader.nextName(); + if (SERIALIZATION_STRAIGHTEN_VALUE.equals(name)) { + float s = (float) reader.nextDouble(); + if (rangeCheck(s)) { + setStraighten(s); + unset = false; + } + } else { + reader.skipValue(); + } + } + if (unset) { + Log.w(TAG, "WARNING: bad value when deserializing " + SERIALIZATION_NAME); + } + reader.endObject(); + } + + private boolean rangeCheck(double s) { + if (s < -45 || s > 45) { + return false; + } + return true; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java new file mode 100644 index 000000000..be1812957 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterTinyPlanetRepresentation.java @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; + +public class FilterTinyPlanetRepresentation extends FilterBasicRepresentation { + private static final String SERIALIZATION_NAME = "TINYPLANET"; + private static final String LOGTAG = "FilterTinyPlanetRepresentation"; + private static final String SERIAL_ANGLE = "Angle"; + private float mAngle = 0; + + public FilterTinyPlanetRepresentation() { + super("TinyPlanet", 0, 50, 100); + setSerializationName(SERIALIZATION_NAME); + setShowParameterValue(true); + setFilterClass(ImageFilterTinyPlanet.class); + setFilterType(FilterRepresentation.TYPE_TINYPLANET); + setTextId(R.string.tinyplanet); + setEditorId(EditorTinyPlanet.ID); + setMinimum(1); + } + + @Override + public FilterRepresentation copy() { + FilterTinyPlanetRepresentation representation = new FilterTinyPlanetRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + FilterTinyPlanetRepresentation representation = (FilterTinyPlanetRepresentation) a; + super.useParametersFrom(a); + mAngle = representation.mAngle; + setZoom(representation.getZoom()); + } + + public void setAngle(float angle) { + mAngle = angle; + } + + public float getAngle() { + return mAngle; + } + + public int getZoom() { + return getValue(); + } + + public void setZoom(int zoom) { + setValue(zoom); + } + + public boolean isNil() { + // TinyPlanet always has an effect + return false; + } + + @Override + public String[][] serializeRepresentation() { + String[][] ret = { + {SERIAL_NAME , getName() }, + {SERIAL_VALUE , Integer.toString(getValue())}, + {SERIAL_ANGLE , Float.toString(mAngle)}}; + return ret; + } + + @Override + public void deSerializeRepresentation(String[][] rep) { + super.deSerializeRepresentation(rep); + for (int i = 0; i < rep.length; i++) { + if (SERIAL_VALUE.equals(rep[i][0])) { + setValue(Integer.parseInt(rep[i][1])); + } else if (SERIAL_ANGLE.equals(rep[i][0])) { + setAngle(Float.parseFloat(rep[i][1])); + } + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java new file mode 100644 index 000000000..dfdb6fcf0 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterUserPresetRepresentation.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; + +public class FilterUserPresetRepresentation extends FilterRepresentation { + + private ImagePreset mPreset; + private int mId; + + public FilterUserPresetRepresentation(String name, ImagePreset preset, int id) { + super(name); + setEditorId(ImageOnlyEditor.ID); + setFilterType(FilterRepresentation.TYPE_FX); + mPreset = preset; + mId = id; + } + + public ImagePreset getImagePreset() { + return mPreset; + } + + public int getId() { + return mId; + } + + public FilterRepresentation copy(){ + FilterRepresentation representation = new FilterUserPresetRepresentation(getName(), + new ImagePreset(mPreset), mId); + return representation; + } + + @Override + public boolean allowsSingleInstanceOnly() { + return true; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java new file mode 100644 index 000000000..42a7406bc --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterVignetteRepresentation.java @@ -0,0 +1,173 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorVignette; +import com.android.gallery3d.filtershow.imageshow.Oval; + +public class FilterVignetteRepresentation extends FilterBasicRepresentation implements Oval { + private static final String LOGTAG = "FilterVignetteRepresentation"; + private float mCenterX = Float.NaN; + private float mCenterY; + private float mRadiusX = Float.NaN; + private float mRadiusY; + + public FilterVignetteRepresentation() { + super("Vignette", -100, 50, 100); + setSerializationName("VIGNETTE"); + setShowParameterValue(true); + setFilterType(FilterRepresentation.TYPE_VIGNETTE); + setTextId(R.string.vignette); + setEditorId(EditorVignette.ID); + setName("Vignette"); + setFilterClass(ImageFilterVignette.class); + setMinimum(-100); + setMaximum(100); + setDefaultValue(0); + } + + @Override + public void useParametersFrom(FilterRepresentation a) { + super.useParametersFrom(a); + mCenterX = ((FilterVignetteRepresentation) a).mCenterX; + mCenterY = ((FilterVignetteRepresentation) a).mCenterY; + mRadiusX = ((FilterVignetteRepresentation) a).mRadiusX; + mRadiusY = ((FilterVignetteRepresentation) a).mRadiusY; + } + + @Override + public FilterRepresentation copy() { + FilterVignetteRepresentation representation = new FilterVignetteRepresentation(); + copyAllParameters(representation); + return representation; + } + + @Override + protected void copyAllParameters(FilterRepresentation representation) { + super.copyAllParameters(representation); + representation.useParametersFrom(this); + } + + @Override + public void setCenter(float centerX, float centerY) { + mCenterX = centerX; + mCenterY = centerY; + } + + @Override + public float getCenterX() { + return mCenterX; + } + + @Override + public float getCenterY() { + return mCenterY; + } + + @Override + public void setRadius(float radiusX, float radiusY) { + mRadiusX = radiusX; + mRadiusY = radiusY; + } + + @Override + public void setRadiusX(float radiusX) { + mRadiusX = radiusX; + } + + @Override + public void setRadiusY(float radiusY) { + mRadiusY = radiusY; + } + + @Override + public float getRadiusX() { + return mRadiusX; + } + + @Override + public float getRadiusY() { + return mRadiusY; + } + + public boolean isCenterSet() { + return mCenterX != Float.NaN; + } + + @Override + public boolean isNil() { + return getValue() == 0; + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterVignetteRepresentation) { + FilterVignetteRepresentation rep = (FilterVignetteRepresentation) representation; + if (rep.getCenterX() == getCenterX() + && rep.getCenterY() == getCenterY() + && rep.getRadiusX() == getRadiusX() + && rep.getRadiusY() == getRadiusY()) { + return true; + } + } + return false; + } + + private static final String[] sParams = { + "Name", "value", "mCenterX", "mCenterY", "mRadiusX", + "mRadiusY" + }; + + @Override + public String[][] serializeRepresentation() { + String[][] ret = { + { sParams[0], getName() }, + { sParams[1], Integer.toString(getValue()) }, + { sParams[2], Float.toString(mCenterX) }, + { sParams[3], Float.toString(mCenterY) }, + { sParams[4], Float.toString(mRadiusX) }, + { sParams[5], Float.toString(mRadiusY) } + }; + return ret; + } + + @Override + public void deSerializeRepresentation(String[][] rep) { + super.deSerializeRepresentation(rep); + for (int i = 0; i < rep.length; i++) { + String key = rep[i][0]; + String value = rep[i][1]; + if (sParams[0].equals(key)) { + setName(value); + } else if (sParams[1].equals(key)) { + setValue(Integer.parseInt(value)); + } else if (sParams[2].equals(key)) { + mCenterX = Float.parseFloat(value); + } else if (sParams[3].equals(key)) { + mCenterY = Float.parseFloat(value); + } else if (sParams[4].equals(key)) { + mRadiusX = Float.parseFloat(value); + } else if (sParams[5].equals(key)) { + mRadiusY = Float.parseFloat(value); + } + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FiltersManagerInterface.java b/src/com/android/gallery3d/filtershow/filters/FiltersManagerInterface.java new file mode 100644 index 000000000..710128f99 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FiltersManagerInterface.java @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +public interface FiltersManagerInterface { + ImageFilter getFilterForRepresentation(FilterRepresentation representation); +} diff --git a/src/com/android/gallery3d/filtershow/filters/IconUtilities.java b/src/com/android/gallery3d/filtershow/filters/IconUtilities.java new file mode 100644 index 000000000..e2a01472d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/IconUtilities.java @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; + +import com.android.gallery3d.R; + +public class IconUtilities { + public static final int PUNCH = R.drawable.filtershow_fx_0005_punch; + public static final int VINTAGE = R.drawable.filtershow_fx_0000_vintage; + public static final int BW_CONTRAST = R.drawable.filtershow_fx_0004_bw_contrast; + public static final int BLEACH = R.drawable.filtershow_fx_0002_bleach; + public static final int INSTANT = R.drawable.filtershow_fx_0001_instant; + public static final int WASHOUT = R.drawable.filtershow_fx_0007_washout; + public static final int BLUECRUSH = R.drawable.filtershow_fx_0003_blue_crush; + public static final int WASHOUT_COLOR = R.drawable.filtershow_fx_0008_washout_color; + public static final int X_PROCESS = R.drawable.filtershow_fx_0006_x_process; + + public static Bitmap getFXBitmap(Resources res, int id) { + Bitmap ret; + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inScaled = false; + + if (id != 0) { + return BitmapFactory.decodeResource(res, id, o); + } + return null; + } + + public static Bitmap loadBitmap(Resources res, int resource) { + + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeResource( + res, + resource, options); + + return bitmap; + } + + public static Bitmap applyFX(Bitmap bitmap, final Bitmap fxBitmap) { + ImageFilterFx fx = new ImageFilterFx() { + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int fxw = fxBitmap.getWidth(); + int fxh = fxBitmap.getHeight(); + int start = 0; + int end = w * h * 4; + nativeApplyFilter(bitmap, w, h, fxBitmap, fxw, fxh, start, end); + return bitmap; + } + }; + return fx.apply(bitmap, 0, 0); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java new file mode 100644 index 000000000..437137416 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilter.java @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.app.Activity; +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.support.v8.renderscript.Allocation; +import android.widget.Toast; + +import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +public abstract class ImageFilter implements Cloneable { + private FilterEnvironment mEnvironment = null; + + protected String mName = "Original"; + private final String LOGTAG = "ImageFilter"; + protected static final boolean SIMPLE_ICONS = true; + // TODO: Temporary, for dogfood note memory issues with toasts for better + // feedback. Remove this when filters actually work in low memory + // situations. + private static Activity sActivity = null; + + public static void setActivityForMemoryToasts(Activity activity) { + sActivity = activity; + } + + public static void resetStatics() { + sActivity = null; + } + + public void freeResources() {} + + public void displayLowMemoryToast() { + if (sActivity != null) { + sActivity.runOnUiThread(new Runnable() { + public void run() { + Toast.makeText(sActivity, "Memory too low for filter " + getName() + + ", please file a bug report", Toast.LENGTH_SHORT).show(); + } + }); + } + } + + public void setName(String name) { + mName = name; + } + + public String getName() { + return mName; + } + + public boolean supportsAllocationInput() { return false; } + + public void apply(Allocation in, Allocation out) { + setGeneralParameters(); + } + + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + // do nothing here, subclasses will implement filtering here + setGeneralParameters(); + return bitmap; + } + + public abstract void useRepresentation(FilterRepresentation representation); + + native protected void nativeApplyGradientFilter(Bitmap bitmap, int w, int h, + int[] redGradient, int[] greenGradient, int[] blueGradient); + + public FilterRepresentation getDefaultRepresentation() { + return null; + } + + protected Matrix getOriginalToScreenMatrix(int w, int h) { + return GeometryMathUtils.getImageToScreenMatrix(getEnvironment().getImagePreset() + .getGeometryFilters(), true, MasterImage.getImage().getOriginalBounds(), w, h); + } + + public void setEnvironment(FilterEnvironment environment) { + mEnvironment = environment; + } + + public FilterEnvironment getEnvironment() { + return mEnvironment; + } + + public void setGeneralParameters() { + // should implement in subclass which like to transport + // some information to other filters. (like the style setting from RetroLux + // and Film to FixedFrame) + mEnvironment.clearGeneralParameters(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java new file mode 100644 index 000000000..a7286f0fa --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBorder.java @@ -0,0 +1,92 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Rect; +import android.graphics.drawable.BitmapDrawable; +import android.graphics.drawable.Drawable; + +import java.util.HashMap; + +public class ImageFilterBorder extends ImageFilter { + private static final float NINEPATCH_ICON_SCALING = 10; + private static final float BITMAP_ICON_SCALING = 1 / 3.0f; + private FilterImageBorderRepresentation mParameters = null; + private Resources mResources = null; + + private HashMap<Integer, Drawable> mDrawables = new HashMap<Integer, Drawable>(); + + public ImageFilterBorder() { + mName = "Border"; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterImageBorderRepresentation parameters = (FilterImageBorderRepresentation) representation; + mParameters = parameters; + } + + public FilterImageBorderRepresentation getParameters() { + return mParameters; + } + + public void freeResources() { + mDrawables.clear(); + } + + public Bitmap applyHelper(Bitmap bitmap, float scale1, float scale2 ) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + Rect bounds = new Rect(0, 0, (int) (w * scale1), (int) (h * scale1)); + Canvas canvas = new Canvas(bitmap); + canvas.scale(scale2, scale2); + Drawable drawable = getDrawable(getParameters().getDrawableResource()); + drawable.setBounds(bounds); + drawable.draw(canvas); + return bitmap; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null || getParameters().getDrawableResource() == 0) { + return bitmap; + } + float scale2 = scaleFactor * 2.0f; + float scale1 = 1 / scale2; + return applyHelper(bitmap, scale1, scale2); + } + + public void setResources(Resources resources) { + if (mResources != resources) { + mResources = resources; + mDrawables.clear(); + } + } + + public Drawable getDrawable(int rsc) { + Drawable drawable = mDrawables.get(rsc); + if (drawable == null && mResources != null && rsc != 0) { + drawable = new BitmapDrawable(mResources, BitmapFactory.decodeResource(mResources, rsc)); + mDrawables.put(rsc, drawable); + } + return drawable; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java new file mode 100644 index 000000000..50837ca2f --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; +import android.graphics.Color; + + +public class ImageFilterBwFilter extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "BWFILTER"; + + public ImageFilterBwFilter() { + mName = "BW Filter"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("BW Filter"); + representation.setSerializationName(SERIALIZATION_NAME); + + representation.setFilterClass(ImageFilterBwFilter.class); + representation.setMaximum(180); + representation.setMinimum(-180); + representation.setTextId(R.string.bwfilter); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, int r, int g, int b); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float[] hsv = new float[] { + 180 + getParameters().getValue(), 1, 1 + }; + int rgb = Color.HSVToColor(hsv); + int r = 0xFF & (rgb >> 16); + int g = 0xFF & (rgb >> 8); + int b = 0xFF & (rgb >> 0); + nativeApplyFilter(bitmap, w, h, r, g, b); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterChanSat.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterChanSat.java new file mode 100644 index 000000000..1ea8edfb8 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterChanSat.java @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.support.v8.renderscript.Allocation; +import android.support.v8.renderscript.Element; +import android.support.v8.renderscript.RenderScript; +import android.support.v8.renderscript.Script.LaunchOptions; +import android.support.v8.renderscript.Type; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +public class ImageFilterChanSat extends ImageFilterRS { + private static final String LOGTAG = "ImageFilterChanSat"; + private ScriptC_saturation mScript; + private Bitmap mSourceBitmap; + + private static final int STRIP_SIZE = 64; + + FilterChanSatRepresentation mParameters = new FilterChanSatRepresentation(); + private Bitmap mOverlayBitmap; + + public ImageFilterChanSat() { + mName = "ChannelSat"; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterChanSatRepresentation(); + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + mParameters = (FilterChanSatRepresentation) representation; + } + + @Override + protected void resetAllocations() { + + } + + @Override + public void resetScripts() { + if (mScript != null) { + mScript.destroy(); + mScript = null; + } + } + @Override + protected void createFilter(android.content.res.Resources res, float scaleFactor, + int quality) { + createFilter(res, scaleFactor, quality, getInPixelsAllocation()); + } + + @Override + protected void createFilter(android.content.res.Resources res, float scaleFactor, + int quality, Allocation in) { + RenderScript rsCtx = getRenderScriptContext(); + + Type.Builder tb_float = new Type.Builder(rsCtx, Element.F32_4(rsCtx)); + tb_float.setX(in.getType().getX()); + tb_float.setY(in.getType().getY()); + mScript = new ScriptC_saturation(rsCtx, res, R.raw.saturation); + } + + + private Bitmap getSourceBitmap() { + assert (mSourceBitmap != null); + return mSourceBitmap; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (SIMPLE_ICONS && FilterEnvironment.QUALITY_ICON == quality) { + return bitmap; + } + + mSourceBitmap = bitmap; + Bitmap ret = super.apply(bitmap, scaleFactor, quality); + mSourceBitmap = null; + + return ret; + } + + @Override + protected void bindScriptValues() { + int width = getInPixelsAllocation().getType().getX(); + int height = getInPixelsAllocation().getType().getY(); + } + + + + @Override + protected void runFilter() { + int []sat = new int[7]; + for(int i = 0;i<sat.length ;i ++){ + sat[i] = mParameters.getValue(i); + } + + + int width = getInPixelsAllocation().getType().getX(); + int height = getInPixelsAllocation().getType().getY(); + Matrix m = getOriginalToScreenMatrix(width, height); + + + mScript.set_saturation(sat); + + mScript.invoke_setupGradParams(); + runSelectiveAdjust( + getInPixelsAllocation(), getOutPixelsAllocation()); + + } + + private void runSelectiveAdjust(Allocation in, Allocation out) { + int width = in.getType().getX(); + int height = in.getType().getY(); + + LaunchOptions options = new LaunchOptions(); + int ty; + options.setX(0, width); + + for (ty = 0; ty < height; ty += STRIP_SIZE) { + int endy = ty + STRIP_SIZE; + if (endy > height) { + endy = height; + } + options.setY(ty, endy); + mScript.forEach_selectiveAdjust(in, out, options); + if (checkStop()) { + return; + } + } + } + + private boolean checkStop() { + RenderScript rsCtx = getRenderScriptContext(); + rsCtx.finish(); + if (getEnvironment().needsStop()) { + return true; + } + return false; + } +} + diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java new file mode 100644 index 000000000..27c0e0877 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; + +public class ImageFilterContrast extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "CONTRAST"; + + public ImageFilterContrast() { + mName = "Contrast"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Contrast"); + representation.setSerializationName(SERIALIZATION_NAME); + + representation.setFilterClass(ImageFilterContrast.class); + representation.setTextId(R.string.contrast); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float strength); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float value = getParameters().getValue(); + nativeApplyFilter(bitmap, w, h, value); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java new file mode 100644 index 000000000..61b60d2e3 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterCurves.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; + +import com.android.gallery3d.filtershow.imageshow.Spline; + +public class ImageFilterCurves extends ImageFilter { + + private static final String LOGTAG = "ImageFilterCurves"; + FilterCurvesRepresentation mParameters = new FilterCurvesRepresentation(); + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterCurvesRepresentation(); + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + FilterCurvesRepresentation parameters = (FilterCurvesRepresentation) representation; + mParameters = parameters; + } + + public ImageFilterCurves() { + mName = "Curves"; + reset(); + } + + public void populateArray(int[] array, int curveIndex) { + Spline spline = mParameters.getSpline(curveIndex); + if (spline == null) { + return; + } + float[] curve = spline.getAppliedCurve(); + for (int i = 0; i < 256; i++) { + array[i] = (int) (curve[i] * 255); + } + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (!mParameters.getSpline(Spline.RGB).isOriginal()) { + int[] rgbGradient = new int[256]; + populateArray(rgbGradient, Spline.RGB); + nativeApplyGradientFilter(bitmap, bitmap.getWidth(), bitmap.getHeight(), + rgbGradient, rgbGradient, rgbGradient); + } + + int[] redGradient = null; + if (!mParameters.getSpline(Spline.RED).isOriginal()) { + redGradient = new int[256]; + populateArray(redGradient, Spline.RED); + } + int[] greenGradient = null; + if (!mParameters.getSpline(Spline.GREEN).isOriginal()) { + greenGradient = new int[256]; + populateArray(greenGradient, Spline.GREEN); + } + int[] blueGradient = null; + if (!mParameters.getSpline(Spline.BLUE).isOriginal()) { + blueGradient = new int[256]; + populateArray(blueGradient, Spline.BLUE); + } + + nativeApplyGradientFilter(bitmap, bitmap.getWidth(), bitmap.getHeight(), + redGradient, greenGradient, blueGradient); + return bitmap; + } + + public void setSpline(Spline spline, int splineIndex) { + mParameters.setSpline(splineIndex, new Spline(spline)); + } + + public Spline getSpline(int splineIndex) { + return mParameters.getSpline(splineIndex); + } + + public void reset() { + Spline spline = new Spline(); + + spline.addPoint(0.0f, 1.0f); + spline.addPoint(1.0f, 0.0f); + + for (int i = 0; i < 4; i++) { + mParameters.setSpline(i, new Spline(spline)); + } + } + + public void useFilter(ImageFilter a) { + ImageFilterCurves c = (ImageFilterCurves) a; + for (int i = 0; i < 4; i++) { + if (c.mParameters.getSpline(i) != null) { + setSpline(c.mParameters.getSpline(i), i); + } + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java new file mode 100644 index 000000000..efb9cde71 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDownsample.java @@ -0,0 +1,83 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Rect; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.imageshow.MasterImage; + +public class ImageFilterDownsample extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "DOWNSAMPLE"; + private static final int ICON_DOWNSAMPLE_FRACTION = 8; + private ImageLoader mImageLoader; + + public ImageFilterDownsample(ImageLoader loader) { + mName = "Downsample"; + mImageLoader = loader; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Downsample"); + representation.setSerializationName(SERIALIZATION_NAME); + + representation.setFilterClass(ImageFilterDownsample.class); + representation.setMaximum(100); + representation.setMinimum(1); + representation.setValue(50); + representation.setDefaultValue(50); + representation.setPreviewValue(3); + representation.setTextId(R.string.downsample); + return representation; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int p = getParameters().getValue(); + + // size of original precached image + Rect size = MasterImage.getImage().getOriginalBounds(); + int orig_w = size.width(); + int orig_h = size.height(); + + if (p > 0 && p < 100) { + // scale preview to same size as the resulting bitmap from a "save" + int newWidth = orig_w * p / 100; + int newHeight = orig_h * p / 100; + + // only scale preview if preview isn't already scaled enough + if (newWidth <= 0 || newHeight <= 0 || newWidth >= w || newHeight >= h) { + return bitmap; + } + Bitmap ret = Bitmap.createScaledBitmap(bitmap, newWidth, newHeight, true); + if (ret != bitmap) { + bitmap.recycle(); + } + return ret; + } + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java new file mode 100644 index 000000000..7df5ffb64 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDraw.java @@ -0,0 +1,278 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Paint.Style; +import android.graphics.Path; +import android.graphics.PathMeasure; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +import java.util.Vector; + +public class ImageFilterDraw extends ImageFilter { + private static final String LOGTAG = "ImageFilterDraw"; + public final static byte SIMPLE_STYLE = 0; + public final static byte BRUSH_STYLE_SPATTER = 1; + public final static byte BRUSH_STYLE_MARKER = 2; + public final static int NUMBER_OF_STYLES = 3; + Bitmap mOverlayBitmap; // this accelerates interaction + int mCachedStrokes = -1; + int mCurrentStyle = 0; + + FilterDrawRepresentation mParameters = new FilterDrawRepresentation(); + + public ImageFilterDraw() { + mName = "Image Draw"; + } + + DrawStyle[] mDrawingsTypes = new DrawStyle[] { + new SimpleDraw(), + new Brush(R.drawable.brush_marker), + new Brush(R.drawable.brush_spatter) + }; + { + for (int i = 0; i < mDrawingsTypes.length; i++) { + mDrawingsTypes[i].setType((byte) i); + } + + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterDrawRepresentation(); + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + FilterDrawRepresentation parameters = (FilterDrawRepresentation) representation; + mParameters = parameters; + } + + public void setStyle(byte style) { + mCurrentStyle = style % mDrawingsTypes.length; + } + + public int getStyle() { + return mCurrentStyle; + } + + public static interface DrawStyle { + public void setType(byte type); + public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, + int quality); + } + + class SimpleDraw implements DrawStyle { + byte mType; + + @Override + public void setType(byte type) { + mType = type; + } + + @Override + public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, + int quality) { + if (sd == null) { + return; + } + if (sd.mPath == null) { + return; + } + Paint paint = new Paint(); + + paint.setStyle(Style.STROKE); + paint.setColor(sd.mColor); + paint.setStrokeWidth(toScrMatrix.mapRadius(sd.mRadius)); + + // done this way because of a bug in path.transform(matrix) + Path mCacheTransPath = new Path(); + mCacheTransPath.addPath(sd.mPath, toScrMatrix); + + canvas.drawPath(mCacheTransPath, paint); + } + } + + class Brush implements DrawStyle { + int mBrushID; + Bitmap mBrush; + byte mType; + + public Brush(int brushID) { + mBrushID = brushID; + } + + public Bitmap getBrush() { + if (mBrush == null) { + BitmapFactory.Options opt = new BitmapFactory.Options(); + opt.inPreferredConfig = Bitmap.Config.ALPHA_8; + mBrush = BitmapFactory.decodeResource(MasterImage.getImage().getActivity() + .getResources(), mBrushID, opt); + mBrush = mBrush.extractAlpha(); + } + return mBrush; + } + + @Override + public void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, + Matrix toScrMatrix, + int quality) { + if (sd == null || sd.mPath == null) { + return; + } + Paint paint = new Paint(); + paint.setStyle(Style.STROKE); + paint.setAntiAlias(true); + Path mCacheTransPath = new Path(); + mCacheTransPath.addPath(sd.mPath, toScrMatrix); + draw(canvas, paint, sd.mColor, toScrMatrix.mapRadius(sd.mRadius) * 2, + mCacheTransPath); + } + + public Bitmap createScaledBitmap(Bitmap src, int dstWidth, int dstHeight, boolean filter) + { + Matrix m = new Matrix(); + m.setScale(dstWidth / (float) src.getWidth(), dstHeight / (float) src.getHeight()); + Bitmap result = Bitmap.createBitmap(dstWidth, dstHeight, src.getConfig()); + Canvas canvas = new Canvas(result); + + Paint paint = new Paint(); + paint.setFilterBitmap(filter); + canvas.drawBitmap(src, m, paint); + + return result; + + } + void draw(Canvas canvas, Paint paint, int color, float size, Path path) { + PathMeasure mPathMeasure = new PathMeasure(); + float[] mPosition = new float[2]; + float[] mTan = new float[2]; + + mPathMeasure.setPath(path, false); + + paint.setAntiAlias(true); + paint.setColor(color); + + paint.setColorFilter(new PorterDuffColorFilter(color, PorterDuff.Mode.MULTIPLY)); + Bitmap brush; + // done this way because of a bug in + // Bitmap.createScaledBitmap(getBrush(),(int) size,(int) size,true); + brush = createScaledBitmap(getBrush(), (int) size, (int) size, true); + float len = mPathMeasure.getLength(); + float s2 = size / 2; + float step = s2 / 8; + for (float i = 0; i < len; i += step) { + mPathMeasure.getPosTan(i, mPosition, mTan); + // canvas.drawCircle(pos[0], pos[1], size, paint); + canvas.drawBitmap(brush, mPosition[0] - s2, mPosition[1] - s2, paint); + } + } + + @Override + public void setType(byte type) { + mType = type; + } + } + + void paint(FilterDrawRepresentation.StrokeData sd, Canvas canvas, Matrix toScrMatrix, + int quality) { + mDrawingsTypes[sd.mType].paint(sd, canvas, toScrMatrix, quality); + } + + public void drawData(Canvas canvas, Matrix originalRotateToScreen, int quality) { + Paint paint = new Paint(); + if (quality == FilterEnvironment.QUALITY_FINAL) { + paint.setAntiAlias(true); + } + paint.setStyle(Style.STROKE); + paint.setColor(Color.RED); + paint.setStrokeWidth(40); + + if (mParameters.getDrawing().isEmpty() && mParameters.getCurrentDrawing() == null) { + return; + } + if (quality == FilterEnvironment.QUALITY_FINAL) { + for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { + paint(strokeData, canvas, originalRotateToScreen, quality); + } + return; + } + + if (mOverlayBitmap == null || + mOverlayBitmap.getWidth() != canvas.getWidth() || + mOverlayBitmap.getHeight() != canvas.getHeight() || + mParameters.getDrawing().size() < mCachedStrokes) { + + mOverlayBitmap = Bitmap.createBitmap( + canvas.getWidth(), canvas.getHeight(), Bitmap.Config.ARGB_8888); + mCachedStrokes = 0; + } + + if (mCachedStrokes < mParameters.getDrawing().size()) { + fillBuffer(originalRotateToScreen); + } + canvas.drawBitmap(mOverlayBitmap, 0, 0, paint); + + StrokeData stroke = mParameters.getCurrentDrawing(); + if (stroke != null) { + paint(stroke, canvas, originalRotateToScreen, quality); + } + } + + public void fillBuffer(Matrix originalRotateToScreen) { + Canvas drawCache = new Canvas(mOverlayBitmap); + Vector<FilterDrawRepresentation.StrokeData> v = mParameters.getDrawing(); + int n = v.size(); + + for (int i = mCachedStrokes; i < n; i++) { + paint(v.get(i), drawCache, originalRotateToScreen, FilterEnvironment.QUALITY_PREVIEW); + } + mCachedStrokes = n; + } + + public void draw(Canvas canvas, Matrix originalRotateToScreen) { + for (FilterDrawRepresentation.StrokeData strokeData : mParameters.getDrawing()) { + paint(strokeData, canvas, originalRotateToScreen, FilterEnvironment.QUALITY_PREVIEW); + } + mDrawingsTypes[mCurrentStyle].paint( + null, canvas, originalRotateToScreen, FilterEnvironment.QUALITY_PREVIEW); + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + Matrix m = getOriginalToScreenMatrix(w, h); + drawData(new Canvas(bitmap), m, quality); + return bitmap; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java new file mode 100644 index 000000000..2d0d7653d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; + +import com.android.gallery3d.R; + +public class ImageFilterEdge extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "EDGE"; + public ImageFilterEdge() { + mName = "Edge"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterRepresentation representation = super.getDefaultRepresentation(); + representation.setName("Edge"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterEdge.class); + representation.setTextId(R.string.edge); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float p); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float p = getParameters().getValue() + 101; + p = (float) p / 100; + nativeApplyFilter(bitmap, w, h, p); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java new file mode 100644 index 000000000..69eab7330 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; + +public class ImageFilterExposure extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "EXPOSURE"; + public ImageFilterExposure() { + mName = "Exposure"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Exposure"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterExposure.class); + representation.setTextId(R.string.exposure); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float value = getParameters().getValue(); + nativeApplyFilter(bitmap, w, h, value); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java new file mode 100644 index 000000000..19bea593b --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterFx.java @@ -0,0 +1,111 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import com.android.gallery3d.app.Log; + +public class ImageFilterFx extends ImageFilter { + private static final String LOGTAG = "ImageFilterFx"; + private FilterFxRepresentation mParameters = null; + private Bitmap mFxBitmap = null; + private Resources mResources = null; + private int mFxBitmapId = 0; + + public ImageFilterFx() { + } + + @Override + public void freeResources() { + if (mFxBitmap != null) mFxBitmap.recycle(); + mFxBitmap = null; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return null; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterFxRepresentation parameters = (FilterFxRepresentation) representation; + mParameters = parameters; + } + + public FilterFxRepresentation getParameters() { + return mParameters; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, + Bitmap fxBitmap, int fxw, int fxh, + int start, int end); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null || mResources == null) { + return bitmap; + } + + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + int bitmapResourceId = getParameters().getBitmapResource(); + if (bitmapResourceId == 0) { // null filter fx + return bitmap; + } + + if (mFxBitmap == null || mFxBitmapId != bitmapResourceId) { + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inScaled = false; + mFxBitmapId = bitmapResourceId; + if (mFxBitmapId != 0) { + mFxBitmap = BitmapFactory.decodeResource(mResources, mFxBitmapId, o); + } else { + Log.w(LOGTAG, "bad resource for filter: " + mName); + } + } + + if (mFxBitmap == null) { + return bitmap; + } + + int fxw = mFxBitmap.getWidth(); + int fxh = mFxBitmap.getHeight(); + + int stride = w * 4; + int max = stride * h; + int increment = stride * 256; // 256 lines + for (int i = 0; i < max; i += increment) { + int start = i; + int end = i + increment; + if (end > max) { + end = max; + } + if (!getEnvironment().needsStop()) { + nativeApplyFilter(bitmap, w, h, mFxBitmap, fxw, fxh, start, end); + } + } + + return bitmap; + } + + public void setResources(Resources resources) { + mResources = resources; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java new file mode 100644 index 000000000..cbdfaa623 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java @@ -0,0 +1,190 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Matrix; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Matrix; +import android.support.v8.renderscript.Allocation; +import android.support.v8.renderscript.Element; +import android.support.v8.renderscript.RenderScript; +import android.support.v8.renderscript.Script.LaunchOptions; +import android.support.v8.renderscript.Type; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +public class ImageFilterGrad extends ImageFilterRS { + private static final String LOGTAG = "ImageFilterGrad"; + private ScriptC_grad mScript; + private Bitmap mSourceBitmap; + private static final int RADIUS_SCALE_FACTOR = 160; + + private static final int STRIP_SIZE = 64; + + FilterGradRepresentation mParameters = new FilterGradRepresentation(); + private Bitmap mOverlayBitmap; + + public ImageFilterGrad() { + mName = "grad"; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterGradRepresentation(); + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + mParameters = (FilterGradRepresentation) representation; + } + + @Override + protected void resetAllocations() { + + } + + @Override + public void resetScripts() { + if (mScript != null) { + mScript.destroy(); + mScript = null; + } + } + @Override + protected void createFilter(android.content.res.Resources res, float scaleFactor, + int quality) { + createFilter(res, scaleFactor, quality, getInPixelsAllocation()); + } + + @Override + protected void createFilter(android.content.res.Resources res, float scaleFactor, + int quality, Allocation in) { + RenderScript rsCtx = getRenderScriptContext(); + + Type.Builder tb_float = new Type.Builder(rsCtx, Element.F32_4(rsCtx)); + tb_float.setX(in.getType().getX()); + tb_float.setY(in.getType().getY()); + mScript = new ScriptC_grad(rsCtx, res, R.raw.grad); + } + + + private Bitmap getSourceBitmap() { + assert (mSourceBitmap != null); + return mSourceBitmap; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (SIMPLE_ICONS && FilterEnvironment.QUALITY_ICON == quality) { + return bitmap; + } + + mSourceBitmap = bitmap; + Bitmap ret = super.apply(bitmap, scaleFactor, quality); + mSourceBitmap = null; + + return ret; + } + + @Override + protected void bindScriptValues() { + int width = getInPixelsAllocation().getType().getX(); + int height = getInPixelsAllocation().getType().getY(); + mScript.set_inputWidth(width); + mScript.set_inputHeight(height); + } + + @Override + protected void runFilter() { + int[] x1 = mParameters.getXPos1(); + int[] y1 = mParameters.getYPos1(); + int[] x2 = mParameters.getXPos2(); + int[] y2 = mParameters.getYPos2(); + + int width = getInPixelsAllocation().getType().getX(); + int height = getInPixelsAllocation().getType().getY(); + Matrix m = getOriginalToScreenMatrix(width, height); + float[] coord = new float[2]; + for (int i = 0; i < x1.length; i++) { + coord[0] = x1[i]; + coord[1] = y1[i]; + m.mapPoints(coord); + x1[i] = (int) coord[0]; + y1[i] = (int) coord[1]; + coord[0] = x2[i]; + coord[1] = y2[i]; + m.mapPoints(coord); + x2[i] = (int) coord[0]; + y2[i] = (int) coord[1]; + } + + mScript.set_mask(mParameters.getMask()); + mScript.set_xPos1(x1); + mScript.set_yPos1(y1); + mScript.set_xPos2(x2); + mScript.set_yPos2(y2); + + mScript.set_brightness(mParameters.getBrightness()); + mScript.set_contrast(mParameters.getContrast()); + mScript.set_saturation(mParameters.getSaturation()); + + mScript.invoke_setupGradParams(); + runSelectiveAdjust( + getInPixelsAllocation(), getOutPixelsAllocation()); + + } + + private void runSelectiveAdjust(Allocation in, Allocation out) { + int width = in.getType().getX(); + int height = in.getType().getY(); + + LaunchOptions options = new LaunchOptions(); + int ty; + options.setX(0, width); + + for (ty = 0; ty < height; ty += STRIP_SIZE) { + int endy = ty + STRIP_SIZE; + if (endy > height) { + endy = height; + } + options.setY(ty, endy); + mScript.forEach_selectiveAdjust(in, out, options); + if (checkStop()) { + return; + } + } + } + + private boolean checkStop() { + RenderScript rsCtx = getRenderScriptContext(); + rsCtx.finish(); + if (getEnvironment().needsStop()) { + return true; + } + return false; + } +} + diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java new file mode 100644 index 000000000..4c837e0bf --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; + +import com.android.gallery3d.R; + +public class ImageFilterHighlights extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "HIGHLIGHTS"; + private static final String LOGTAG = "ImageFilterVignette"; + + public ImageFilterHighlights() { + mName = "Highlights"; + } + + SplineMath mSpline = new SplineMath(5); + double[] mHighlightCurve = { 0.0, 0.32, 0.418, 0.476, 0.642 }; + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Highlights"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterHighlights.class); + representation.setTextId(R.string.highlight_recovery); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float[] luminanceMap); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + float p = getParameters().getValue(); + double t = p/100.; + for (int i = 0; i < 5; i++) { + double x = i / 4.; + double y = mHighlightCurve[i] *t+x*(1-t); + mSpline.setPoint(i, x, y); + } + + float[][] curve = mSpline.calculatetCurve(256); + float[] luminanceMap = new float[curve.length]; + for (int i = 0; i < luminanceMap.length; i++) { + luminanceMap[i] = curve[i][1]; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + nativeApplyFilter(bitmap, w, h, luminanceMap); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java new file mode 100644 index 000000000..b87c25490 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.BasicEditor; + +import android.graphics.Bitmap; + +public class ImageFilterHue extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "HUE"; + private ColorSpaceMatrix cmatrix = null; + + public ImageFilterHue() { + mName = "Hue"; + cmatrix = new ColorSpaceMatrix(); + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Hue"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterHue.class); + representation.setMinimum(-180); + representation.setMaximum(180); + representation.setTextId(R.string.hue); + representation.setEditorId(BasicEditor.ID); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float []matrix); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float value = getParameters().getValue(); + cmatrix.identity(); + cmatrix.setHue(value); + + nativeApplyFilter(bitmap, w, h, cmatrix.getMatrix()); + + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java new file mode 100644 index 000000000..77cdf47b3 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java @@ -0,0 +1,95 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.text.format.Time; + +import com.android.gallery3d.R; + +public class ImageFilterKMeans extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "KMEANS"; + private int mSeed = 0; + + public ImageFilterKMeans() { + mName = "KMeans"; + + // set random seed for session + Time t = new Time(); + t.setToNow(); + mSeed = (int) t.toMillis(false); + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("KMeans"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterKMeans.class); + representation.setMaximum(20); + representation.setMinimum(2); + representation.setValue(4); + representation.setDefaultValue(4); + representation.setPreviewValue(4); + representation.setTextId(R.string.kmeans); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int width, int height, + Bitmap large_ds_bm, int lwidth, int lheight, Bitmap small_ds_bm, + int swidth, int sheight, int p, int seed); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + Bitmap large_bm_ds = bitmap; + Bitmap small_bm_ds = bitmap; + + // find width/height for larger downsampled bitmap + int lw = w; + int lh = h; + while (lw > 256 && lh > 256) { + lw /= 2; + lh /= 2; + } + if (lw != w) { + large_bm_ds = Bitmap.createScaledBitmap(bitmap, lw, lh, true); + } + + // find width/height for smaller downsampled bitmap + int sw = lw; + int sh = lh; + while (sw > 64 && sh > 64) { + sw /= 2; + sh /= 2; + } + if (sw != lw) { + small_bm_ds = Bitmap.createScaledBitmap(large_bm_ds, sw, sh, true); + } + + if (getParameters() != null) { + int p = Math.max(getParameters().getValue(), getParameters().getMinimum()) % (getParameters().getMaximum() + 1); + nativeApplyFilter(bitmap, w, h, large_bm_ds, lw, lh, small_bm_ds, sw, sh, p, mSeed); + } + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java new file mode 100644 index 000000000..98497596b --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java @@ -0,0 +1,39 @@ +package com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; + +public class ImageFilterNegative extends ImageFilter { + private static final String SERIALIZATION_NAME = "NEGATIVE"; + public ImageFilterNegative() { + mName = "Negative"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterRepresentation representation = new FilterDirectRepresentation("Negative"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterNegative.class); + representation.setTextId(R.string.negative); + representation.setShowParameterValue(false); + representation.setEditorId(ImageOnlyEditor.ID); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h); + + @Override + public void useRepresentation(FilterRepresentation representation) { + + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + nativeApplyFilter(bitmap, w, h); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java new file mode 100644 index 000000000..25e5d1476 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterParametricBorder.java @@ -0,0 +1,69 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Path; +import android.graphics.RectF; + +public class ImageFilterParametricBorder extends ImageFilter { + private FilterColorBorderRepresentation mParameters = null; + + public ImageFilterParametricBorder() { + mName = "Border"; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterColorBorderRepresentation parameters = (FilterColorBorderRepresentation) representation; + mParameters = parameters; + } + + public FilterColorBorderRepresentation getParameters() { + return mParameters; + } + + private void applyHelper(Canvas canvas, int w, int h) { + if (getParameters() == null) { + return; + } + Path border = new Path(); + border.moveTo(0, 0); + float bs = getParameters().getBorderSize() / 100.0f * w; + float r = getParameters().getBorderRadius() / 100.0f * w; + border.lineTo(0, h); + border.lineTo(w, h); + border.lineTo(w, 0); + border.lineTo(0, 0); + border.addRoundRect(new RectF(bs, bs, w - bs, h - bs), + r, r, Path.Direction.CW); + + Paint paint = new Paint(); + paint.setAntiAlias(true); + paint.setColor(getParameters().getColor()); + canvas.drawPath(border, paint); + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + Canvas canvas = new Canvas(bitmap); + applyHelper(canvas, bitmap.getWidth(), bitmap.getHeight()); + return bitmap; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java new file mode 100644 index 000000000..5695ef53e --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRS.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.support.v8.renderscript.*; +import android.util.Log; +import android.content.res.Resources; +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.pipeline.PipelineInterface; + +public abstract class ImageFilterRS extends ImageFilter { + private static final String LOGTAG = "ImageFilterRS"; + private boolean DEBUG = false; + private int mLastInputWidth = 0; + private int mLastInputHeight = 0; + private long mLastTimeCalled; + + public static boolean PERF_LOGGING = false; + + private static ScriptC_grey mGreyConvert = null; + private static RenderScript mRScache = null; + + private volatile boolean mResourcesLoaded = false; + + protected abstract void createFilter(android.content.res.Resources res, + float scaleFactor, int quality); + + protected void createFilter(android.content.res.Resources res, + float scaleFactor, int quality, Allocation in) {} + protected void bindScriptValues(Allocation in) {} + + protected abstract void runFilter(); + + protected void update(Bitmap bitmap) { + getOutPixelsAllocation().copyTo(bitmap); + } + + protected RenderScript getRenderScriptContext() { + PipelineInterface pipeline = getEnvironment().getPipeline(); + return pipeline.getRSContext(); + } + + protected Allocation getInPixelsAllocation() { + PipelineInterface pipeline = getEnvironment().getPipeline(); + return pipeline.getInPixelsAllocation(); + } + + protected Allocation getOutPixelsAllocation() { + PipelineInterface pipeline = getEnvironment().getPipeline(); + return pipeline.getOutPixelsAllocation(); + } + + @Override + public void apply(Allocation in, Allocation out) { + long startOverAll = System.nanoTime(); + if (PERF_LOGGING) { + long delay = (startOverAll - mLastTimeCalled) / 1000; + String msg = String.format("%s; image size %dx%d; ", getName(), + in.getType().getX(), in.getType().getY()); + msg += String.format("called after %.2f ms (%.2f FPS); ", + delay / 1000.f, 1000000.f / delay); + Log.i(LOGTAG, msg); + } + mLastTimeCalled = startOverAll; + long startFilter = 0; + long endFilter = 0; + if (!mResourcesLoaded) { + PipelineInterface pipeline = getEnvironment().getPipeline(); + createFilter(pipeline.getResources(), getEnvironment().getScaleFactor(), + getEnvironment().getQuality(), in); + mResourcesLoaded = true; + } + startFilter = System.nanoTime(); + bindScriptValues(in); + run(in, out); + if (PERF_LOGGING) { + getRenderScriptContext().finish(); + endFilter = System.nanoTime(); + long endOverAll = System.nanoTime(); + String msg = String.format("%s; image size %dx%d; ", getName(), + in.getType().getX(), in.getType().getY()); + long timeOverAll = (endOverAll - startOverAll) / 1000; + long timeFilter = (endFilter - startFilter) / 1000; + msg += String.format("over all %.2f ms (%.2f FPS); ", + timeOverAll / 1000.f, 1000000.f / timeOverAll); + msg += String.format("run filter %.2f ms (%.2f FPS)", + timeFilter / 1000.f, 1000000.f / timeFilter); + Log.i(LOGTAG, msg); + } + } + + protected void run(Allocation in, Allocation out) {} + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (bitmap == null || bitmap.getWidth() == 0 || bitmap.getHeight() == 0) { + return bitmap; + } + try { + PipelineInterface pipeline = getEnvironment().getPipeline(); + if (DEBUG) { + Log.v(LOGTAG, "apply filter " + getName() + " in pipeline " + pipeline.getName()); + } + Resources rsc = pipeline.getResources(); + boolean sizeChanged = false; + if (getInPixelsAllocation() != null + && ((getInPixelsAllocation().getType().getX() != mLastInputWidth) + || (getInPixelsAllocation().getType().getY() != mLastInputHeight))) { + sizeChanged = true; + } + if (pipeline.prepareRenderscriptAllocations(bitmap) + || !isResourcesLoaded() || sizeChanged) { + freeResources(); + createFilter(rsc, scaleFactor, quality); + setResourcesLoaded(true); + mLastInputWidth = getInPixelsAllocation().getType().getX(); + mLastInputHeight = getInPixelsAllocation().getType().getY(); + } + bindScriptValues(); + runFilter(); + update(bitmap); + if (DEBUG) { + Log.v(LOGTAG, "DONE apply filter " + getName() + " in pipeline " + pipeline.getName()); + } + } catch (android.renderscript.RSIllegalArgumentException e) { + Log.e(LOGTAG, "Illegal argument? " + e); + } catch (android.renderscript.RSRuntimeException e) { + Log.e(LOGTAG, "RS runtime exception ? " + e); + } catch (java.lang.OutOfMemoryError e) { + // Many of the renderscript filters allocated large (>16Mb resources) in order to apply. + System.gc(); + displayLowMemoryToast(); + Log.e(LOGTAG, "not enough memory for filter " + getName(), e); + } + return bitmap; + } + + protected static Allocation convertBitmap(RenderScript RS, Bitmap bitmap) { + return Allocation.createFromBitmap(RS, bitmap, + Allocation.MipmapControl.MIPMAP_NONE, + Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE); + } + + private static Allocation convertRGBAtoA(RenderScript RS, Bitmap bitmap) { + if (RS != mRScache || mGreyConvert == null) { + mGreyConvert = new ScriptC_grey(RS, RS.getApplicationContext().getResources(), + R.raw.grey); + mRScache = RS; + } + + Type.Builder tb_a8 = new Type.Builder(RS, Element.A_8(RS)); + + Allocation bitmapTemp = convertBitmap(RS, bitmap); + if (bitmapTemp.getType().getElement().isCompatible(Element.A_8(RS))) { + return bitmapTemp; + } + + tb_a8.setX(bitmapTemp.getType().getX()); + tb_a8.setY(bitmapTemp.getType().getY()); + Allocation bitmapAlloc = Allocation.createTyped(RS, tb_a8.create(), + Allocation.MipmapControl.MIPMAP_NONE, + Allocation.USAGE_SCRIPT | Allocation.USAGE_GRAPHICS_TEXTURE); + mGreyConvert.forEach_RGBAtoA(bitmapTemp, bitmapAlloc); + bitmapTemp.destroy(); + return bitmapAlloc; + } + + public Allocation loadScaledResourceAlpha(int resource, int inSampleSize) { + Resources res = getEnvironment().getPipeline().getResources(); + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ALPHA_8; + options.inSampleSize = inSampleSize; + Bitmap bitmap = BitmapFactory.decodeResource( + res, + resource, options); + Allocation ret = convertRGBAtoA(getRenderScriptContext(), bitmap); + bitmap.recycle(); + return ret; + } + + public Allocation loadScaledResourceAlpha(int resource, int w, int h, int inSampleSize) { + Resources res = getEnvironment().getPipeline().getResources(); + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ALPHA_8; + options.inSampleSize = inSampleSize; + Bitmap bitmap = BitmapFactory.decodeResource( + res, + resource, options); + Bitmap resizeBitmap = Bitmap.createScaledBitmap(bitmap, w, h, true); + Allocation ret = convertRGBAtoA(getRenderScriptContext(), resizeBitmap); + resizeBitmap.recycle(); + bitmap.recycle(); + return ret; + } + + public Allocation loadResourceAlpha(int resource) { + return loadScaledResourceAlpha(resource, 1); + } + + public Allocation loadResource(int resource) { + Resources res = getEnvironment().getPipeline().getResources(); + final BitmapFactory.Options options = new BitmapFactory.Options(); + options.inPreferredConfig = Bitmap.Config.ARGB_8888; + Bitmap bitmap = BitmapFactory.decodeResource( + res, + resource, options); + Allocation ret = convertBitmap(getRenderScriptContext(), bitmap); + bitmap.recycle(); + return ret; + } + + private boolean isResourcesLoaded() { + return mResourcesLoaded; + } + + private void setResourcesLoaded(boolean resourcesLoaded) { + mResourcesLoaded = resourcesLoaded; + } + + /** + * Bitmaps and RS Allocations should be cleared here + */ + abstract protected void resetAllocations(); + + /** + * RS Script objects (and all other RS objects) should be cleared here + */ + public abstract void resetScripts(); + + /** + * Scripts values should be bound here + */ + abstract protected void bindScriptValues(); + + public void freeResources() { + if (!isResourcesLoaded()) { + return; + } + resetAllocations(); + mLastInputWidth = 0; + mLastInputHeight = 0; + setResourcesLoaded(false); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java new file mode 100644 index 000000000..511f9e90f --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterRedEye.java @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Matrix; +import android.graphics.RectF; + +import java.util.Vector; + +public class ImageFilterRedEye extends ImageFilter { + private static final String LOGTAG = "ImageFilterRedEye"; + FilterRedEyeRepresentation mParameters = new FilterRedEyeRepresentation(); + + public ImageFilterRedEye() { + mName = "Red Eye"; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterRedEyeRepresentation(); + } + + public boolean isNil() { + return mParameters.isNil(); + } + + public Vector<FilterPoint> getCandidates() { + return mParameters.getCandidates(); + } + + public void clear() { + mParameters.clearCandidates(); + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, short[] matrix); + + @Override + public void useRepresentation(FilterRepresentation representation) { + FilterRedEyeRepresentation parameters = (FilterRedEyeRepresentation) representation; + mParameters = parameters; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + short[] rect = new short[4]; + + int size = mParameters.getNumberOfCandidates(); + Matrix originalToScreen = getOriginalToScreenMatrix(w, h); + for (int i = 0; i < size; i++) { + RectF r = new RectF(((RedEyeCandidate) (mParameters.getCandidate(i))).mRect); + originalToScreen.mapRect(r); + if (r.intersect(0, 0, w, h)) { + rect[0] = (short) r.left; + rect[1] = (short) r.top; + rect[2] = (short) r.width(); + rect[3] = (short) r.height(); + nativeApplyFilter(bitmap, w, h, rect); + } + } + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java new file mode 100644 index 000000000..c3124ff77 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; + +public class ImageFilterSaturated extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "SATURATED"; + public ImageFilterSaturated() { + mName = "Saturated"; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Saturated"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterSaturated.class); + representation.setTextId(R.string.saturation); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float saturation); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + int p = getParameters().getValue(); + float value = 1 + p / 100.0f; + nativeApplyFilter(bitmap, w, h, value); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java new file mode 100644 index 000000000..bd119bbc9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; + +public class ImageFilterShadows extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "SHADOWS"; + public ImageFilterShadows() { + mName = "Shadows"; + + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Shadows"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterShadows.class); + representation.setTextId(R.string.shadow_recovery); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float factor); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float p = getParameters().getValue(); + + nativeApplyFilter(bitmap, w, h, p); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java new file mode 100644 index 000000000..3bd794464 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java @@ -0,0 +1,107 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +public class ImageFilterSharpen extends ImageFilterRS { + private static final String SERIALIZATION_NAME = "SHARPEN"; + private static final String LOGTAG = "ImageFilterSharpen"; + private ScriptC_convolve3x3 mScript; + + private FilterBasicRepresentation mParameters; + + public ImageFilterSharpen() { + mName = "Sharpen"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterRepresentation representation = new FilterBasicRepresentation("Sharpen", 0, 0, 100); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setShowParameterValue(true); + representation.setFilterClass(ImageFilterSharpen.class); + representation.setTextId(R.string.sharpness); + representation.setOverlayId(R.drawable.filtershow_button_colors_sharpen); + representation.setEditorId(R.id.imageShow); + representation.setSupportsPartialRendering(true); + return representation; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation; + mParameters = parameters; + } + + @Override + protected void resetAllocations() { + // nothing to do + } + + @Override + public void resetScripts() { + if (mScript != null) { + mScript.destroy(); + mScript = null; + } + } + + @Override + protected void createFilter(android.content.res.Resources res, float scaleFactor, + int quality) { + if (mScript == null) { + mScript = new ScriptC_convolve3x3(getRenderScriptContext(), res, R.raw.convolve3x3); + } + } + + private void computeKernel() { + float scaleFactor = getEnvironment().getScaleFactor(); + float p1 = mParameters.getValue() * scaleFactor; + float value = p1 / 100.0f; + float f[] = new float[9]; + float p = value; + f[0] = -p; + f[1] = -p; + f[2] = -p; + f[3] = -p; + f[4] = 8 * p + 1; + f[5] = -p; + f[6] = -p; + f[7] = -p; + f[8] = -p; + mScript.set_gCoeffs(f); + } + + @Override + protected void bindScriptValues() { + int w = getInPixelsAllocation().getType().getX(); + int h = getInPixelsAllocation().getType().getY(); + mScript.set_gWidth(w); + mScript.set_gHeight(h); + } + + @Override + protected void runFilter() { + if (mParameters == null) { + return; + } + computeKernel(); + mScript.set_gIn(getInPixelsAllocation()); + mScript.bind_gPixels(getInPixelsAllocation()); + mScript.forEach_root(getInPixelsAllocation(), getOutPixelsAllocation()); + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java new file mode 100644 index 000000000..77250bd7a --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTinyPlanet.java @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.RectF; + +import com.adobe.xmp.XMPException; +import com.adobe.xmp.XMPMeta; +import com.android.gallery3d.app.Log; +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; + +/** + * An image filter which creates a tiny planet projection. + */ +public class ImageFilterTinyPlanet extends SimpleImageFilter { + + + private static final String LOGTAG = ImageFilterTinyPlanet.class.getSimpleName(); + public static final String GOOGLE_PANO_NAMESPACE = "http://ns.google.com/photos/1.0/panorama/"; + FilterTinyPlanetRepresentation mParameters = new FilterTinyPlanetRepresentation(); + + public static final String CROPPED_AREA_IMAGE_WIDTH_PIXELS = + "CroppedAreaImageWidthPixels"; + public static final String CROPPED_AREA_IMAGE_HEIGHT_PIXELS = + "CroppedAreaImageHeightPixels"; + public static final String CROPPED_AREA_FULL_PANO_WIDTH_PIXELS = + "FullPanoWidthPixels"; + public static final String CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS = + "FullPanoHeightPixels"; + public static final String CROPPED_AREA_LEFT = + "CroppedAreaLeftPixels"; + public static final String CROPPED_AREA_TOP = + "CroppedAreaTopPixels"; + + public ImageFilterTinyPlanet() { + mName = "TinyPlanet"; + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + FilterTinyPlanetRepresentation parameters = (FilterTinyPlanetRepresentation) representation; + mParameters = parameters; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + return new FilterTinyPlanetRepresentation(); + } + + + native protected void nativeApplyFilter( + Bitmap bitmapIn, int width, int height, Bitmap bitmapOut, int outSize, float scale, + float angle); + + + @Override + public Bitmap apply(Bitmap bitmapIn, float scaleFactor, int quality) { + int w = bitmapIn.getWidth(); + int h = bitmapIn.getHeight(); + int outputSize = (int) (w / 2f); + ImagePreset preset = getEnvironment().getImagePreset(); + Bitmap mBitmapOut = null; + if (preset != null) { + XMPMeta xmp = ImageLoader.getXmpObject(MasterImage.getImage().getActivity()); + // Do nothing, just use bitmapIn as is if we don't have XMP. + if(xmp != null) { + bitmapIn = applyXmp(bitmapIn, xmp, w); + } + } + if (mBitmapOut != null) { + if (outputSize != mBitmapOut.getHeight()) { + mBitmapOut = null; + } + } + while (mBitmapOut == null) { + try { + mBitmapOut = getEnvironment().getBitmap(outputSize, outputSize); + } catch (java.lang.OutOfMemoryError e) { + System.gc(); + outputSize /= 2; + Log.v(LOGTAG, "No memory to create Full Tiny Planet create half"); + } + } + nativeApplyFilter(bitmapIn, bitmapIn.getWidth(), bitmapIn.getHeight(), mBitmapOut, + outputSize, mParameters.getZoom() / 100f, mParameters.getAngle()); + + return mBitmapOut; + } + + private Bitmap applyXmp(Bitmap bitmapIn, XMPMeta xmp, int intermediateWidth) { + try { + int croppedAreaWidth = + getInt(xmp, CROPPED_AREA_IMAGE_WIDTH_PIXELS); + int croppedAreaHeight = + getInt(xmp, CROPPED_AREA_IMAGE_HEIGHT_PIXELS); + int fullPanoWidth = + getInt(xmp, CROPPED_AREA_FULL_PANO_WIDTH_PIXELS); + int fullPanoHeight = + getInt(xmp, CROPPED_AREA_FULL_PANO_HEIGHT_PIXELS); + int left = getInt(xmp, CROPPED_AREA_LEFT); + int top = getInt(xmp, CROPPED_AREA_TOP); + + if (fullPanoWidth == 0 || fullPanoHeight == 0) { + return bitmapIn; + } + // Make sure the intermediate image has the similar size to the + // input. + Bitmap paddedBitmap = null; + float scale = intermediateWidth / (float) fullPanoWidth; + while (paddedBitmap == null) { + try { + paddedBitmap = Bitmap.createBitmap( + (int) (fullPanoWidth * scale), (int) (fullPanoHeight * scale), + Bitmap.Config.ARGB_8888); + } catch (java.lang.OutOfMemoryError e) { + System.gc(); + scale /= 2; + } + } + Canvas paddedCanvas = new Canvas(paddedBitmap); + + int right = left + croppedAreaWidth; + int bottom = top + croppedAreaHeight; + RectF destRect = new RectF(left * scale, top * scale, right * scale, bottom * scale); + paddedCanvas.drawBitmap(bitmapIn, null, destRect, null); + bitmapIn = paddedBitmap; + } catch (XMPException ex) { + // Do nothing, just use bitmapIn as is. + } + return bitmapIn; + } + + private static int getInt(XMPMeta xmp, String key) throws XMPException { + if (xmp.doesPropertyExist(GOOGLE_PANO_NAMESPACE, key)) { + return xmp.getPropertyInteger(GOOGLE_PANO_NAMESPACE, key); + } else { + return 0; + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java new file mode 100644 index 000000000..86be9a155 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; + +import android.graphics.Bitmap; + +public class ImageFilterVibrance extends SimpleImageFilter { + private static final String SERIALIZATION_NAME = "VIBRANCE"; + public ImageFilterVibrance() { + mName = "Vibrance"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterBasicRepresentation representation = + (FilterBasicRepresentation) super.getDefaultRepresentation(); + representation.setName("Vibrance"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterVibrance.class); + representation.setTextId(R.string.vibrance); + representation.setMinimum(-100); + representation.setMaximum(100); + representation.setDefaultValue(0); + representation.setSupportsPartialRendering(true); + return representation; + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, float bright); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float value = getParameters().getValue(); + nativeApplyFilter(bitmap, w, h, value); + + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java new file mode 100644 index 000000000..7e0a452bf --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterVignette.java @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Rect; +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; + +public class ImageFilterVignette extends SimpleImageFilter { + private static final String LOGTAG = "ImageFilterVignette"; + private Bitmap mOverlayBitmap; + + public ImageFilterVignette() { + mName = "Vignette"; + } + + @Override + public FilterRepresentation getDefaultRepresentation() { + FilterVignetteRepresentation representation = new FilterVignetteRepresentation(); + return representation; + } + + native protected void nativeApplyFilter( + Bitmap bitmap, int w, int h, int cx, int cy, float radx, float rady, float strength); + + private float calcRadius(float cx, float cy, int w, int h) { + float d = cx; + if (d < (w - cx)) { + d = w - cx; + } + if (d < cy) { + d = cy; + } + if (d < (h - cy)) { + d = h - cy; + } + return d * d * 2.0f; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (SIMPLE_ICONS && FilterEnvironment.QUALITY_ICON == quality) { + if (mOverlayBitmap == null) { + Resources res = getEnvironment().getPipeline().getResources(); + mOverlayBitmap = IconUtilities.getFXBitmap(res, + R.drawable.filtershow_icon_vignette); + } + Canvas c = new Canvas(bitmap); + int dim = Math.max(bitmap.getWidth(), bitmap.getHeight()); + Rect r = new Rect(0, 0, dim, dim); + c.drawBitmap(mOverlayBitmap, null, r, null); + return bitmap; + } + FilterVignetteRepresentation rep = (FilterVignetteRepresentation) getParameters(); + if (rep == null) { + return bitmap; + } + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + float value = rep.getValue() / 100.0f; + float cx = w / 2; + float cy = h / 2; + float r = calcRadius(cx, cy, w, h); + float rx = r; + float ry = r; + if (rep.isCenterSet()) { + Matrix m = getOriginalToScreenMatrix(w, h); + cx = rep.getCenterX(); + cy = rep.getCenterY(); + float[] center = new float[] { cx, cy }; + m.mapPoints(center); + cx = center[0]; + cy = center[1]; + rx = m.mapRadius(rep.getRadiusX()); + ry = m.mapRadius(rep.getRadiusY()); + } + nativeApplyFilter(bitmap, w, h, (int) cx, (int) cy, rx, ry, value); + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java new file mode 100644 index 000000000..6bb88ec21 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2012 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 com.android.gallery3d.filtershow.filters; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; + +import android.graphics.Bitmap; + +public class ImageFilterWBalance extends ImageFilter { + private static final String SERIALIZATION_NAME = "WBALANCE"; + private static final String TAG = "ImageFilterWBalance"; + + public ImageFilterWBalance() { + mName = "WBalance"; + } + + public FilterRepresentation getDefaultRepresentation() { + FilterRepresentation representation = new FilterDirectRepresentation("WBalance"); + representation.setSerializationName(SERIALIZATION_NAME); + representation.setFilterClass(ImageFilterWBalance.class); + representation.setFilterType(FilterRepresentation.TYPE_WBALANCE); + representation.setTextId(R.string.wbalance); + representation.setShowParameterValue(false); + representation.setEditorId(ImageOnlyEditor.ID); + representation.setSupportsPartialRendering(true); + return representation; + } + + @Override + public void useRepresentation(FilterRepresentation representation) { + + } + + native protected void nativeApplyFilter(Bitmap bitmap, int w, int h, int locX, int locY); + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + nativeApplyFilter(bitmap, w, h, -1, -1); + return bitmap; + } + +} diff --git a/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java new file mode 100644 index 000000000..a40d4fa3b --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/RedEyeCandidate.java @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +import android.graphics.RectF; + +public class RedEyeCandidate implements FilterPoint { + RectF mRect = new RectF(); + RectF mBounds = new RectF(); + + public RedEyeCandidate(RedEyeCandidate candidate) { + mRect.set(candidate.mRect); + mBounds.set(candidate.mBounds); + } + + public RedEyeCandidate(RectF rect, RectF bounds) { + mRect.set(rect); + mBounds.set(bounds); + } + + public boolean equals(RedEyeCandidate candidate) { + if (candidate.mRect.equals(mRect) + && candidate.mBounds.equals(mBounds)) { + return true; + } + return false; + } + + public boolean intersect(RectF rect) { + return mRect.intersect(rect); + } + + public RectF getRect() { + return mRect; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java new file mode 100644 index 000000000..c891d20f3 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/SimpleImageFilter.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2013 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 com.android.gallery3d.filtershow.filters; + +public class SimpleImageFilter extends ImageFilter { + + private FilterBasicRepresentation mParameters; + + public FilterRepresentation getDefaultRepresentation() { + FilterRepresentation representation = new FilterBasicRepresentation("Default", 0, 50, 100); + representation.setShowParameterValue(true); + return representation; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation; + mParameters = parameters; + } + + public FilterBasicRepresentation getParameters() { + return mParameters; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/SplineMath.java b/src/com/android/gallery3d/filtershow/filters/SplineMath.java new file mode 100644 index 000000000..5b12d0a61 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/SplineMath.java @@ -0,0 +1,166 @@ +package com.android.gallery3d.filtershow.filters; + + +public class SplineMath { + double[][] mPoints = new double[6][2]; + double[] mDerivatives; + SplineMath(int n) { + mPoints = new double[n][2]; + } + + public void setPoint(int index, double x, double y) { + mPoints[index][0] = x; + mPoints[index][1] = y; + mDerivatives = null; + } + + public float[][] calculatetCurve(int n) { + float[][] curve = new float[n][2]; + double[][] points = new double[mPoints.length][2]; + for (int i = 0; i < mPoints.length; i++) { + + points[i][0] = mPoints[i][0]; + points[i][1] = mPoints[i][1]; + + } + double[] derivatives = solveSystem(points); + float start = (float) points[0][0]; + float end = (float) (points[points.length - 1][0]); + + curve[0][0] = (float) (points[0][0]); + curve[0][1] = (float) (points[0][1]); + int last = curve.length - 1; + curve[last][0] = (float) (points[points.length - 1][0]); + curve[last][1] = (float) (points[points.length - 1][1]); + + for (int i = 0; i < curve.length; i++) { + + double[] cur = null; + double[] next = null; + double x = start + i * (end - start) / (curve.length - 1); + int pivot = 0; + for (int j = 0; j < points.length - 1; j++) { + if (x >= points[j][0] && x <= points[j + 1][0]) { + pivot = j; + } + } + cur = points[pivot]; + next = points[pivot + 1]; + if (x <= next[0]) { + double x1 = cur[0]; + double x2 = next[0]; + double y1 = cur[1]; + double y2 = next[1]; + + // Use the second derivatives to apply the cubic spline + // equation: + double delta = (x2 - x1); + double delta2 = delta * delta; + double b = (x - x1) / delta; + double a = 1 - b; + double ta = a * y1; + double tb = b * y2; + double tc = (a * a * a - a) * derivatives[pivot]; + double td = (b * b * b - b) * derivatives[pivot + 1]; + double y = ta + tb + (delta2 / 6) * (tc + td); + + curve[i][0] = (float) (x); + curve[i][1] = (float) (y); + } else { + curve[i][0] = (float) (next[0]); + curve[i][1] = (float) (next[1]); + } + } + return curve; + } + + public double getValue(double x) { + double[] cur = null; + double[] next = null; + if (mDerivatives == null) + mDerivatives = solveSystem(mPoints); + int pivot = 0; + for (int j = 0; j < mPoints.length - 1; j++) { + pivot = j; + if (x <= mPoints[j][0]) { + break; + } + } + cur = mPoints[pivot]; + next = mPoints[pivot + 1]; + double x1 = cur[0]; + double x2 = next[0]; + double y1 = cur[1]; + double y2 = next[1]; + + // Use the second derivatives to apply the cubic spline + // equation: + double delta = (x2 - x1); + double delta2 = delta * delta; + double b = (x - x1) / delta; + double a = 1 - b; + double ta = a * y1; + double tb = b * y2; + double tc = (a * a * a - a) * mDerivatives[pivot]; + double td = (b * b * b - b) * mDerivatives[pivot + 1]; + double y = ta + tb + (delta2 / 6) * (tc + td); + + return y; + + } + + double[] solveSystem(double[][] points) { + int n = points.length; + double[][] system = new double[n][3]; + double[] result = new double[n]; // d + double[] solution = new double[n]; // returned coefficients + system[0][1] = 1; + system[n - 1][1] = 1; + double d6 = 1.0 / 6.0; + double d3 = 1.0 / 3.0; + + // let's create a tridiagonal matrix representing the + // system, and apply the TDMA algorithm to solve it + // (see http://en.wikipedia.org/wiki/Tridiagonal_matrix_algorithm) + for (int i = 1; i < n - 1; i++) { + double deltaPrevX = points[i][0] - points[i - 1][0]; + double deltaX = points[i + 1][0] - points[i - 1][0]; + double deltaNextX = points[i + 1][0] - points[i][0]; + double deltaNextY = points[i + 1][1] - points[i][1]; + double deltaPrevY = points[i][1] - points[i - 1][1]; + system[i][0] = d6 * deltaPrevX; // a_i + system[i][1] = d3 * deltaX; // b_i + system[i][2] = d6 * deltaNextX; // c_i + result[i] = (deltaNextY / deltaNextX) - (deltaPrevY / deltaPrevX); // d_i + } + + // Forward sweep + for (int i = 1; i < n; i++) { + // m = a_i/b_i-1 + double m = system[i][0] / system[i - 1][1]; + // b_i = b_i - m(c_i-1) + system[i][1] = system[i][1] - m * system[i - 1][2]; + // d_i = d_i - m(d_i-1) + result[i] = result[i] - m * result[i - 1]; + } + + // Back substitution + solution[n - 1] = result[n - 1] / system[n - 1][1]; + for (int i = n - 2; i >= 0; --i) { + solution[i] = (result[i] - system[i][2] * solution[i + 1]) / system[i][1]; + } + return solution; + } + + public static void main(String[] args) { + SplineMath s = new SplineMath(10); + for (int i = 0; i < 10; i++) { + s.setPoint(i, i, i); + } + float[][] curve = s.calculatetCurve(40); + + for (int j = 0; j < curve.length; j++) { + System.out.println(curve[j][0] + "," + curve[j][1]); + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs b/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs new file mode 100644 index 000000000..2acffab06 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/convolve3x3.rs @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2012 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.gallery3d.filtershow.filters) +#pragma rs_fp_relaxed + +int32_t gWidth; +int32_t gHeight; +const uchar4 *gPixels; +rs_allocation gIn; + +float gCoeffs[9]; + +void root(const uchar4 *in, uchar4 *out, const void *usrData, uint32_t x, uint32_t y) { + uint32_t x1 = min((int32_t)x+1, gWidth-1); + uint32_t x2 = max((int32_t)x-1, 0); + uint32_t y1 = min((int32_t)y+1, gHeight-1); + uint32_t y2 = max((int32_t)y-1, 0); + + float4 p00 = rsUnpackColor8888(gPixels[x1 + gWidth * y1]); + float4 p01 = rsUnpackColor8888(gPixels[x + gWidth * y1]); + float4 p02 = rsUnpackColor8888(gPixels[x2 + gWidth * y1]); + float4 p10 = rsUnpackColor8888(gPixels[x1 + gWidth * y]); + float4 p11 = rsUnpackColor8888(gPixels[x + gWidth * y]); + float4 p12 = rsUnpackColor8888(gPixels[x2 + gWidth * y]); + float4 p20 = rsUnpackColor8888(gPixels[x1 + gWidth * y2]); + float4 p21 = rsUnpackColor8888(gPixels[x + gWidth * y2]); + float4 p22 = rsUnpackColor8888(gPixels[x2 + gWidth * y2]); + + p00 *= gCoeffs[0]; + p01 *= gCoeffs[1]; + p02 *= gCoeffs[2]; + p10 *= gCoeffs[3]; + p11 *= gCoeffs[4]; + p12 *= gCoeffs[5]; + p20 *= gCoeffs[6]; + p21 *= gCoeffs[7]; + p22 *= gCoeffs[8]; + + p00 += p01; + p02 += p10; + p11 += p12; + p20 += p21; + + p22 += p00; + p02 += p11; + + p20 += p22; + p20 += p02; + + p20 = clamp(p20, 0.f, 1.f); + *out = rsPackColorTo8888(p20.r, p20.g, p20.b); +} diff --git a/src/com/android/gallery3d/filtershow/filters/grad.rs b/src/com/android/gallery3d/filtershow/filters/grad.rs new file mode 100644 index 000000000..ddbafd349 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/grad.rs @@ -0,0 +1,121 @@ +/* + * Copyright (C) 2012 Unknown + * + * 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.gallery3d.filtershow.filters) + +#define MAX_POINTS 16 + +uint32_t inputWidth; +uint32_t inputHeight; +static const float Rf = 0.2999f; +static const float Gf = 0.587f; +static const float Bf = 0.114f; +//static const float size_scale = 0.01f; + +typedef struct { + rs_matrix3x3 colorMatrix; + float rgbOff; + float dx; + float dy; + float off; +} UPointData; +int mNumberOfLines; +// input data +bool mask[MAX_POINTS]; +int xPos1[MAX_POINTS]; +int yPos1[MAX_POINTS]; +int xPos2[MAX_POINTS]; +int yPos2[MAX_POINTS]; +int size[MAX_POINTS]; +int brightness[MAX_POINTS]; +int contrast[MAX_POINTS]; +int saturation[MAX_POINTS]; + +// generated data +static UPointData grads[MAX_POINTS]; + +void setupGradParams() { + int k = 0; + for (int i = 0; i < MAX_POINTS; i++) { + if (!mask[i]) { + continue; + } + float x1 = xPos1[i]; + float y1 = yPos1[i]; + float x2 = xPos2[i]; + float y2 = yPos2[i]; + + float denom = (y2 * y2 - 2 * y1 * y2 + x2 * x2 - 2 * x1 * x2 + y1 * y1 + x1 * x1); + if (denom == 0) { + continue; + } + grads[k].dy = (y1 - y2) / denom; + grads[k].dx = (x1 - x2) / denom; + grads[k].off = (y2 * y2 + x2 * x2 - x1 * x2 - y1 * y2) / denom; + + float S = 1+saturation[i]/100.f; + float MS = 1-S; + float Rt = Rf * MS; + float Gt = Gf * MS; + float Bt = Bf * MS; + + float b = 1+brightness[i]/100.f; + float c = 1+contrast[i]/100.f; + b *= c; + grads[k].rgbOff = .5f - c/2.f; + rsMatrixSet(&grads[i].colorMatrix, 0, 0, b * (Rt + S)); + rsMatrixSet(&grads[i].colorMatrix, 1, 0, b * Gt); + rsMatrixSet(&grads[i].colorMatrix, 2, 0, b * Bt); + rsMatrixSet(&grads[i].colorMatrix, 0, 1, b * Rt); + rsMatrixSet(&grads[i].colorMatrix, 1, 1, b * (Gt + S)); + rsMatrixSet(&grads[i].colorMatrix, 2, 1, b * Bt); + rsMatrixSet(&grads[i].colorMatrix, 0, 2, b * Rt); + rsMatrixSet(&grads[i].colorMatrix, 1, 2, b * Gt); + rsMatrixSet(&grads[i].colorMatrix, 2, 2, b * (Bt + S)); + + k++; + } + mNumberOfLines = k; +} + +void init() { + +} + +uchar4 __attribute__((kernel)) selectiveAdjust(const uchar4 in, uint32_t x, + uint32_t y) { + float4 pixel = rsUnpackColor8888(in); + + float4 wsum = pixel; + wsum.a = 0.f; + for (int i = 0; i < mNumberOfLines; i++) { + UPointData* grad = &grads[i]; + float t = clamp(x*grad->dx+y*grad->dy+grad->off,0.f,1.0f); + wsum.xyz = wsum.xyz*(1-t)+ + t*(rsMatrixMultiply(&grad->colorMatrix ,wsum.xyz)+grad->rgbOff); + + } + + pixel.rgb = wsum.rgb; + pixel.a = 1.0f; + + uchar4 out = rsPackColorTo8888(clamp(pixel, 0.f, 1.0f)); + return out; +} + + + diff --git a/src/com/android/gallery3d/filtershow/filters/grey.rs b/src/com/android/gallery3d/filtershow/filters/grey.rs new file mode 100644 index 000000000..e01880360 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/grey.rs @@ -0,0 +1,22 @@ + /* + * Copyright (C) 2013 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.gallery3d.filtershow.filters) + +uchar __attribute__((kernel)) RGBAtoA(uchar4 in) { + return in.r; +} diff --git a/src/com/android/gallery3d/filtershow/filters/saturation.rs b/src/com/android/gallery3d/filtershow/filters/saturation.rs new file mode 100644 index 000000000..5210e34a3 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/saturation.rs @@ -0,0 +1,161 @@ +/* + * Copyright (C) 2012 Unknown + * + * 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. + */ + +#pragma version(1) +#pragma rs java_package_name(com.android.gallery3d.filtershow.filters) + +#define MAX_CHANELS 7 +#define MAX_HUE 4096 +static const int ABITS = 4; +static const int HSCALE = 256; +static const int k1=255 << ABITS; +static const int k2=HSCALE << ABITS; + +static const float Rf = 0.2999f; +static const float Gf = 0.587f; +static const float Bf = 0.114f; + +rs_matrix3x3 colorMatrix_min; +rs_matrix3x3 colorMatrix_max; + +int mNumberOfLines; +// input data +int saturation[MAX_CHANELS]; +float sat[MAX_CHANELS]; + +float satLut[MAX_HUE]; +// generated data + + +void setupGradParams() { + + int master = saturation[0]; + int max = master+saturation[1]; + int min = max; + + // calculate the minimum and maximum saturation + for (int i = 1; i < MAX_CHANELS; i++) { + int v = master+saturation[i]; + if (max < v) { + max = v; + } + else if (min > v) { + min = v; + } + } + // generate a lookup table for all hue 0 to 4K which goes from 0 to 1 0=min sat 1 = max sat + min = min - 1; + for(int i = 0; i < MAX_HUE ; i++) { + float p = i * 6 / (float)MAX_HUE; + int ip = ((int)(p + .5f)) % 6; + int v = master + saturation[ip + 1]; + satLut[i] = (v - min)/(float)(max - min); + } + + float S = 1 + max / 100.f; + float MS = 1 - S; + float Rt = Rf * MS; + float Gt = Gf * MS; + float Bt = Bf * MS; + float b = 1.f; + + // Generate 2 color matrix one at min sat and one at max + rsMatrixSet(&colorMatrix_max, 0, 0, b * (Rt + S)); + rsMatrixSet(&colorMatrix_max, 1, 0, b * Gt); + rsMatrixSet(&colorMatrix_max, 2, 0, b * Bt); + rsMatrixSet(&colorMatrix_max, 0, 1, b * Rt); + rsMatrixSet(&colorMatrix_max, 1, 1, b * (Gt + S)); + rsMatrixSet(&colorMatrix_max, 2, 1, b * Bt); + rsMatrixSet(&colorMatrix_max, 0, 2, b * Rt); + rsMatrixSet(&colorMatrix_max, 1, 2, b * Gt); + rsMatrixSet(&colorMatrix_max, 2, 2, b * (Bt + S)); + + S = 1 + min / 100.f; + MS = 1-S; + Rt = Rf * MS; + Gt = Gf * MS; + Bt = Bf * MS; + b = 1; + + rsMatrixSet(&colorMatrix_min, 0, 0, b * (Rt + S)); + rsMatrixSet(&colorMatrix_min, 1, 0, b * Gt); + rsMatrixSet(&colorMatrix_min, 2, 0, b * Bt); + rsMatrixSet(&colorMatrix_min, 0, 1, b * Rt); + rsMatrixSet(&colorMatrix_min, 1, 1, b * (Gt + S)); + rsMatrixSet(&colorMatrix_min, 2, 1, b * Bt); + rsMatrixSet(&colorMatrix_min, 0, 2, b * Rt); + rsMatrixSet(&colorMatrix_min, 1, 2, b * Gt); + rsMatrixSet(&colorMatrix_min, 2, 2, b * (Bt + S)); +} + +static ushort rgb2hue( uchar4 rgb) +{ + int iMin,iMax,chroma; + + int ri = rgb.r; + int gi = rgb.g; + int bi = rgb.b; + short rv,rs,rh; + + if (ri > gi) { + iMax = max (ri, bi); + iMin = min (gi, bi); + } else { + iMax = max (gi, bi); + iMin = min (ri, bi); + } + + rv = (short) (iMax << ABITS); + + if (rv == 0) { + return 0; + } + + chroma = iMax - iMin; + rs = (short) ((k1 * chroma) / iMax); + if (rs == 0) { + return 0; + } + + if ( ri == iMax ) { + rh = (short) ((k2 * (6 * chroma + gi - bi))/(6 * chroma)); + if (rh >= k2) { + rh -= k2; + } + return rh; + } + + if (gi == iMax) { + return(short) ((k2 * (2 * chroma + bi - ri)) / (6 * chroma)); + } + + return (short) ((k2 * (4 * chroma + ri - gi)) / (6 * chroma)); +} + +uchar4 __attribute__((kernel)) selectiveAdjust(const uchar4 in, uint32_t x, + uint32_t y) { + float4 pixel = rsUnpackColor8888(in); + + float4 wsum = pixel; + int hue = rgb2hue(in); + + float t = satLut[hue]; + pixel.xyz = rsMatrixMultiply(&colorMatrix_min ,pixel.xyz) * (1 - t) + + t * (rsMatrixMultiply(&colorMatrix_max ,pixel.xyz)); + + pixel.a = 1.0f; + return rsPackColorTo8888(clamp(pixel, 0.f, 1.0f)); +}
\ No newline at end of file |