1a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard/* 2a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Copyright (C) 2012 The Android Open Source Project 3a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 4a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Licensed under the Apache License, Version 2.0 (the "License"); 5a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * you may not use this file except in compliance with the License. 6a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * You may obtain a copy of the License at 7a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 8a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * http://www.apache.org/licenses/LICENSE-2.0 9a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * 10a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * Unless required by applicable law or agreed to in writing, software 11a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * distributed under the License is distributed on an "AS IS" BASIS, 12a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * See the License for the specific language governing permissions and 14a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard * limitations under the License. 15a9f280f938b5fd5891c5cfe0999f8f1d4945d7a1nicolasroard */ 160d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 17368ae73ad0627dac41709b925fc02a12548ab80dnicolasroardpackage com.android.gallery3d.filtershow.imageshow; 180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 190d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.content.Context; 203992ae6cf1cbb7b57a22d8287c40451558408335nicolasroardimport android.graphics.Bitmap; 210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Canvas; 223992ae6cf1cbb7b57a22d8287c40451558408335nicolasroardimport android.graphics.Color; 230d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Paint; 240d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.graphics.Path; 253992ae6cf1cbb7b57a22d8287c40451558408335nicolasroardimport android.graphics.PorterDuff; 263992ae6cf1cbb7b57a22d8287c40451558408335nicolasroardimport android.graphics.PorterDuffXfermode; 273992ae6cf1cbb7b57a22d8287c40451558408335nicolasroardimport android.os.AsyncTask; 280d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.util.AttributeSet; 299820e7e753b7e1977ef3d2163605431769ce9165nicolasroardimport android.view.MenuItem; 300d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroardimport android.view.MotionEvent; 319820e7e753b7e1977ef3d2163605431769ce9165nicolasroardimport android.view.View; 326a07dfbe03c8396cc43840a1630ea480a2cff663John Hofordimport android.widget.Button; 339820e7e753b7e1977ef3d2163605431769ce9165nicolasroardimport android.widget.LinearLayout; 349820e7e753b7e1977ef3d2163605431769ce9165nicolasroardimport android.widget.PopupMenu; 350d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 36c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroardimport com.android.gallery3d.R; 3764fc2ed005e2f1dc9ed0b34481c46a370c244b86John Hofordimport com.android.gallery3d.filtershow.FilterShowActivity; 387638772c0ceb5528b12c9943bad5391658d6c78dJohn Reckimport com.android.gallery3d.filtershow.editors.Editor; 3919161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hofordimport com.android.gallery3d.filtershow.editors.EditorCurves; 4019161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hofordimport com.android.gallery3d.filtershow.filters.FilterCurvesRepresentation; 4171f04cbaedbb89e313e0b86b531640db2d3f6016nicolasroardimport com.android.gallery3d.filtershow.filters.FiltersManager; 4292e2341248e99c691f38820503984bc5e2f18811nicolasroardimport com.android.gallery3d.filtershow.filters.ImageFilterCurves; 43ce9ceff5776a9b0479c30cbeb2a9388b44df1865nicolasroardimport com.android.gallery3d.filtershow.pipeline.ImagePreset; 4492e2341248e99c691f38820503984bc5e2f18811nicolasroard 456a07dfbe03c8396cc43840a1630ea480a2cff663John Hofordimport java.util.HashMap; 466a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford 4763a7dac01d394523799939596b960cb03321798dJohn Hofordpublic class ImageCurves extends ImageShow { 480d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 490d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private static final String LOGTAG = "ImageCurves"; 500d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard Paint gPaint = new Paint(); 510d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard Path gPathSpline = new Path(); 526a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford HashMap<Integer, String> mIdStrLut; 533992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 54c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard private int mCurrentCurveIndex = Spline.RGB; 550d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private boolean mDidAddPoint = false; 560d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private boolean mDidDelete = false; 570d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private ControlPoint mCurrentControlPoint = null; 58952144dd3146a195ea4bd0be3f88275df8b31c64nicolasroard private int mCurrentPick = -1; 593992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard private ImagePreset mLastPreset = null; 603992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int[] redHistogram = new int[256]; 613992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int[] greenHistogram = new int[256]; 623992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int[] blueHistogram = new int[256]; 633992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard Path gHistoPath = new Path(); 640d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 65c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard boolean mDoingTouchMove = false; 6619161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford private EditorCurves mEditorCurves; 6719161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford private FilterCurvesRepresentation mFilterCurvesRepresentation; 68c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard 690d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard public ImageCurves(Context context) { 700d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard super(context); 71f7cfa85f7dc2bb29affefff9374f3a4029b8a057nicolasroard setLayerType(LAYER_TYPE_SOFTWARE, gPaint); 720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard resetCurve(); 730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 740d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 750d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard public ImageCurves(Context context, AttributeSet attrs) { 760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard super(context, attrs); 77f7cfa85f7dc2bb29affefff9374f3a4029b8a057nicolasroard setLayerType(LAYER_TYPE_SOFTWARE, gPaint); 780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard resetCurve(); 790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 800d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 819820e7e753b7e1977ef3d2163605431769ce9165nicolasroard @Override 823024aa22d372c0d6608b143a0c46b86c2104f9b1nicolasroard protected boolean enableComparison() { 833024aa22d372c0d6608b143a0c46b86c2104f9b1nicolasroard return false; 843024aa22d372c0d6608b143a0c46b86c2104f9b1nicolasroard } 853024aa22d372c0d6608b143a0c46b86c2104f9b1nicolasroard 863024aa22d372c0d6608b143a0c46b86c2104f9b1nicolasroard @Override 879820e7e753b7e1977ef3d2163605431769ce9165nicolasroard public boolean useUtilityPanel() { 889820e7e753b7e1977ef3d2163605431769ce9165nicolasroard return true; 899820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 909820e7e753b7e1977ef3d2163605431769ce9165nicolasroard 919820e7e753b7e1977ef3d2163605431769ce9165nicolasroard private void showPopupMenu(LinearLayout accessoryViewList) { 926a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford final Button button = (Button) accessoryViewList.findViewById( 936a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford R.id.applyEffect); 949820e7e753b7e1977ef3d2163605431769ce9165nicolasroard if (button == null) { 959820e7e753b7e1977ef3d2163605431769ce9165nicolasroard return; 969820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 976a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford if (mIdStrLut == null){ 986a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford mIdStrLut = new HashMap<Integer, String>(); 996a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford mIdStrLut.put(R.id.curve_menu_rgb, 1006a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford getContext().getString(R.string.curves_channel_rgb)); 1016a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford mIdStrLut.put(R.id.curve_menu_red, 1026a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford getContext().getString(R.string.curves_channel_red)); 1036a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford mIdStrLut.put(R.id.curve_menu_green, 1046a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford getContext().getString(R.string.curves_channel_green)); 1056a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford mIdStrLut.put(R.id.curve_menu_blue, 1066a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford getContext().getString(R.string.curves_channel_blue)); 1076a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford } 1089820e7e753b7e1977ef3d2163605431769ce9165nicolasroard PopupMenu popupMenu = new PopupMenu(getActivity(), button); 1099820e7e753b7e1977ef3d2163605431769ce9165nicolasroard popupMenu.getMenuInflater().inflate(R.menu.filtershow_menu_curves, popupMenu.getMenu()); 1109820e7e753b7e1977ef3d2163605431769ce9165nicolasroard popupMenu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { 1119820e7e753b7e1977ef3d2163605431769ce9165nicolasroard @Override 1129820e7e753b7e1977ef3d2163605431769ce9165nicolasroard public boolean onMenuItemClick(MenuItem item) { 1139820e7e753b7e1977ef3d2163605431769ce9165nicolasroard setChannel(item.getItemId()); 1146a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford button.setText(mIdStrLut.get(item.getItemId())); 1159820e7e753b7e1977ef3d2163605431769ce9165nicolasroard return true; 1169820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 1179820e7e753b7e1977ef3d2163605431769ce9165nicolasroard }); 1187638772c0ceb5528b12c9943bad5391658d6c78dJohn Reck Editor.hackFixStrings(popupMenu.getMenu()); 1199820e7e753b7e1977ef3d2163605431769ce9165nicolasroard popupMenu.show(); 12064fc2ed005e2f1dc9ed0b34481c46a370c244b86John Hoford ((FilterShowActivity)getContext()).onShowMenu(popupMenu); 1219820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 1229820e7e753b7e1977ef3d2163605431769ce9165nicolasroard 1239820e7e753b7e1977ef3d2163605431769ce9165nicolasroard @Override 1249820e7e753b7e1977ef3d2163605431769ce9165nicolasroard public void openUtilityPanel(final LinearLayout accessoryViewList) { 1256a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford Context context = accessoryViewList.getContext(); 1266a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford Button view = (Button) accessoryViewList.findViewById(R.id.applyEffect); 1276a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford view.setText(context.getString(R.string.curves_channel_rgb)); 1286a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford view.setVisibility(View.VISIBLE); 1296a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford 1306a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford view.setOnClickListener(new OnClickListener() { 1319820e7e753b7e1977ef3d2163605431769ce9165nicolasroard @Override 1326a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford public void onClick(View arg0) { 1336a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford showPopupMenu(accessoryViewList); 1346a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford } 1356a07dfbe03c8396cc43840a1630ea480a2cff663John Hoford }); 1369820e7e753b7e1977ef3d2163605431769ce9165nicolasroard 1379820e7e753b7e1977ef3d2163605431769ce9165nicolasroard if (view != null) { 1389820e7e753b7e1977ef3d2163605431769ce9165nicolasroard view.setVisibility(View.VISIBLE); 1399820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 1409820e7e753b7e1977ef3d2163605431769ce9165nicolasroard } 1419820e7e753b7e1977ef3d2163605431769ce9165nicolasroard 1423992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard public void nextChannel() { 1433992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard mCurrentCurveIndex = ((mCurrentCurveIndex + 1) % 4); 1443992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard invalidate(); 1453992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 1463992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 147d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard private ImageFilterCurves curves() { 14863a7dac01d394523799939596b960cb03321798dJohn Hoford String filterName = getFilterName(); 14963a7dac01d394523799939596b960cb03321798dJohn Hoford ImagePreset p = getImagePreset(); 15063a7dac01d394523799939596b960cb03321798dJohn Hoford if (p != null) { 15171f04cbaedbb89e313e0b86b531640db2d3f6016nicolasroard return (ImageFilterCurves) FiltersManager.getManager().getFilter(ImageFilterCurves.class); 1520d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 153d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard return null; 154d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard } 155d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard 156d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard private Spline getSpline(int index) { 157d009e38321c3e46966370623f950215534d96925John Hoford return mFilterCurvesRepresentation.getSpline(index); 1580d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 1590d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 16092e2341248e99c691f38820503984bc5e2f18811nicolasroard @Override 16192e2341248e99c691f38820503984bc5e2f18811nicolasroard public void resetParameter() { 16292e2341248e99c691f38820503984bc5e2f18811nicolasroard super.resetParameter(); 16392e2341248e99c691f38820503984bc5e2f18811nicolasroard resetCurve(); 1643992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard mLastPreset = null; 1653992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard invalidate(); 16692e2341248e99c691f38820503984bc5e2f18811nicolasroard } 16792e2341248e99c691f38820503984bc5e2f18811nicolasroard 1680d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard public void resetCurve() { 169d009e38321c3e46966370623f950215534d96925John Hoford if (mFilterCurvesRepresentation != null) { 170d009e38321c3e46966370623f950215534d96925John Hoford mFilterCurvesRepresentation.reset(); 171d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard updateCachedImage(); 1720d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 1730d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 1740d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 17592e2341248e99c691f38820503984bc5e2f18811nicolasroard @Override 1760d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard public void onDraw(Canvas canvas) { 1770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard super.onDraw(canvas); 178f5eedf1635eba7edfa7d41fd4e991cced978c4b2nicolasroard if (mFilterCurvesRepresentation == null) { 179f5eedf1635eba7edfa7d41fd4e991cced978c4b2nicolasroard return; 180f5eedf1635eba7edfa7d41fd4e991cced978c4b2nicolasroard } 1810d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 1820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard gPaint.setAntiAlias(true); 1830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 18431529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard if (getImagePreset() != mLastPreset && getFilteredImage() != null) { 18531529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard new ComputeHistogramTask().execute(getFilteredImage()); 1863992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard mLastPreset = getImagePreset(); 1870d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 1880d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 18915a056e3cc1970bc0b99dba71df8222ba0345859nicolasroard if (curves() == null) { 19015a056e3cc1970bc0b99dba71df8222ba0345859nicolasroard return; 19115a056e3cc1970bc0b99dba71df8222ba0345859nicolasroard } 19215a056e3cc1970bc0b99dba71df8222ba0345859nicolasroard 1933992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (mCurrentCurveIndex == Spline.RGB || mCurrentCurveIndex == Spline.RED) { 1943992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard drawHistogram(canvas, redHistogram, Color.RED, PorterDuff.Mode.SCREEN); 1953992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 1963992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (mCurrentCurveIndex == Spline.RGB || mCurrentCurveIndex == Spline.GREEN) { 1973992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard drawHistogram(canvas, greenHistogram, Color.GREEN, PorterDuff.Mode.SCREEN); 1983992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 1993992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (mCurrentCurveIndex == Spline.RGB || mCurrentCurveIndex == Spline.BLUE) { 2003992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard drawHistogram(canvas, blueHistogram, Color.BLUE, PorterDuff.Mode.SCREEN); 2013992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 2023992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard // We only display the other channels curves when showing the RGB curve 2033992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (mCurrentCurveIndex == Spline.RGB) { 2043992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard for (int i = 0; i < 4; i++) { 205d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard Spline spline = getSpline(i); 2063992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (i != mCurrentCurveIndex && !spline.isOriginal()) { 2073992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard // And we only display a curve if it has more than two 2083992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard // points 209c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard spline.draw(canvas, Spline.colorForCurve(i), getWidth(), 210c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard getHeight(), false, mDoingTouchMove); 2113992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 2120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2130d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2143992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard // ...but we always display the current curve. 215d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard getSpline(mCurrentCurveIndex) 2163992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard .draw(canvas, Spline.colorForCurve(mCurrentCurveIndex), getWidth(), getHeight(), 217c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard true, mDoingTouchMove); 2180d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2190d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2200d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2210d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private int pickControlPoint(float x, float y) { 2220d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard int pick = 0; 223d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard Spline spline = getSpline(mCurrentCurveIndex); 224d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard float px = spline.getPoint(0).x; 225d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard float py = spline.getPoint(0).y; 2260d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard double delta = Math.sqrt((px - x) * (px - x) + (py - y) * (py - y)); 227d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard for (int i = 1; i < spline.getNbPoints(); i++) { 228d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard px = spline.getPoint(i).x; 229d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard py = spline.getPoint(i).y; 2300d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard double currentDelta = Math.sqrt((px - x) * (px - x) + (py - y) 2310d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard * (py - y)); 2320d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (currentDelta < delta) { 2330d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard delta = currentDelta; 2340d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard pick = i; 2350d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2360d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2370d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2380d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (!mDidAddPoint && (delta * getWidth() > 100) 239d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard && (spline.getNbPoints() < 10)) { 2400d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard return -1; 2410d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2420d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2433992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard return pick; 2440d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2450d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2460d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard private String getFilterName() { 2473992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard return "Curves"; 2480d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2490d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2500d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard @Override 2510d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard public synchronized boolean onTouchEvent(MotionEvent e) { 252df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (e.getPointerCount() != 1) { 253df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard return true; 254df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } 255df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard 256df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (didFinishScalingOperation()) { 257df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard return true; 258df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } 259df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard 2603992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float margin = Spline.curveHandleSize() / 2; 2611fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard float posX = e.getX(); 2621fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard if (posX < margin) { 2631fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard posX = margin; 2641fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard } 2651fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard float posY = e.getY(); 2663992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (posY < margin) { 2673992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard posY = margin; 2683992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 2691fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard if (posX > getWidth() - margin) { 2701fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard posX = getWidth() - margin; 2711fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard } 2723992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (posY > getHeight() - margin) { 2733992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard posY = getHeight() - margin; 2743992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 2751fe7caeeaab314cd70d0b54f8f3dd3225c71c081nicolasroard posX = (posX - margin) / (getWidth() - 2 * margin); 2763992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard posY = (posY - margin) / (getHeight() - 2 * margin); 2770d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2780d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (e.getActionMasked() == MotionEvent.ACTION_UP) { 2790d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard mCurrentControlPoint = null; 280952144dd3146a195ea4bd0be3f88275df8b31c64nicolasroard mCurrentPick = -1; 281d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard updateCachedImage(); 2820d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard mDidAddPoint = false; 2830d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (mDidDelete) { 2840d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard mDidDelete = false; 2850d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 286c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard mDoingTouchMove = false; 2870d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard return true; 2880d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2890d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 2900d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (mDidDelete) { 2910d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard return true; 2920d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 2930d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 29431529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard if (curves() == null) { 29531529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard return true; 29631529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard } 29731529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard 298df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (e.getActionMasked() == MotionEvent.ACTION_MOVE) { 299df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mDoingTouchMove = true; 300df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard Spline spline = getSpline(mCurrentCurveIndex); 301df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard int pick = mCurrentPick; 302df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (mCurrentControlPoint == null) { 303df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard pick = pickControlPoint(posX, posY); 304df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (pick == -1) { 305df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mCurrentControlPoint = new ControlPoint(posX, posY); 306df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard pick = spline.addPoint(mCurrentControlPoint); 307df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mDidAddPoint = true; 308df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } else { 309df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mCurrentControlPoint = spline.getPoint(pick); 310df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } 311df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mCurrentPick = pick; 3120d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 3133992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 314df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard if (spline.isPointContained(posX, pick)) { 315df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard spline.movePoint(pick, posX, posY); 316df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } else if (pick != -1 && spline.getNbPoints() > 2) { 317df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard spline.deletePoint(pick); 318df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard mDidDelete = true; 319df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard } 320df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard updateCachedImage(); 321df0b0c4eaafcc9e4652fe6ec0791e4abe1c3b750nicolasroard invalidate(); 3220d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 3230d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard return true; 3240d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 3250d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 326d7899c56b8df278dfd6720ae11eadc2f89fe8094nicolasroard public synchronized void updateCachedImage() { 3270d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard if (getImagePreset() != null) { 32831529940021b9a18611b1a3fb4a0317ab8c89618nicolasroard resetImageCaches(this); 32919161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford if (mEditorCurves != null) { 33019161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford mEditorCurves.commitLocalRepresentation(); 33119161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford } 3320d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard invalidate(); 3330d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 3340d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard } 3350d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard 3363992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard class ComputeHistogramTask extends AsyncTask<Bitmap, Void, int[]> { 3373992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard @Override 3383992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard protected int[] doInBackground(Bitmap... params) { 3393992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int[] histo = new int[256 * 3]; 3403992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard Bitmap bitmap = params[0]; 3413992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int w = bitmap.getWidth(); 3423992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int h = bitmap.getHeight(); 3433992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int[] pixels = new int[w * h]; 3443992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard bitmap.getPixels(pixels, 0, w, 0, 0, w, h); 3453992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard for (int i = 0; i < w; i++) { 3463992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard for (int j = 0; j < h; j++) { 3473992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int index = j * w + i; 3483992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int r = Color.red(pixels[index]); 3493992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int g = Color.green(pixels[index]); 3503992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int b = Color.blue(pixels[index]); 3513992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard histo[r]++; 3523992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard histo[256 + g]++; 3533992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard histo[512 + b]++; 3543992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3553992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3563992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard return histo; 3573992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3583992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 3593992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard @Override 3603992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard protected void onPostExecute(int[] result) { 3613992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard System.arraycopy(result, 0, redHistogram, 0, 256); 3623992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard System.arraycopy(result, 256, greenHistogram, 0, 256); 3633992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard System.arraycopy(result, 512, blueHistogram, 0, 256); 3643992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard invalidate(); 3653992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3663992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3673992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 3683992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard private void drawHistogram(Canvas canvas, int[] histogram, int color, PorterDuff.Mode mode) { 3693992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard int max = 0; 3703992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard for (int i = 0; i < histogram.length; i++) { 3713992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (histogram[i] > max) { 3723992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard max = histogram[i]; 3733992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 3743992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 375599393ecad6803161d5e901ef625e34cfe088009nicolasroard float w = getWidth() - Spline.curveHandleSize(); 376599393ecad6803161d5e901ef625e34cfe088009nicolasroard float h = getHeight() - Spline.curveHandleSize() / 2.0f; 377599393ecad6803161d5e901ef625e34cfe088009nicolasroard float dx = Spline.curveHandleSize() / 2.0f; 3783992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float wl = w / histogram.length; 3793992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float wh = (0.3f * h) / max; 3803992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard Paint paint = new Paint(); 3813992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint.setARGB(100, 255, 255, 255); 3823992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint.setStrokeWidth((int) Math.ceil(wl)); 3833992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard 3843992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard Paint paint2 = new Paint(); 3853992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setColor(color); 3863992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setStrokeWidth(6); 3873992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setXfermode(new PorterDuffXfermode(mode)); 3883992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.reset(); 389599393ecad6803161d5e901ef625e34cfe088009nicolasroard gHistoPath.moveTo(dx, h); 3903992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard boolean firstPointEncountered = false; 3913992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float prev = 0; 3923992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float last = 0; 3933992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard for (int i = 0; i < histogram.length; i++) { 394599393ecad6803161d5e901ef625e34cfe088009nicolasroard float x = i * wl + dx; 3953992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float l = histogram[i] * wh; 3963992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (l != 0) { 3973992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard float v = h - (l + prev) / 2.0f; 3983992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard if (!firstPointEncountered) { 3993992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.lineTo(x, h); 4003992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard firstPointEncountered = true; 4013992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 4023992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.lineTo(x, v); 4033992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard prev = l; 4043992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard last = x; 4053992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 4063992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 4073992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.lineTo(last, h); 4083992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.lineTo(w, h); 4093992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard gHistoPath.close(); 4103992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard canvas.drawPath(gHistoPath, paint2); 4113992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setStrokeWidth(2); 4123992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setStyle(Paint.Style.STROKE); 4133992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard paint2.setARGB(255, 200, 200, 200); 4143992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard canvas.drawPath(gHistoPath, paint2); 4153992ae6cf1cbb7b57a22d8287c40451558408335nicolasroard } 416c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard 417c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard public void setChannel(int itemId) { 418c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard switch (itemId) { 419c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard case R.id.curve_menu_rgb: { 420c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard mCurrentCurveIndex = Spline.RGB; 421c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard break; 422c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 423c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard case R.id.curve_menu_red: { 424c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard mCurrentCurveIndex = Spline.RED; 425c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard break; 426c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 427c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard case R.id.curve_menu_green: { 428c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard mCurrentCurveIndex = Spline.GREEN; 429c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard break; 430c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 431c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard case R.id.curve_menu_blue: { 432c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard mCurrentCurveIndex = Spline.BLUE; 433c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard break; 434c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 435c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 43619161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford mEditorCurves.commitLocalRepresentation(); 437c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard invalidate(); 438c5590eb1a20b112e67e4c43684790587f844fc6bnicolasroard } 43919161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford 44019161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford public void setEditor(EditorCurves editorCurves) { 44119161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford mEditorCurves = editorCurves; 44219161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford } 44319161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford 44419161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford public void setFilterDrawRepresentation(FilterCurvesRepresentation drawRep) { 44519161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford mFilterCurvesRepresentation = drawRep; 44619161944e0efb1ffe23274d7cf5315ce047e9dacJohn Hoford } 4470d7cdf8e763fb65c32bfad65245b3753deb75737nicolasroard} 448