From 014bbe68d6e407269a0d843083be56f8df58adba Mon Sep 17 00:00:00 2001 From: John Hoford Date: Tue, 30 Jul 2013 14:40:18 -0700 Subject: add Per Channel Saturation Change-Id: Icfd24c817674b81ac9caecc2d73348dc7734f037 --- .../gallery3d/filtershow/FilterShowActivity.java | 2 + .../filtershow/controller/BasicParameterInt.java | 8 + .../filtershow/editors/EditorChanSat.java | 227 +++++++++++++++++++++ .../filtershow/filters/BaseFiltersManager.java | 3 +- .../filters/FilterChanSatRepresentation.java | 211 +++++++++++++++++++ .../filters/FilterGradRepresentation.java | 1 - .../filtershow/filters/ImageFilterChanSat.java | 161 +++++++++++++++ .../gallery3d/filtershow/filters/saturation.rs | 161 +++++++++++++++ .../gallery3d/filtershow/pipeline/ImagePreset.java | 2 +- .../filtershow/editors/EditorManager.java | 1 + 10 files changed, 774 insertions(+), 3 deletions(-) create mode 100644 src/com/android/gallery3d/filtershow/editors/EditorChanSat.java create mode 100644 src/com/android/gallery3d/filtershow/filters/FilterChanSatRepresentation.java create mode 100644 src/com/android/gallery3d/filtershow/filters/ImageFilterChanSat.java create mode 100644 src/com/android/gallery3d/filtershow/filters/saturation.rs diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index f0b1aa8c2..ab508b6f2 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -59,6 +59,7 @@ import android.widget.Toast; import com.android.gallery3d.R; import com.android.gallery3d.app.PhotoPage; import com.android.gallery3d.data.LocalAlbum; +import com.android.gallery3d.filtershow.editors.EditorChanSat; import com.android.gallery3d.filtershow.editors.EditorGrad; import com.android.gallery3d.filtershow.data.FilterStackSource; import com.android.gallery3d.filtershow.data.UserPresetsManager; @@ -386,6 +387,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } private void fillEditors() { + mEditorPlaceHolder.addEditor(new EditorChanSat()); mEditorPlaceHolder.addEditor(new EditorGrad()); mEditorPlaceHolder.addEditor(new EditorDraw()); mEditorPlaceHolder.addEditor(new BasicEditor()); diff --git a/src/com/android/gallery3d/filtershow/controller/BasicParameterInt.java b/src/com/android/gallery3d/filtershow/controller/BasicParameterInt.java index 777bc4382..92145e9be 100644 --- a/src/com/android/gallery3d/filtershow/controller/BasicParameterInt.java +++ b/src/com/android/gallery3d/filtershow/controller/BasicParameterInt.java @@ -45,6 +45,14 @@ public class BasicParameterInt implements ParameterInteger { ID = id; mValue = value; } + + public BasicParameterInt(int id, int value, int min, int max) { + ID = id; + mValue = value; + mMinimum = min; + mMaximum = max; + } + @Override public String getParameterName() { return mParameterName; diff --git a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java new file mode 100644 index 000000000..7e31f09ae --- /dev/null +++ b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java @@ -0,0 +1,227 @@ +/* + * 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.editors; + +import android.content.Context; +import android.graphics.Bitmap; +import android.os.Handler; +import android.view.MenuItem; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.LinearLayout; +import android.widget.PopupMenu; +import android.widget.SeekBar.OnSeekBarChangeListener; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.controller.BasicParameterStyle; +import com.android.gallery3d.filtershow.controller.FilterView; +import com.android.gallery3d.filtershow.controller.Parameter; +import com.android.gallery3d.filtershow.filters.FilterChanSatRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.ImagePreset; +import com.android.gallery3d.filtershow.pipeline.RenderingRequest; +import com.android.gallery3d.filtershow.pipeline.RenderingRequestCaller; + +public class EditorChanSat extends ParametricEditor implements OnSeekBarChangeListener, FilterView { + public static final int ID = R.id.editorChanSat; + private final String LOGTAG = "EditorGrunge"; + private SwapButton mButton; + private final Handler mHandler = new Handler(); + + int[] mMenuStrings = { + R.string.editor_chan_sat_main, + R.string.editor_chan_sat_red, + R.string.editor_chan_sat_yellow, + R.string.editor_chan_sat_green, + R.string.editor_chan_sat_cyan, + R.string.editor_chan_sat_blue, + R.string.editor_chan_sat_magenta + }; + + String mCurrentlyEditing = null; + + public EditorChanSat() { + super(ID, R.layout.filtershow_default_editor, R.id.basicEditor); + } + + @Override + public String calculateUserMessage(Context context, String effectName, Object parameterValue) { + FilterRepresentation rep = getLocalRepresentation(); + if (rep == null || !(rep instanceof FilterChanSatRepresentation)) { + return ""; + } + FilterChanSatRepresentation csrep = (FilterChanSatRepresentation) rep; + int mode = csrep.getParameterMode(); + String paramString; + + paramString = mContext.getString(mMenuStrings[mode]); + + int val = csrep.getCurrentParameter(); + return paramString + ((val > 0) ? " +" : " ") + val; + } + + @Override + public void openUtilityPanel(final LinearLayout accessoryViewList) { + mButton = (SwapButton) accessoryViewList.findViewById(R.id.applyEffect); + mButton.setText(mContext.getString(R.string.editor_chan_sat_main)); + + final PopupMenu popupMenu = new PopupMenu(mImageShow.getActivity(), mButton); + + popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_chan_sat, popupMenu.getMenu()); + + popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { + @Override + public boolean onMenuItemClick(MenuItem item) { + selectMenuItem(item); + return true; + } + }); + mButton.setOnClickListener(new OnClickListener() { + @Override + public void onClick(View arg0) { + popupMenu.show(); + } + }); + mButton.setListener(this); + + FilterChanSatRepresentation csrep = getChanSatRep(); + String menuString = mContext.getString(mMenuStrings[0]); + switchToMode(csrep, FilterChanSatRepresentation.MODE_MASTER, menuString); + + } + + public int getParameterIndex(int id) { + switch (id) { + case R.id.editor_chan_sat_main: + return FilterChanSatRepresentation.MODE_MASTER; + case R.id.editor_chan_sat_red: + return FilterChanSatRepresentation.MODE_RED; + case R.id.editor_chan_sat_yellow: + return FilterChanSatRepresentation.MODE_YELLOW; + case R.id.editor_chan_sat_green: + return FilterChanSatRepresentation.MODE_GREEN; + case R.id.editor_chan_sat_cyan: + return FilterChanSatRepresentation.MODE_CYAN; + case R.id.editor_chan_sat_blue: + return FilterChanSatRepresentation.MODE_BLUE; + case R.id.editor_chan_sat_magenta: + return FilterChanSatRepresentation.MODE_MAGENTA; + } + return -1; + } + + @Override + public void detach() { + mButton.setListener(null); + mButton.setOnClickListener(null); + } + + private void updateSeekBar(FilterChanSatRepresentation rep) { + mControl.updateUI(); + } + + @Override + protected Parameter getParameterToEdit(FilterRepresentation rep) { + if (rep instanceof FilterChanSatRepresentation) { + FilterChanSatRepresentation csrep = (FilterChanSatRepresentation) rep; + Parameter param = csrep.getFilterParameter(csrep.getParameterMode()); + if (param instanceof BasicParameterStyle) { + param.setFilterView(EditorChanSat.this); + } + return param; + } + return null; + } + + private FilterChanSatRepresentation getChanSatRep() { + FilterRepresentation rep = getLocalRepresentation(); + if (rep != null + && rep instanceof FilterChanSatRepresentation) { + FilterChanSatRepresentation csrep = (FilterChanSatRepresentation) rep; + return csrep; + } + return null; + } + + @Override + public void computeIcon(int n, RenderingRequestCaller caller) { + FilterChanSatRepresentation rep = getChanSatRep(); + if (rep == null) return; + rep = (FilterChanSatRepresentation) rep.copy(); + ImagePreset preset = new ImagePreset(); + preset.addFilter(rep); + Bitmap src = MasterImage.getImage().getThumbnailBitmap(); + RenderingRequest.post(null, src, preset, RenderingRequest.STYLE_ICON_RENDERING, + caller); + } + + protected void selectMenuItem(MenuItem item) { + if (getLocalRepresentation() != null + && getLocalRepresentation() instanceof FilterChanSatRepresentation) { + FilterChanSatRepresentation csrep = + (FilterChanSatRepresentation) getLocalRepresentation(); + + switchToMode(csrep, getParameterIndex(item.getItemId()), item.getTitle().toString()); + + } + } + + protected void switchToMode(FilterChanSatRepresentation csrep, int mode, String title) { + csrep.setParameterMode(mode); + mCurrentlyEditing = title; + mButton.setText(mCurrentlyEditing); + { + Parameter param = getParameterToEdit(csrep); + + control(param, mEditControl); + } + updateSeekBar(csrep); + mView.invalidate(); + } + + @Override + public void swapLeft(MenuItem item) { + super.swapLeft(item); + mButton.setTranslationX(0); + mButton.animate().translationX(mButton.getWidth()).setDuration(SwapButton.ANIM_DURATION); + Runnable updateButton = new Runnable() { + @Override + public void run() { + mButton.animate().cancel(); + mButton.setTranslationX(0); + } + }; + mHandler.postDelayed(updateButton, SwapButton.ANIM_DURATION); + selectMenuItem(item); + } + + @Override + public void swapRight(MenuItem item) { + super.swapRight(item); + mButton.setTranslationX(0); + mButton.animate().translationX(-mButton.getWidth()).setDuration(SwapButton.ANIM_DURATION); + Runnable updateButton = new Runnable() { + @Override + public void run() { + mButton.animate().cancel(); + mButton.setTranslationX(0); + } + }; + mHandler.postDelayed(updateButton, SwapButton.ANIM_DURATION); + selectMenuItem(item); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java index 4708abb24..3fa91916d 100644 --- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -133,6 +133,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { 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); @@ -232,7 +233,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { mEffects.add(getRepresentation(ImageFilterSharpen.class)); mEffects.add(getRepresentation(ImageFilterCurves.class)); mEffects.add(getRepresentation(ImageFilterHue.class)); - mEffects.add(getRepresentation(ImageFilterSaturated.class)); + mEffects.add(getRepresentation(ImageFilterChanSat.class)); mEffects.add(getRepresentation(ImageFilterBwFilter.class)); mEffects.add(getRepresentation(ImageFilterNegative.class)); mEffects.add(getRepresentation(ImageFilterEdge.class)); 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/FilterGradRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java index 64e7fb0c9..0c272d48a 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java @@ -419,7 +419,6 @@ public class FilterGradRepresentation extends FilterRepresentation public float getPoint1Y() { return mCurrentBand.yPos1; } - @Override public float getPoint2X() { return mCurrentBand.xPos2; 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 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/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 diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index 64643e455..d34216ad6 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -613,7 +613,7 @@ public class ImagePreset { writer.endObject(); } catch (IOException e) { - e.printStackTrace(); + Log.e(LOGTAG,"Error encoding JASON",e); } } diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java index 8ea21ad26..32664258a 100644 --- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java +++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java @@ -25,6 +25,7 @@ public class EditorManager { public static void addEditors(EditorPlaceHolder editorPlaceHolder) { editorPlaceHolder.addEditor(new EditorGrad()); + editorPlaceHolder.addEditor(new EditorChanSat()); editorPlaceHolder.addEditor(new EditorZoom()); editorPlaceHolder.addEditor(new EditorCurves()); editorPlaceHolder.addEditor(new EditorTinyPlanet()); -- cgit v1.2.3