summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java2
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorGrad.java315
-rw-r--r--src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java2
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java514
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java201
-rw-r--r--src/com/android/gallery3d/filtershow/filters/grad.rs131
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/GradControl.java274
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java218
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/Line.java26
-rw-r--r--src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java1
10 files changed, 1684 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 590b04862..8bbdd0c32 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -58,6 +58,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.EditorGrad;
import com.android.gallery3d.filtershow.pipeline.CachingPipeline;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.category.Action;
@@ -376,6 +377,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
private void fillEditors() {
+ mEditorPlaceHolder.addEditor(new EditorGrad());
mEditorPlaceHolder.addEditor(new EditorDraw());
mEditorPlaceHolder.addEditor(new BasicEditor());
mEditorPlaceHolder.addEditor(new ImageOnlyEditor());
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
new file mode 100644
index 000000000..f427ccbd8
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
@@ -0,0 +1,315 @@
+/*
+ * 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.view.MenuItem;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+import android.widget.PopupMenu;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.ToggleButton;
+
+import com.android.gallery3d.R;
+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.ParameterActionAndInt;
+import com.android.gallery3d.filtershow.filters.FilterGradRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageGrad;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+
+public class EditorGrad extends ParametricEditor
+ implements OnSeekBarChangeListener, ParameterActionAndInt {
+ private static final String LOGTAG = "EditorGrad";
+ public static final int ID = R.id.editorGrad;
+ PopupMenu mPopupMenu;
+ ToggleButton mAddModeButton;
+ String mEffectName = "";
+ private static final int MODE_BRIGHTNESS = FilterGradRepresentation.PARAM_BRIGHTNESS;
+ private static final int MODE_SATURATION = FilterGradRepresentation.PARAM_SATURATION;
+ private static final int MODE_CONTRAST = FilterGradRepresentation.PARAM_CONTRAST;
+ private static final int ADD_ICON = R.drawable.ic_grad_add;
+ private static final int DEL_ICON = R.drawable.ic_grad_del;
+ private int mSliderMode = MODE_BRIGHTNESS;
+ ImageGrad mImageGrad;
+
+ public EditorGrad() {
+ super(ID, R.layout.filtershow_grad_editor, R.id.gradEditor);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ mImageGrad = (ImageGrad) mImageShow;
+ mImageGrad.setEditor(this);
+
+ }
+
+ public void clearAddMode() {
+ mAddModeButton.setChecked(false);
+ FilterRepresentation tmpRep = getLocalRepresentation();
+ if (tmpRep instanceof FilterGradRepresentation) {
+ updateMenuItems((FilterGradRepresentation) tmpRep);
+ }
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ super.reflectCurrentFilter();
+ FilterRepresentation tmpRep = getLocalRepresentation();
+ if (tmpRep instanceof FilterGradRepresentation) {
+ FilterGradRepresentation rep = (FilterGradRepresentation) tmpRep;
+ boolean f = rep.showParameterValue();
+
+ mImageGrad.setRepresentation(rep);
+ }
+ }
+
+ public void updateSeekBar(FilterGradRepresentation rep) {
+ mControl.updateUI();
+ }
+
+ @Override
+ public void onProgressChanged(SeekBar sbar, int progress, boolean arg2) {
+ FilterRepresentation tmpRep = getLocalRepresentation();
+ if (tmpRep instanceof FilterGradRepresentation) {
+ FilterGradRepresentation rep = (FilterGradRepresentation) tmpRep;
+ int min = rep.getParameterMin(mSliderMode);
+ int value = progress + min;
+ rep.setParameter(mSliderMode, value);
+ mView.invalidate();
+ commitLocalRepresentation();
+ }
+ }
+
+ @Override
+ public void openUtilityPanel(final LinearLayout accessoryViewList) {
+ Button view = (Button) accessoryViewList.findViewById(R.id.applyEffect);
+ view.setText(mContext.getString(R.string.editor_grad_brightness));
+ view.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View arg0) {
+ showPopupMenu(accessoryViewList);
+ }
+ });
+
+ setUpPopupMenu(view);
+ setEffectName();
+ }
+
+ private void updateMenuItems(FilterGradRepresentation rep) {
+ int n = rep.getNumberOfBands();
+ }
+
+ public void setEffectName() {
+ if (mPopupMenu != null) {
+ MenuItem item = mPopupMenu.getMenu().findItem(R.id.editor_grad_brightness);
+ mEffectName = item.getTitle().toString();
+ }
+ }
+
+ private void showPopupMenu(LinearLayout accessoryViewList) {
+ Button button = (Button) accessoryViewList.findViewById(R.id.applyEffect);
+ if (button == null) {
+ return;
+ }
+
+ if (mPopupMenu == null) {
+ setUpPopupMenu(button);
+ }
+ mPopupMenu.show();
+ }
+
+ private void setUpPopupMenu(Button button) {
+ mPopupMenu = new PopupMenu(mImageShow.getActivity(), button);
+ mPopupMenu.getMenuInflater()
+ .inflate(R.menu.filtershow_menu_grad, mPopupMenu.getMenu());
+ FilterGradRepresentation rep = (FilterGradRepresentation) getLocalRepresentation();
+ if (rep == null) {
+ return;
+ }
+ updateMenuItems(rep);
+ hackFixStrings(mPopupMenu.getMenu());
+ setEffectName();
+ updateText();
+
+ mPopupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
+ @Override
+ public boolean onMenuItemClick(MenuItem item) {
+ FilterRepresentation tmpRep = getLocalRepresentation();
+
+ if (tmpRep instanceof FilterGradRepresentation) {
+ FilterGradRepresentation rep = (FilterGradRepresentation) tmpRep;
+ int cmdID = item.getItemId();
+ switch (cmdID) {
+ case R.id.editor_grad_brightness:
+ mSliderMode = MODE_BRIGHTNESS;
+ mEffectName = item.getTitle().toString();
+ break;
+ case R.id.editor_grad_contrast:
+ mSliderMode = MODE_CONTRAST;
+ mEffectName = item.getTitle().toString();
+ break;
+ case R.id.editor_grad_saturation:
+ mSliderMode = MODE_SATURATION;
+ mEffectName = item.getTitle().toString();
+ break;
+ }
+ updateMenuItems(rep);
+ updateSeekBar(rep);
+
+ commitLocalRepresentation();
+ mView.invalidate();
+ }
+ return true;
+ }
+ });
+ }
+
+ @Override
+ public String calculateUserMessage(Context context, String effectName, Object parameterValue) {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return mEffectName;
+ }
+ int val = rep.getParameter(mSliderMode);
+ return mEffectName.toUpperCase() + ((val > 0) ? " +" : " ") + val;
+ }
+
+ private FilterGradRepresentation getGradRepresentation() {
+ FilterRepresentation tmpRep = getLocalRepresentation();
+ if (tmpRep instanceof FilterGradRepresentation) {
+ return (FilterGradRepresentation) tmpRep;
+ }
+ return null;
+ }
+
+ @Override
+ public int getMaximum() {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return 0;
+ }
+ return rep.getParameterMax(mSliderMode);
+ }
+
+ @Override
+ public int getMinimum() {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return 0;
+ }
+ return rep.getParameterMin(mSliderMode);
+ }
+
+ @Override
+ public int getDefaultValue() {
+ return 0;
+ }
+
+ @Override
+ public int getValue() {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return 0;
+ }
+ return rep.getParameter(mSliderMode);
+ }
+
+ @Override
+ public String getValueString() {
+ return null;
+ }
+
+ @Override
+ public void setValue(int value) {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return;
+ }
+ rep.setParameter(mSliderMode, value);
+ }
+
+ @Override
+ public String getParameterName() {
+ return mEffectName;
+ }
+
+ @Override
+ public String getParameterType() {
+ return sParameterType;
+ }
+
+ @Override
+ public void setController(Control c) {
+
+ }
+
+ @Override
+ public void fireLeftAction() {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return;
+ }
+ rep.addBand(MasterImage.getImage().getOriginalBounds());
+ updateMenuItems(rep);
+ updateSeekBar(rep);
+
+ commitLocalRepresentation();
+ mView.invalidate();
+ }
+
+ @Override
+ public int getLeftIcon() {
+ return ADD_ICON;
+ }
+
+ @Override
+ public void fireRightAction() {
+ FilterGradRepresentation rep = getGradRepresentation();
+ if (rep == null) {
+ return;
+ }
+ rep.deleteCurrentBand();
+
+ updateMenuItems(rep);
+ updateSeekBar(rep);
+ commitLocalRepresentation();
+ mView.invalidate();
+ }
+
+ @Override
+ public int getRightIcon() {
+ return DEL_ICON;
+ }
+
+ @Override
+ public void setFilterView(FilterView editor) {
+
+ }
+
+ @Override
+ public void copyFrom(Parameter src) {
+
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index d140f0d8d..550b9d7fc 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -121,6 +121,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
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);
@@ -217,6 +218,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
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));
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..1bfce6f05
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterGradRepresentation.java
@@ -0,0 +1,514 @@
+/*
+ * 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_colors_vignette);
+ 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 boolean active = 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;
+ private boolean inking;
+
+ 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;
+ active = copy.active;
+ xPos1 = copy.xPos1;
+ yPos1 = copy.yPos1;
+ xPos2 = copy.xPos2;
+ yPos2 = copy.yPos2;
+ brightness = copy.brightness;
+ contrast = copy.contrast;
+ saturation = copy.saturation;
+ inking = copy.inking;
+ }
+
+ }
+
+ @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.active = true;
+ p.xPos1 = -1;
+ p.yPos1 = 100;
+ p.xPos2 = -1;
+ p.yPos2 = 100;
+ p.brightness = 40;
+ p.contrast = 0;
+ p.saturation = 0;
+ p.inking = false;
+ 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) {
+ return true; // TODO much more extensive equals needed
+ }
+ return false;
+ }
+
+ public int getNumberOfBands() {
+ int count = 0;
+ for (Band point : mBands) {
+ if (!point.mask) {
+ count++;
+ }
+ }
+ return count;
+ }
+
+ public void toggleInking() {
+ mCurrentBand.inking = !mCurrentBand.inking;
+ }
+
+ public void setInking(boolean on) {
+ for (Band point : mBands) {
+ point.inking = false;
+ }
+ mCurrentBand.inking = on;
+ }
+
+ 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 boolean[] getActive() {
+ boolean[] ret = new boolean[mBands.size()];
+ int i = 0;
+ String s = "";
+ for (Band point : mBands) {
+ ret[i++] = point.active;
+ s += (point.active) ? "1" : "0";
+ }
+ 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 boolean[] getInking() {
+ boolean[] ret = new boolean[mBands.size()];
+ int i = 0;
+ for (Band point : mBands) {
+ ret[i++] = point.inking;
+ }
+ 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/ImageFilterGrad.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java
new file mode 100644
index 000000000..e5e9f13f5
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterGrad.java
@@ -0,0 +1,201 @@
+/*
+ * 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);
+ }
+
+ private boolean hasInk() {
+ boolean[] ink = mParameters.getInking();
+ for (int i = 0; i < ink.length; i++) {
+ if (ink[i])
+ return true;
+ }
+ return false;
+ }
+
+ @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_active(mParameters.getActive());
+ 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.set_inking(mParameters.getInking());
+
+ 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/grad.rs b/src/com/android/gallery3d/filtershow/filters/grad.rs
new file mode 100644
index 000000000..42e1e5faf
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/grad.rs
@@ -0,0 +1,131 @@
+/*
+ * 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 {
+ bool active;
+ bool inking;
+ rs_matrix3x3 colorMatrix;
+ float rgbOff;
+ float dx;
+ float dy;
+ float off;
+} UPointData;
+int mNumberOfLines;
+// input data
+bool mask[MAX_POINTS];
+bool active[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];
+bool inking[MAX_POINTS];
+
+
+// generated data
+static UPointData grads[MAX_POINTS];
+
+void setupGradParams() {
+ int k = 0;
+ for (int i = 0; i < MAX_POINTS; i++) {
+ grads[i].active = false;
+ 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) {
+ grads[i].active = false;
+ 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));
+
+
+ grads[k].active = true;
+ grads[k].inking = inking[i];
+ 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/imageshow/GradControl.java b/src/com/android/gallery3d/filtershow/imageshow/GradControl.java
new file mode 100644
index 000000000..964da99e9
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/GradControl.java
@@ -0,0 +1,274 @@
+/*
+ * 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.imageshow;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.DashPathEffect;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.RadialGradient;
+import android.graphics.Rect;
+import android.graphics.Shader;
+
+import com.android.gallery3d.R;
+
+public class GradControl {
+ private float mPoint1X = Float.NaN; // used to flag parameters have not been set
+ private float mPoint1Y = 0;
+ private float mPoint2X = 200;
+ private float mPoint2Y = 300;
+ private int mMinTouchDist = 80;// should be a resource & in dips
+
+ private float[] handlex = new float[3];
+ private float[] handley = new float[3];
+ private int mSliderColor;
+ private int mCenterDotSize;
+ private float mDownX;
+ private float mDownY;
+ private float mDownPoint1X;
+ private float mDownPoint1Y;
+ private float mDownPoint2X;
+ private float mDownPoint2Y;
+ Rect mImageBounds;
+ int mImageHeight;
+ private Matrix mScrToImg;
+ Paint mPaint = new Paint();
+ DashPathEffect mDash = new DashPathEffect(new float[]{30, 30}, 0);
+ private boolean mShowReshapeHandles = true;
+ public final static int HAN_CENTER = 0;
+ public final static int HAN_NORTH = 2;
+ public final static int HAN_SOUTH = 1;
+ private int[] mPointColorPatern;
+ private int[] mGrayPointColorPatern;
+ private float[] mPointRadialPos = new float[]{0, .3f, .31f, 1};
+ private int mLineColor;
+ private int mlineShadowColor;
+
+ public GradControl(Context context) {
+
+ Resources res = context.getResources();
+ mCenterDotSize = (int) res.getDimension(R.dimen.gradcontrol_dot_size);
+ mMinTouchDist = (int) res.getDimension(R.dimen.gradcontrol_min_touch_dist);
+ int grayPointCenterColor = res.getColor(R.color.gradcontrol_graypoint_center);
+ int grayPointEdgeColor = res.getColor(R.color.gradcontrol_graypoint_edge);
+ int pointCenterColor = res.getColor(R.color.gradcontrol_point_center);
+ int pointEdgeColor = res.getColor(R.color.gradcontrol_point_edge);
+ int pointShadowStartColor = res.getColor(R.color.gradcontrol_point_shadow_start);
+ int pointShadowEndColor = res.getColor(R.color.gradcontrol_point_shadow_end);
+ mPointColorPatern = new int[]{
+ pointCenterColor, pointEdgeColor, pointShadowStartColor, pointShadowEndColor};
+ mGrayPointColorPatern = new int[]{
+ grayPointCenterColor, grayPointEdgeColor, pointShadowStartColor, pointShadowEndColor};
+ mSliderColor = Color.WHITE;
+ mLineColor = res.getColor(R.color.gradcontrol_line_color);
+ mlineShadowColor = res.getColor(R.color.gradcontrol_line_shadow);
+ }
+
+ public void setPoint2(float x, float y) {
+ mPoint2X = x;
+ mPoint2Y = y;
+ }
+
+ public void setPoint1(float x, float y) {
+ mPoint1X = x;
+ mPoint1Y = y;
+ }
+
+ public int getCloseHandle(float x, float y) {
+ float min = Float.MAX_VALUE;
+ int handle = -1;
+ for (int i = 0; i < handlex.length; i++) {
+ float dx = handlex[i] - x;
+ float dy = handley[i] - y;
+ float dist = dx * dx + dy * dy;
+ if (dist < min) {
+ min = dist;
+ handle = i;
+ }
+ }
+
+ if (min < mMinTouchDist * mMinTouchDist) {
+ return handle;
+ }
+ for (int i = 0; i < handlex.length; i++) {
+ float dx = handlex[i] - x;
+ float dy = handley[i] - y;
+ float dist = (float) Math.sqrt(dx * dx + dy * dy);
+ }
+
+ return -1;
+ }
+
+ public void setScrImageInfo(Matrix scrToImg, Rect imageBounds) {
+ mScrToImg = scrToImg;
+ mImageBounds = new Rect(imageBounds);
+ }
+
+ private boolean centerIsOutside(float x1, float y1, float x2, float y2) {
+ return (!mImageBounds.contains((int) ((x1 + x2) / 2), (int) ((y1 + y2) / 2)));
+ }
+
+ public void actionDown(float x, float y, Line line) {
+ float[] point = new float[]{
+ x, y};
+ mScrToImg.mapPoints(point);
+ mDownX = point[0];
+ mDownY = point[1];
+ mDownPoint1X = line.getPoint1X();
+ mDownPoint1Y = line.getPoint1Y();
+ mDownPoint2X = line.getPoint2X();
+ mDownPoint2Y = line.getPoint2Y();
+ }
+
+ public void actionMove(int handle, float x, float y, Line line) {
+ float[] point = new float[]{
+ x, y};
+ mScrToImg.mapPoints(point);
+ x = point[0];
+ y = point[1];
+
+ // Test if the matrix is swapping x and y
+ point[0] = 0;
+ point[1] = 1;
+ mScrToImg.mapVectors(point);
+ boolean swapxy = (point[0] > 0.0f);
+
+ int sign = 1;
+
+ float dx = x - mDownX;
+ float dy = y - mDownY;
+ switch (handle) {
+ case HAN_CENTER:
+ if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy,
+ mDownPoint2X + dx, mDownPoint2Y + dy)) {
+ break;
+ }
+ line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy);
+ line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy);
+ break;
+ case HAN_SOUTH:
+ if (centerIsOutside(mDownPoint1X + dx, mDownPoint1Y + dy,
+ mDownPoint2X, mDownPoint2Y)) {
+ break;
+ }
+ line.setPoint1(mDownPoint1X + dx, mDownPoint1Y + dy);
+ break;
+ case HAN_NORTH:
+ if (centerIsOutside(mDownPoint1X, mDownPoint1Y,
+ mDownPoint2X + dx, mDownPoint2Y + dy)) {
+ break;
+ }
+ line.setPoint2(mDownPoint2X + dx, mDownPoint2Y + dy);
+ break;
+ }
+ }
+
+ public void paintGrayPoint(Canvas canvas, float x, float y) {
+ if (isUndefined()) {
+ return;
+ }
+
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.FILL);
+ RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mGrayPointColorPatern,
+ mPointRadialPos, Shader.TileMode.CLAMP);
+ paint.setShader(g);
+ canvas.drawCircle(x, y, mCenterDotSize, paint);
+ }
+
+ public void paintPoint(Canvas canvas, float x, float y) {
+ if (isUndefined()) {
+ return;
+ }
+
+ Paint paint = new Paint();
+ paint.setStyle(Paint.Style.FILL);
+ RadialGradient g = new RadialGradient(x, y, mCenterDotSize, mPointColorPatern,
+ mPointRadialPos, Shader.TileMode.CLAMP);
+ paint.setShader(g);
+ canvas.drawCircle(x, y, mCenterDotSize, paint);
+ }
+
+ void paintLines(Canvas canvas, float p1x, float p1y, float p2x, float p2y) {
+ if (isUndefined()) {
+ return;
+ }
+
+ mPaint.setAntiAlias(true);
+ mPaint.setStyle(Paint.Style.STROKE);
+
+ mPaint.setStrokeWidth(6);
+ mPaint.setColor(mlineShadowColor);
+ mPaint.setPathEffect(mDash);
+ paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y);
+
+ mPaint.setStrokeWidth(3);
+ mPaint.setColor(mLineColor);
+ mPaint.setPathEffect(mDash);
+ paintOvallines(canvas, mPaint, p1x, p1y, p2x, p2y);
+ }
+
+ public void paintOvallines(
+ Canvas canvas, Paint paint, float p1x, float p1y, float p2x, float p2y) {
+
+
+
+ canvas.drawLine(p1x, p1y, p2x, p2y, paint);
+
+ float cx = (p1x + p2x) / 2;
+ float cy = (p1y + p2y) / 2;
+ float dx = p1x - p2x;
+ float dy = p1y - p2y;
+ float len = (float) Math.sqrt(dx * dx + dy * dy);
+ dx *= 2048 / len;
+ dy *= 2048 / len;
+
+ canvas.drawLine(p1x + dy, p1y - dx, p1x - dy, p1y + dx, paint);
+ canvas.drawLine(p2x + dy, p2y - dx, p2x - dy, p2y + dx, paint);
+ }
+
+ public void fillHandles(Canvas canvas, float p1x, float p1y, float p2x, float p2y) {
+ float cx = (p1x + p2x) / 2;
+ float cy = (p1y + p2y) / 2;
+ handlex[0] = cx;
+ handley[0] = cy;
+ handlex[1] = p1x;
+ handley[1] = p1y;
+ handlex[2] = p2x;
+ handley[2] = p2y;
+
+ }
+
+ public void draw(Canvas canvas) {
+ paintLines(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y);
+ fillHandles(canvas, mPoint1X, mPoint1Y, mPoint2X, mPoint2Y);
+ paintPoint(canvas, mPoint2X, mPoint2Y);
+ paintPoint(canvas, mPoint1X, mPoint1Y);
+ paintPoint(canvas, (mPoint1X + mPoint2X) / 2, (mPoint1Y + mPoint2Y) / 2);
+ }
+
+ public boolean isUndefined() {
+ return Float.isNaN(mPoint1X);
+ }
+
+ public void setShowReshapeHandles(boolean showReshapeHandles) {
+ this.mShowReshapeHandles = showReshapeHandles;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java b/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java
new file mode 100644
index 000000000..ef72e8a6e
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageGrad.java
@@ -0,0 +1,218 @@
+package com.android.gallery3d.filtershow.imageshow;
+/*
+ * 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.
+ */
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Canvas;
+import android.graphics.Matrix;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+
+import com.android.gallery3d.R;
+import com.android.gallery3d.filtershow.editors.EditorGrad;
+import com.android.gallery3d.filtershow.filters.FilterGradRepresentation;
+
+public class ImageGrad extends ImageShow {
+ private static final String LOGTAG = "ImageGrad";
+ private FilterGradRepresentation mGradRep;
+ private EditorGrad mEditorGrad;
+ private int mMinTouchDist;
+ private int mActiveHandle = -1;
+ private GradControl mEllipse;
+
+ Matrix mToScr = new Matrix();
+ float[] mPointsX = new float[FilterGradRepresentation.MAX_POINTS];
+ float[] mPointsY = new float[FilterGradRepresentation.MAX_POINTS];
+
+ public ImageGrad(Context context) {
+ super(context);
+ Resources res = context.getResources();
+ mMinTouchDist = res.getDimensionPixelSize(R.dimen.gradcontrol_min_touch_dist);
+ mEllipse = new GradControl(context);
+ mEllipse.setShowReshapeHandles(false);
+ }
+
+ public ImageGrad(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mEllipse = new GradControl(context);
+ mEllipse.setShowReshapeHandles(false);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int mask = event.getActionMasked();
+
+ if (mask == MotionEvent.ACTION_DOWN || mask == MotionEvent.ACTION_UP) {
+ mGradRep.setInking(MotionEvent.ACTION_DOWN == mask);
+ }
+
+ if (mActiveHandle == -1) {
+ if (MotionEvent.ACTION_DOWN != mask) {
+ return super.onTouchEvent(event);
+ }
+ if (event.getPointerCount() == 1) {
+ mActiveHandle = mEllipse.getCloseHandle(event.getX(), event.getY());
+ if (mActiveHandle == -1) {
+ float x = event.getX();
+ float y = event.getY();
+ float min_d = Float.MAX_VALUE;
+ int pos = -1;
+ for (int i = 0; i < mPointsX.length; i++) {
+ if (mPointsX[i] == -1) {
+ continue;
+ }
+ float d = (float) Math.hypot(x - mPointsX[i], y - mPointsY[i]);
+ if ( min_d > d) {
+ min_d = d;
+ pos = i;
+ }
+ }
+ if (min_d > mMinTouchDist){
+ pos = -1;
+ }
+
+ if (pos != -1) {
+ mGradRep.setSelectedPoint(pos);
+ mGradRep.setInking(true);
+ resetImageCaches(this);
+ mEditorGrad.updateSeekBar(mGradRep);
+ mEditorGrad.commitLocalRepresentation();
+ invalidate();
+ }
+ }
+ }
+ if (mActiveHandle == -1) {
+ return super.onTouchEvent(event);
+ }
+ } else {
+ switch (mask) {
+ case MotionEvent.ACTION_UP: {
+
+ mActiveHandle = -1;
+ break;
+ }
+ case MotionEvent.ACTION_DOWN: {
+ break;
+ }
+ }
+ }
+ float x = event.getX();
+ float y = event.getY();
+
+ mEllipse.setScrImageInfo(getScreenToImageMatrix(true),
+ MasterImage.getImage().getOriginalBounds());
+
+ switch (mask) {
+ case (MotionEvent.ACTION_DOWN): {
+ mEllipse.actionDown(x, y, mGradRep);
+ break;
+ }
+ case (MotionEvent.ACTION_UP):
+ case (MotionEvent.ACTION_MOVE): {
+ mEllipse.actionMove(mActiveHandle, x, y, mGradRep);
+ setRepresentation(mGradRep);
+ break;
+ }
+ }
+ invalidate();
+ mEditorGrad.commitLocalRepresentation();
+ return true;
+ }
+
+ public void setRepresentation(FilterGradRepresentation pointRep) {
+ mGradRep = pointRep;
+ Matrix toImg = getScreenToImageMatrix(false);
+
+ toImg.invert(mToScr);
+
+ float[] c1 = new float[] { mGradRep.getPoint1X(), mGradRep.getPoint1Y() };
+ float[] c2 = new float[] { mGradRep.getPoint2X(), mGradRep.getPoint2Y() };
+
+ if (c1[0] == -1) {
+ float cx = MasterImage.getImage().getOriginalBounds().width() / 2;
+ float cy = MasterImage.getImage().getOriginalBounds().height() / 2;
+ float rx = Math.min(cx, cy) * .4f;
+
+ mGradRep.setPoint1(cx, cy-rx);
+ mGradRep.setPoint2(cx, cy+rx);
+ c1[0] = cx;
+ c1[1] = cy-rx;
+ mToScr.mapPoints(c1);
+ if (getWidth() != 0) {
+ mEllipse.setPoint1(c1[0], c1[1]);
+ c2[0] = cx;
+ c2[1] = cy+rx;
+ mToScr.mapPoints(c2);
+ mEllipse.setPoint2(c2[0], c2[1]);
+ }
+ mEditorGrad.commitLocalRepresentation();
+ } else {
+ mToScr.mapPoints(c1);
+ mToScr.mapPoints(c2);
+ mEllipse.setPoint1(c1[0], c1[1]);
+ mEllipse.setPoint2(c2[0], c2[1]);
+ }
+ }
+
+ public void drawOtherPoints(Canvas canvas) {
+ computCenterLocations();
+ for (int i = 0; i < mPointsX.length; i++) {
+ if (mPointsX[i] != -1) {
+ mEllipse.paintGrayPoint(canvas, mPointsX[i], mPointsY[i]);
+ }
+ }
+ }
+
+ public void computCenterLocations() {
+ int x1[] = mGradRep.getXPos1();
+ int y1[] = mGradRep.getYPos1();
+ int x2[] = mGradRep.getXPos2();
+ int y2[] = mGradRep.getYPos2();
+ int selected = mGradRep.getSelectedPoint();
+ boolean m[] = mGradRep.getMask();
+ float[] c = new float[2];
+ for (int i = 0; i < m.length; i++) {
+ if (selected == i || !m[i]) {
+ mPointsX[i] = -1;
+ continue;
+ }
+
+ c[0] = (x1[i]+x2[i])/2;
+ c[1] = (y1[i]+y2[i])/2;
+ mToScr.mapPoints(c);
+
+ mPointsX[i] = c[0];
+ mPointsY[i] = c[1];
+ }
+ }
+
+ public void setEditor(EditorGrad editorGrad) {
+ mEditorGrad = editorGrad;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ super.onDraw(canvas);
+ if (mGradRep == null) {
+ return;
+ }
+ setRepresentation(mGradRep);
+ mEllipse.draw(canvas);
+ drawOtherPoints(canvas);
+ }
+
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/Line.java b/src/com/android/gallery3d/filtershow/imageshow/Line.java
new file mode 100644
index 000000000..a767bd809
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/Line.java
@@ -0,0 +1,26 @@
+/*
+ * 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.imageshow;
+
+public interface Line {
+ void setPoint1(float x, float y);
+ void setPoint2(float x, float y);
+ float getPoint1X();
+ float getPoint1Y();
+ float getPoint2X();
+ float getPoint2Y();
+}
diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
index 2a39b688f..ab85110fe 100644
--- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
+++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java
@@ -24,6 +24,7 @@ import com.android.gallery3d.filtershow.editors.EditorZoom;
public class EditorManager {
public static void addEditors(EditorPlaceHolder editorPlaceHolder) {
+ editorPlaceHolder.addEditor(new EditorGrad());
editorPlaceHolder.addEditor(new EditorZoom());
editorPlaceHolder.addEditor(new EditorCurves());
editorPlaceHolder.addEditor(new EditorTinyPlanet());