summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorJay Wang <jaywang@codeaurora.org>2016-06-09 12:49:49 -0700
committerJay Wang <jaywang@codeaurora.org>2016-08-08 12:07:32 -0700
commitf19b070884f491ecae432914131a302876e1fcf6 (patch)
tree2c3ddb4f766e1aa6e390b46f901cacb8183c8533 /src
parent933ff5d0c4124f4e57a08d6e6a18fa1705241dab (diff)
downloadandroid_packages_apps_Gallery2-f19b070884f491ecae432914131a302876e1fcf6.tar.gz
android_packages_apps_Gallery2-f19b070884f491ecae432914131a302876e1fcf6.tar.bz2
android_packages_apps_Gallery2-f19b070884f491ecae432914131a302876e1fcf6.zip
Gallery: Add TruePortrait post proc feature
Add TruePortrait post processing feature to Gallery CRs-Fixed: 1029226 Change-Id: Id7ea0a8f810990952008fc28d30df27421c91d14
Diffstat (limited to 'src')
-rw-r--r--src/com/android/gallery3d/filtershow/FilterShowActivity.java240
-rw-r--r--src/com/android/gallery3d/filtershow/cache/BitmapCache.java12
-rw-r--r--src/com/android/gallery3d/filtershow/category/Action.java35
-rw-r--r--src/com/android/gallery3d/filtershow/category/CategoryAdapter.java18
-rw-r--r--src/com/android/gallery3d/filtershow/category/CategoryPanel.java8
-rw-r--r--src/com/android/gallery3d/filtershow/category/MainPanel.java68
-rw-r--r--src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java87
-rw-r--r--src/com/android/gallery3d/filtershow/controller/BasicSlider.java3
-rw-r--r--src/com/android/gallery3d/filtershow/editors/Editor.java37
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorChanSat.java5
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java12
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorCrop.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorCurves.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorDraw.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java2
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorGrad.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorMakeup.java4
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorPanel.java13
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java84
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java226
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java92
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java222
-rw-r--r--src/com/android/gallery3d/filtershow/editors/EditorVignette.java5
-rw-r--r--src/com/android/gallery3d/filtershow/editors/ParametricEditor.java6
-rw-r--r--src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java77
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java6
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java39
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java1
-rw-r--r--src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java158
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java195
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java58
-rw-r--r--src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java46
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageShow.java60
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java84
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java675
-rw-r--r--src/com/android/gallery3d/filtershow/imageshow/MasterImage.java8
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/Buffer.java5
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java58
-rw-r--r--src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java2
-rw-r--r--src/com/android/gallery3d/filtershow/tools/SaveImage.java114
-rw-r--r--src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java247
-rw-r--r--src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java57
-rw-r--r--src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java79
-rw-r--r--src/com/android/gallery3d/util/GalleryUtils.java30
44 files changed, 2971 insertions, 223 deletions
diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
index 157087972..c12635f06 100644
--- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java
+++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java
@@ -57,7 +57,6 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
-import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
@@ -90,6 +89,7 @@ import com.android.gallery3d.filtershow.category.EditorCropPanel;
import com.android.gallery3d.filtershow.category.MainPanel;
import com.android.gallery3d.filtershow.category.StraightenPanel;
import com.android.gallery3d.filtershow.category.SwipableView;
+import com.android.gallery3d.filtershow.category.TruePortraitMaskEditorPanel;
import com.android.gallery3d.filtershow.category.TrueScannerPanel;
import com.android.gallery3d.filtershow.data.UserPresetsManager;
import com.android.gallery3d.filtershow.editors.Editor;
@@ -98,6 +98,9 @@ import com.android.gallery3d.filtershow.editors.EditorDualCamFusion;
import com.android.gallery3d.filtershow.editors.EditorManager;
import com.android.gallery3d.filtershow.editors.EditorPanel;
import com.android.gallery3d.filtershow.editors.EditorStraighten;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitImageOnly;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
import com.android.gallery3d.filtershow.editors.HazeBusterEditor;
import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
import com.android.gallery3d.filtershow.editors.SeeStraightEditor;
@@ -125,6 +128,7 @@ import com.android.gallery3d.filtershow.state.StateAdapter;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine.DdmStatus;
import com.android.gallery3d.filtershow.tools.SaveImage;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
import com.android.gallery3d.filtershow.tools.XmpPresets;
import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults;
import com.android.gallery3d.filtershow.ui.ExportDialog;
@@ -132,13 +136,15 @@ import com.android.gallery3d.filtershow.ui.FramedTextButton;
import com.android.gallery3d.mpo.MpoParser;
import com.android.gallery3d.util.GalleryUtils;
import com.android.photos.data.GalleryBitmapPool;
+import com.thundersoft.hz.selfportrait.detect.FaceDetect;
+import com.thundersoft.hz.selfportrait.detect.FaceInfo;
import com.thundersoft.hz.selfportrait.makeup.engine.MakeupEngine;
import static android.app.Activity.RESULT_OK;
public class FilterShowActivity extends FragmentActivity implements OnItemClickListener,
- OnShareTargetSelectedListener, DialogInterface.OnShowListener,
- DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{
+OnShareTargetSelectedListener, DialogInterface.OnShowListener,
+DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{
private String mAction = "";
MasterImage mMasterImage = null;
@@ -176,6 +182,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
private LoadHighresBitmapTask mHiResBitmapTask;
private ParseMpoDataTask mParseMpoTask;
private LoadMpoDataTask mLoadMpoTask;
+ private LoadTruePortraitTask mLoadTruePortraitTask;
private Uri mOriginalImageUri = null;
private ImagePreset mOriginalPreset = null;
@@ -195,6 +202,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
private CategoryAdapter mCategoryVersionsAdapter = null;
private CategoryAdapter mCategoryMakeupAdapter = null;
private CategoryAdapter mCategoryDualCamAdapter = null;
+ private CategoryAdapter mCategoryTruePortraitAdapter = null;
private int mCurrentPanel = MainPanel.LOOKS;
private Vector<FilterUserPresetRepresentation> mVersions =
new Vector<FilterUserPresetRepresentation>();
@@ -365,20 +373,31 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
transaction.commitAllowingStateLoss();
}
- public void loadEditorPanel(final FilterRepresentation representation,
- final Editor currentEditor) {
- if (currentEditor.showsActionBar()) {
+ public void loadEditorPanel(final FilterRepresentation representation) {
+ final int currentId = representation.getEditorId();
+
+ // show representation
+ if (mCurrentEditor != null) {
+ mCurrentEditor.detach();
+ }
+ mCurrentEditor = mEditorPlaceHolder.showEditor(currentId);
+
+ if (mCurrentEditor.showsActionBar()) {
setActionBar();
showActionBar(true);
} else {
showActionBar(false);
}
- if (representation.getEditorId() == ImageOnlyEditor.ID) {
- currentEditor.reflectCurrentFilter();
+ if (currentId == ImageOnlyEditor.ID) {
+ mCurrentEditor.reflectCurrentFilter();
+ return;
+ }
+ if (currentId == EditorTruePortraitImageOnly.ID) {
+ mCurrentEditor.reflectCurrentFilter();
+ setActionBarForEffects(mCurrentEditor);
return;
}
- final int currentId = currentEditor.getID();
if (currentId == EditorCrop.ID) {
loadEditorCropPanel();
return;
@@ -419,12 +438,30 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}.run();
return;
}
+ if(currentId == EditorTruePortraitMask.ID) {
+ new Runnable() {
+ @Override
+ public void run() {
+ setActionBarForEffects(mCurrentEditor);
+ TruePortraitMaskEditorPanel panel = new TruePortraitMaskEditorPanel();
+ FragmentTransaction transaction =
+ getSupportFragmentManager().beginTransaction();
+ transaction.remove(getSupportFragmentManager().findFragmentByTag(
+ MainPanel.FRAGMENT_TAG));
+ transaction.replace(R.id.main_panel_container, panel,
+ MainPanel.FRAGMENT_TAG);
+ transaction.commit();
+ }
+ }.run();
+ return;
+ }
+
Runnable showEditor = new Runnable() {
@Override
public void run() {
EditorPanel panel = new EditorPanel();
panel.setEditor(currentId);
- setActionBarForEffects(currentEditor);
+ setActionBarForEffects(mCurrentEditor);
Fragment main =
getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
if (main instanceof MainPanel) {
@@ -484,6 +521,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
if (currentPanel instanceof MainPanel) {
((MainPanel) currentPanel).removeEditorPanelFragment();
+ if (mCurrentEditor != null) {
+ mCurrentEditor.detach();
+ }
+ mCurrentEditor = null;
}
}
@@ -540,8 +581,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
public void toggleComparisonButtonVisibility() {
- if (imgComparison.getVisibility() == View.VISIBLE)
- imgComparison.setVisibility(View.GONE);
+ if (imgComparison.getVisibility() == View.VISIBLE)
+ imgComparison.setVisibility(View.GONE);
}
private void showSaveButtonIfNeed() {
@@ -592,10 +633,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
public void setActionBarForEffects(final Editor currentEditor) {
- View view;
- LayoutInflater inflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- view = inflater.inflate(R.layout.filtershow_editor_panel, null);
- View editControl = view.findViewById(R.id.controlArea);
ActionBar actionBar = getActionBar();
actionBar.setDisplayOptions(ActionBar.DISPLAY_SHOW_CUSTOM);
actionBar.setBackgroundDrawable(new ColorDrawable(getResources()
@@ -628,7 +665,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
});
if (currentEditor != null) {
- currentEditor.setUpEditorUI(editTitle, actionControl, editControl);
+ if(!currentEditor.showsActionBarControls()) {
+ cancelButton.setVisibility(View.GONE);
+ applyButton.setVisibility(View.GONE);
+ }
+ currentEditor.setEditorTitle(editTitle);
currentEditor.reflectCurrentFilter();
if (currentEditor.useUtilityPanel()) {
currentEditor.openUtilityPanel((LinearLayout) actionControl);
@@ -658,6 +699,12 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
int position = adapter.undo();
masterImage.onHistoryItemClick(position);
invalidateViews();
+
+ if(!masterImage.hasFusionApplied()) {
+ masterImage.setFusionUnderlay(null);
+ masterImage.setScaleFactor(1);
+ masterImage.resetTranslation();
+ }
}
public void adjustCompareButton(boolean scaled) {
@@ -686,6 +733,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
fillVersions();
fillMakeup();
fillDualCamera();
+ fillTruePortrait();
}
public void setupStatePanel() {
@@ -808,6 +856,21 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
}
+ private void fillTruePortrait() {
+ FiltersManager filtersManager = FiltersManager.getManager();
+ ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTruePortrait();
+ if (mCategoryTruePortraitAdapter != null) {
+ mCategoryTruePortraitAdapter.clear();
+ }
+ mCategoryTruePortraitAdapter = new CategoryAdapter(this);
+ for (FilterRepresentation representation : filtersRepresentations) {
+ if (representation.getTextId() != 0) {
+ representation.setName(getString(representation.getTextId()));
+ }
+ mCategoryTruePortraitAdapter.add(new Action(this, representation));
+ }
+ }
+
private void fillTrueScanner() {
FiltersManager filtersManager = FiltersManager.getManager();
ArrayList<FilterRepresentation> trueScannerRepresentations = filtersManager.getTrueScanner();
@@ -926,6 +989,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mainPanel.updateDualCameraButton();
}
}
+
+ if(TruePortraitNativeEngine.getInstance().isLibLoaded()) {
+ mLoadTruePortraitTask = new LoadTruePortraitTask();
+ mLoadTruePortraitTask.execute(uri);
+ }
}
private void fillBorders() {
@@ -987,6 +1055,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
return mCategoryDualCamAdapter;
}
+ public CategoryAdapter getCategoryTruePortraitAdapter() {
+ return mCategoryTruePortraitAdapter;
+ }
+
public void removeFilterRepresentation(FilterRepresentation filterRepresentation) {
if (filterRepresentation == null) {
return;
@@ -1006,8 +1078,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
return;
}
if (!(filterRepresentation instanceof FilterRotateRepresentation)
- && !(filterRepresentation instanceof FilterMirrorRepresentation)
- && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
+ && !(filterRepresentation instanceof FilterMirrorRepresentation)
+ && MasterImage.getImage().getCurrentFilterRepresentation() == filterRepresentation) {
return;
}
if (filterRepresentation instanceof FilterUserPresetRepresentation
@@ -1085,12 +1157,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
}
useFilterRepresentation(representation);
- // show representation
- if (mCurrentEditor != null) {
- mCurrentEditor.detach();
- }
- mCurrentEditor = mEditorPlaceHolder.showEditor(representation.getEditorId());
- loadEditorPanel(representation, mCurrentEditor);
+ loadEditorPanel(representation);
}
public Editor getEditor(int editorID) {
@@ -1122,6 +1189,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryMakeupAdapter.reflectImagePreset(preset);
}
mCategoryDualCamAdapter.reflectImagePreset(preset);
+ mCategoryTruePortraitAdapter.reflectImagePreset(preset);
}
public View getMainStatePanelContainer(int id) {
@@ -1221,16 +1289,15 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mAuxImgData == null) {
// parse failed
MasterImage.getImage().setDepthMapLoadingStatus(DdmStatus.DDM_FAILED);
+ Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
+ if (currentPanel instanceof MainPanel) {
+ MainPanel mainPanel = (MainPanel) currentPanel;
+ mainPanel.updateDualCameraButton();
+ }
} else {
mLoadMpoTask = new LoadMpoDataTask();
mLoadMpoTask.execute(mPrimaryImgData, mAuxImgData);
}
-
- Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG);
- if (currentPanel instanceof MainPanel) {
- MainPanel mainPanel = (MainPanel) currentPanel;
- mainPanel.updateDualCameraButton();
- }
}
}
@@ -1288,7 +1355,40 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
if(mLoadingDialog != null && mLoadingDialog.isShowing()) {
mLoadingDialog.dismiss();
}
- }
+ }
+
+ private class LoadTruePortraitTask extends AsyncTask<Uri, Void, Boolean> {
+
+ @Override
+ protected Boolean doInBackground(Uri... params) {
+ boolean result = false;
+ Bitmap src = ImageLoader.loadBitmap(FilterShowActivity.this, params[0], null);
+ FaceDetect fDetect = new FaceDetect();
+ fDetect.initialize();
+ FaceInfo[] faceInfos = fDetect.dectectFeatures(src);
+ fDetect.uninitialize();
+
+ if(faceInfos != null && faceInfos.length > 0) {
+ Rect[] faces = new Rect[faceInfos.length];
+ for(int i=0; i<faceInfos.length; i++) {
+ faces[i] = faceInfos[i].face;
+ }
+
+ result = TruePortraitNativeEngine.getInstance().init(FilterShowActivity.this, src, faces);
+ } else {
+ TruePortraitNativeEngine.getInstance().setFacesDetected(false);
+ }
+
+ src.recycle();
+ src = null;
+
+ return result;
+ }
+
+ @Override
+ protected void onPostExecute(Boolean result) {
+ }
+ }
private class LoadBitmapTask extends AsyncTask<Uri, Boolean, Boolean> {
int mBitmapSize;
@@ -1362,6 +1462,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mCategoryGeometryAdapter.imageLoaded();
mCategoryFiltersAdapter.imageLoaded();
mCategoryDualCamAdapter.imageLoaded();
+ mCategoryTruePortraitAdapter.imageLoaded();
if(mCategoryMakeupAdapter != null) {
mCategoryMakeupAdapter.imageLoaded();
}
@@ -1421,6 +1522,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
mLoadMpoTask.cancel(false);
}
+ if(mLoadTruePortraitTask != null) {
+ mLoadTruePortraitTask.cancel(false);
+ }
+
mUserPresetsManager.close();
unregisterReceiver(mHandlerReceiver);
doUnbindService();
@@ -1515,11 +1620,15 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
menu.clear();
getMenuInflater().inflate(R.menu.filtershow_activity_menu, menu);
mShareActionProvider = (ShareActionProvider) menu.findItem(
- R.id.menu_share).getActionProvider();
+ R.id.menu_share).getActionProvider();
mShareActionProvider.setShareIntent(getDefaultShareIntent());
mShareActionProvider.setOnShareTargetSelectedListener(this);
mMenu = menu;
setupMenu();
+
+ if(mCurrentEditor != null) {
+ mCurrentEditor.onPrepareOptionsMenu(menu);
+ }
return true;
}
@@ -1560,7 +1669,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
- /*case R.id.undoButton: {
+ /*case R.id.undoButton: {
HistoryManager adapter = mMasterImage.getHistory();
int position = adapter.undo();
mMasterImage.onHistoryItemClick(position);
@@ -1575,26 +1684,26 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
invalidateViews();
return true;
}*/
- case R.id.resetHistoryButton: {
- resetHistory();
- return true;
- }
- /*case R.id.showImageStateButton: {
+ case R.id.resetHistoryButton: {
+ resetHistory();
+ return true;
+ }
+ /*case R.id.showImageStateButton: {
toggleImageStatePanel();
return true;
}*/
- case R.id.exportFlattenButton: {
- showExportOptionsDialog();
- return true;
- }
- case android.R.id.home: {
- saveImage();
- return true;
- }
- case R.id.manageUserPresets: {
- manageUserPresets();
- return true;
- }
+ case R.id.exportFlattenButton: {
+ showExportOptionsDialog();
+ return true;
+ }
+ case android.R.id.home: {
+ saveImage();
+ return true;
+ }
+ case R.id.manageUserPresets: {
+ manageUserPresets();
+ return true;
+ }
}
return false;
}
@@ -1891,18 +2000,18 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
R.string.save_before_exit);
mBackAlertDialogBuilder.setPositiveButton(mPopUpText,
new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- done();
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ done();
+ }
+ });
mBackAlertDialogBuilder.setNegativeButton(mCancel,
new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialog, int id) {
- dialog.dismiss();
- }
- });
+ @Override
+ public void onClick(DialogInterface dialog, int id) {
+ dialog.dismiss();
+ }
+ });
}
public void cannotLoadImage() {
@@ -1942,8 +2051,13 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL
} else if (requestCode == SELECT_FUSION_UNDERLAY) {
Uri underlayImageUri = data.getData();
// find fusion representation
- EditorDualCamFusion editor = (EditorDualCamFusion)getEditor(EditorDualCamFusion.ID);
- editor.setUnderlayImageUri(underlayImageUri);
+ if(mCurrentEditor instanceof EditorDualCamFusion) {
+ EditorDualCamFusion editor = (EditorDualCamFusion)mCurrentEditor;
+ editor.setUnderlayImageUri(underlayImageUri);
+ } else if (mCurrentEditor instanceof EditorTruePortraitFusion) {
+ EditorTruePortraitFusion editor = (EditorTruePortraitFusion)mCurrentEditor;
+ editor.setUnderlayImageUri(underlayImageUri);
+ }
}
}
}
diff --git a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
index 10cadcfd2..82129c2c6 100644
--- a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
+++ b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java
@@ -16,18 +16,18 @@
package com.android.gallery3d.filtershow.cache;
+import java.lang.ref.WeakReference;
+import java.util.ArrayList;
+import java.util.HashMap;
+
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.PorterDuff;
+import android.graphics.Color;
import android.util.Log;
import com.android.gallery3d.filtershow.pipeline.Buffer;
import com.android.gallery3d.filtershow.pipeline.CacheProcessing;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.HashMap;
-
public class BitmapCache {
private static final String LOGTAG = "BitmapCache";
private HashMap<Long, ArrayList<WeakReference<Bitmap>>>
@@ -207,8 +207,8 @@ public class BitmapCache {
public synchronized Bitmap getBitmapCopy(Bitmap source, int type) {
Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight(), type);
+ bitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(bitmap);
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(source, 0, 0, null);
return bitmap;
}
diff --git a/src/com/android/gallery3d/filtershow/category/Action.java b/src/com/android/gallery3d/filtershow/category/Action.java
index 9c0587bfc..75982d851 100644
--- a/src/com/android/gallery3d/filtershow/category/Action.java
+++ b/src/com/android/gallery3d/filtershow/category/Action.java
@@ -30,6 +30,7 @@ import android.widget.ListAdapter;
import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.cache.BitmapCache;
import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.pipeline.RenderingRequest;
@@ -121,6 +122,16 @@ public class Action implements RenderingRequestCaller {
if (getType() == Action.ADD_ACTION) {
return;
}
+
+ if(mRepresentation.getOverlayOnly()) {
+ mImageFrame = imageFrame;
+ int w = mImageFrame.width();
+ int h = mImageFrame.height();
+ mImage = MasterImage.getImage().getBitmapCache().getBitmap(w, h, BitmapCache.ICON);
+ drawOverlay(true);
+ return;
+ }
+
Bitmap temp = MasterImage.getImage().getTemporaryThumbnailBitmap();
if (temp != null) {
mImage = temp;
@@ -175,14 +186,7 @@ public class Action implements RenderingRequestCaller {
canvas.drawBitmap(source, m, new Paint(Paint.FILTER_BITMAP_FLAG));
}
- @Override
- public void available(RenderingRequest request) {
- clearBitmap();
- mImage = request.getBitmap();
- if (mImage == null) {
- mImageFrame = null;
- return;
- }
+ private void drawOverlay(boolean scale) {
if (mRepresentation.getOverlayId() != 0 && mOverlayBitmap == null) {
mOverlayBitmap = BitmapFactory.decodeResource(
mContext.getResources(),
@@ -196,9 +200,22 @@ public class Action implements RenderingRequestCaller {
} else {
Canvas canvas = new Canvas(mImage);
canvas.drawARGB(128, 0, 0, 0);
- drawCenteredImage(mOverlayBitmap, mImage, false);
+ drawCenteredImage(mOverlayBitmap, mImage, scale);
}
}
+ }
+
+ @Override
+ public void available(RenderingRequest request) {
+ clearBitmap();
+ mImage = request.getBitmap();
+ if (mImage == null) {
+ mImageFrame = null;
+ return;
+ }
+
+ drawOverlay(false);
+
if (mAdapter != null) {
mAdapter.notifyDataSetChanged();
}
diff --git a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
index 4062bf0ef..6c4f9fe87 100644
--- a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
+++ b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java
@@ -80,15 +80,18 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
mSelectedPosition = 0;
mAddButtonText = getContext().getString(R.string.filtershow_add_button_looks);
}
-// if (category == MainPanel.MAKEUP) {
-// mSelectedPosition = 0;
-// }
+ // if (category == MainPanel.MAKEUP) {
+ // mSelectedPosition = 0;
+ // }
if (category == MainPanel.BORDERS) {
mSelectedPosition = 0;
}
if (category == MainPanel.DUALCAM) {
mSelectedPosition = 0;
}
+ if (category == MainPanel.TRUEPORTRAIT) {
+ mSelectedPosition = 0;
+ }
if (category == MainPanel.TRUESCANNER) {
mSelectedPosition = 0;
@@ -149,6 +152,10 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
return (Integer) v.getTag() == mSelectedPosition;
}
+ public int getCurrentSelection() {
+ return mSelectedPosition;
+ }
+
private void invalidateView(int position) {
View child = null;
if (mContainer instanceof ListView) {
@@ -235,6 +242,11 @@ public class CategoryAdapter extends ArrayAdapter<Action> {
if (pos != -1) {
rep = preset.getFilterRepresentation(pos);
}
+ } else if (mCategory == MainPanel.TRUEPORTRAIT) {
+ int pos = preset.getPositionForType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ if (pos != -1) {
+ rep = preset.getFilterRepresentation(pos);
+ }
} else if (mCategory == MainPanel.FILTERS || mCategory == MainPanel.MAKEUP) {
selected = UNKNOWN_INDEX;
}
diff --git a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
index 87f347586..3b91f024e 100644
--- a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java
@@ -90,6 +90,14 @@ public class CategoryPanel extends Fragment implements View.OnClickListener {
activity.updateCategories();
break;
}
+ case MainPanel.TRUEPORTRAIT: {
+ mAdapter = activity.getCategoryTruePortraitAdapter();
+ if (mAdapter != null) {
+ mAdapter.initializeSelection(MainPanel.TRUEPORTRAIT);
+ }
+ activity.updateCategories();
+ break;
+ }
case MainPanel.TRUESCANNER: {
mAdapter = activity.getCategoryTrueScannerAdapter();
if (mAdapter != null) {
diff --git a/src/com/android/gallery3d/filtershow/category/MainPanel.java b/src/com/android/gallery3d/filtershow/category/MainPanel.java
index 6571c46a3..4c909789d 100644
--- a/src/com/android/gallery3d/filtershow/category/MainPanel.java
+++ b/src/com/android/gallery3d/filtershow/category/MainPanel.java
@@ -17,6 +17,8 @@
package com.android.gallery3d.filtershow.category;
import android.content.res.Configuration;
+import android.content.Context;
+import android.content.DialogInterface;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
@@ -40,6 +42,9 @@ import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.state.StatePanel;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine;
import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine.DdmStatus;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelegate {
@@ -56,6 +61,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
private ImageButton trueScannerButton;
private ImageButton hazeBusterButton;
private ImageButton seeStraightButton;
+ private ImageButton truePortraitButton;
public static final String FRAGMENT_TAG = "MainPanel";
public static final String EDITOR_TAG = "coming-from-editor-panel";
@@ -69,6 +75,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
public static final int TRUESCANNER = 7;
public static final int HAZEBUSTER = 8;
public static final int SEESTRAIGHT = 9;
+ public static final int TRUEPORTRAIT = 10;
private int mCurrentSelected = -1;
private int mPreviousToggleVersions = -1;
@@ -105,6 +112,10 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
dualCamButton.setSelected(value);
break;
}
+ case TRUEPORTRAIT: {
+ truePortraitButton.setSelected(value);
+ break;
+ }
case TRUESCANNER: {
if (trueScannerButton != null) {
trueScannerButton.setSelected(value);
@@ -139,7 +150,7 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
+ Bundle savedInstanceState) {
mMainView = (LinearLayout) inflater.inflate(
R.layout.filtershow_main_panel, null, false);
@@ -204,6 +215,11 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
seeStraightButton.setVisibility(View.GONE);
}
+ truePortraitButton = (ImageButton) bottomPanel.findViewById(R.id.truePortraitButton);
+ if(!TruePortraitNativeEngine.getInstance().isLibLoaded()) {
+ truePortraitButton.setVisibility(View.GONE);
+ }
+
looksButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
@@ -235,9 +251,42 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
}
});
+ truePortraitButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(final View v) {
+ Context context = getActivity();
+ boolean skipIntro = GalleryUtils.getBooleanPref(context,
+ context.getString(R.string.pref_trueportrait_intro_show_key), false);
+ final boolean facesDetected = TruePortraitNativeEngine.getInstance().facesDetected();
+ if(skipIntro && facesDetected) {
+ showPanel(TRUEPORTRAIT);
+ } else if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.trueportrait, R.string.trueportrait_intro,
+ R.string.pref_trueportrait_intro_show_key) {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ if(facesDetected) {
+ showPanel(TRUEPORTRAIT);
+ } else {
+ v.setEnabled(false);
+ TruePortraitNativeEngine.getInstance().showNoFaceDetectedDialog(getFragmentManager());
+ }
+ }
+ };
+ dialog.show(getFragmentManager(), "trueportrait_intro");
+ } else {
+ v.setEnabled(false);
+ TruePortraitNativeEngine.getInstance().showNoFaceDetectedDialog(getFragmentManager());
+ }
+ }
+ });
+
trueScannerButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
+
showPanel(TRUESCANNER);
}
});
@@ -449,6 +498,19 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
}
}
+ public void loadCategoryTruePortraitPanel() {
+ if (mCurrentSelected == TRUEPORTRAIT) {
+ return;
+ }
+ boolean fromRight = isRightAnimation(TRUEPORTRAIT);
+ selection(mCurrentSelected, false);
+ CategoryPanel categoryPanel = new CategoryPanel();
+ categoryPanel.setAdapter(TRUEPORTRAIT);
+ setCategoryFragment(categoryPanel, fromRight);
+ mCurrentSelected = TRUEPORTRAIT;
+ selection(mCurrentSelected, true);
+ }
+
public void showPanel(int currentPanel) {
FilterShowActivity activity = (FilterShowActivity) getActivity();
switch (currentPanel) {
@@ -492,6 +554,10 @@ public class MainPanel extends Fragment implements BottomPanel.BottomPanelDelega
loadCategoryMakeupPanel();
break;
}
+ case TRUEPORTRAIT: {
+ loadCategoryTruePortraitPanel();
+ break;
+ }
}
if (currentPanel > 0) {
activity.adjustCompareButton(true);
diff --git a/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java b/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java
new file mode 100644
index 000000000..03935edc0
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/category/TruePortraitMaskEditorPanel.java
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.category;
+
+
+import android.content.Context;
+import android.os.Bundle;
+import android.support.v4.app.Fragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class TruePortraitMaskEditorPanel extends Fragment {
+ private View mMainView;
+ private EditorTruePortraitMask mEditor;
+
+ @Override
+ public void onAttach(Context context) {
+ super.onAttach(context);
+ FilterShowActivity filterShowActivity = (FilterShowActivity) context;
+ mEditor = (EditorTruePortraitMask) filterShowActivity.getEditor(EditorTruePortraitMask.ID);
+ }
+
+ @Override
+ public View onCreateView(LayoutInflater inflater, ViewGroup container,
+ Bundle savedInstanceState) {
+ mMainView = inflater.inflate(R.layout.filtershow_trueportrait_editor_panel, container, false);
+ mEditor.setUpEditorUI(mMainView, null);
+ return mMainView;
+ }
+
+ @Override
+ public void onResume() {
+ super.onResume();
+ Context context = getActivity();
+ boolean skipIntro = GalleryUtils.getBooleanPref(context,
+ context.getString(R.string.pref_trueportrait_edit_intro_show_key), false);
+ if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.trueportrait_touch_up, R.string.trueportrait_edit_intro,
+ R.string.pref_trueportrait_edit_intro_show_key);
+ dialog.setCancelable(false);
+ dialog.show(getFragmentManager(), "trueportrait_edit_intro");
+ }
+ }
+
+ @Override
+ public void onDetach() {
+ if (mEditor != null) {
+ mEditor.detach();
+ }
+ super.onDetach();
+ }
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/controller/BasicSlider.java b/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
index eb6a491f4..d0d0fcaa6 100644
--- a/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
+++ b/src/com/android/gallery3d/filtershow/controller/BasicSlider.java
@@ -20,7 +20,6 @@ import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.LinearLayout;
import android.widget.SeekBar;
import android.widget.SeekBar.OnSeekBarChangeListener;
@@ -41,7 +40,7 @@ public class BasicSlider implements Control {
mParameter = (ParameterInteger) parameter;
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LinearLayout lp = (LinearLayout) inflater.inflate(
+ View lp = inflater.inflate(
R.layout.filtershow_seekbar, container, true);
mSeekBar = (SeekBar) lp.findViewById(R.id.primarySeekBar);
mSeekBar.setVisibility(View.VISIBLE);
diff --git a/src/com/android/gallery3d/filtershow/editors/Editor.java b/src/com/android/gallery3d/filtershow/editors/Editor.java
index f68689388..e5d9e486e 100644
--- a/src/com/android/gallery3d/filtershow/editors/Editor.java
+++ b/src/com/android/gallery3d/filtershow/editors/Editor.java
@@ -16,10 +16,11 @@
package com.android.gallery3d.filtershow.editors;
+import java.util.ArrayList;
+import java.util.Collection;
+
import android.content.Context;
import android.content.res.Configuration;
-import android.util.AttributeSet;
-import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
@@ -41,9 +42,6 @@ import com.android.gallery3d.filtershow.imageshow.ImageShow;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
-import java.util.ArrayList;
-import java.util.Collection;
-
/**
* Base class for Editors Must contain a mImageShow and a top level view
*/
@@ -102,6 +100,10 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
return !showsSeekBar();
}
+ public boolean showsActionBarControls() {
+ return showsActionBar();
+ }
+
/*public void setUpEditorUI(View actionButton, View editControl,
Button editTitle, Button stateButton) {
mEditTitle = editTitle;
@@ -116,14 +118,12 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mFilterTitle = stateButton;
MasterImage.getImage().resetGeometryImages(false);
mEditControl = editControl;
- setUtilityPanelUI(null, editControl);
+ setEditPanelUI(editControl);
}
- public void setUpEditorUI(Button editTitle, View actionButton,
- View editControl) {
+ public void setEditorTitle(Button editTitle) {
mEditTitle = editTitle;
mButton = editTitle;
- setUtilityPanelUI(actionButton, editControl);
}
public void setBasicFilterUI(TextView textFilterName,
@@ -132,21 +132,18 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mBasicFilterValue = textFilterValue;
}
- public boolean showsPopupIndicator() {
+ public boolean showsPopupIndicator() {
return false;
}
/**
- * @param actionButton the would be the area for menu etc
* @param editControl this is the black area for sliders etc
*/
- public void setUtilityPanelUI(View actionButton, View editControl) {
-
- AttributeSet aset;
+ public void setEditPanelUI(View editControl) {
Context context = editControl.getContext();
LayoutInflater inflater =
(LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
- LinearLayout lp = (LinearLayout) inflater.inflate(
+ View lp = inflater.inflate(
R.layout.filtershow_seekbar, (ViewGroup) editControl, true);
mSeekBar = (SeekBar) lp.findViewById(R.id.primarySeekBar);
mSeekBar.setOnSeekBarChangeListener(this);
@@ -298,7 +295,7 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
String[] split = text.split("[+-]");
int length = split.length;
if (length == 2)
- mBasicFilterValue.setText(split[1] != null ? split[1] : "");
+ mBasicFilterValue.setText(split[1] != null ? split[1] : "");
mBasicFilterText.setVisibility(View.VISIBLE);
mBasicFilterValue.setVisibility(View.VISIBLE);
mButton.setVisibility(View.INVISIBLE);
@@ -380,4 +377,12 @@ public class Editor implements OnSeekBarChangeListener, SwapButton.SwapButtonLis
mImageShow.detach();
}
}
+
+ public void resume() {
+
+ }
+
+ public void onPrepareOptionsMenu(Menu menu) {
+
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
index 0cc2ee322..664aa6c40 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorChanSat.java
@@ -168,12 +168,11 @@ public class EditorChanSat extends ParametricEditor implements OnSeekBarChangeLi
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
- mActionButton = actionButton;
mEditControl = editControl;
mEditTitle.setCompoundDrawables(null, null, null, null);
LinearLayout group = (LinearLayout) editControl;
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
index 71f4dcb58..90252859f 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorColorBorder.java
@@ -17,15 +17,9 @@
package com.android.gallery3d.filtershow.editors;
import android.content.Context;
-import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
-import android.graphics.Color;
-import android.util.Log;
-import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
-import android.view.ViewGroup;
import android.widget.Button;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
@@ -34,9 +28,7 @@ import android.widget.SeekBar;
import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.FilterShowActivity;
-import com.android.gallery3d.filtershow.controller.BitmapCaller;
import com.android.gallery3d.filtershow.controller.ColorChooser;
-import com.android.gallery3d.filtershow.controller.FilterView;
import com.android.gallery3d.filtershow.filters.FilterColorBorderRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.ImageFilterColorBorder;
@@ -187,9 +179,9 @@ public class EditorColorBorder extends ParametricEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
index e4db1f23d..425915736 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorCrop.java
@@ -145,8 +145,8 @@ public class EditorCrop extends Editor implements EditorInfo {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton,editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
setMenuIcon(true);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorCurves.java b/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
index 475c86422..e305f7abd 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorCurves.java
@@ -61,8 +61,8 @@ public class EditorCurves extends Editor {
}
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton,editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
setMenuIcon(true);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
index 20d788510..5298cab1c 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorDraw.java
@@ -241,9 +241,9 @@ public class EditorDraw extends ParametricEditor implements FilterView {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
index d20b15511..2371ccb15 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java
@@ -76,7 +76,7 @@ public class EditorDualCamFusion extends ImageOnlyEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
editControl.setVisibility(View.GONE);
}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
index 3624a6e10..25000117b 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorGrad.java
@@ -140,9 +140,9 @@ public class EditorGrad extends ParametricEditor
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (ParametricEditor.useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java b/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
index 26ecd4f49..50377c1ee 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorMakeup.java
@@ -31,8 +31,8 @@ public class EditorMakeup extends BasicEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- super.setUtilityPanelUI(actionButton, editControl);
+ public void setEditPanelUI(View editControl) {
+ super.setEditPanelUI(editControl);
mSeekBar = (SeekBar) editControl.findViewById(R.id.primarySeekBar);
if (mSeekBar != null) {
mSeekBar.setVisibility(View.INVISIBLE);
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
index 34f711df9..00c0aa795 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java
@@ -22,6 +22,7 @@ import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.LayoutInflater;
+import android.view.Menu;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
@@ -68,10 +69,6 @@ public class EditorPanel extends Fragment {
int position = adapter.undo();
masterImage.onHistoryItemClick(position);
((FilterShowActivity)getActivity()).invalidateViews();
-
- if(!masterImage.hasFusionApplied()) {
- masterImage.setFusionUnderlay(null);
- }
}
@Override
@@ -100,6 +97,14 @@ public class EditorPanel extends Fragment {
}
@Override
+ public void onResume() {
+ if (mEditor != null) {
+ mEditor.resume();
+ }
+ super.onResume();
+ }
+
+ @Override
public void onDetach() {
if (mEditor != null) {
mEditor.detach();
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java
new file mode 100644
index 000000000..a09e216b5
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitBasic.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+
+public class EditorTruePortraitBasic extends BasicEditor {
+ private static final String LOGTAG = "EditorTruePortraitBasic";
+ public static final int ID = R.id.editorTruePortraitBasic;
+
+ public EditorTruePortraitBasic() {
+ super(ID);
+ }
+
+ @Override
+ public boolean showsActionBar() {
+ return true;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait, accessoryViewList);
+
+ View editMask = accessoryViewList.findViewById(R.id.editMask);
+ editMask.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java
new file mode 100644
index 000000000..cfeea1375
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitFusion.java
@@ -0,0 +1,226 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+
+import android.content.Context;
+import android.content.DialogInterface;
+import android.net.Uri;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageTruePortraitFusion;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.ui.DoNotShowAgainDialog;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class EditorTruePortraitFusion extends Editor {
+ public static final String TAG = "EditorTruePortraitFusion";
+ public static final int ID = R.id.editorTruePortraitFusion;
+
+ protected ImageTruePortraitFusion mImageFusion;
+ private Uri mUnderlayUri = Uri.EMPTY;
+
+ public EditorTruePortraitFusion() {
+ super(ID);
+ }
+
+ @Override
+ public boolean showsActionBar() {
+ return true;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ if (mImageFusion == null) {
+ mImageFusion = new ImageTruePortraitFusion(context);
+ }
+ mView = mImageShow = mImageFusion;
+ mImageFusion.setEditor(this);
+ }
+
+ @Override
+ public void setEditPanelUI(View editControl) {
+ ViewGroup controlContainer = (ViewGroup)editControl;
+ controlContainer.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ View controls = inflater.inflate(R.layout.filtershow_seekbar, controlContainer);
+ View seekbar = controls.findViewById(R.id.primarySeekBar);
+ seekbar.setVisibility(View.GONE);
+ View saveButton = controls.findViewById(R.id.slider_save);
+ if (saveButton != null) {
+ saveButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ finalApplyCalled();
+ activity.leaveSeekBarPanel();
+ }
+ });
+ }
+ View cancelButton = controls.findViewById(R.id.slider_cancel);
+ if (cancelButton != null) {
+ cancelButton.setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ activity.cancelCurrentFilter();
+ activity.leaveSeekBarPanel();
+ }
+ });
+ }
+ }
+
+ @Override
+ public void openUtilityPanel(final LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait_fusion, accessoryViewList);
+
+ View pickUnderlayBtn = accessoryViewList.findViewById(R.id.pick_underlay);
+ pickUnderlayBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ MasterImage.getImage().getActivity().pickImage(FilterShowActivity.SELECT_FUSION_UNDERLAY);
+ }
+ });
+
+ View editMaskBtn = accessoryViewList.findViewById(R.id.editMask);
+ editMaskBtn.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+
+ // Look for previous underlay
+ String fusionUnderlay = GalleryUtils.getStringPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_underlay_key), null);
+ Uri fusionUri = Uri.EMPTY;
+
+ if(fusionUnderlay != null) {
+ fusionUri = Uri.parse(fusionUnderlay);
+ if(!uriExists(mContext, fusionUri))
+ fusionUri = Uri.EMPTY;
+ }
+
+ setUnderlayImageUri(fusionUri);
+ }
+
+ @Override
+ public void resume() {
+ if(mUnderlayUri.equals(Uri.EMPTY)) {
+ // No underlay set.
+ boolean skipIntro = GalleryUtils.getBooleanPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_intro_show_key), false);
+ if(!skipIntro) {
+ DoNotShowAgainDialog dialog = new DoNotShowAgainDialog(
+ R.string.fusion_pick_background, R.string.trueportrait_fusion_intro,
+ R.string.pref_trueportrait_fusion_intro_show_key) {
+ @Override
+ public void onDismiss(DialogInterface dialog) {
+ super.onDismiss(dialog);
+ MasterImage.getImage().getActivity().pickImage(FilterShowActivity.SELECT_FUSION_UNDERLAY);
+ }
+ };
+ FragmentManager fm = ((FilterShowActivity)mContext).getSupportFragmentManager();
+ dialog.setCancelable(false);
+ dialog.show(fm, "trueportrait_fusion_intro");
+ }
+ }
+ }
+
+ public void setUnderlayImageUri(Uri uri) {
+ mUnderlayUri = uri;
+ FilterRepresentation filter = getLocalRepresentation();
+ if(filter instanceof FilterTruePortraitFusionRepresentation) {
+ mImageFusion.setUnderlay(uri);
+ commitLocalRepresentation();
+
+ // save fusion underlay uri
+ GalleryUtils.setStringPref(mContext,
+ mContext.getString(R.string.pref_trueportrait_fusion_underlay_key),
+ (uri != null)?uri.toString():null);
+ }
+ }
+
+ @Override
+ public void reflectCurrentFilter() {
+ super.reflectCurrentFilter();
+ FilterRepresentation rep = getLocalRepresentation();
+ if (rep != null && rep instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation fusionRep = (FilterTruePortraitFusionRepresentation) rep;
+ mImageFusion.setRepresentation(fusionRep);
+ }
+ }
+
+ private boolean uriExists(Context context, Uri uri) {
+ try {
+ InputStream stream = context.getContentResolver().openInputStream(uri);
+ stream.close();
+ } catch (FileNotFoundException e) {
+ e.printStackTrace();
+ return false;
+ } catch (IOException e) {
+ e.printStackTrace();
+ }
+ return true;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java
new file mode 100644
index 000000000..781b2e417
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitImageOnly.java
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+import android.content.Context;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.FrameLayout;
+import android.widget.LinearLayout;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.imageshow.ImageShow;
+
+public class EditorTruePortraitImageOnly extends Editor {
+ private static final String LOGTAG = "EditorTruePortraitImageOnly";
+ public static final int ID = R.id.editorTruePortraitImageOnly;
+
+ public EditorTruePortraitImageOnly() {
+ super(ID);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ mView = mImageShow = new ImageShow(context);
+ }
+
+ @Override
+ public boolean showsSeekBar() {
+ return false;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait, accessoryViewList);
+
+ View editMask = accessoryViewList.findViewById(R.id.editMask);
+ editMask.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ FilterRepresentation representation = new FilterRepresentation("");
+ representation.setEditorId(EditorTruePortraitMask.ID);
+ ((FilterShowActivity)mContext).loadEditorPanel(representation);
+ }
+ });
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java
new file mode 100644
index 000000000..7c5842f7f
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/editors/EditorTruePortraitMask.java
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.editors;
+
+
+import android.content.Context;
+import android.support.v4.app.FragmentManager;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Button;
+import android.widget.CompoundButton;
+import android.widget.FrameLayout;
+import android.widget.ImageButton;
+import android.widget.LinearLayout;
+import android.widget.TextView;
+import android.widget.Toast;
+import android.widget.ToggleButton;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.FilterShowActivity;
+import com.android.gallery3d.filtershow.imageshow.ImageTruePortraitMask;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.ui.AlertMsgDialog;
+
+public class EditorTruePortraitMask extends Editor {
+ private static final String LOGTAG = "EditorTruePortraitMask";
+ public static final int ID = R.id.editorTruePortraitMask;
+
+ private AlertMsgDialog mHelpDialog;
+ private ImageTruePortraitMask mTruePortraitImage;
+ private ToggleButton mForeground;
+ private ToggleButton mBackground;
+ private ImageButton mExitButton;
+ private ImageButton mApplyButton;
+ private View mMaskUndoButton;
+ private View mBrushSizeButton;
+ private View[] mBrushSizes = new View[3];
+ private int mBrushIndex = 0;
+
+ private static final int[] BRUSH_SIZES = {
+ 10, 30, 50
+ };
+
+ private OnClickListener mDoneClickListener = new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if(view.getId() == R.id.done) {
+ finalApplyCalled();
+ }
+ FilterShowActivity activity = (FilterShowActivity) mContext;
+ activity.backToMain();
+ activity.setActionBar();
+ }
+ };
+
+ public EditorTruePortraitMask() {
+ super(ID);
+ }
+
+ @Override
+ public void createEditor(Context context, FrameLayout frameLayout) {
+ super.createEditor(context, frameLayout);
+ unpack(R.id.truePortraitMaskEditor, R.layout.filtershow_trueportrait_mask_editor);
+ mTruePortraitImage = (ImageTruePortraitMask)mImageShow;
+ mTruePortraitImage.setEditor(this);
+ }
+
+ @Override
+ public boolean showsSeekBar() {
+ return false;
+ }
+
+ @Override
+ public boolean showsActionBarControls() {
+ return false;
+ }
+
+ @Override
+ public void openUtilityPanel(LinearLayout accessoryViewList) {
+ accessoryViewList.removeAllViews();
+
+ LayoutInflater inflater = (LayoutInflater) mContext.getSystemService
+ (Context.LAYOUT_INFLATER_SERVICE);
+ inflater.inflate(R.layout.filtershow_actionbar_trueportrait_mask, accessoryViewList);
+
+ mMaskUndoButton = accessoryViewList.findViewById(R.id.maskUndo);
+ mMaskUndoButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ mTruePortraitImage.undoLastEdit();
+ }
+ });
+ refreshUndoButton();
+
+ View maskHelp = accessoryViewList.findViewById(R.id.maskHelp);
+ maskHelp.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ if(mHelpDialog == null)
+ mHelpDialog = new AlertMsgDialog(R.string.help, R.string.trueportrait_edit_help);
+
+ FragmentManager fm = ((FilterShowActivity)mContext).getSupportFragmentManager();
+ mHelpDialog.show(fm, "tp_edit_help");
+ }
+ });
+
+ mForeground = (ToggleButton)accessoryViewList.findViewById(R.id.maskForeground);
+ mForeground.setChecked(true);
+ mForeground.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if(mBackground.isChecked() == isChecked)
+ mBackground.toggle();
+ mTruePortraitImage.invalidate();
+ showToast();
+ }
+ });
+
+ mBackground = (ToggleButton)accessoryViewList.findViewById(R.id.maskBackground);
+ mBackground.setChecked(false);
+ mBackground.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
+ public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
+ if(mForeground.isChecked() == isChecked)
+ mForeground.toggle();
+ }
+ });
+ }
+
+ @Override
+ public void setUpEditorUI(View editControl, Button stateButton) {
+ mExitButton = (ImageButton) editControl.findViewById(R.id.cancel);
+ mApplyButton = (ImageButton) editControl.findViewById(R.id.done);
+ mExitButton.setOnClickListener(mDoneClickListener);
+ mApplyButton.setOnClickListener(mDoneClickListener);
+
+ mBrushSizeButton = editControl.findViewById(R.id.brush_size);
+ mBrushSizeButton.setOnClickListener(new OnClickListener() {
+ @Override
+ public void onClick(View view) {
+ cycleBrushSize();
+ }
+ });
+
+ mBrushSizes[0] = editControl.findViewById(R.id.brush_size_sm);
+ mBrushSizes[0].setSelected(false);
+ mBrushSizes[1] = editControl.findViewById(R.id.brush_size_med);
+ mBrushSizes[1].setSelected(false);
+ mBrushSizes[2] = editControl.findViewById(R.id.brush_size_large);
+ mBrushSizes[2].setSelected(false);
+
+ mBrushSizes[mBrushIndex].setSelected(true);
+ }
+
+ @Override
+ public void onPrepareOptionsMenu(Menu menu) {
+ menu.clear();
+ }
+
+ @Override
+ public void finalApplyCalled() {
+ mTruePortraitImage.applyMaskUpdates();
+ MasterImage.getImage().invalidateFiltersOnly();
+ }
+
+ private void showToast() {
+ Toast toast;
+ if(isBackgroundMode()) {
+ toast = Toast.makeText(mContext, R.string.trueportrait_edit_background_toast, Toast.LENGTH_SHORT);
+ } else {
+ toast = Toast.makeText(mContext, R.string.trueportrait_edit_foreground_toast, Toast.LENGTH_SHORT);
+ }
+
+ toast.show();
+ }
+
+ public void refreshUndoButton() {
+ mMaskUndoButton.setEnabled(mTruePortraitImage.canUndoEdit());
+ }
+
+ public boolean isBackgroundMode() {
+ return mBackground.isChecked();
+ }
+
+ public int cycleBrushSize() {
+ mBrushSizes[mBrushIndex].setSelected(false);
+ mBrushIndex = (mBrushIndex+1)%BRUSH_SIZES.length;
+ mBrushSizes[mBrushIndex].setSelected(true);
+ return getBrushSize();
+ }
+
+ public int getBrushSize() {
+ return BRUSH_SIZES[mBrushIndex];
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
index 8b5fcb505..e3dd7ff67 100644
--- a/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
+++ b/src/com/android/gallery3d/filtershow/editors/EditorVignette.java
@@ -187,12 +187,11 @@ public class EditorVignette extends ParametricEditor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
+ public void setEditPanelUI(View editControl) {
if (useCompact(mContext)) {
- super.setUtilityPanelUI(actionButton, editControl);
+ super.setEditPanelUI(editControl);
return;
}
- mActionButton = actionButton;
mEditControl = editControl;
mEditTitle.setCompoundDrawables(null, null, null, null);
LinearLayout group = (LinearLayout) editControl;
diff --git a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
index c13c9f822..3ee36134f 100644
--- a/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
+++ b/src/com/android/gallery3d/filtershow/editors/ParametricEditor.java
@@ -135,7 +135,8 @@ public class ParametricEditor extends Editor {
public void reflectCurrentFilter() {
super.reflectCurrentFilter();
if (getLocalRepresentation() != null
- && getLocalRepresentation() instanceof FilterBasicRepresentation) {
+ && getLocalRepresentation() instanceof FilterBasicRepresentation
+ && mControl != null) {
FilterBasicRepresentation interval = (FilterBasicRepresentation) getLocalRepresentation();
mControl.setPrameter(interval);
}
@@ -164,8 +165,7 @@ public class ParametricEditor extends Editor {
}
@Override
- public void setUtilityPanelUI(View actionButton, View editControl) {
- mActionButton = actionButton;
+ public void setEditPanelUI(View editControl) {
mEditControl = editControl;
FilterRepresentation rep = getLocalRepresentation();
Parameter param = getParameterToEdit(rep);
diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
index e6ac0a6ef..b9c24fc27 100644
--- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
+++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java
@@ -21,6 +21,8 @@ import android.graphics.Color;
import android.util.Log;
import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitBasic;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitImageOnly;
import com.android.gallery3d.filtershow.editors.ImageOnlyEditor;
import com.android.gallery3d.filtershow.pipeline.ImagePreset;
@@ -42,6 +44,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
protected ArrayList<FilterRepresentation> mTrueScanner = new ArrayList<FilterRepresentation>();
protected ArrayList<FilterRepresentation> mHazeBuster = new ArrayList<FilterRepresentation>();
protected ArrayList<FilterRepresentation> mSeeStraight = new ArrayList<FilterRepresentation>();
+ protected ArrayList<FilterRepresentation> mTruePortrait = new ArrayList<FilterRepresentation>();
private static int mImageBorderSize = 4; // in percent
protected void init() {
@@ -152,6 +155,8 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
filters.add(ImageFilterDualCamera.class);
filters.add(ImageFilterDualCamFusion.class);
filters.add(ImageFilterDualCamSketch.class);
+ filters.add(ImageFilterTruePortrait.class);
+ filters.add(ImageFilterTruePortraitFusion.class);
if(SimpleMakeupImageFilter.HAS_TS_MAKEUP) {
filters.add(ImageFilterMakeupWhiten.class);
@@ -185,6 +190,10 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
return mDualCam;
}
+ public ArrayList<FilterRepresentation> getTruePortrait() {
+ return mTruePortrait;
+ }
+
public ArrayList<FilterRepresentation> getTools() {
return mTools;
}
@@ -462,6 +471,74 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface {
mDualCam.add(getRepresentation(ImageFilterDualCamFusion.class));
}
+ public void addTruePortrait(Context context) {
+ int[] textId = {
+ R.string.none,
+ R.string.blur,
+ R.string.motion_blur,
+ R.string.halo,
+ R.string.sketch
+ };
+
+ int[] overlayId = {
+ R.drawable.ic_tp_normal,
+ R.drawable.ic_tp_bokeh,
+ R.drawable.ic_tp_motion_blur,
+ R.drawable.ic_tp_halo,
+ R.drawable.ic_tp_sketch
+ };
+
+ String[] serializationNames = {
+ "TRUE_PORTRAIT_NONE",
+ "TRUE_PORTRAIT_BLUR",
+ "TRUE_PORTRAIT_MOTION_BLUR",
+ "TRUE_PORTRAIT_HALO",
+ "TRUE_PORTRAIT_SKETCH"
+ };
+
+ int[][] minMaxValues = {
+ {0,0,0},
+ {0,3,7},
+ {0,3,7},
+ {0,3,7},
+ {0,0,0}
+ };
+
+ boolean[] showParams = {
+ false,
+ true,
+ true,
+ true,
+ false
+ };
+
+ int[] editorIDs = {
+ ImageOnlyEditor.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitBasic.ID,
+ EditorTruePortraitImageOnly.ID
+ };
+
+ for (int i = 0; i < textId.length; i++) {
+ FilterRepresentation tPortrait =
+ new FilterBasicRepresentation(context.getString(textId[i]),
+ minMaxValues[i][0], minMaxValues[i][1], minMaxValues[i][2]);
+ tPortrait.setFilterClass(ImageFilterTruePortrait.class);
+ tPortrait.setFilterType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ tPortrait.setTextId(textId[i]);
+ tPortrait.setOverlayId(overlayId[i]);
+ tPortrait.setOverlayOnly(true);
+ tPortrait.setSerializationName(serializationNames[i]);
+ tPortrait.setShowParameterValue(showParams[i]);
+ tPortrait.setEditorId(editorIDs[i]);
+ mTruePortrait.add(tPortrait);
+ addRepresentation(tPortrait);
+ }
+
+ mTruePortrait.add(getRepresentation(ImageFilterTruePortraitFusion.class));
+ }
+
public void removeRepresentation(ArrayList<FilterRepresentation> list,
FilterRepresentation representation) {
for (int i = 0; i < list.size(); i++) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
index f8d8263d3..8caa9b2b8 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java
@@ -40,7 +40,7 @@ import org.codeaurora.gallery.R;
import com.android.gallery3d.filtershow.editors.EditorDualCamFusion;
-public class FilterDualCamFusionRepresentation extends FilterRepresentation {
+public class FilterDualCamFusionRepresentation extends FilterRepresentation implements FilterFusionRepresentation {
private static final String LOGTAG = "FilterFusionRepresentation";
public static final String SERIALIZATION_NAME = "FUSION";
@@ -112,6 +112,7 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
return mPoint;
}
+ @Override
public void setUnderlay(Uri uri) {
if(uri != null) {
mUri = uri.toString();
@@ -120,6 +121,7 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
}
}
+ @Override
public void setUnderlay(String uri) {
if(uri != null)
mUri = uri;
@@ -127,10 +129,12 @@ public class FilterDualCamFusionRepresentation extends FilterRepresentation {
mUri = "";
}
+ @Override
public boolean hasUnderlay() {
return (mUri != null) && (mUri.isEmpty() == false);
}
+ @Override
public String getUnderlay() {
return mUri;
}
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java
new file mode 100644
index 000000000..ff850c8bc
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterFusionRepresentation.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.net.Uri;
+
+public interface FilterFusionRepresentation {
+ public void setUnderlay(Uri uri);
+ public void setUnderlay(String uri);
+ public boolean hasUnderlay();
+ public String getUnderlay();
+} \ No newline at end of file
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
index 8d1911315..bded1f506 100644
--- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
+++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
@@ -50,6 +50,7 @@ public class FilterRepresentation {
public static final byte TYPE_GEOMETRY = 7;
public static final byte TYPE_MAKEUP = 8;
public static final byte TYPE_DUALCAM = 9;
+ public static final byte TYPE_TRUEPORTRAIT = 10;
protected static final String NAME_TAG = "Name";
public FilterRepresentation(String name) {
diff --git a/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java
new file mode 100644
index 000000000..3864eacfd
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/FilterTruePortraitFusionRepresentation.java
@@ -0,0 +1,158 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import java.io.IOException;
+
+import android.net.Uri;
+import android.util.JsonReader;
+import android.util.JsonWriter;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+
+
+public class FilterTruePortraitFusionRepresentation extends FilterRepresentation implements FilterFusionRepresentation {
+ private static final String LOGTAG = "FilterTruePortraitFusionRepresentation";
+ public static final String SERIALIZATION_NAME = "TP_FUSION";
+ private static final String SERIAL_UNDERLAY_IMAGE = "image";
+
+ private String mUri = "";
+
+ public FilterTruePortraitFusionRepresentation() {
+ super("Fusion");
+ setSerializationName(SERIALIZATION_NAME);
+ setFilterType(FilterRepresentation.TYPE_TRUEPORTRAIT);
+ setFilterClass(ImageFilterTruePortraitFusion.class);
+ setEditorId(EditorTruePortraitFusion.ID);
+ setShowParameterValue(false);
+ setTextId(R.string.fusion);
+ setOverlayId(R.drawable.ic_tp_fusion);
+ setOverlayOnly(true);
+ }
+
+ @Override
+ public FilterRepresentation copy() {
+ FilterTruePortraitFusionRepresentation representation =
+ new FilterTruePortraitFusionRepresentation();
+ copyAllParameters(representation);
+ return representation;
+ }
+
+ @Override
+ protected void copyAllParameters(FilterRepresentation representation) {
+ super.copyAllParameters(representation);
+ representation.useParametersFrom(this);
+ }
+
+ public void useParametersFrom(FilterRepresentation a) {
+ super.useParametersFrom(a);
+ if (a instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation representation = (FilterTruePortraitFusionRepresentation) a;
+ setUnderlay(representation.getUnderlay());
+ }
+ }
+
+ @Override
+ public boolean equals(FilterRepresentation representation) {
+ if (!super.equals(representation)) {
+ return false;
+ }
+ if (representation instanceof FilterTruePortraitFusionRepresentation) {
+ FilterTruePortraitFusionRepresentation fusion = (FilterTruePortraitFusionRepresentation) representation;
+ if (fusion.mUri.equals(mUri)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ @Override
+ public void setUnderlay(Uri uri) {
+ if(uri != null) {
+ mUri = uri.toString();
+ } else {
+ mUri = "";
+ }
+ }
+
+ @Override
+ public void setUnderlay(String uri) {
+ if(uri != null)
+ mUri = uri;
+ else
+ mUri = "";
+ }
+
+ @Override
+ public boolean hasUnderlay() {
+ return (mUri != null) && (mUri.isEmpty() == false);
+ }
+
+ @Override
+ public String getUnderlay() {
+ return mUri;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder();
+ sb.append("fusion - underlay: ").append(getUnderlay());
+
+ return sb.toString();
+ }
+
+ // Serialization...
+ public void serializeRepresentation(JsonWriter writer) throws IOException {
+ writer.beginObject();
+ {
+ writer.name(NAME_TAG);
+ writer.value(getName());
+ writer.name(SERIAL_UNDERLAY_IMAGE);
+ writer.value(mUri);
+ }
+ writer.endObject();
+ }
+
+ public void deSerializeRepresentation(JsonReader reader) throws IOException {
+ reader.beginObject();
+ while (reader.hasNext()) {
+ String name = reader.nextName();
+ if (name.equalsIgnoreCase(NAME_TAG)) {
+ setName(reader.nextString());
+ } else if (name.equalsIgnoreCase(SERIAL_UNDERLAY_IMAGE)) {
+ setUnderlay(reader.nextString());
+ } else {
+ reader.skipValue();
+ }
+ }
+ reader.endObject();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
new file mode 100644
index 000000000..86a2a7404
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortrait.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.Log;
+import android.widget.Toast;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.cache.BitmapCache;
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
+import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils.GeometryHolder;
+import com.android.gallery3d.filtershow.imageshow.MasterImage;
+import com.android.gallery3d.filtershow.pipeline.FilterEnvironment;
+import com.android.gallery3d.filtershow.pipeline.ImagePreset;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine.EffectType;
+
+public class ImageFilterTruePortrait extends ImageFilter {
+ private static final String TAG = "ImageFilterTruePortrait";
+ private static Toast sSegmentToast;
+
+ private FilterRepresentation mParameters;
+ private Paint mPaint = new Paint();
+
+ public void useRepresentation(FilterRepresentation representation) {
+ mParameters = representation;
+ }
+
+ public FilterRepresentation getParameters() {
+ return mParameters;
+ }
+
+ @Override
+ public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) {
+ if (getParameters() == null) {
+ return bitmap;
+ }
+
+ Bitmap filteredBitmap = null;
+ boolean result = false;
+ int orientation = MasterImage.getImage().getOrientation();
+ Rect originalBounds = MasterImage.getImage().getOriginalBounds();
+ int filteredW;
+ int filteredH;
+
+ if(quality == FilterEnvironment.QUALITY_FINAL) {
+ filteredW = originalBounds.width();
+ filteredH = originalBounds.height();
+ } else {
+ Bitmap originalBmp = MasterImage.getImage().getOriginalBitmapHighres();
+ filteredW = originalBmp.getWidth();
+ filteredH = originalBmp.getHeight();
+
+ // image is rotated
+ if (orientation == ImageLoader.ORI_ROTATE_90 ||
+ orientation == ImageLoader.ORI_ROTATE_270 ||
+ orientation == ImageLoader.ORI_TRANSPOSE ||
+ orientation == ImageLoader.ORI_TRANSVERSE) {
+ int tmp = filteredW;
+ filteredW = filteredH;
+ filteredH = tmp;
+ }
+
+ // non even width or height
+ if(filteredW%2 != 0 || filteredH%2 != 0) {
+ float aspect = (float)filteredH / (float)filteredW;
+ if(filteredW >= filteredH) {
+ filteredW = MasterImage.MAX_BITMAP_DIM;
+ filteredH = (int)(filteredW * aspect);
+ } else {
+ filteredH = MasterImage.MAX_BITMAP_DIM;
+ filteredW = (int)(filteredH / aspect);
+ }
+ }
+ }
+
+ filteredBitmap = MasterImage.getImage().getBitmapCache().getBitmap(filteredW, filteredH, BitmapCache.FILTERS);
+
+ result = applyEffect(filteredBitmap);
+
+ if(result == false) {
+ Log.e(TAG, "Imagelib API failed");
+ sActivity.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ if(sSegmentToast == null) {
+ sSegmentToast = Toast.makeText(sActivity, "No Faces Found", Toast.LENGTH_SHORT);
+ }
+ sSegmentToast.show();
+ }
+ });
+
+ return bitmap;
+ } else {
+
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ if(quality == FilterEnvironment.QUALITY_FINAL) {
+ mPaint.setFilterBitmap(true);
+ mPaint.setDither(true);
+ }
+
+ if(needsClear()) {
+ bitmap.setHasAlpha(true);
+ bitmap.eraseColor(Color.TRANSPARENT);
+ }
+
+ Canvas canvas = new Canvas(bitmap);
+ ImagePreset preset = getEnvironment().getImagePreset();
+ int bmWidth = bitmap.getWidth();
+ int bmHeight = bitmap.getHeight();
+ GeometryHolder holder;
+ if(preset.getDoApplyGeometry()) {
+ holder = GeometryMathUtils.unpackGeometry(preset.getGeometryFilters());
+ } else {
+ holder = new GeometryHolder();
+ }
+
+ RectF crop = new RectF();
+ Matrix m = GeometryMathUtils.getOriginalToScreen(holder, crop, true,
+ filteredW, filteredH, bmWidth, bmHeight);
+
+ canvas.save();
+ canvas.clipRect(crop);
+ canvas.drawBitmap(filteredBitmap, m, mPaint);
+ canvas.restore();
+
+ MasterImage.getImage().getBitmapCache().cache(filteredBitmap);
+ }
+
+ return bitmap;
+ }
+
+ protected boolean applyEffect(Bitmap filteredBitmap) {
+ FilterBasicRepresentation basicRep = (FilterBasicRepresentation) getParameters();
+ int value = basicRep.getValue();
+
+ boolean result = false;
+ switch(mParameters.getTextId()) {
+ case R.string.blur:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.BLUR, value, filteredBitmap);
+ break;
+ case R.string.motion_blur:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.MOTION_BLUR, value, filteredBitmap);
+ break;
+ case R.string.halo:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.HALO, value, filteredBitmap);
+ break;
+ case R.string.sketch:
+ result = TruePortraitNativeEngine.getInstance().applyEffect(EffectType.SKETCH, value, filteredBitmap);
+ break;
+ }
+
+ return result;
+ }
+
+ protected boolean needsClear() {
+ return false;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java
new file mode 100644
index 000000000..59a15a325
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitFusion.java
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+import android.graphics.Bitmap;
+
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+
+public class ImageFilterTruePortraitFusion extends ImageFilterTruePortrait {
+ private static final String TAG = "ImageFilterTruePortraitFusion";
+
+ public ImageFilterTruePortraitFusion() {
+ mName = "Fusion";
+ }
+
+ @Override
+ protected boolean applyEffect(Bitmap filteredBitmap) {
+ filteredBitmap.setHasAlpha(true);
+ return TruePortraitNativeEngine.getInstance().nativeGetForegroundImg(filteredBitmap);
+ }
+
+ @Override
+ protected boolean needsClear() {
+ return true;
+ }
+
+ @Override
+ public FilterRepresentation getDefaultRepresentation() {
+ return new FilterTruePortraitFusionRepresentation();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java
new file mode 100644
index 000000000..88601c4ff
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterTruePortraitMask.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.filters;
+
+
+public class ImageFilterTruePortraitMask extends ImageFilter {
+ private static final String TAG = "ImageFilterTruePortraitMask";
+
+ private FilterBasicRepresentation mParameters;
+
+ public void useRepresentation(FilterRepresentation representation) {
+ FilterBasicRepresentation parameters = (FilterBasicRepresentation) representation;
+ mParameters = parameters;
+ }
+
+ public FilterBasicRepresentation getParameters() {
+ return mParameters;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
index c3a7b7f38..7926d6fa6 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
@@ -66,8 +66,8 @@ public class ImageShow extends View implements OnGestureListener,
protected int mBackgroundColor;
- private GestureDetector mGestureDetector = null;
- private ScaleGestureDetector mScaleGestureDetector = null;
+ protected GestureDetector mGestureDetector = null;
+ protected ScaleGestureDetector mScaleGestureDetector = null;
private RectF mFusionBounds = new RectF();
protected Rect mImageBounds = new Rect();
@@ -78,32 +78,32 @@ public class ImageShow extends View implements OnGestureListener,
private int mShadowMargin = 15; // not scaled, fixed in the asset
private boolean mShadowDrawn = false;
- private Point mTouchDown = new Point();
- private Point mTouch = new Point();
- private boolean mFinishedScalingOperation = false;
+ protected Point mTouchDown = new Point();
+ protected Point mTouch = new Point();
+ protected boolean mFinishedScalingOperation = false;
private boolean mZoomIn = false;
Point mOriginalTranslation = new Point();
float mOriginalScale;
float mStartFocusX, mStartFocusY;
- private EdgeEffectCompat mEdgeEffect = null;
- private static final int EDGE_LEFT = 1;
- private static final int EDGE_TOP = 2;
- private static final int EDGE_RIGHT = 3;
- private static final int EDGE_BOTTOM = 4;
- private int mCurrentEdgeEffect = 0;
- private int mEdgeSize = 100;
+ protected EdgeEffectCompat mEdgeEffect = null;
+ protected static final int EDGE_LEFT = 1;
+ protected static final int EDGE_TOP = 2;
+ protected static final int EDGE_RIGHT = 3;
+ protected static final int EDGE_BOTTOM = 4;
+ protected int mCurrentEdgeEffect = 0;
+ protected int mEdgeSize = 100;
- private static final int mAnimationSnapDelay = 200;
- private static final int mAnimationZoomDelay = 400;
- private ValueAnimator mAnimatorScale = null;
- private ValueAnimator mAnimatorTranslateX = null;
- private ValueAnimator mAnimatorTranslateY = null;
+ protected static final int mAnimationSnapDelay = 200;
+ protected static final int mAnimationZoomDelay = 400;
+ protected ValueAnimator mAnimatorScale = null;
+ protected ValueAnimator mAnimatorTranslateX = null;
+ protected ValueAnimator mAnimatorTranslateY = null;
protected boolean mAllowScaleAndTranslate = false;
- private enum InteractionMode {
+ protected enum InteractionMode {
NONE,
SCALE,
MOVE
@@ -298,16 +298,7 @@ public class ImageShow extends View implements OnGestureListener,
mShadowDrawn = false;
if (!drawCompareImage(canvas, MasterImage.getImage().getOriginalBitmapLarge())) {
- Bitmap highresPreview = MasterImage.getImage().getHighresImage();
- Bitmap fullHighres = MasterImage.getImage().getPartialImage();
-
- boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation();
-
- if (highresPreview == null || isDoingNewLookAnimation) {
- drawImageAndAnimate(canvas, getFilteredImage());
- } else {
- drawImageAndAnimate(canvas, highresPreview);
- }
+ drawImageAndAnimate(canvas, getImageToDraw());
}
canvas.restore();
@@ -337,6 +328,17 @@ public class ImageShow extends View implements OnGestureListener,
}
}
+ protected Bitmap getImageToDraw() {
+ Bitmap highresPreview = MasterImage.getImage().getHighresImage();
+ boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation();
+
+ if (highresPreview == null || isDoingNewLookAnimation) {
+ return getFilteredImage();
+ } else {
+ return highresPreview;
+ }
+ }
+
private void drawHighresImage(Canvas canvas, Bitmap fullHighres) {
Matrix originalToScreen = MasterImage.getImage().originalImageToScreen();
if (fullHighres != null && originalToScreen != null) {
@@ -774,7 +776,7 @@ public class ImageShow extends View implements OnGestureListener,
return true;
}
- private void constrainTranslation(Point translation, float scale) {
+ protected void constrainTranslation(Point translation, float scale) {
int currentEdgeEffect = 0;
if (mAllowScaleAndTranslate || scale <= 1) {
mCurrentEdgeEffect = 0;
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java
new file mode 100644
index 000000000..8413c5dd9
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitFusion.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.imageshow;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Rect;
+import android.net.Uri;
+import android.util.AttributeSet;
+
+import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitFusion;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
+
+public class ImageTruePortraitFusion extends ImageShow {
+ private static final String LOGTAG = "ImageTruePortraitFusion";
+ protected EditorTruePortraitFusion mEditor;
+ protected FilterTruePortraitFusionRepresentation mRepresentation;
+ private Bitmap mUnderlay;
+
+ public ImageTruePortraitFusion(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ mAllowScaleAndTranslate = true;
+ }
+
+ public ImageTruePortraitFusion(Context context) {
+ super(context);
+ mAllowScaleAndTranslate = true;
+ }
+
+ public void setUnderlay(Uri uri) {
+ mRepresentation.setUnderlay(uri);
+
+ if(mUnderlay != null) {
+ mUnderlay.recycle();
+ mUnderlay = null;
+ MasterImage.getImage().setFusionUnderlay(null);
+ }
+
+ mUnderlay = ImageLoader.loadConstrainedBitmap(uri, getContext(), MasterImage.MAX_BITMAP_DIM, new Rect(), false);
+ MasterImage.getImage().setFusionUnderlay(mUnderlay);
+ invalidate();
+ }
+
+ public void setEditor(EditorTruePortraitFusion editor) {
+ mEditor = editor;
+ }
+
+ public void setRepresentation(FilterTruePortraitFusionRepresentation representation) {
+ mRepresentation = representation;
+ }
+
+ @Override
+ public boolean enableComparison() {
+ return false;
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java
new file mode 100644
index 000000000..052035714
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/imageshow/ImageTruePortraitMask.java
@@ -0,0 +1,675 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ * Not a Contribution.
+ *
+ * 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 java.util.Arrays;
+import java.util.Stack;
+
+import android.animation.Animator;
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.ColorMatrixColorFilter;
+import android.graphics.LightingColorFilter;
+import android.graphics.Matrix;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Path;
+import android.graphics.Point;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.Rect;
+import android.graphics.RectF;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+
+import com.android.gallery3d.filtershow.editors.EditorTruePortraitMask;
+import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData;
+import com.android.gallery3d.filtershow.tools.TruePortraitNativeEngine;
+
+public class ImageTruePortraitMask extends ImageShow {
+
+ private static final String LOGTAG = "ImageTruePortraitMask";
+
+ private boolean mZoomIn = false;
+ private Point mScaleTranslation = new Point();
+ private float mScaleStartFocusX, mScaleStartFocusY;
+
+ private Point mTranslation = new Point();
+ private Point mOriginalTranslation = new Point();
+ private float mScaleFactor = 1f;
+ private float mMaxScaleFactor = 3f;
+
+ private Paint mMaskPaintForeground = new Paint();
+ private Paint mMaskPaintBackground = new Paint();
+ private Paint mMaskEditPaint = new Paint();
+
+ private StrokeData mCurrent;
+ private Stack<StrokeData> mDrawing = new Stack<StrokeData>();
+
+ private EditorTruePortraitMask mEditor;
+ private Bitmap mPreview;
+ private Bitmap mOriginalMask;
+ private Bitmap mMask;
+
+ private Mode mMode = Mode.MODE_NONE;
+ private enum Mode {
+ MODE_NONE,
+ MODE_MOVE,
+ MODE_SCALE,
+ MODE_DRAW
+ }
+
+ public ImageTruePortraitMask(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setup();
+ }
+
+ public ImageTruePortraitMask(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ setup();
+ }
+
+ public ImageTruePortraitMask(Context context) {
+ super(context);
+ setup();
+ }
+
+ private void setup() {
+ mMaskPaintForeground.setAntiAlias(true);
+ mMaskPaintForeground.setColor(Color.RED);
+ mMaskPaintForeground.setColorFilter(new LightingColorFilter(Color.RED, 1));
+ mMaskPaintForeground.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
+
+ mMaskPaintBackground.setAntiAlias(true);
+ mMaskPaintBackground.setColor(Color.GREEN);
+ mMaskPaintBackground.setColorFilter(new ColorMatrixColorFilter(new float[] {
+ // Set color to GREEN and inverse ALPHA channel
+ // of original mask to get background
+ 0,0,0,0,0,
+ 0,0,0,0,255,
+ 0,0,0,0,0,
+ 0,0,0,-1,255
+ }));
+ mMaskPaintBackground.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SCREEN));
+
+ mMaskEditPaint.setAntiAlias(true);
+ mMaskEditPaint.setStyle(Style.STROKE);
+ mMaskEditPaint.setStrokeCap(Paint.Cap.ROUND);
+ }
+
+ @Override
+ public void attach() {
+ mPreview = TruePortraitNativeEngine.getInstance().getPreview();
+ mOriginalMask = TruePortraitNativeEngine.getInstance().getMask();
+ mMask = Bitmap.createBitmap(mOriginalMask.getWidth(), mOriginalMask.getHeight(), mOriginalMask.getConfig());
+ }
+
+ @Override
+ public void detach() {
+ if(mPreview != null) {
+ mPreview.recycle();
+ mPreview = null;
+ }
+
+ if(mOriginalMask != null) {
+ mOriginalMask.recycle();
+ mOriginalMask = null;
+ }
+
+ if(mMask != null) {
+ mMask.recycle();
+ mMask = null;
+ }
+
+ mDrawing.clear();
+ }
+
+ public void setEditor(EditorTruePortraitMask editor) {
+ mEditor = editor;
+ }
+
+ @Override
+ public void onDraw(Canvas canvas) {
+ toggleComparisonButtonVisibility();
+
+ mPaint.reset();
+ mPaint.setAntiAlias(true);
+ mPaint.setFilterBitmap(true);
+
+ drawImage(canvas, mPreview, mPaint);
+ updateEditsToMask(mMask);
+ drawImage(canvas, mMask,
+ mEditor.isBackgroundMode()?mMaskPaintBackground:mMaskPaintForeground);
+
+ if (!mEdgeEffect.isFinished()) {
+ canvas.save();
+ float dx = (getHeight() - getWidth()) / 2f;
+ if (getWidth() > getHeight()) {
+ dx = - (getWidth() - getHeight()) / 2f;
+ }
+ if (mCurrentEdgeEffect == EDGE_BOTTOM) {
+ canvas.rotate(180, getWidth()/2, getHeight()/2);
+ } else if (mCurrentEdgeEffect == EDGE_RIGHT) {
+ canvas.rotate(90, getWidth()/2, getHeight()/2);
+ canvas.translate(0, dx);
+ } else if (mCurrentEdgeEffect == EDGE_LEFT) {
+ canvas.rotate(270, getWidth()/2, getHeight()/2);
+ canvas.translate(0, dx);
+ }
+ if (mCurrentEdgeEffect != 0) {
+ mEdgeEffect.draw(canvas);
+ }
+ canvas.restore();
+ invalidate();
+ } else {
+ mCurrentEdgeEffect = 0;
+ }
+ }
+
+ private void drawImage(Canvas canvas, Bitmap image, Paint paint) {
+ if (image == null) {
+ return;
+ }
+
+ Matrix m = computeImageToScreen(image.getWidth(), image.getHeight());
+ if (m == null) {
+ return;
+ }
+
+ canvas.save();
+ image.setHasAlpha(true);
+ canvas.drawBitmap(image, m, paint);
+ canvas.restore();
+ }
+
+ private void updateEditsToMask(Bitmap mask) {
+ // clear mask and reset with original
+ mask.eraseColor(Color.TRANSPARENT);
+ Canvas canvas = new Canvas(mask);
+ canvas.drawBitmap(mOriginalMask, 0, 0, null);
+
+ for(StrokeData sd:mDrawing) {
+ drawEdit(canvas, sd);
+ }
+
+ // update current edit
+ if(mCurrent != null) {
+ drawEdit(canvas, mCurrent);
+ }
+ }
+
+ private void drawEdit(Canvas canvas, StrokeData sd) {
+ if (sd == null) {
+ return;
+ }
+ if (sd.mPath == null) {
+ return;
+ }
+ mMaskEditPaint.setColor(sd.mColor);
+ if(sd.mColor == Color.TRANSPARENT)
+ mMaskEditPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
+ else
+ mMaskEditPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));
+ mMaskEditPaint.setStrokeWidth(sd.mRadius);
+
+ canvas.drawPath(sd.mPath, mMaskEditPaint);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ int action = event.getAction();
+ action = action & MotionEvent.ACTION_MASK;
+
+ boolean scaleInProgress = scaleInProgress();
+ mGestureDetector.onTouchEvent(event);
+ mScaleGestureDetector.onTouchEvent(event);
+
+ if (mMode == Mode.MODE_SCALE) {
+ return true;
+ }
+ if (!scaleInProgress() && scaleInProgress) {
+ // If we were scaling, the scale will stop but we will
+ // still issue an ACTION_UP. Let the subclasses know.
+ mFinishedScalingOperation = true;
+ }
+
+ int ex = (int) event.getX();
+ int ey = (int) event.getY();
+ if (action == MotionEvent.ACTION_DOWN) {
+ mTouchDown.x = ex;
+ mTouchDown.y = ey;
+ if(event.getPointerCount() == 2) {
+ mMode = Mode.MODE_MOVE;
+ setOriginalTranslation(getTranslation());
+ } else if (event.getPointerCount() == 1) {
+ mMode = Mode.MODE_DRAW;
+ Point mapPoint = mapPoint(ex, ey);
+ startNewSection(mapPoint.x, mapPoint.y);
+ }
+ } else if (action == MotionEvent.ACTION_MOVE) {
+ mTouch.x = ex;
+ mTouch.y = ey;
+
+ float scaleFactor = getScaleFactor();
+ if (scaleFactor > 1 && event.getPointerCount() == 2
+ && mMode == Mode.MODE_MOVE) {
+ float translateX = (mTouch.x - mTouchDown.x) / scaleFactor;
+ float translateY = (mTouch.y - mTouchDown.y) / scaleFactor;
+ Point originalTranslation = getOriginalTranslation();
+ Point translation = getTranslation();
+ translation.x = (int) (originalTranslation.x + translateX);
+ translation.y = (int) (originalTranslation.y + translateY);
+ setTranslation(translation);
+ } else if(event.getPointerCount() == 1
+ && mMode == Mode.MODE_DRAW) {
+ Point mapPoint = mapPoint(ex, ey);
+ addPoint(mapPoint.x, mapPoint.y);
+ }
+ } else if (action == MotionEvent.ACTION_UP
+ || action == MotionEvent.ACTION_CANCEL
+ || action == MotionEvent.ACTION_OUTSIDE) {
+ if(event.getPointerCount() == 1
+ && mMode == Mode.MODE_DRAW) {
+ Point mapPoint = mapPoint(ex, ey);
+ endSection(mapPoint.x, mapPoint.y);
+ }
+
+ mMode = Mode.MODE_NONE;
+ mTouchDown.x = 0;
+ mTouchDown.y = 0;
+ mTouch.x = 0;
+ mTouch.y = 0;
+ if (getScaleFactor() <= 1) {
+ setScaleFactor(1);
+ setTranslation(new Point(0,0));
+ }
+ }
+
+ float scaleFactor = getScaleFactor();
+ Point translation = getTranslation();
+ constrainTranslation(translation, scaleFactor);
+ setTranslation(translation);
+
+ invalidate();
+ return true;
+ }
+
+ private void startAnimTranslation(int fromX, int toX,
+ int fromY, int toY, int delay) {
+ if (fromX == toX && fromY == toY) {
+ return;
+ }
+ if (mAnimatorTranslateX != null) {
+ mAnimatorTranslateX.cancel();
+ }
+ if (mAnimatorTranslateY != null) {
+ mAnimatorTranslateY.cancel();
+ }
+ mAnimatorTranslateX = ValueAnimator.ofInt(fromX, toX);
+ mAnimatorTranslateY = ValueAnimator.ofInt(fromY, toY);
+ mAnimatorTranslateX.setDuration(delay);
+ mAnimatorTranslateY.setDuration(delay);
+ mAnimatorTranslateX.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ Point translation = getTranslation();
+ translation.x = (Integer) animation.getAnimatedValue();
+ setTranslation(translation);
+ invalidate();
+ }
+ });
+ mAnimatorTranslateY.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ Point translation = getTranslation();
+ translation.y = (Integer) animation.getAnimatedValue();
+ setTranslation(translation);
+ invalidate();
+ }
+ });
+ mAnimatorTranslateX.start();
+ mAnimatorTranslateY.start();
+ }
+
+ private void applyTranslationConstraints() {
+ float scaleFactor = getScaleFactor();
+ Point translation = getTranslation();
+ int x = translation.x;
+ int y = translation.y;
+ constrainTranslation(translation, scaleFactor);
+
+ if (x != translation.x || y != translation.y) {
+ startAnimTranslation(x, translation.x,
+ y, translation.y,
+ mAnimationSnapDelay);
+ }
+ }
+
+ @Override
+ public boolean onDoubleTap(MotionEvent arg0) {
+ if(hasFusionApplied())
+ return true;
+
+ mZoomIn = !mZoomIn;
+ float scale = 1.0f;
+ final float x = arg0.getX();
+ final float y = arg0.getY();
+ if (mZoomIn) {
+ scale = getMaxScaleFactor();
+ }
+ if (scale != getScaleFactor()) {
+ if (mAnimatorScale != null) {
+ mAnimatorScale.cancel();
+ }
+ mAnimatorScale = ValueAnimator.ofFloat(
+ getScaleFactor(),
+ scale
+ );
+ float translateX = (getWidth() / 2 - x);
+ float translateY = (getHeight() / 2 - y);
+ Point translation = getTranslation();
+ int startTranslateX = translation.x;
+ int startTranslateY = translation.y;
+ if (scale != 1.0f) {
+ translation.x = (int) (mScaleTranslation.x + translateX);
+ translation.y = (int) (mScaleTranslation.y + translateY);
+ } else {
+ translation.x = 0;
+ translation.y = 0;
+ }
+ constrainTranslation(translation, scale);
+
+ startAnimTranslation(startTranslateX, translation.x,
+ startTranslateY, translation.y,
+ mAnimationZoomDelay);
+ mAnimatorScale.setDuration(mAnimationZoomDelay);
+ mAnimatorScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ setScaleFactor((Float) animation.getAnimatedValue());
+ invalidate();
+ }
+ });
+ mAnimatorScale.addListener(new Animator.AnimatorListener() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ }
+
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ applyTranslationConstraints();
+ invalidate();
+ }
+
+ @Override
+ public void onAnimationCancel(Animator animation) {
+
+ }
+
+ @Override
+ public void onAnimationRepeat(Animator animation) {
+
+ }
+ });
+ mAnimatorScale.start();
+ }
+ return true;
+ }
+
+ protected void constrainTranslation(Point translation, float scale) {
+ int currentEdgeEffect = 0;
+ if (mAllowScaleAndTranslate || scale <= 1) {
+ mCurrentEdgeEffect = 0;
+ mEdgeEffect.finish();
+ return;
+ }
+
+ Rect originalBounds = MasterImage.getImage().getOriginalBounds();
+ Matrix originalToScreen = computeImageToScreen(originalBounds.width(), originalBounds.height());
+ RectF screenPos = new RectF(originalBounds);
+ originalToScreen.mapRect(screenPos);
+
+ boolean rightConstraint = screenPos.right < getWidth();
+ boolean leftConstraint = screenPos.left > 0;
+ boolean topConstraint = screenPos.top > 0;
+ boolean bottomConstraint = screenPos.bottom < getHeight();
+
+ if (screenPos.width() > getWidth()) {
+ if (rightConstraint && !leftConstraint) {
+ float tx = screenPos.right - translation.x * scale;
+ translation.x = (int) ((getWidth() - tx) / scale);
+ currentEdgeEffect = EDGE_RIGHT;
+ } else if (leftConstraint && !rightConstraint) {
+ float tx = screenPos.left - translation.x * scale;
+ translation.x = (int) ((-tx) / scale);
+ currentEdgeEffect = EDGE_LEFT;
+ }
+ } else {
+ float tx = screenPos.right - translation.x * scale;
+ float dx = (getWidth() - screenPos.width()) / 2f;
+ translation.x = (int) ((getWidth() - tx - dx) / scale);
+ }
+
+ if (screenPos.height() > getHeight()) {
+ if (bottomConstraint && !topConstraint) {
+ float ty = screenPos.bottom - translation.y * scale;
+ translation.y = (int) ((getHeight() - ty) / scale);
+ currentEdgeEffect = EDGE_BOTTOM;
+ } else if (topConstraint && !bottomConstraint) {
+ float ty = screenPos.top - translation.y * scale;
+ translation.y = (int) ((-ty) / scale);
+ currentEdgeEffect = EDGE_TOP;
+ }
+ } else {
+ float ty = screenPos.bottom - translation.y * scale;
+ float dy = (getHeight()- screenPos.height()) / 2f;
+ translation.y = (int) ((getHeight() - ty - dy) / scale);
+ }
+
+ if (mCurrentEdgeEffect != currentEdgeEffect) {
+ if (mCurrentEdgeEffect == 0 || currentEdgeEffect != 0) {
+ mCurrentEdgeEffect = currentEdgeEffect;
+ mEdgeEffect.finish();
+ }
+ mEdgeEffect.setSize(getWidth(), mEdgeSize);
+ }
+ if (currentEdgeEffect != 0) {
+ mEdgeEffect.onPull(mEdgeSize);
+ }
+ }
+
+ @Override
+ public boolean onScale(ScaleGestureDetector detector) {
+ float scaleFactor = getScaleFactor();
+
+ scaleFactor = scaleFactor * detector.getScaleFactor();
+ if (scaleFactor > getMaxScaleFactor()) {
+ scaleFactor = getMaxScaleFactor();
+ }
+
+ if (scaleFactor < 1.0f) {
+ scaleFactor = 1.0f;
+ }
+
+ setScaleFactor(scaleFactor);
+ float focusx = detector.getFocusX();
+ float focusy = detector.getFocusY();
+ float translateX = (focusx - mScaleStartFocusX) / scaleFactor;
+ float translateY = (focusy - mScaleStartFocusY) / scaleFactor;
+ Point translation = getTranslation();
+ translation.x = (int) (mScaleTranslation.x + translateX);
+ translation.y = (int) (mScaleTranslation.y + translateY);
+ setTranslation(translation);
+ invalidate();
+ return true;
+ }
+
+ @Override
+ public boolean onScaleBegin(ScaleGestureDetector detector) {
+ Point pos = getTranslation();
+ mScaleTranslation.x = pos.x;
+ mScaleTranslation.y = pos.y;
+ mScaleStartFocusX = detector.getFocusX();
+ mScaleStartFocusY = detector.getFocusY();
+ mMode = Mode.MODE_SCALE;
+ return true;
+ }
+
+ @Override
+ public void onScaleEnd(ScaleGestureDetector detector) {
+ mMode = Mode.MODE_NONE;
+ if (getScaleFactor() < 1) {
+ setScaleFactor(1);
+ invalidate();
+ }
+ }
+
+ @Override
+ public boolean hasFusionApplied() {
+ return false;
+ }
+
+ private Matrix computeImageToScreen(int bmWidth, int bmHeight) {
+ float scale = 1f;
+ float translateX = 0;
+ float translateY = 0;
+
+ RectF size = new RectF(0, 0,
+ bmWidth, bmHeight);
+ float scaleW = getWidth() / size.width();
+ float scaleH = getHeight() / size.height();
+ scale = Math.min(scaleW, scaleH);
+ translateX = (getWidth() - (size.width() * scale)) / 2.0f;
+ translateY = (getHeight() - (size.height() * scale)) / 2.0f;
+
+ Point translation = getTranslation();
+ Matrix m = new Matrix();
+ m.postScale(scale, scale);
+ m.postTranslate(translateX, translateY);
+ m.postScale(getScaleFactor(), getScaleFactor(),
+ getWidth() / 2.0f,
+ getHeight() / 2.0f);
+ m.postTranslate(translation.x * getScaleFactor(),
+ translation.y * getScaleFactor());
+ return m;
+ }
+
+ private Matrix computeScreenToImage(int bmWidth, int bmHeight) {
+ Matrix m = computeImageToScreen(bmWidth, bmHeight);
+ Matrix inverse = new Matrix();
+ m.invert(inverse);
+ return inverse;
+ }
+
+ private Point mapPoint(int x, int y) {
+ Matrix screenToImage = computeScreenToImage(mMask.getWidth(), mMask.getHeight());
+ float[] tmpPoint = {x,y};
+ screenToImage.mapPoints(tmpPoint);
+
+ return new Point((int)tmpPoint[0], (int)tmpPoint[1]);
+ }
+
+ private void setTranslation(Point translation) {
+ mTranslation.x = translation.x;
+ mTranslation.y = translation.y;
+ }
+
+ private void setOriginalTranslation(Point translation) {
+ mOriginalTranslation.x = translation.x;
+ mOriginalTranslation.y = translation.y;
+ }
+
+ private void setScaleFactor(float scale) {
+ mScaleFactor = scale;
+ }
+
+ private Point getTranslation() {
+ return mTranslation;
+ }
+
+ private Point getOriginalTranslation() {
+ return mOriginalTranslation;
+ }
+
+ private float getScaleFactor() {
+ return mScaleFactor;
+ }
+
+ private float getMaxScaleFactor() {
+ return mMaxScaleFactor;
+ }
+
+ private void fillStrokeParameters(StrokeData sd){
+ sd.mColor = mEditor.isBackgroundMode()?Color.TRANSPARENT:Color.BLACK;
+ sd.mRadius = mEditor.getBrushSize();
+ }
+
+ private void startNewSection(float x, float y) {
+ mCurrent = new StrokeData();
+ fillStrokeParameters(mCurrent);
+ mCurrent.mPath = new Path();
+ mCurrent.mPath.moveTo(x, y);
+ mCurrent.mPoints[0] = x;
+ mCurrent.mPoints[1] = y;
+ mCurrent.noPoints = 1;
+ }
+
+ private void addPoint(float x, float y) {
+ int len = mCurrent.noPoints * 2;
+ mCurrent.mPath.lineTo(x, y);
+ if ((len+2) > mCurrent.mPoints.length) {
+ mCurrent.mPoints = Arrays.copyOf(mCurrent.mPoints, mCurrent.mPoints.length * 2);
+ }
+ mCurrent.mPoints[len] = x;
+ mCurrent.mPoints[len + 1] = y;
+ mCurrent.noPoints++;
+ }
+
+ private void endSection(float x, float y) {
+ addPoint(x, y);
+ mDrawing.push(mCurrent);
+ mCurrent = null;
+ mEditor.refreshUndoButton();
+ }
+
+ private void resetDrawing() {
+ mCurrent = null;
+ }
+
+ public boolean canUndoEdit() {
+ return !mDrawing.isEmpty();
+ }
+
+ public void undoLastEdit() {
+ if(!mDrawing.isEmpty()) {
+ mDrawing.pop();
+ mEditor.refreshUndoButton();
+ invalidate();
+ }
+ }
+
+ public void applyMaskUpdates() {
+ TruePortraitNativeEngine.getInstance().updateMask(mDrawing);
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
index 09bf27bd9..0a13da737 100644
--- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
+++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
@@ -40,6 +40,7 @@ import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentatio
import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.filters.ImageFilter;
import com.android.gallery3d.filtershow.history.HistoryItem;
@@ -442,9 +443,12 @@ public class MasterImage implements RenderingRequestCaller {
}
public synchronized boolean hasFusionApplied() {
- FilterRepresentation representation =
+ FilterRepresentation dcRepresentation =
mPreset.getFilterWithSerializationName(FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
- if(representation instanceof FilterDualCamFusionRepresentation) {
+ FilterRepresentation tpRepresentation =
+ mPreset.getFilterWithSerializationName(FilterTruePortraitFusionRepresentation.SERIALIZATION_NAME);
+ if(dcRepresentation instanceof FilterDualCamFusionRepresentation ||
+ tpRepresentation instanceof FilterTruePortraitFusionRepresentation) {
return true;
}
return false;
diff --git a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
index 0cdbed76d..c3120d72b 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java
@@ -18,9 +18,10 @@ package com.android.gallery3d.filtershow.pipeline;
import android.graphics.Bitmap;
import android.graphics.Canvas;
-import android.graphics.PorterDuff;
+import android.graphics.Color;
import android.renderscript.Allocation;
import android.renderscript.RenderScript;
+
import com.android.gallery3d.filtershow.cache.BitmapCache;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
@@ -57,8 +58,8 @@ public class Buffer {
}
public synchronized void useBitmap(Bitmap bitmap) {
+ mBitmap.eraseColor(Color.TRANSPARENT);
Canvas canvas = new Canvas(mBitmap);
- canvas.drawColor(0, PorterDuff.Mode.CLEAR);
canvas.drawBitmap(bitmap, 0, 0, null);
}
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
index 1640dac66..445407df9 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java
@@ -42,6 +42,7 @@ import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.filters.ImageFilter;
@@ -333,15 +334,19 @@ public class ImagePreset {
public void removeFilter(FilterRepresentation filterRepresentation) {
if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER
- || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) {
+ || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_DUALCAM
+ || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation filter = mFilters.elementAt(i);
if (filter.getFilterType() == filterRepresentation.getFilterType()) {
mFilters.remove(i);
// reset fusion underlay image.
- if(filter instanceof FilterDualCamFusionRepresentation) {
+ if(filter instanceof FilterDualCamFusionRepresentation ||
+ filter instanceof FilterTruePortraitFusionRepresentation) {
MasterImage.getImage().setFusionUnderlay(null);
+ MasterImage.getImage().setScaleFactor(1);
+ MasterImage.getImage().resetTranslation();
}
break;
}
@@ -399,6 +404,11 @@ public class ImagePreset {
if (!isNoneDualCamFilter(representation)) {
mFilters.add(representation);
}
+ } else if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ removeFilter(representation);
+ if (!isNoneTruePortraitFilter(representation)) {
+ mFilters.add(representation);
+ }
} else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) {
boolean replaced = false;
for (int i = 0; i < mFilters.size(); i++) {
@@ -422,6 +432,7 @@ public class ImagePreset {
// Enforces Filter type ordering for borders and dual cam
FilterRepresentation border = null;
FilterRepresentation dualcam = null;
+ FilterRepresentation trueportrait = null;
for (int i = 0; i < mFilters.size();) {
FilterRepresentation rep = mFilters.elementAt(i);
if (rep.getFilterType() == FilterRepresentation.TYPE_BORDER) {
@@ -432,6 +443,10 @@ public class ImagePreset {
dualcam = rep;
mFilters.remove(i);
continue;
+ } else if (rep.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ trueportrait = rep;
+ mFilters.remove(i);
+ continue;
}
i++;
}
@@ -448,6 +463,16 @@ public class ImagePreset {
}
mFilters.add(i, dualcam);
}
+ if (trueportrait != null) {
+ int i = 0;
+ for (; i < mFilters.size(); i++) {
+ FilterRepresentation rep = mFilters.elementAt(i);
+ if (rep.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
+ break;
+ }
+ }
+ mFilters.add(i, trueportrait);
+ }
}
private boolean isNoneBorderFilter(FilterRepresentation representation) {
@@ -465,6 +490,11 @@ public class ImagePreset {
((FilterDualCamSketchRepresentation) representation).getTextId() == R.string.none;
}
+ private boolean isNoneTruePortraitFilter(FilterRepresentation representation) {
+ return representation.getTextId() == R.string.none &&
+ representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT;
+ }
+
public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
for (int i = 0; i < mFilters.size(); i++) {
FilterRepresentation representation = mFilters.elementAt(i);
@@ -478,6 +508,7 @@ public class ImagePreset {
public Bitmap apply(Bitmap original, FilterEnvironment environment) {
Bitmap bitmap = original;
bitmap = applyDualCamera(bitmap, environment);
+ bitmap = applyTruePortrait(bitmap, environment);
bitmap = applyFilters(bitmap, -1, -1, environment);
return applyBorder(bitmap, environment);
}
@@ -540,6 +571,25 @@ public class ImagePreset {
return bitmap;
}
+ public Bitmap applyTruePortrait(Bitmap bitmap, FilterEnvironment environment) {
+ // Apply trueportrait filters
+ // Returns a new bitmap.
+ for (FilterRepresentation representation:mFilters) {
+ if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ Bitmap tmp = bitmap;
+ bitmap = environment.applyRepresentation(representation, bitmap);
+ if (tmp != bitmap) {
+ environment.cache(tmp);
+ }
+ if (environment.needsStop()) {
+ return bitmap;
+ }
+ }
+ }
+
+ return bitmap;
+ }
+
public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) {
// get the border from the list of filters.
FilterRepresentation border = getFilterRepresentationForType(
@@ -580,6 +630,10 @@ public class ImagePreset {
// skip the dual cam as it's already applied.
continue;
}
+ if (representation.getFilterType() == FilterRepresentation.TYPE_TRUEPORTRAIT) {
+ // skip the true portrait as it's already applied.
+ continue;
+ }
Bitmap tmp = bitmap;
bitmap = environment.applyRepresentation(representation, bitmap);
if (tmp != bitmap) {
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
index b5e9609e2..d42834457 100644
--- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
+++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java
@@ -307,6 +307,7 @@ public class ProcessingService extends Service {
filtersManager.addTrueScanner();
filtersManager.addHazeBuster();
filtersManager.addSeeStraight();
+ filtersManager.addTruePortrait(this);
FiltersManager highresFiltersManager = FiltersManager.getHighresManager();
highresFiltersManager.addLooks(this);
@@ -318,6 +319,7 @@ public class ProcessingService extends Service {
highresFiltersManager.addTrueScanner();
highresFiltersManager.addHazeBuster();
highresFiltersManager.addSeeStraight();
+ highresFiltersManager.addTruePortrait(this);
}
private void tearDownPipeline() {
diff --git a/src/com/android/gallery3d/filtershow/tools/SaveImage.java b/src/com/android/gallery3d/filtershow/tools/SaveImage.java
index 0f615da25..87492a335 100644
--- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java
+++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java
@@ -50,7 +50,9 @@ import com.android.gallery3d.exif.ExifInterface;
import com.android.gallery3d.filtershow.FilterShowActivity;
import com.android.gallery3d.filtershow.cache.ImageLoader;
import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FilterRepresentation;
+import com.android.gallery3d.filtershow.filters.FilterTruePortraitFusionRepresentation;
import com.android.gallery3d.filtershow.filters.FiltersManager;
import com.android.gallery3d.filtershow.imageshow.MasterImage;
import com.android.gallery3d.filtershow.pipeline.CachingPipeline;
@@ -361,35 +363,11 @@ public class SaveImage {
if (mPreviewImage != null) {
Bitmap previewBmp;
// Check for Fusion
- FilterDualCamFusionRepresentation fusionRep =
- (FilterDualCamFusionRepresentation) preset.getFilterWithSerializationName(
- FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
+ FilterFusionRepresentation fusionRep = findFusionRepresentation(preset);
boolean hasFusion = (fusionRep != null && fusionRep.hasUnderlay());
if(hasFusion) {
- // fusion. decode underlay image and get dest rect
- Uri underLayUri = Uri.parse(fusionRep.getUnderlay());
- Bitmap underlay = ImageLoader.loadConstrainedBitmap(underLayUri, mContext,
- Math.max(mPreviewImage.getWidth(), mPreviewImage.getHeight()), null, false);
- RectF destRect = new RectF();
- Rect imageBounds = MasterImage.getImage().getImageBounds();
- Rect underlayBounds = MasterImage.getImage().getFusionBounds();
- float underlayScaleFactor = (float)underlay.getWidth()
- / (float)underlayBounds.width();
-
- destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
- destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
- destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
- destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
-
- Canvas canvas = new Canvas(underlay);
- Paint paint = new Paint();
- paint.reset();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
-
- canvas.drawBitmap(mPreviewImage, null, destRect, paint);
- previewBmp = underlay;
+ previewBmp = flattenFusion(Uri.parse(fusionRep.getUnderlay()), mPreviewImage,
+ Math.max(mPreviewImage.getWidth(), mPreviewImage.getHeight()), 0);
} else {
previewBmp = mPreviewImage;
}
@@ -464,31 +442,11 @@ public class SaveImage {
bitmap = pipeline.renderFinalImage(bitmap, preset);
// Check for Fusion
- FilterDualCamFusionRepresentation fusionRep = (FilterDualCamFusionRepresentation) preset.getFilterWithSerializationName(
- FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
-
- if(fusionRep != null && fusionRep.hasUnderlay()) {
- // fusion. decode underlay image and get dest rect
- Uri underLayUri = Uri.parse(fusionRep.getUnderlay());
- Bitmap underlay = ImageLoader.loadBitmapWithBackouts(mContext, underLayUri, sampleSize);
- RectF destRect = new RectF();
- Rect imageBounds = MasterImage.getImage().getImageBounds();
- Rect underlayBounds = MasterImage.getImage().getFusionBounds();
- float underlayScaleFactor = (float)underlay.getWidth() / (float)underlayBounds.width();
-
- destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
- destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
- destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
- destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
-
- Canvas canvas = new Canvas(underlay);
- Paint paint = new Paint();
- paint.reset();
- paint.setAntiAlias(true);
- paint.setFilterBitmap(true);
- paint.setDither(true);
-
- canvas.drawBitmap(bitmap, null, destRect, paint);
+ FilterFusionRepresentation fusionRep = findFusionRepresentation(preset);
+ boolean hasFusion = (fusionRep != null && fusionRep.hasUnderlay());
+ if(hasFusion) {
+ Bitmap underlay = flattenFusion(
+ Uri.parse(fusionRep.getUnderlay()), bitmap, 0, sampleSize);
bitmap.recycle();
bitmap = underlay;
@@ -832,4 +790,56 @@ public class SaveImage {
return false;
}
+ private FilterFusionRepresentation findFusionRepresentation(ImagePreset preset) {
+ FilterDualCamFusionRepresentation dcRepresentation =
+ (FilterDualCamFusionRepresentation)preset.getFilterWithSerializationName(
+ FilterDualCamFusionRepresentation.SERIALIZATION_NAME);
+ FilterTruePortraitFusionRepresentation tpRepresentation =
+ (FilterTruePortraitFusionRepresentation)preset.getFilterWithSerializationName(
+ FilterTruePortraitFusionRepresentation.SERIALIZATION_NAME);
+
+ FilterFusionRepresentation fusionRep = null;
+
+ if(dcRepresentation != null)
+ fusionRep = (FilterFusionRepresentation) dcRepresentation;
+ else if (tpRepresentation != null)
+ fusionRep = (FilterFusionRepresentation) tpRepresentation;
+
+ return fusionRep;
+ }
+
+ private Bitmap flattenFusion(Uri underlayUri, Bitmap bitmap, int sizeConstraint, int sampleSize) {
+ // fusion. decode underlay image and get dest rect
+
+ Bitmap underlay = null;
+
+ if(sizeConstraint != 0) {
+ underlay = ImageLoader.loadConstrainedBitmap(underlayUri, mContext,
+ sizeConstraint, null, false);
+ } else if (sampleSize != 0) {
+ underlay = ImageLoader.loadBitmapWithBackouts(mContext, underlayUri, sampleSize);
+ }
+
+ RectF destRect = new RectF();
+ Rect imageBounds = MasterImage.getImage().getImageBounds();
+ Rect underlayBounds = MasterImage.getImage().getFusionBounds();
+ float underlayScaleFactor = (float)underlay.getWidth()
+ / (float)underlayBounds.width();
+
+ destRect.left = (imageBounds.left - underlayBounds.left) * underlayScaleFactor;
+ destRect.right = (imageBounds.right - underlayBounds.left) * underlayScaleFactor;
+ destRect.top = (imageBounds.top - underlayBounds.top) * underlayScaleFactor;
+ destRect.bottom = (imageBounds.bottom - underlayBounds.top) * underlayScaleFactor;
+
+ Canvas canvas = new Canvas(underlay);
+ Paint paint = new Paint();
+ paint.reset();
+ paint.setAntiAlias(true);
+ paint.setFilterBitmap(true);
+ paint.setDither(true);
+
+ canvas.drawBitmap(bitmap, null, destRect, paint);
+
+ return underlay;
+ }
}
diff --git a/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java b/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java
new file mode 100644
index 000000000..03972638c
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/tools/TruePortraitNativeEngine.java
@@ -0,0 +1,247 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.tools;
+
+import java.util.Stack;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.BitmapFactory;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.Paint;
+import android.graphics.Paint.Style;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.v4.app.FragmentManager;
+import android.util.Log;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation.StrokeData;
+import com.android.gallery3d.filtershow.ui.AlertMsgDialog;
+
+public class TruePortraitNativeEngine {
+ private static final String TAG = "TruePortraitNativeEngine";
+ static {
+ try {
+ System.loadLibrary("jni_trueportrait");
+ mLibLoaded = true;
+ Log.v(TAG, "successfully loaded true portrait lib");
+ } catch (UnsatisfiedLinkError e) {
+ Log.e(TAG, "failed to load true portrait lib");
+ mLibLoaded = false;
+ }
+ }
+
+ public static enum EffectType {
+ BLUR,
+ MOTION_BLUR,
+ HALO,
+ SKETCH
+ };
+
+ private static final int MASK_UPDATE_FOREGROUND = 0x7F000000;
+ private static final int MASK_UPDATE_BACKGROUND = 0x81000000;
+
+ private static boolean mLibLoaded;
+ private static TruePortraitNativeEngine mInstance;
+
+ private Bitmap mSketchBm;
+ private boolean mFacesDetected;
+ private Point mPreviewSize = new Point();
+ private Bitmap mUpdateBm;
+
+ private TruePortraitNativeEngine() {}
+
+ public static void createInstance() {
+ if(mInstance == null) {
+ mInstance = new TruePortraitNativeEngine();
+ }
+ }
+
+ public static TruePortraitNativeEngine getInstance() {
+ createInstance();
+ return mInstance;
+ }
+
+ public boolean isLibLoaded() {
+ return mLibLoaded;
+ }
+
+ public boolean init(Context context, Bitmap src, Rect[] faces) {
+ setFacesDetected(true);
+ if(nativeInit(src, faces.length, faces)) {
+ nativeGetPreviewSize(mPreviewSize);
+ mSketchBm = BitmapFactory.decodeResource(context.getResources(), R.raw.sketch_bm);
+ return true;
+ } else {
+ mSketchBm = null;
+ return false;
+ }
+ }
+
+ public void release() {
+ if(mUpdateBm != null) {
+ mUpdateBm.recycle();
+ mUpdateBm = null;
+ }
+
+ if(mSketchBm != null) {
+ mSketchBm.recycle();
+ mSketchBm = null;
+ }
+
+ nativeRelease();
+ }
+
+ public void setFacesDetected(boolean detected) {
+ mFacesDetected = detected;
+ }
+
+ public boolean facesDetected() {
+ return mFacesDetected;
+ }
+
+ public void showNoFaceDetectedDialog(FragmentManager fragmentManager) {
+ AlertMsgDialog dialog = new AlertMsgDialog(R.string.trueportrait, R.string.trueportrait_no_face);
+ dialog.show(fragmentManager, "tp_no_face");
+ }
+
+ public boolean applyEffect(EffectType type, int intensity, Bitmap outBm) {
+ boolean result = false;
+ switch(type) {
+ case BLUR:
+ result = nativeApplyBlur(intensity, outBm);
+ break;
+ case MOTION_BLUR:
+ result = nativeApplyMotionBlur(intensity, outBm);
+ break;
+ case HALO:
+ result = nativeApplyHalo(intensity, outBm);
+ break;
+ case SKETCH:
+ result = nativeApplySketch(outBm, mSketchBm);
+ break;
+ }
+
+ return result;
+ }
+
+ public Bitmap getMask() {
+ Bitmap mask = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ALPHA_8);
+ if(mask != null) {
+ nativeGetPreviewMask(mask);
+ }
+
+ return mask;
+ }
+
+ public Bitmap getPreview() {
+ Bitmap previewBm = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ARGB_8888);
+ if(previewBm != null) {
+ nativeGetPreviewImage(previewBm);
+ }
+
+ return previewBm;
+ }
+
+ public boolean updateMask(Stack<StrokeData> edits) {
+ if(mUpdateBm == null) {
+ mUpdateBm = Bitmap.createBitmap(mPreviewSize.x, mPreviewSize.y, Config.ALPHA_8);
+ }
+
+ mUpdateBm.eraseColor(Color.TRANSPARENT);
+ Canvas canvas = new Canvas(mUpdateBm);
+ for(StrokeData sd:edits) {
+ drawEdit(canvas, sd);
+ }
+
+ // DEBUG
+ for(int i = 0; i<mPreviewSize.y; i++) {
+ StringBuilder sb = new StringBuilder();
+ sb.append("[ ");
+ for(int j = 0; j<mPreviewSize.x; j++) {
+ int pixel = mUpdateBm.getPixel(j, i);
+ sb.append(Color.alpha(pixel));
+ sb.append(" ");
+ }
+ sb.append("]");
+ Log.e(TAG, sb.toString());
+ }
+ //
+ return nativeUpdatePreviewMask(mUpdateBm);
+ }
+
+ private void drawEdit(Canvas canvas, StrokeData sd) {
+ if (sd == null) {
+ return;
+ }
+ if (sd.mPath == null) {
+ return;
+ }
+ // USER_INPUT_MASK_UNCHANGED_VALUE = 0
+ // USER_INPUT_MASK_BACKGROUND_VALUE = 129
+ // USER_INPUT_MASK_FOREGROUND_VALUE = 127
+ Paint paint = new Paint();
+ paint.setAntiAlias(false);
+ paint.setStyle(Style.STROKE);
+ paint.setStrokeCap(Paint.Cap.ROUND);
+ if(sd.mColor == Color.TRANSPARENT)
+ paint.setColor(MASK_UPDATE_BACKGROUND);
+ else
+ paint.setColor(MASK_UPDATE_FOREGROUND);
+ paint.setStrokeWidth(sd.mRadius);
+
+ canvas.drawPath(sd.mPath, paint);
+ }
+
+ native public boolean nativeInit(Bitmap srcRGBA, int numFaces, Rect[] faces);
+
+ native public void nativeRelease();
+
+ native public boolean nativeGetPreviewSize(Point point);
+
+ native public boolean nativeGetPreviewImage(Bitmap outBm);
+
+ native public boolean nativeGetPreviewMask(Bitmap outBm);
+
+ native public boolean nativeUpdatePreviewMask(Bitmap mask);
+
+ native public boolean nativeApplyBlur(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplyMotionBlur(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplyHalo(int intensity, Bitmap outBm);
+
+ native public boolean nativeApplySketch(Bitmap outBm, Bitmap sketchBm);
+
+ native public boolean nativeGetForegroundImg(Bitmap outBm);
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java b/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java
new file mode 100644
index 000000000..2041eb2ce
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/ui/AlertMsgDialog.java
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.ui;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+
+import org.codeaurora.gallery.R;
+
+public class AlertMsgDialog extends DialogFragment {
+ private int mTitleId;
+ private int mMessageId;
+
+ public AlertMsgDialog(int titleId, int msgId) {
+ mTitleId = titleId;
+ mMessageId = msgId;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
+ ab.setTitle(mTitleId);
+ ab.setMessage(mMessageId);
+ ab.setCancelable(false);
+ ab.setNeutralButton(R.string.ok, null);
+ return ab.create();
+ }
+}
diff --git a/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java b/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java
new file mode 100644
index 000000000..aad403bd1
--- /dev/null
+++ b/src/com/android/gallery3d/filtershow/ui/DoNotShowAgainDialog.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016, The Linux Foundation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of The Linux Foundation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
+ * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+package com.android.gallery3d.filtershow.ui;
+
+import android.app.AlertDialog;
+import android.app.Dialog;
+import android.content.Context;
+import android.content.DialogInterface;
+import android.os.Bundle;
+import android.support.v4.app.DialogFragment;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.CheckBox;
+import android.widget.TextView;
+
+import org.codeaurora.gallery.R;
+import com.android.gallery3d.util.GalleryUtils;
+
+public class DoNotShowAgainDialog extends DialogFragment {
+ private int mSharedPrefKeyId;
+ private int mTitleId;
+ private int mMessageId;
+ private CheckBox mDoNotShowAgainChk;
+
+ public DoNotShowAgainDialog(int titleId, int msgId, int sharedPrefKeyId) {
+ mTitleId = titleId;
+ mMessageId = msgId;
+ mSharedPrefKeyId = sharedPrefKeyId;
+ }
+
+ @Override
+ public Dialog onCreateDialog(Bundle savedInstanceState) {
+ LayoutInflater inflater = getActivity().getLayoutInflater();
+ View view = inflater.inflate(R.layout.do_not_show_again_dialog, null);
+ TextView message = (TextView) view.findViewById(R.id.message);
+ message.setText(mMessageId);
+ mDoNotShowAgainChk = (CheckBox) view.findViewById(R.id.do_not_show_chk);
+
+ AlertDialog.Builder ab = new AlertDialog.Builder(getActivity());
+ ab.setTitle(mTitleId);
+ ab.setView(view);
+ ab.setCancelable(false);
+ ab.setNeutralButton(R.string.ok, new DialogInterface.OnClickListener() {
+ public void onClick(DialogInterface dialog, int id) {
+ Context context = getActivity();
+ GalleryUtils.setBooleanPref(context,
+ context.getString(mSharedPrefKeyId), mDoNotShowAgainChk.isChecked());
+ }
+ });
+ return ab.create();
+ }
+}
diff --git a/src/com/android/gallery3d/util/GalleryUtils.java b/src/com/android/gallery3d/util/GalleryUtils.java
index a0580016b..3a50dbfbd 100644
--- a/src/com/android/gallery3d/util/GalleryUtils.java
+++ b/src/com/android/gallery3d/util/GalleryUtils.java
@@ -423,7 +423,7 @@ public class GalleryUtils {
return (h > 0 && w / h >= 2);
}
// Newly added methods
- public static int getIntPref(Context context, String name, int def) {
+ public static int getIntPref(Context context, String name, int def) {
SharedPreferences prefs =
context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
return prefs.getInt(name, def);
@@ -437,6 +437,34 @@ public class GalleryUtils {
ed.commit();
}
+ public static boolean getBooleanPref(Context context, String name, boolean def) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ return prefs.getBoolean(name, def);
+ }
+
+ public static void setBooleanPref(Context context, String name, boolean value) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ Editor ed = prefs.edit();
+ ed.putBoolean(name, value);
+ ed.commit();
+ }
+
+ public static String getStringPref(Context context, String name, String def) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ return prefs.getString(name, def);
+ }
+
+ public static void setStringPref(Context context, String name, String value) {
+ SharedPreferences prefs =
+ context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE);
+ Editor ed = prefs.edit();
+ ed.putString(name, value);
+ ed.commit();
+ }
+
public static boolean isTelephonyCallInProgress(Context context) {
TelephonyManager telephonyManager =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);