diff options
author | Byunghun Jeon <bjeon@codeaurora.org> | 2015-08-03 16:50:11 -0700 |
---|---|---|
committer | Gerrit - the friendly Code Review server <code-review@localhost> | 2015-10-13 04:31:27 -0700 |
commit | 8ea62fb010059f600f0e26ad468ceab6bf0c8232 (patch) | |
tree | d622960b2312d56b98b99d5747064f8a54682e90 | |
parent | 8c969c5cf077a33082ea113f7421797ec1f89eb0 (diff) | |
download | android_packages_apps_Gallery2-8ea62fb010059f600f0e26ad468ceab6bf0c8232.tar.gz android_packages_apps_Gallery2-8ea62fb010059f600f0e26ad468ceab6bf0c8232.tar.bz2 android_packages_apps_Gallery2-8ea62fb010059f600f0e26ad468ceab6bf0c8232.zip |
Gallery2: Add dual camera filters
Add dual camera based filters.
CRs-Fixed: 892007
Change-Id: Ide26135ef8e83137f86abb96ca7ce29e94801bba
63 files changed, 2489 insertions, 139 deletions
diff --git a/gallerycommon/src/com/android/gallery3d/exif/CountedDataInputStream.java b/gallerycommon/src/com/android/gallery3d/exif/CountedDataInputStream.java index dfd4a1a10..c8300ad6e 100644 --- a/gallerycommon/src/com/android/gallery3d/exif/CountedDataInputStream.java +++ b/gallerycommon/src/com/android/gallery3d/exif/CountedDataInputStream.java @@ -24,7 +24,7 @@ import java.nio.ByteBuffer; import java.nio.ByteOrder; import java.nio.charset.Charset; -class CountedDataInputStream extends FilterInputStream { +public class CountedDataInputStream extends FilterInputStream { private int mCount = 0; @@ -32,7 +32,7 @@ class CountedDataInputStream extends FilterInputStream { private final byte mByteArray[] = new byte[8]; private final ByteBuffer mByteBuffer = ByteBuffer.wrap(mByteArray); - protected CountedDataInputStream(InputStream in) { + public CountedDataInputStream(InputStream in) { super(in); } diff --git a/res/drawable-hdpi/filtershow_dualcam_blur.png b/res/drawable-hdpi/filtershow_dualcam_blur.png Binary files differnew file mode 100644 index 000000000..ef0a93171 --- /dev/null +++ b/res/drawable-hdpi/filtershow_dualcam_blur.png diff --git a/res/drawable-hdpi/filtershow_dualcam_focus.png b/res/drawable-hdpi/filtershow_dualcam_focus.png Binary files differnew file mode 100644 index 000000000..d1d92c171 --- /dev/null +++ b/res/drawable-hdpi/filtershow_dualcam_focus.png diff --git a/res/drawable-hdpi/filtershow_dualcam_fusion.png b/res/drawable-hdpi/filtershow_dualcam_fusion.png Binary files differnew file mode 100644 index 000000000..344ce25d5 --- /dev/null +++ b/res/drawable-hdpi/filtershow_dualcam_fusion.png diff --git a/res/drawable-hdpi/filtershow_dualcam_halo.png b/res/drawable-hdpi/filtershow_dualcam_halo.png Binary files differnew file mode 100644 index 000000000..cd4359b69 --- /dev/null +++ b/res/drawable-hdpi/filtershow_dualcam_halo.png diff --git a/res/drawable-hdpi/filtershow_dualcam_sketch.png b/res/drawable-hdpi/filtershow_dualcam_sketch.png Binary files differnew file mode 100644 index 000000000..f04db3e6f --- /dev/null +++ b/res/drawable-hdpi/filtershow_dualcam_sketch.png diff --git a/res/drawable-hdpi/ic_photoeditor_dualcam.png b/res/drawable-hdpi/ic_photoeditor_dualcam.png Binary files differnew file mode 100644 index 000000000..f3227f1a9 --- /dev/null +++ b/res/drawable-hdpi/ic_photoeditor_dualcam.png diff --git a/res/drawable-mdpi/filtershow_dualcam_blur.png b/res/drawable-mdpi/filtershow_dualcam_blur.png Binary files differnew file mode 100644 index 000000000..a654c2034 --- /dev/null +++ b/res/drawable-mdpi/filtershow_dualcam_blur.png diff --git a/res/drawable-mdpi/filtershow_dualcam_focus.png b/res/drawable-mdpi/filtershow_dualcam_focus.png Binary files differnew file mode 100644 index 000000000..b06d7027f --- /dev/null +++ b/res/drawable-mdpi/filtershow_dualcam_focus.png diff --git a/res/drawable-mdpi/filtershow_dualcam_fusion.png b/res/drawable-mdpi/filtershow_dualcam_fusion.png Binary files differnew file mode 100644 index 000000000..3be06b9cf --- /dev/null +++ b/res/drawable-mdpi/filtershow_dualcam_fusion.png diff --git a/res/drawable-mdpi/filtershow_dualcam_halo.png b/res/drawable-mdpi/filtershow_dualcam_halo.png Binary files differnew file mode 100644 index 000000000..9f3692126 --- /dev/null +++ b/res/drawable-mdpi/filtershow_dualcam_halo.png diff --git a/res/drawable-mdpi/filtershow_dualcam_sketch.png b/res/drawable-mdpi/filtershow_dualcam_sketch.png Binary files differnew file mode 100644 index 000000000..5dc2c1931 --- /dev/null +++ b/res/drawable-mdpi/filtershow_dualcam_sketch.png diff --git a/res/drawable-mdpi/ic_photoeditor_dualcam.png b/res/drawable-mdpi/ic_photoeditor_dualcam.png Binary files differnew file mode 100644 index 000000000..6b05972a8 --- /dev/null +++ b/res/drawable-mdpi/ic_photoeditor_dualcam.png diff --git a/res/drawable-xhdpi/filtershow_dualcam_blur.png b/res/drawable-xhdpi/filtershow_dualcam_blur.png Binary files differnew file mode 100644 index 000000000..5fa98ecbc --- /dev/null +++ b/res/drawable-xhdpi/filtershow_dualcam_blur.png diff --git a/res/drawable-xhdpi/filtershow_dualcam_focus.png b/res/drawable-xhdpi/filtershow_dualcam_focus.png Binary files differnew file mode 100644 index 000000000..9d972d389 --- /dev/null +++ b/res/drawable-xhdpi/filtershow_dualcam_focus.png diff --git a/res/drawable-xhdpi/filtershow_dualcam_fusion.png b/res/drawable-xhdpi/filtershow_dualcam_fusion.png Binary files differnew file mode 100644 index 000000000..747c7e2de --- /dev/null +++ b/res/drawable-xhdpi/filtershow_dualcam_fusion.png diff --git a/res/drawable-xhdpi/filtershow_dualcam_halo.png b/res/drawable-xhdpi/filtershow_dualcam_halo.png Binary files differnew file mode 100644 index 000000000..c62e5ef9d --- /dev/null +++ b/res/drawable-xhdpi/filtershow_dualcam_halo.png diff --git a/res/drawable-xhdpi/filtershow_dualcam_sketch.png b/res/drawable-xhdpi/filtershow_dualcam_sketch.png Binary files differnew file mode 100644 index 000000000..8eb72b1ac --- /dev/null +++ b/res/drawable-xhdpi/filtershow_dualcam_sketch.png diff --git a/res/drawable-xhdpi/ic_photoeditor_dualcam.png b/res/drawable-xhdpi/ic_photoeditor_dualcam.png Binary files differnew file mode 100644 index 000000000..663df2f8c --- /dev/null +++ b/res/drawable-xhdpi/ic_photoeditor_dualcam.png diff --git a/res/drawable-xxhdpi/filtershow_dualcam_blur.png b/res/drawable-xxhdpi/filtershow_dualcam_blur.png Binary files differnew file mode 100644 index 000000000..22f46f0dd --- /dev/null +++ b/res/drawable-xxhdpi/filtershow_dualcam_blur.png diff --git a/res/drawable-xxhdpi/filtershow_dualcam_focus.png b/res/drawable-xxhdpi/filtershow_dualcam_focus.png Binary files differnew file mode 100644 index 000000000..57de383e3 --- /dev/null +++ b/res/drawable-xxhdpi/filtershow_dualcam_focus.png diff --git a/res/drawable-xxhdpi/filtershow_dualcam_fusion.png b/res/drawable-xxhdpi/filtershow_dualcam_fusion.png Binary files differnew file mode 100644 index 000000000..8533a9075 --- /dev/null +++ b/res/drawable-xxhdpi/filtershow_dualcam_fusion.png diff --git a/res/drawable-xxhdpi/filtershow_dualcam_halo.png b/res/drawable-xxhdpi/filtershow_dualcam_halo.png Binary files differnew file mode 100644 index 000000000..345c1f83a --- /dev/null +++ b/res/drawable-xxhdpi/filtershow_dualcam_halo.png diff --git a/res/drawable-xxhdpi/filtershow_dualcam_sketch.png b/res/drawable-xxhdpi/filtershow_dualcam_sketch.png Binary files differnew file mode 100644 index 000000000..383dcff75 --- /dev/null +++ b/res/drawable-xxhdpi/filtershow_dualcam_sketch.png diff --git a/res/drawable-xxhdpi/ic_photoeditor_dualcam.png b/res/drawable-xxhdpi/ic_photoeditor_dualcam.png Binary files differnew file mode 100644 index 000000000..0953e2c0c --- /dev/null +++ b/res/drawable-xxhdpi/ic_photoeditor_dualcam.png diff --git a/res/layout-land/filtershow_main_panel.xml b/res/layout-land/filtershow_main_panel.xml index e508e767b..2202f102c 100644 --- a/res/layout-land/filtershow_main_panel.xml +++ b/res/layout-land/filtershow_main_panel.xml @@ -93,6 +93,15 @@ android:scaleType="centerInside" android:visibility="gone" android:src="@drawable/ic_photoeditor_makeup"/> + <ImageButton + android:id="@+id/dualCamButton" + android:layout_width="@dimen/thumbnail_size" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/filtershow_button_background" + android:padding="2dip" + android:scaleType="centerInside" + android:src="@drawable/ic_photoeditor_dualcam"/> </LinearLayout> diff --git a/res/layout/filtershow_dualcamera_editor.xml b/res/layout/filtershow_dualcamera_editor.xml new file mode 100644 index 000000000..a845e25c9 --- /dev/null +++ b/res/layout/filtershow_dualcamera_editor.xml @@ -0,0 +1,44 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2015, 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. +--> + + +<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" + xmlns:iconbutton="http://schemas.android.com/apk/res/com.android.gallery3d" + android:id="@+id/editorDualCam" + android:layout_width="match_parent" + android:layout_height="wrap_content" + android:layout_weight="1" > + + <com.android.gallery3d.filtershow.imageshow.ImageDualCamera + android:id="@+id/imageDualCamera" + android:layout_width="match_parent" + android:layout_height="wrap_content" /> + +</FrameLayout> diff --git a/res/layout/filtershow_main_panel.xml b/res/layout/filtershow_main_panel.xml index f8b26b088..1dc4e9f3f 100644 --- a/res/layout/filtershow_main_panel.xml +++ b/res/layout/filtershow_main_panel.xml @@ -106,6 +106,15 @@ android:visibility="gone" android:src="@drawable/ic_photoeditor_makeup"/> + <ImageButton + android:id="@+id/dualCamButton" + android:layout_width="@dimen/thumbnail_size" + android:layout_height="match_parent" + android:layout_weight="1" + android:background="@drawable/filtershow_button_background" + android:padding="2dip" + android:scaleType="centerInside" + android:src="@drawable/ic_photoeditor_dualcam"/> </LinearLayout> </com.android.gallery3d.filtershow.CenteredLinearLayout> diff --git a/res/menu/filtershow_menu_fusion.xml b/res/menu/filtershow_menu_fusion.xml new file mode 100644 index 000000000..f80349eb1 --- /dev/null +++ b/res/menu/filtershow_menu_fusion.xml @@ -0,0 +1,42 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + Copyright (c) 2015, 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. +--> + +<menu xmlns:android="http://schemas.android.com/apk/res/android" > + + <group android:id="@+id/fusion_popupmenu" > + <item + android:id="@+id/fusion_menu_choose_segment" + android:title="@string/fusion_pick_point"/> + <item + android:id="@+id/fusion_menu_choose_underlay" + android:title="@string/fusion_pick_underlay"/> + </group> + +</menu>
\ No newline at end of file diff --git a/res/raw/sketch.jpg b/res/raw/sketch.jpg Binary files differnew file mode 100644 index 000000000..bf347f702 --- /dev/null +++ b/res/raw/sketch.jpg diff --git a/res/values/filtershow_ids.xml b/res/values/filtershow_ids.xml index 58f16dcd1..7dc34c357 100644 --- a/res/values/filtershow_ids.xml +++ b/res/values/filtershow_ids.xml @@ -51,4 +51,7 @@ <item type="id" name="editorGrad" /> <item type="id" name="editorChanSat" /> <item type="id" name="editorMakeup" /> + <item type="id" name="editorDualCam" /> + <item type="id" name="editorDualCamSketch" /> + <item type="id" name="editorDualCamFusion" /> </resources> diff --git a/res/values/filtershow_strings.xml b/res/values/filtershow_strings.xml index 9a6b08f08..fc75fb9b9 100644 --- a/res/values/filtershow_strings.xml +++ b/res/values/filtershow_strings.xml @@ -192,6 +192,16 @@ <string name="downsample">Downsample</string> <!-- Label for the "neutral density graduated filter" filter effect [CHAR LIMIT=15] --> <string name="grad">Graduated</string> + <!-- Label for the "refocus" dual camera effect [CHAR LIMIT=15] --> + <string name="focus">Focus</string> + <!-- Label for the "bokeh" dual camera effect [CHAR LIMIT=15] --> + <string name="blur">Bokeh</string> + <!-- Label for the "fusion" dual camera effect [CHAR LIMIT=15] --> + <string name="fusion">Fusion</string> + <!-- Label for the "sketch" dual camera effect [CHAR LIMIT=15] --> + <string name="sketch">Sketch</string> + <!-- Label for the "halo" dual camera effect [CHAR LIMIT=15] --> + <string name="halo">Halo</string> <!-- Label for the Brightness effect [CHAR LIMIT=20] --> <string name="editor_grad_brightness">Brightness</string> <!-- Label for the Contrast filter effect [CHAR LIMIT=20] --> @@ -328,4 +338,7 @@ <!-- Label for exif tags in the information panel [CHAR LIMIT=50] --> <string name="filtershow_exif_copyright">Copyright</string> + <string name="fusion_pick_point">Pick Segment</string> + <string name="fusion_pick_underlay">Pick Underlay</string> + </resources> diff --git a/src/com/android/gallery3d/filtershow/FilterShowActivity.java b/src/com/android/gallery3d/filtershow/FilterShowActivity.java index 67fd3fe32..1b0318bc4 100644 --- a/src/com/android/gallery3d/filtershow/FilterShowActivity.java +++ b/src/com/android/gallery3d/filtershow/FilterShowActivity.java @@ -16,6 +16,11 @@ package com.android.gallery3d.filtershow; +import java.io.File; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.Vector; + import android.app.ActionBar; import android.app.AlertDialog; import android.app.ProgressDialog; @@ -30,16 +35,13 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.graphics.Bitmap; import android.graphics.Color; -import android.graphics.Matrix; import android.graphics.Point; import android.graphics.Rect; -import android.graphics.RectF; import android.graphics.drawable.ColorDrawable; import android.graphics.drawable.Drawable; import android.net.Uri; import android.os.AsyncTask; import android.os.Bundle; -import android.os.CancellationSignal; import android.os.Handler; import android.os.IBinder; import android.support.v4.app.DialogFragment; @@ -63,7 +65,6 @@ import android.widget.FrameLayout; import android.widget.PopupMenu; import android.widget.ShareActionProvider; import android.widget.ShareActionProvider.OnShareTargetSelectedListener; -import android.widget.Spinner; import android.widget.Toast; import com.android.gallery3d.R; @@ -77,27 +78,15 @@ import com.android.gallery3d.filtershow.category.CategoryView; import com.android.gallery3d.filtershow.category.MainPanel; import com.android.gallery3d.filtershow.category.SwipableView; import com.android.gallery3d.filtershow.data.UserPresetsManager; -import com.android.gallery3d.filtershow.editors.BasicEditor; import com.android.gallery3d.filtershow.editors.Editor; -import com.android.gallery3d.filtershow.editors.EditorChanSat; -import com.android.gallery3d.filtershow.editors.EditorColorBorder; -import com.android.gallery3d.filtershow.editors.EditorCrop; -import com.android.gallery3d.filtershow.editors.EditorDraw; -import com.android.gallery3d.filtershow.editors.EditorGrad; -import com.android.gallery3d.filtershow.editors.EditorMakeup; +import com.android.gallery3d.filtershow.editors.EditorDualCamFusion; import com.android.gallery3d.filtershow.editors.EditorManager; -import com.android.gallery3d.filtershow.editors.EditorMirror; import com.android.gallery3d.filtershow.editors.EditorPanel; -import com.android.gallery3d.filtershow.editors.EditorRedEye; -import com.android.gallery3d.filtershow.editors.EditorRotate; -import com.android.gallery3d.filtershow.editors.EditorStraighten; -import com.android.gallery3d.filtershow.editors.EditorTinyPlanet; import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; import com.android.gallery3d.filtershow.filters.FilterDrawRepresentation; 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.FilterUserPresetRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.filters.ImageFilter; @@ -115,6 +104,7 @@ import com.android.gallery3d.filtershow.presets.PresetManagementDialog; import com.android.gallery3d.filtershow.presets.UserPresetsAdapter; import com.android.gallery3d.filtershow.provider.SharedImageProvider; import com.android.gallery3d.filtershow.state.StateAdapter; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; import com.android.gallery3d.filtershow.tools.SaveImage; import com.android.gallery3d.filtershow.tools.XmpPresets; import com.android.gallery3d.filtershow.tools.XmpPresets.XMresults; @@ -124,13 +114,6 @@ import com.android.gallery3d.util.GalleryUtils; import com.android.photos.data.GalleryBitmapPool; import com.thundersoft.hz.selfportrait.makeup.engine.MakeupEngine; -import java.io.File; -import java.io.FileDescriptor; -import java.io.FileOutputStream; -import java.lang.ref.WeakReference; -import java.util.ArrayList; -import java.util.Vector; - public class FilterShowActivity extends FragmentActivity implements OnItemClickListener, OnShareTargetSelectedListener, DialogInterface.OnShowListener, DialogInterface.OnDismissListener, PopupMenu.OnDismissListener{ @@ -151,6 +134,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private Editor mCurrentEditor = null; private static final int SELECT_PICTURE = 1; + public static final int SELECT_FUSION_UNDERLAY = 2; private static final String LOGTAG = "FilterShowActivity"; private boolean mShowingTinyPlanet = false; @@ -182,6 +166,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL private CategoryAdapter mCategoryFiltersAdapter = null; private CategoryAdapter mCategoryVersionsAdapter = null; private CategoryAdapter mCategoryMakeupAdapter = null; + private CategoryAdapter mCategoryDualCamAdapter = null; private int mCurrentPanel = MainPanel.LOOKS; private Vector<FilterUserPresetRepresentation> mVersions = new Vector<FilterUserPresetRepresentation>(); @@ -264,7 +249,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL setupMasterImage(); setupMenu(); setDefaultValues(); - fillEditors(); getWindow().setBackgroundDrawable(new ColorDrawable(0)); loadXML(); @@ -385,6 +369,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL fillEffects(); fillVersions(); fillMakeup(); + fillDualCamera(); } public void setupStatePanel() { @@ -492,6 +477,21 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } } + private void fillDualCamera() { + FiltersManager filtersManager = FiltersManager.getManager(); + ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getDualCamera(); + if (mCategoryDualCamAdapter != null) { + mCategoryDualCamAdapter.clear(); + } + mCategoryDualCamAdapter = new CategoryAdapter(this); + for (FilterRepresentation representation : filtersRepresentations) { + if (representation.getTextId() != 0) { + representation.setName(getString(representation.getTextId())); + } + mCategoryDualCamAdapter.add(new Action(this, representation)); + } + } + private void fillTools() { FiltersManager filtersManager = FiltersManager.getManager(); ArrayList<FilterRepresentation> filtersRepresentations = filtersManager.getTools(); @@ -530,7 +530,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL if (loadUri != null) { startLoadBitmap(loadUri); } else { - pickImage(); + pickImage(SELECT_PICTURE); } } @@ -540,22 +540,6 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL mEditorPlaceHolder.setOldViews(mImageViews); } - private void fillEditors() { - mEditorPlaceHolder.addEditor(new EditorChanSat()); - mEditorPlaceHolder.addEditor(new EditorGrad()); - mEditorPlaceHolder.addEditor(new EditorDraw()); - mEditorPlaceHolder.addEditor(new EditorColorBorder()); - mEditorPlaceHolder.addEditor(new BasicEditor()); - mEditorPlaceHolder.addEditor(new ImageOnlyEditor()); - mEditorPlaceHolder.addEditor(new EditorTinyPlanet()); - mEditorPlaceHolder.addEditor(new EditorRedEye()); - mEditorPlaceHolder.addEditor(new EditorCrop()); - mEditorPlaceHolder.addEditor(new EditorMirror()); - mEditorPlaceHolder.addEditor(new EditorRotate()); - mEditorPlaceHolder.addEditor(new EditorStraighten()); - mEditorPlaceHolder.addEditor(new EditorMakeup()); - } - private void setDefaultValues() { Resources res = getResources(); @@ -624,6 +608,10 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL return mCategoryVersionsAdapter; } + public CategoryAdapter getCategoryDualCamAdapter() { + return mCategoryDualCamAdapter; + } + public void removeFilterRepresentation(FilterRepresentation filterRepresentation) { if (filterRepresentation == null) { return; @@ -729,6 +717,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL ImagePreset preset = mMasterImage.getPreset(); mCategoryLooksAdapter.reflectImagePreset(preset); mCategoryBordersAdapter.reflectImagePreset(preset); + mCategoryDualCamAdapter.reflectImagePreset(preset); } public View getMainStatePanelContainer(int id) { @@ -790,10 +779,33 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL Log.d(LOGTAG, "FilterShowActivity.LoadHighresBitmapTask.onPostExecute(): highResPreviewScale is " + highResPreviewScale); mBoundService.setHighresPreviewScaleFactor(highResPreviewScale); } + + if(DualCameraNativeEngine.getInstance().isLibLoaded()) { + LoadMpoDataTask mpoLoad = new LoadMpoDataTask(); + mpoLoad.execute(); + } MasterImage.getImage().warnListeners(); } } + private class LoadMpoDataTask extends AsyncTask<Void, Void, Boolean> { + @Override + protected Boolean doInBackground(Void... params) { + return MasterImage.getImage().loadMpo(); + } + + @Override + protected void onPostExecute(Boolean result) { + MasterImage.getImage().warnListeners(); + + Fragment currentPanel = getSupportFragmentManager().findFragmentByTag(MainPanel.FRAGMENT_TAG); + if (currentPanel instanceof MainPanel) { + MainPanel mainPanel = (MainPanel) currentPanel; + mainPanel.enableDualCameraButton(result); + } + } + } + public boolean isLoadingVisible() { return mLoadingVisible; } @@ -881,6 +893,7 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL mCategoryBordersAdapter.imageLoaded(); mCategoryGeometryAdapter.imageLoaded(); mCategoryFiltersAdapter.imageLoaded(); + mCategoryDualCamAdapter.imageLoaded(); if(mCategoryMakeupAdapter != null) { mCategoryMakeupAdapter.imageLoaded(); } @@ -929,6 +942,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL } mUserPresetsManager.close(); doUnbindService(); + if(DualCameraNativeEngine.getInstance().isLibLoaded()) + DualCameraNativeEngine.getInstance().releaseDepthMap(); super.onDestroy(); } @@ -1060,6 +1075,8 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL if(SimpleMakeupImageFilter.HAS_TS_MAKEUP) { MakeupEngine.getMakeupObj().setContext(getBaseContext()); } + + DualCameraNativeEngine.createInstance(); } @Override @@ -1402,12 +1419,12 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL invalidateViews(); } - public void pickImage() { + public void pickImage(int requestCode) { Intent intent = new Intent(); intent.setType("image/*"); - intent.setAction(Intent.ACTION_GET_CONTENT); + intent.setAction(Intent.ACTION_PICK); startActivityForResult(Intent.createChooser(intent, getString(R.string.select_image)), - SELECT_PICTURE); + requestCode); } @Override @@ -1416,6 +1433,11 @@ public class FilterShowActivity extends FragmentActivity implements OnItemClickL if (requestCode == SELECT_PICTURE) { Uri selectedImageUri = data.getData(); startLoadBitmap(selectedImageUri); + } else if (requestCode == SELECT_FUSION_UNDERLAY) { + Uri underlayImageUri = data.getData(); + // find fusion representation + EditorDualCamFusion editor = (EditorDualCamFusion)getEditor(EditorDualCamFusion.ID); + editor.setUnderlayImageUri(underlayImageUri); } } } diff --git a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java index cd63d309a..4c246a482 100644 --- a/src/com/android/gallery3d/filtershow/cache/BitmapCache.java +++ b/src/com/android/gallery3d/filtershow/cache/BitmapCache.java @@ -18,7 +18,9 @@ package com.android.gallery3d.filtershow.cache; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.PorterDuff; import android.util.Log; + import com.android.gallery3d.filtershow.pipeline.Buffer; import com.android.gallery3d.filtershow.pipeline.CacheProcessing; @@ -206,6 +208,7 @@ public class BitmapCache { public synchronized Bitmap getBitmapCopy(Bitmap source, int type) { Bitmap bitmap = getBitmap(source.getWidth(), source.getHeight(), type); 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/CategoryAdapter.java b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java index 50f0e9436..9571d8b16 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryAdapter.java @@ -85,6 +85,9 @@ public class CategoryAdapter extends ArrayAdapter<Action> { if (category == MainPanel.BORDERS) { mSelectedPosition = 0; } + if (category == MainPanel.DUALCAM) { + mSelectedPosition = 0; + } if (category == MainPanel.VERSIONS) { mAddButtonText = getContext().getString(R.string.filtershow_add_button_versions); } @@ -213,6 +216,11 @@ public class CategoryAdapter extends ArrayAdapter<Action> { if (pos != -1) { rep = preset.getFilterRepresentation(pos); } + } else if (mCategory == MainPanel.DUALCAM) { + int pos = preset.getPositionForType(FilterRepresentation.TYPE_DUALCAM); + if (pos != -1) { + rep = preset.getFilterRepresentation(pos); + } } if (rep != null) { for (int i = 0; i < getCount(); i++) { diff --git a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java index 66b352ffb..3ee9e45eb 100644 --- a/src/com/android/gallery3d/filtershow/category/CategoryPanel.java +++ b/src/com/android/gallery3d/filtershow/category/CategoryPanel.java @@ -82,6 +82,14 @@ public class CategoryPanel extends Fragment implements View.OnClickListener { } break; } + case MainPanel.DUALCAM: { + mAdapter = activity.getCategoryDualCamAdapter(); + if (mAdapter != null) { + mAdapter.initializeSelection(MainPanel.DUALCAM); + } + activity.updateCategories(); + break; + } case MainPanel.VERSIONS: { mAdapter = activity.getCategoryVersionsAdapter(); if (mAdapter != null) { diff --git a/src/com/android/gallery3d/filtershow/category/MainPanel.java b/src/com/android/gallery3d/filtershow/category/MainPanel.java index 1dbe42083..a80df3bfa 100644 --- a/src/com/android/gallery3d/filtershow/category/MainPanel.java +++ b/src/com/android/gallery3d/filtershow/category/MainPanel.java @@ -24,12 +24,13 @@ import android.view.View; import android.view.ViewGroup; import android.widget.ImageButton; import android.widget.LinearLayout; -import android.util.Log; + import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.filters.SimpleMakeupImageFilter; import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.state.StatePanel; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; public class MainPanel extends Fragment { @@ -40,6 +41,7 @@ public class MainPanel extends Fragment { private ImageButton bordersButton; private ImageButton geometryButton; private ImageButton filtersButton; + private ImageButton dualCamButton; private ImageButton makeupButton; public static final String FRAGMENT_TAG = "MainPanel"; @@ -47,8 +49,9 @@ public class MainPanel extends Fragment { public static final int BORDERS = 1; public static final int GEOMETRY = 2; public static final int FILTERS = 3; - public static final int VERSIONS = 4; - public static final int MAKEUP = 5; + public static final int DUALCAM = 4; + public static final int VERSIONS = 5; + public static final int MAKEUP = 6; private int mCurrentSelected = -1; private int mPreviousToggleVersions = -1; @@ -81,6 +84,10 @@ public class MainPanel extends Fragment { } break; } + case DUALCAM: { + dualCamButton.setSelected(value); + break; + } } } @@ -106,6 +113,7 @@ public class MainPanel extends Fragment { bordersButton = (ImageButton) mMainView.findViewById(R.id.borderButton); geometryButton = (ImageButton) mMainView.findViewById(R.id.geometryButton); filtersButton = (ImageButton) mMainView.findViewById(R.id.colorsButton); + dualCamButton = (ImageButton) mMainView.findViewById(R.id.dualCamButton); if(SimpleMakeupImageFilter.HAS_TS_MAKEUP) { makeupButton = (ImageButton) mMainView.findViewById(R.id.makeupButton); makeupButton.setVisibility(View.VISIBLE); @@ -144,6 +152,13 @@ public class MainPanel extends Fragment { showPanel(FILTERS); } }); + dualCamButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + showPanel(DUALCAM); + } + }); + enableDualCameraButton(DualCameraNativeEngine.getInstance().isLibLoaded()); FilterShowActivity activity = (FilterShowActivity) getActivity(); showImageStatePanel(activity.isShowingImageStatePanel()); @@ -252,6 +267,19 @@ public class MainPanel extends Fragment { selection(mCurrentSelected, true); } + public void loadCategoryDualCamPanel() { + if (mCurrentSelected == DUALCAM) { + return; + } + boolean fromRight = isRightAnimation(DUALCAM); + selection(mCurrentSelected, false); + CategoryPanel categoryPanel = new CategoryPanel(); + categoryPanel.setAdapter(DUALCAM); + setCategoryFragment(categoryPanel, fromRight); + mCurrentSelected = DUALCAM; + selection(mCurrentSelected, true); + } + public void showPanel(int currentPanel) { switch (currentPanel) { case LOOKS: { @@ -270,6 +298,10 @@ public class MainPanel extends Fragment { loadCategoryFiltersPanel(); break; } + case DUALCAM: { + loadCategoryDualCamPanel(); + break; + } case VERSIONS: { loadCategoryVersionsPanel(); break; @@ -334,4 +366,10 @@ public class MainPanel extends Fragment { showPanel(currentPanel); transaction.commit(); } + + public void enableDualCameraButton(boolean enable) { + if(dualCamButton != null) { + dualCamButton.setVisibility(enable?View.VISIBLE:View.GONE); + } + } } diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java new file mode 100644 index 000000000..1ce56b3d9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/editors/EditorDualCamFusion.java @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015, 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.net.Uri; +import android.view.View; +import android.view.View.OnClickListener; +import android.widget.Button; +import android.widget.FrameLayout; +import android.widget.LinearLayout; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.FilterShowActivity; +import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.imageshow.ImageFusion; +import com.android.gallery3d.filtershow.imageshow.MasterImage; + +public class EditorDualCamFusion extends ImageOnlyEditor { + public static final String TAG = EditorDualCamFusion.class.getSimpleName(); + public static final int ID = R.id.editorDualCamFusion; + + protected ImageFusion mImageFusion; + private Button mPickUnderlayBtn; + private OnClickListener mPickBtnClickListener = new OnClickListener() { + @Override + public void onClick(View arg0) { + MasterImage.getImage().getActivity().pickImage(FilterShowActivity.SELECT_FUSION_UNDERLAY); + } + }; + + public EditorDualCamFusion() { + super(ID); + } + + public boolean useUtilityPanel() { + return true; + } + + @Override + public void createEditor(Context context, FrameLayout frameLayout) { + super.createEditor(context, frameLayout); + if (mImageFusion == null) { + mImageFusion = new ImageFusion(context); + } + mView = mImageShow = mImageFusion; + mImageFusion.setEditor(this); + } + + @Override + public void setUtilityPanelUI(View actionButton, View editControl) { + editControl.setVisibility(View.GONE); + } + + @Override + public void openUtilityPanel(final LinearLayout accessoryViewList) { + super.openUtilityPanel(accessoryViewList); + mPickUnderlayBtn = (Button) accessoryViewList.findViewById(R.id.applyEffect); + updateText(); + } + + public void setUnderlayImageUri(Uri uri) { + FilterRepresentation filter = getLocalRepresentation(); + if(filter instanceof FilterDualCamFusionRepresentation) { + mImageFusion.setUnderlay(uri); + commitLocalRepresentation(); + } + } + + private void updateEffectButton(boolean enabled) { + mPickUnderlayBtn.setEnabled(enabled); + if(enabled) { + mPickUnderlayBtn.setOnClickListener(mPickBtnClickListener); + mPickUnderlayBtn.setText(R.string.fusion_pick_underlay); + } else { + mPickUnderlayBtn.setOnClickListener(null); + mPickUnderlayBtn.setText(R.string.fusion_pick_point); + } + } + + + protected void updateText() { + if(mPickUnderlayBtn != null) { + updateEffectButton(hasSegment()); + } + } + + private boolean hasSegment() { + FilterRepresentation filter = getLocalRepresentation(); + if(filter instanceof FilterDualCamFusionRepresentation) { + return !((FilterDualCamFusionRepresentation) filter).getPoint().equals(-1,-1); + } + return false; + } + + @Override + public void reflectCurrentFilter() { + super.reflectCurrentFilter(); + FilterRepresentation rep = getLocalRepresentation(); + if (rep != null && rep instanceof FilterDualCamFusionRepresentation) { + FilterDualCamFusionRepresentation dualRep = (FilterDualCamFusionRepresentation) rep; + mImageFusion.setRepresentation(dualRep); + } + } +} diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDualCamSketch.java b/src/com/android/gallery3d/filtershow/editors/EditorDualCamSketch.java new file mode 100644 index 000000000..94b511177 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/editors/EditorDualCamSketch.java @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015, 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.widget.FrameLayout; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.filters.FilterDualCamSketchRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.imageshow.ImageDualCamera; + +public class EditorDualCamSketch extends ImageOnlyEditor { + public static final int ID = R.id.editorDualCamSketch; + private static final String LOGTAG = "EditorDualCamSketch"; + private ImageDualCamera mImageDualCam; + + public EditorDualCamSketch() { + super(ID); + } + + @Override + public void createEditor(Context context, FrameLayout frameLayout) { + super.createEditor(context, frameLayout); + if (mImageDualCam == null) { + mImageDualCam = new ImageDualCamera(context); + } + mView = mImageShow = mImageDualCam; + mImageDualCam.setEditor(this); + } + + @Override + public void reflectCurrentFilter() { + super.reflectCurrentFilter(); + FilterRepresentation rep = getLocalRepresentation(); + if (rep != null && rep instanceof FilterDualCamSketchRepresentation) { + FilterDualCamSketchRepresentation dualRep = (FilterDualCamSketchRepresentation) rep; + mImageDualCam.setRepresentation(dualRep); + } + } + + @Override + public boolean showsSeekBar() { + return false; + } +}
\ No newline at end of file diff --git a/src/com/android/gallery3d/filtershow/editors/EditorDualCamera.java b/src/com/android/gallery3d/filtershow/editors/EditorDualCamera.java new file mode 100644 index 000000000..f2c7091ba --- /dev/null +++ b/src/com/android/gallery3d/filtershow/editors/EditorDualCamera.java @@ -0,0 +1,65 @@ +/* + * Copyright (c) 2015, 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.widget.FrameLayout; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.filters.FilterDualCamBasicRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.imageshow.ImageDualCamera; + +public class EditorDualCamera extends BasicEditor { + public static final int ID = R.id.editorDualCam; + private static final String LOGTAG = "EditorDualCamera"; + private ImageDualCamera mImageDualCam; + + public EditorDualCamera() { + super(ID, R.layout.filtershow_dualcamera_editor, R.id.editorDualCam); + } + + @Override + public void createEditor(Context context, FrameLayout frameLayout) { + super.createEditor(context, frameLayout); + mImageDualCam = (ImageDualCamera) mImageShow; + mImageDualCam.setEditor(this); + } + + @Override + public void reflectCurrentFilter() { + super.reflectCurrentFilter(); + FilterRepresentation rep = getLocalRepresentation(); + if (rep != null && rep instanceof FilterDualCamBasicRepresentation) { + FilterDualCamBasicRepresentation dualRep = (FilterDualCamBasicRepresentation) rep; + mImageDualCam.setRepresentation(dualRep); + } + } +}
\ No newline at end of file diff --git a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java index 0581835f4..54409923e 100644 --- a/src/com/android/gallery3d/filtershow/editors/EditorPanel.java +++ b/src/com/android/gallery3d/filtershow/editors/EditorPanel.java @@ -61,6 +61,10 @@ public class EditorPanel extends Fragment { int position = adapter.undo(); masterImage.onHistoryItemClick(position); ((FilterShowActivity)getActivity()).invalidateViews(); + + if(!masterImage.hasFusionApplied()) { + masterImage.setFusionUnderlay(null); + } } @Override diff --git a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java index e93175a92..f1e7e6c26 100644 --- a/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java +++ b/src/com/android/gallery3d/filtershow/filters/BaseFiltersManager.java @@ -21,6 +21,7 @@ import android.graphics.Color; import android.util.Log; import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.ImageOnlyEditor; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import java.util.ArrayList; @@ -37,6 +38,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { protected ArrayList<FilterRepresentation> mTools = new ArrayList<FilterRepresentation>(); protected ArrayList<FilterRepresentation> mEffects = new ArrayList<FilterRepresentation>(); protected ArrayList<FilterRepresentation> mMakeup = new ArrayList<FilterRepresentation>(); + protected ArrayList<FilterRepresentation> mDualCam = new ArrayList<FilterRepresentation>(); private static int mImageBorderSize = 4; // in percent protected void init() { @@ -51,7 +53,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { mFilters.put(filterClass, (ImageFilter) filterInstance); FilterRepresentation rep = - ((ImageFilter) filterInstance).getDefaultRepresentation(); + ((ImageFilter) filterInstance).getDefaultRepresentation(); if (rep != null) { addRepresentation(rep); } @@ -141,6 +143,10 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { filters.add(ImageFilterFx.class); filters.add(ImageFilterBorder.class); filters.add(ImageFilterColorBorder.class); + filters.add(ImageFilterDualCamera.class); + filters.add(ImageFilterDualCamFusion.class); + filters.add(ImageFilterDualCamSketch.class); + if(SimpleMakeupImageFilter.HAS_TS_MAKEUP) { filters.add(ImageFilterMakeupWhiten.class); filters.add(ImageFilterMakeupSoften.class); @@ -157,6 +163,10 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { return mBorders; } + public ArrayList<FilterRepresentation> getDualCamera() { + return mDualCam; + } + public ArrayList<FilterRepresentation> getTools() { return mTools; } @@ -313,6 +323,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { mEffects.add(getRepresentation(ImageFilterNegative.class)); mEffects.add(getRepresentation(ImageFilterEdge.class)); mEffects.add(getRepresentation(ImageFilterKMeans.class)); + mEffects.add(getRepresentation(ImageFilterRedEye.class)); } public void addMakeups(Context context) { @@ -362,8 +373,62 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { mTools.add(getRepresentation(ImageFilterDraw.class)); } + public void addDualCam(Context context) { + int[] textId = { + R.string.focus, + R.string.halo, + R.string.blur + }; + + int[] overlayId = { + R.drawable.filtershow_dualcam_focus, + R.drawable.filtershow_dualcam_halo, + R.drawable.filtershow_dualcam_blur + }; + + String[] serializationNames = { + "DUAL_CAM_FOCUS", + "DUAL_CAM_HALO", + "DUAL_CAM_BLUR" + }; + + // intensity range as defined by ddm lib + int[][] minMaxValues = { + {0,5,10}, + {0,3,7}, + {0,4,9} + }; + + FilterDualCamSketchRepresentation none = + new FilterDualCamSketchRepresentation(context.getString(R.string.none), 0, 0); + none.setEditorId(ImageOnlyEditor.ID); + mDualCam.add(none); + + for (int i = 0; i < textId.length; i++) { + FilterRepresentation dualCam = + new FilterDualCamBasicRepresentation(context.getString(textId[i]), + minMaxValues[i][0], minMaxValues[i][1], minMaxValues[i][2]); + dualCam.setTextId(textId[i]); + dualCam.setOverlayId(overlayId[i]); + dualCam.setOverlayOnly(true); + dualCam.setSerializationName(serializationNames[i]); + mDualCam.add(dualCam); + addRepresentation(dualCam); + } + + FilterDualCamSketchRepresentation sketch = new FilterDualCamSketchRepresentation( + context.getString(R.string.sketch), R.string.sketch, R.raw.sketch); + sketch.setOverlayId(R.drawable.filtershow_dualcam_sketch); + sketch.setOverlayOnly(true); + sketch.setSerializationName("DUAL_CAM_SKETCH"); + mDualCam.add(sketch); + addRepresentation(sketch); + + mDualCam.add(getRepresentation(ImageFilterDualCamFusion.class)); + } + public void removeRepresentation(ArrayList<FilterRepresentation> list, - FilterRepresentation representation) { + FilterRepresentation representation) { for (int i = 0; i < list.size(); i++) { FilterRepresentation r = list.get(i); if (r.getFilterClass() == representation.getFilterClass()) { @@ -378,5 +443,7 @@ public abstract class BaseFiltersManager implements FiltersManagerInterface { filterBorder.setResources(resources); ImageFilterFx filterFx = (ImageFilterFx) getFilter(ImageFilterFx.class); filterFx.setResources(resources); + ImageFilterDualCamSketch filterSketch = (ImageFilterDualCamSketch) getFilter(ImageFilterDualCamSketch.class); + filterSketch.setResources(resources); } } diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDualCamBasicRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDualCamBasicRepresentation.java new file mode 100644 index 000000000..3da5f7054 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterDualCamBasicRepresentation.java @@ -0,0 +1,149 @@ +/* + * Copyright (c) 2015, 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.graphics.Point; +import android.util.JsonReader; +import android.util.JsonWriter; + +import com.android.gallery3d.filtershow.editors.EditorDualCamera; + + +public class FilterDualCamBasicRepresentation extends FilterBasicRepresentation { + private static final String LOGTAG = "FilterDualCameraRepresentation"; + + private static final String SERIAL_VALUE = "value"; + private static final String SERIAL_POINT = "point"; + + private Point mPoint = new Point(-1, -1); + + public FilterDualCamBasicRepresentation(String name, int minVal, int defVal, int maxVal) { + super(name, minVal, defVal, maxVal); + setFilterType(FilterRepresentation.TYPE_DUALCAM); + setFilterClass(ImageFilterDualCamera.class); + setEditorId(EditorDualCamera.ID); + setShowParameterValue(true); + } + + @Override + public FilterRepresentation copy() { + FilterDualCamBasicRepresentation representation = + new FilterDualCamBasicRepresentation(getName(), 0,0,0); + 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 FilterDualCamBasicRepresentation) { + FilterDualCamBasicRepresentation representation = (FilterDualCamBasicRepresentation) a; + setPoint(representation.getPoint()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterDualCamBasicRepresentation) { + FilterDualCamBasicRepresentation dualCam = (FilterDualCamBasicRepresentation) representation; + if (dualCam.mPoint.equals(mPoint)) { + return true; + } + } + return false; + } + + public void setPoint(int x, int y) { + mPoint = new Point(x,y); + } + + public void setPoint(Point point) { + mPoint = point; + } + + public Point getPoint() { + return mPoint; + } + + @Override + public String toString() { + return "dualcam - value: " + getValue() + ", point: " + getPoint().toString(); + } + + // Serialization... + + public void serializeRepresentation(JsonWriter writer) throws IOException { + writer.beginObject(); + { + writer.name(NAME_TAG); + writer.value(getName()); + writer.name(SERIAL_VALUE); + writer.value(getValue()); + writer.name(SERIAL_POINT); + writer.beginArray(); + writer.value(mPoint.x); + writer.value(mPoint.y); + writer.endArray(); + } + 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_VALUE)) { + setValue(reader.nextInt()); + } else if (name.equalsIgnoreCase(SERIAL_POINT)) { + reader.beginArray(); + reader.hasNext(); + mPoint.x = reader.nextInt(); + reader.hasNext(); + mPoint.y = reader.nextInt(); + reader.endArray(); + } else { + reader.skipValue(); + } + } + reader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java new file mode 100644 index 000000000..0e3598b48 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterDualCamFusionRepresentation.java @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2015, 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.graphics.Point; +import android.net.Uri; +import android.util.JsonReader; +import android.util.JsonWriter; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.editors.EditorDualCamFusion; + + +public class FilterDualCamFusionRepresentation extends FilterRepresentation { + private static final String LOGTAG = "FilterFusionRepresentation"; + public static final String SERIALIZATION_NAME = "FUSION"; + + private static final String SERIAL_UNDERLAY_IMAGE = "image"; + private static final String SERIAL_POINT = "point"; + + private Point mPoint = new Point(-1, -1); + private String mUri = ""; + + public FilterDualCamFusionRepresentation() { + super("Fusion"); + setSerializationName(SERIALIZATION_NAME); + setFilterType(FilterRepresentation.TYPE_DUALCAM); + setFilterClass(ImageFilterDualCamFusion.class); + setEditorId(EditorDualCamFusion.ID); + setShowParameterValue(false); + setTextId(R.string.fusion); + setOverlayId(R.drawable.filtershow_dualcam_fusion); + setOverlayOnly(true); + } + + @Override + public FilterRepresentation copy() { + FilterDualCamFusionRepresentation representation = + new FilterDualCamFusionRepresentation(); + 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 FilterDualCamFusionRepresentation) { + FilterDualCamFusionRepresentation representation = (FilterDualCamFusionRepresentation) a; + setPoint(representation.getPoint()); + setUnderlay(representation.getUnderlay()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterDualCamFusionRepresentation) { + FilterDualCamFusionRepresentation fusion = (FilterDualCamFusionRepresentation) representation; + if (fusion.mPoint.equals(mPoint) && + fusion.mUri.equals(mUri)) { + return true; + } + } + return false; + } + + public void setPoint(int x, int y) { + mPoint = new Point(x,y); + } + + public void setPoint(Point point) { + mPoint = point; + } + + public Point getPoint() { + return mPoint; + } + + public void setUnderlay(Uri uri) { + if(uri != null) { + mUri = uri.toString(); + } else { + mUri = ""; + } + } + + public void setUnderlay(String uri) { + if(uri != null) + mUri = uri; + else + mUri = ""; + } + + public boolean hasUnderlay() { + return (mUri != null) && (mUri.isEmpty() == false); + } + + public String getUnderlay() { + return mUri; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(); + sb.append("fusion - underlay: ").append(getUnderlay()); + sb.append(", point: ").append(getPoint().toString()); + + 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.name(SERIAL_POINT); + writer.beginArray(); + writer.value(mPoint.x); + writer.value(mPoint.y); + writer.endArray(); + } + 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 if (name.equalsIgnoreCase(SERIAL_POINT)) { + reader.beginArray(); + reader.hasNext(); + mPoint.x = reader.nextInt(); + reader.hasNext(); + mPoint.y = reader.nextInt(); + reader.endArray(); + } else { + reader.skipValue(); + } + } + reader.endObject(); + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterDualCamSketchRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterDualCamSketchRepresentation.java new file mode 100644 index 000000000..92b3f156b --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/FilterDualCamSketchRepresentation.java @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2015, 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 com.android.gallery3d.filtershow.editors.EditorDualCamSketch; + + +public class FilterDualCamSketchRepresentation extends FilterDualCamBasicRepresentation { + private static final String LOGTAG = "FilterDualCamSketchRepresentation"; + + private int mSketchResource = 0; + + public FilterDualCamSketchRepresentation(String name, int nameResId, int sketchResId) { + super(name, 0, 0, 0); + setFilterType(FilterRepresentation.TYPE_DUALCAM); + setFilterClass(ImageFilterDualCamSketch.class); + setEditorId(EditorDualCamSketch.ID); + setTextId(nameResId); + setShowParameterValue(false); + mSketchResource = sketchResId; + } + + @Override + public FilterRepresentation copy() { + FilterDualCamSketchRepresentation representation = + new FilterDualCamSketchRepresentation(getName(), 0, 0); + copyAllParameters(representation); + return representation; + } + + public void useParametersFrom(FilterRepresentation a) { + super.useParametersFrom(a); + if (a instanceof FilterDualCamSketchRepresentation) { + FilterDualCamSketchRepresentation representation = (FilterDualCamSketchRepresentation) a; + setSketchResId(representation.getSketchResId()); + } + } + + @Override + public boolean equals(FilterRepresentation representation) { + if (!super.equals(representation)) { + return false; + } + if (representation instanceof FilterDualCamSketchRepresentation) { + FilterDualCamSketchRepresentation dualCam = (FilterDualCamSketchRepresentation) representation; + if (dualCam.getSketchResId() == mSketchResource) { + return true; + } + } + return false; + } + + public void setSketchResId(int bmResource) { + mSketchResource = bmResource; + } + + public int getSketchResId() { + return mSketchResource; + } + + @Override + public String toString() { + return "dualcam - point: " + getPoint().toString() + ", sketchResId: " + mSketchResource; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java index 36675b71b..198e741c3 100644 --- a/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java +++ b/src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java @@ -48,6 +48,7 @@ public class FilterRepresentation { public static final byte TYPE_TINYPLANET = 6; public static final byte TYPE_GEOMETRY = 7; public static final byte TYPE_MAKEUP = 8; + public static final byte TYPE_DUALCAM = 9; protected static final String NAME_TAG = "Name"; public FilterRepresentation(String name) { diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java new file mode 100644 index 000000000..bc181e33d --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamFusion.java @@ -0,0 +1,138 @@ +/* + * Copyright (c) 2015, 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.Matrix; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.PorterDuff; +import android.graphics.Rect; +import android.util.Log; + +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; + +public class ImageFilterDualCamFusion extends ImageFilter { + private static final String TAG = ImageFilterDualCamFusion.class.getSimpleName(); + + private FilterDualCamFusionRepresentation mParameters; + private Paint mPaint = new Paint(); + private Bitmap mFilteredBitmap = null; + private Point mPoint = null; + + public ImageFilterDualCamFusion() { + mName = "Fusion"; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterDualCamFusionRepresentation parameters = (FilterDualCamFusionRepresentation) representation; + mParameters = parameters; + } + + public FilterDualCamFusionRepresentation getParameters() { + return mParameters; + } + + public FilterRepresentation getDefaultRepresentation() { + return new FilterDualCamFusionRepresentation(); + } + + @Override + public void freeResources() { + if (mFilteredBitmap != null) + mFilteredBitmap.recycle(); + mFilteredBitmap = null; + mPoint = null; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + + Point point = getParameters().getPoint(); + + if(!point.equals(-1,-1)) { + long startTime = System.currentTimeMillis(); + Log.e(TAG, "dual cam fusion - start processing: " + startTime); + + if(!point.equals(mPoint)) { + mPoint = point; + + if(mFilteredBitmap == null) { + Rect originalBounds = MasterImage.getImage().getOriginalBounds(); + int origW = originalBounds.width(); + int origH = originalBounds.height(); + + mFilteredBitmap = Bitmap.createBitmap(origW, origH, Bitmap.Config.ARGB_8888); + mFilteredBitmap.setHasAlpha(true); + } + + + boolean result = DualCameraNativeEngine.getInstance().getForegroundImg(mPoint.x, mPoint.y, + mFilteredBitmap); + + if(result == false) { + Log.e(TAG, "Imagelib API failed"); + return bitmap; + } + } + + mPaint.reset(); + if(quality == FilterEnvironment.QUALITY_FINAL) { + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); + mPaint.setDither(true); + } + + bitmap.setHasAlpha(true); + + Canvas canvas = new Canvas(bitmap); + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + + canvas.drawColor(0, PorterDuff.Mode.CLEAR); + if(getEnvironment().getImagePreset().getDoApplyGeometry()) { + Matrix originalToScreen = getOriginalToScreenMatrix(w, h); + canvas.drawBitmap(mFilteredBitmap, originalToScreen, null); + } else { + canvas.drawBitmap(mFilteredBitmap, null, new Rect(0,0,w,h), null); + } + + Log.e(TAG, "dual cam fusion - finish processing: " + (System.currentTimeMillis()-startTime)); + } + + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java new file mode 100644 index 000000000..b0acb1a70 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamSketch.java @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2015, 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.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.Matrix; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.Log; + +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; + +public class ImageFilterDualCamSketch extends ImageFilter { + private static final String TAG = ImageFilterDualCamSketch.class.getSimpleName(); + + private FilterDualCamSketchRepresentation mParameters; + private Paint mPaint = new Paint(); + private Bitmap mFilteredBitmap = null; + private Bitmap mSketchBm = null; + private int mSketchResId = 0; + private Point mPoint = null; + private Resources mResources = null; + + public FilterRepresentation getDefaultRepresentation() { + return null; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterDualCamSketchRepresentation parameters = (FilterDualCamSketchRepresentation) representation; + mParameters = parameters; + } + + public FilterDualCamSketchRepresentation getParameters() { + return mParameters; + } + + public void setResources(Resources resources) { + mResources = resources; + } + + @Override + public void freeResources() { + if(mFilteredBitmap != null) + mFilteredBitmap.recycle(); + if (mSketchBm != null) + mSketchBm.recycle(); + + mFilteredBitmap = null; + mSketchBm = null; + mSketchResId = 0; + mPoint = null; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + + Point point = getParameters().getPoint(); + if(!point.equals(-1,-1)) { + + int sketchResId = getParameters().getSketchResId(); + if (sketchResId == 0) { + return bitmap; + } + + if (mSketchBm == null || mSketchResId != sketchResId) { + loadSketchImage(sketchResId); + } + + if (mSketchBm == null) { + return bitmap; + } + + if(!point.equals(mPoint)) { + mPoint = point; + + boolean result = false; + + if(mFilteredBitmap == null) { + Rect originalBounds = MasterImage.getImage().getOriginalBounds(); + int origW = originalBounds.width(); + int origH = originalBounds.height(); + + mFilteredBitmap = Bitmap.createBitmap(origW, origH, Bitmap.Config.ARGB_8888); + } + + result = DualCameraNativeEngine.getInstance().applySketch(mSketchBm, mPoint.x, mPoint.y, mFilteredBitmap); + + if(result == false) { + Log.e(TAG, "Imagelib API failed"); + return bitmap; + } + } + + if(quality == FilterEnvironment.QUALITY_FINAL) { + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); + mPaint.setDither(true); + } + + Canvas canvas = new Canvas(bitmap); + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + if(getEnvironment().getImagePreset().getDoApplyGeometry()) { + Matrix originalToScreen = getOriginalToScreenMatrix(w, h); + canvas.drawBitmap(mFilteredBitmap, originalToScreen, mPaint); + } else { + canvas.drawBitmap(mFilteredBitmap, null, new Rect(0,0,w,h), mPaint); + } + } + + return bitmap; + } + + private void loadSketchImage(int sketchResId) { + if(mResources == null) { + Log.w(TAG, "resources not set"); + return; + } + + BitmapFactory.Options o = new BitmapFactory.Options(); + o.inScaled = false; + mSketchResId = sketchResId; + if (mSketchResId != 0) { + mSketchBm = BitmapFactory.decodeResource(mResources, mSketchResId, o); + if(mSketchBm == null) { + Log.w(TAG, "could not decode sketch image"); + } + } else { + Log.w(TAG, "bad sketch resource for filter: " + mName); + } + } +} diff --git a/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java new file mode 100644 index 000000000..31e7d0318 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/filters/ImageFilterDualCamera.java @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2015, 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.Matrix; +import android.graphics.Paint; +import android.graphics.Point; +import android.graphics.Rect; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.pipeline.FilterEnvironment; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; + +public class ImageFilterDualCamera extends ImageFilter { + private static final String TAG = ImageFilterDualCamera.class.getSimpleName(); + + private FilterDualCamBasicRepresentation mParameters; + private Paint mPaint = new Paint(); + private Bitmap mFilteredBitmap = null; + private Point mPoint = null; + private int mIntensity = -1; + + public FilterRepresentation getDefaultRepresentation() { + return null; + } + + public void useRepresentation(FilterRepresentation representation) { + FilterDualCamBasicRepresentation parameters = (FilterDualCamBasicRepresentation) representation; + mParameters = parameters; + } + + public FilterDualCamBasicRepresentation getParameters() { + return mParameters; + } + + @Override + public void freeResources() { + if(mFilteredBitmap != null) + mFilteredBitmap.recycle(); + + mFilteredBitmap = null; + mPoint = null; + mIntensity = -1; + } + + @Override + public Bitmap apply(Bitmap bitmap, float scaleFactor, int quality) { + if (getParameters() == null) { + return bitmap; + } + + Point point = getParameters().getPoint(); + int intensity = getParameters().getValue(); + + if(!point.equals(-1,-1)) { + + // if parameters change, generate new filtered bitmap + if(!point.equals(mPoint) || mIntensity != intensity) { + mPoint = point; + mIntensity = intensity; + + if(mFilteredBitmap == null) { + Rect originalBounds = MasterImage.getImage().getOriginalBounds(); + int origW = originalBounds.width(); + int origH = originalBounds.height(); + + mFilteredBitmap = Bitmap.createBitmap(origW, origH, Bitmap.Config.ARGB_8888); + } + + boolean result = false; + + switch(mParameters.getTextId()) { + case R.string.focus: + result = DualCameraNativeEngine.getInstance().applyFocus(mPoint.x, mPoint.y, mIntensity, + mFilteredBitmap); + break; + case R.string.halo: + result = DualCameraNativeEngine.getInstance().applyHalo(mPoint.x, mPoint.y, mIntensity, + mFilteredBitmap); + break; + case R.string.blur: + result = DualCameraNativeEngine.getInstance().applyBokeh(mPoint.x, mPoint.y, mIntensity, + mFilteredBitmap); + break; + } + + if(result == false) { + Log.e(TAG, "Imagelib API failed"); + return bitmap; + } + } + + if(quality == FilterEnvironment.QUALITY_FINAL) { + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); + mPaint.setDither(true); + } + + Canvas canvas = new Canvas(bitmap); + int w = bitmap.getWidth(); + int h = bitmap.getHeight(); + if(getEnvironment().getImagePreset().getDoApplyGeometry()) { + Matrix originalToScreen = getOriginalToScreenMatrix(w, h); + canvas.drawBitmap(mFilteredBitmap, originalToScreen, mPaint); + } else { + canvas.drawBitmap(mFilteredBitmap, null, new Rect(0,0,w,h), mPaint); + } + } + + return bitmap; + } +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageDualCamera.java b/src/com/android/gallery3d/filtershow/imageshow/ImageDualCamera.java new file mode 100644 index 000000000..962519373 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageDualCamera.java @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2015, 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.Matrix; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; + +import com.android.gallery3d.filtershow.editors.Editor; +import com.android.gallery3d.filtershow.filters.FilterDualCamBasicRepresentation; + +public class ImageDualCamera extends ImageShow { + private static final String LOGTAG = "ImageDualCamera"; + protected Editor mEditor; + protected FilterDualCamBasicRepresentation mRepresentation; + private Matrix mToOrig; + private float[] mTmpPoint = new float[2]; + + public ImageDualCamera(Context context, AttributeSet attrs) { + super(context, attrs); + } + + public ImageDualCamera(Context context) { + super(context); + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent event) { + Log.e(LOGTAG, "single tap: " + event.getX() + "x" + event.getY()); + calcScreenMapping(); + mTmpPoint[0] = event.getX(); + mTmpPoint[1] = event.getY(); + mToOrig.mapPoints(mTmpPoint); + + mRepresentation.setPoint((int)mTmpPoint[0], (int)mTmpPoint[1]); + mEditor.commitLocalRepresentation(); + return true; + } + + public void setEditor(Editor editor) { + mEditor = editor; + } + + public void setRepresentation(FilterDualCamBasicRepresentation representation) { + mRepresentation = representation; + } + + private void calcScreenMapping() { + mToOrig = getScreenToImageMatrix(true); + } +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageFusion.java b/src/com/android/gallery3d/filtershow/imageshow/ImageFusion.java new file mode 100644 index 000000000..6d4ef9fc7 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageFusion.java @@ -0,0 +1,100 @@ +/* + * Copyright (c) 2015, 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.Matrix; +import android.graphics.Rect; +import android.net.Uri; +import android.util.AttributeSet; +import android.util.Log; +import android.view.MotionEvent; + +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.editors.EditorDualCamFusion; +import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation; + +public class ImageFusion extends ImageShow { + private static final String LOGTAG = "ImageFusion"; + protected EditorDualCamFusion mEditor; + protected FilterDualCamFusionRepresentation mRepresentation; + private Matrix mToOrig; + private float[] mTmpPoint = new float[2]; + private Bitmap mUnderlay; + + public ImageFusion(Context context, AttributeSet attrs) { + super(context, attrs); + mAllowScaleAndTranslate = true; + } + + public ImageFusion(Context context) { + super(context); + mAllowScaleAndTranslate = true; + } + + @Override + public boolean onSingleTapConfirmed(MotionEvent event) { + Log.d(LOGTAG, "single tap: " + event.getX() + "x" + event.getY()); + calcScreenMapping(); + mTmpPoint[0] = event.getX(); + mTmpPoint[1] = event.getY(); + mToOrig.mapPoints(mTmpPoint); + + mRepresentation.setPoint((int)mTmpPoint[0], (int)mTmpPoint[1]); + mEditor.commitLocalRepresentation(); + return true; + } + + public void setUnderlay(Uri uri) { + mRepresentation.setUnderlay(uri); + + mUnderlay = ImageLoader.loadConstrainedBitmap(uri, getContext(), MasterImage.MAX_BITMAP_DIM, new Rect(), false); + MasterImage.getImage().setFusionUnderlay(mUnderlay); + invalidate(); + } + + public void setEditor(EditorDualCamFusion editor) { + mEditor = editor; + } + + public void setRepresentation(FilterDualCamFusionRepresentation representation) { + mRepresentation = representation; + } + + private void calcScreenMapping() { + mToOrig = getScreenToImageMatrix(true); + } + + @Override + public boolean enableComparison() { + return false; + } +} diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index d7c2eb4f8..9ca143fde 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -16,6 +16,9 @@ package com.android.gallery3d.filtershow.imageshow; +import java.io.File; +import java.util.ArrayList; + import android.animation.Animator; import android.animation.ValueAnimator; import android.content.Context; @@ -30,11 +33,11 @@ import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; import android.graphics.RectF; +import android.graphics.Region; import android.graphics.Shader; import android.graphics.drawable.NinePatchDrawable; import android.support.v4.widget.EdgeEffectCompat; import android.util.AttributeSet; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; @@ -51,12 +54,9 @@ import com.android.gallery3d.filtershow.filters.ImageFilter; import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.tools.SaveImage; -import java.io.File; -import java.util.ArrayList; - public class ImageShow extends View implements OnGestureListener, - ScaleGestureDetector.OnScaleGestureListener, - OnDoubleTapListener { + ScaleGestureDetector.OnScaleGestureListener, + OnDoubleTapListener { private static final String LOGTAG = "ImageShow"; private static final boolean ENABLE_ZOOMED_COMPARISON = false; @@ -70,14 +70,15 @@ public class ImageShow extends View implements OnGestureListener, private GestureDetector mGestureDetector = null; private ScaleGestureDetector mScaleGestureDetector = null; + private RectF mFusionBounds = new RectF(); protected Rect mImageBounds = new Rect(); private boolean mOriginalDisabled = false; private boolean mTouchShowOriginal = false; private long mTouchShowOriginalDate = 0; private final long mTouchShowOriginalDelayMin = 200; // 200ms private int mShowOriginalDirection = 0; - private static int UNVEIL_HORIZONTAL = 1; - private static int UNVEIL_VERTICAL = 2; + private static final int UNVEIL_HORIZONTAL = 1; + private static final int UNVEIL_VERTICAL = 2; private NinePatchDrawable mShadow = null; private Rect mShadowBounds = new Rect(); @@ -110,6 +111,8 @@ public class ImageShow extends View implements OnGestureListener, private ValueAnimator mAnimatorTranslateX = null; private ValueAnimator mAnimatorTranslateY = null; + protected boolean mAllowScaleAndTranslate = false; + private enum InteractionMode { NONE, SCALE, @@ -143,6 +146,10 @@ public class ImageShow extends View implements OnGestureListener, return MasterImage.getImage().hasModifications(); } + public boolean hasFusionApplied() { + return MasterImage.getImage().hasFusionApplied(); + } + public void resetParameter() { // TODO: implement reset } @@ -273,6 +280,34 @@ public class ImageShow extends View implements OnGestureListener, mActivity.stopLoadingIndicator(); } + Bitmap fusionUnderlay = MasterImage.getImage().getFusionUnderlay(); + if(fusionUnderlay != null) { + float canvWidth = canvas.getWidth(); + float canvHeight = canvas.getHeight(); + float width, height; + float underlayAspect = (float)fusionUnderlay.getWidth() / (float)fusionUnderlay.getHeight(); + + if(canvHeight * underlayAspect > canvWidth) { + // width is constraint + width = canvWidth; + height = canvWidth / underlayAspect; + } else { + // height is constraint + height = canvHeight; + width = canvHeight * underlayAspect; + } + + // center in canvas + mFusionBounds.top = (canvHeight - height)/2; + mFusionBounds.bottom = mFusionBounds.top + height; + mFusionBounds.left = (canvWidth - width)/2; + mFusionBounds.right = mFusionBounds.left + width; + + canvas.drawBitmap(fusionUnderlay, null, mFusionBounds, null); + canvas.clipRect(mFusionBounds, Region.Op.REPLACE); + MasterImage.getImage().setFusionBounds(canvas, mFusionBounds); + } + canvas.save(); mShadowDrawn = false; @@ -350,7 +385,7 @@ public class ImageShow extends View implements OnGestureListener, } public void drawImageAndAnimate(Canvas canvas, - Bitmap image) { + Bitmap image) { if (image == null) { return; } @@ -366,6 +401,8 @@ public class ImageShow extends View implements OnGestureListener, m.mapRect(d); d.roundOut(mImageBounds); + master.setImageBounds(canvas, mImageBounds); + boolean showAnimatedImage = master.onGoingNewLookAnimation(); if (!showAnimatedImage && mDidStartAnimation) { // animation ended, but do we have the correct image to show? @@ -477,12 +514,20 @@ public class ImageShow extends View implements OnGestureListener, if (needsToDrawImage) { drawShadow(canvas, previousBounds); // as needed + + if(hasFusionApplied() || this instanceof ImageFusion) { + previousImage.setHasAlpha(true); + } canvas.drawBitmap(previousImage, mp, mPaint); } canvas.restore(); } else { drawShadow(canvas, mImageBounds); // as needed + + if(hasFusionApplied() || this instanceof ImageFusion) { + image.setHasAlpha(true); + } canvas.drawBitmap(image, m, mPaint); } @@ -504,7 +549,7 @@ public class ImageShow extends View implements OnGestureListener, } private void drawShadow(Canvas canvas, Rect d) { - if (!mShadowDrawn) { + if (!mShadowDrawn && !hasFusionApplied() && !(this instanceof ImageFusion)) { mShadowBounds.set(d.left - mShadowMargin, d.top - mShadowMargin, d.right + mShadowMargin, d.bottom + mShadowMargin); mShadow.setBounds(mShadowBounds); @@ -614,9 +659,12 @@ public class ImageShow extends View implements OnGestureListener, int action = event.getAction(); action = action & MotionEvent.ACTION_MASK; - mGestureDetector.onTouchEvent(event); + if(!hasFusionApplied() || mAllowScaleAndTranslate) + mGestureDetector.onTouchEvent(event); boolean scaleInProgress = scaleInProgress(); - mScaleGestureDetector.onTouchEvent(event); + if(!hasFusionApplied() || mAllowScaleAndTranslate) + mScaleGestureDetector.onTouchEvent(event); + if (mInteractionMode == InteractionMode.SCALE) { return true; } @@ -642,7 +690,8 @@ public class ImageShow extends View implements OnGestureListener, mTouch.y = ey; float scaleFactor = MasterImage.getImage().getScaleFactor(); - if (scaleFactor > 1 && (!ENABLE_ZOOMED_COMPARISON || event.getPointerCount() == 2)) { + if ((scaleFactor > 1 && (!ENABLE_ZOOMED_COMPARISON || event.getPointerCount() == 2) && !hasFusionApplied()) + || mAllowScaleAndTranslate) { float translateX = (mTouch.x - mTouchDown.x) / scaleFactor; float translateY = (mTouch.y - mTouchDown.y) / scaleFactor; Point originalTranslation = MasterImage.getImage().getOriginalTranslation(); @@ -654,7 +703,7 @@ public class ImageShow extends View implements OnGestureListener, } else if (enableComparison() && !mOriginalDisabled && (System.currentTimeMillis() - mTouchShowOriginalDate > mTouchShowOriginalDelayMin) - && event.getPointerCount() == 1) { + && event.getPointerCount() == 1) { mTouchShowOriginal = true; } } @@ -668,7 +717,8 @@ public class ImageShow extends View implements OnGestureListener, mTouchDown.y = 0; mTouch.x = 0; mTouch.y = 0; - if (MasterImage.getImage().getScaleFactor() <= 1) { + if (!(mAllowScaleAndTranslate || hasFusionApplied()) && + MasterImage.getImage().getScaleFactor() <= 1) { MasterImage.getImage().setScaleFactor(1); MasterImage.getImage().resetTranslation(); } @@ -684,7 +734,7 @@ public class ImageShow extends View implements OnGestureListener, } private void startAnimTranslation(int fromX, int toX, - int fromY, int toY, int delay) { + int fromY, int toY, int delay) { if (fromX == toX && fromY == toY) { return; } @@ -729,8 +779,8 @@ public class ImageShow extends View implements OnGestureListener, if (x != translation.x || y != translation.y) { startAnimTranslation(x, translation.x, - y, translation.y, - mAnimationSnapDelay); + y, translation.y, + mAnimationSnapDelay); } } @@ -740,6 +790,9 @@ public class ImageShow extends View implements OnGestureListener, @Override public boolean onDoubleTap(MotionEvent arg0) { + if(hasFusionApplied()) + return true; + mZoomIn = !mZoomIn; float scale = 1.0f; final float x = arg0.getX(); @@ -754,7 +807,7 @@ public class ImageShow extends View implements OnGestureListener, mAnimatorScale = ValueAnimator.ofFloat( MasterImage.getImage().getScaleFactor(), scale - ); + ); float translateX = (getWidth() / 2 - x); float translateY = (getHeight() / 2 - y); Point translation = MasterImage.getImage().getTranslation(); @@ -770,8 +823,8 @@ public class ImageShow extends View implements OnGestureListener, constrainTranslation(translation, scale); startAnimTranslation(startTranslateX, translation.x, - startTranslateY, translation.y, - mAnimationZoomDelay); + startTranslateY, translation.y, + mAnimationZoomDelay); mAnimatorScale.setDuration(mAnimationZoomDelay); mAnimatorScale.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override @@ -809,7 +862,7 @@ public class ImageShow extends View implements OnGestureListener, private void constrainTranslation(Point translation, float scale) { int currentEdgeEffect = 0; - if (scale <= 1) { + if (mAllowScaleAndTranslate || scale <= 1) { mCurrentEdgeEffect = 0; mEdgeEffect.finish(); return; @@ -929,9 +982,11 @@ public class ImageShow extends View implements OnGestureListener, if (scaleFactor > MasterImage.getImage().getMaxScaleFactor()) { scaleFactor = MasterImage.getImage().getMaxScaleFactor(); } - if (scaleFactor < 1.0f) { + + if (!mAllowScaleAndTranslate && scaleFactor < 1.0f) { scaleFactor = 1.0f; } + MasterImage.getImage().setScaleFactor(scaleFactor); scaleFactor = img.getScaleFactor(); float focusx = detector.getFocusX(); @@ -961,7 +1016,8 @@ public class ImageShow extends View implements OnGestureListener, @Override public void onScaleEnd(ScaleGestureDetector detector) { mInteractionMode = InteractionMode.NONE; - if (MasterImage.getImage().getScaleFactor() < 1) { + if (!mAllowScaleAndTranslate && + MasterImage.getImage().getScaleFactor() < 1) { MasterImage.getImage().setScaleFactor(1); invalidate(); } diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index 5e27f4213..2ef0b8362 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -16,9 +16,16 @@ package com.android.gallery3d.filtershow.imageshow; +import java.io.File; +import java.nio.ByteBuffer; +import java.util.List; +import java.util.Vector; + import android.animation.Animator; import android.animation.ValueAnimator; import android.graphics.Bitmap; +import android.graphics.Bitmap.Config; +import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Point; @@ -31,6 +38,7 @@ import com.android.gallery3d.exif.ExifTag; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation; import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; import com.android.gallery3d.filtershow.filters.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; @@ -45,9 +53,8 @@ import com.android.gallery3d.filtershow.pipeline.RenderingRequestCaller; import com.android.gallery3d.filtershow.pipeline.SharedBuffer; import com.android.gallery3d.filtershow.pipeline.SharedPreset; import com.android.gallery3d.filtershow.state.StateAdapter; - -import java.util.List; -import java.util.Vector; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; +import com.android.gallery3d.mpo.MpoParser; public class MasterImage implements RenderingRequestCaller { @@ -73,6 +80,7 @@ public class MasterImage implements RenderingRequestCaller { private Bitmap mOriginalBitmapLarge = null; private Bitmap mOriginalBitmapHighres = null; private Bitmap mTemporaryThumbnail = null; + private int mOrientation; private Rect mOriginalBounds; private final Vector<ImageShow> mLoadListeners = new Vector<ImageShow>(); @@ -87,6 +95,10 @@ public class MasterImage implements RenderingRequestCaller { private int mShadowMargin = 15; // not scaled, fixed in the asset private Rect mPartialBounds = new Rect(); + private Bitmap mFusionUnderlay = null; + private Rect mImageBounds = null; + private Rect mFusionBounds = null; + private ValueAnimator mAnimator = null; private float mMaskScale = 1; private boolean mOnGoingNewLookAnimation = false; @@ -328,6 +340,15 @@ public class MasterImage implements RenderingRequestCaller { } } + public synchronized boolean hasFusionApplied() { + FilterRepresentation representation = + mPreset.getFilterWithSerializationName(FilterDualCamFusionRepresentation.SERIALIZATION_NAME); + if(representation instanceof FilterDualCamFusionRepresentation) { + return true; + } + return false; + } + public SharedBuffer getPreviewBuffer() { return mPreviewBuffer; } @@ -619,11 +640,11 @@ public class MasterImage implements RenderingRequestCaller { mImageShowSize.x / 2.0f, mImageShowSize.y / 2.0f); m.postTranslate(translation.x * getScaleFactor(), - translation.y * getScaleFactor()); + translation.y * getScaleFactor()); return m; } - private Matrix getImageToScreenMatrix(boolean reflectRotation) { + public Matrix getImageToScreenMatrix(boolean reflectRotation) { if (getOriginalBounds() == null || mImageShowSize.x == 0 || mImageShowSize.y == 0) { return new Matrix(); } @@ -840,4 +861,116 @@ public class MasterImage implements RenderingRequestCaller { public boolean hasTinyPlanet() { return mPreset.contains(FilterRepresentation.TYPE_TINYPLANET); } + + public boolean loadMpo() { + boolean loaded = false; + MpoParser parser = MpoParser.parse(getActivity(), getUri()); + byte[] primaryMpoData = parser.readImgData(true); + byte[] auxiliaryMpoData = parser.readImgData(false); + + if(primaryMpoData != null && auxiliaryMpoData != null) { + Bitmap primaryBm = BitmapFactory.decodeByteArray(primaryMpoData, 0, primaryMpoData.length); + primaryMpoData = null; + + if(primaryBm == null) { + return false; + } + + int primaryWidth = primaryBm.getWidth(); + int primaryHeight = primaryBm.getHeight(); + int primaryStride = primaryBm.getRowBytes(); + + Log.v(LOGTAG, "primary info: " + primaryWidth + "x" + primaryHeight + ", s:" + primaryStride); + + ByteBuffer primaryMpoBuffer = ByteBuffer.allocateDirect(primaryBm.getByteCount()); + primaryBm.copyPixelsToBuffer(primaryMpoBuffer); + primaryBm.recycle(); + primaryBm = null; + + // check for pre-generated dm file + String mpoFilepath = ImageLoader.getLocalPathFromUri(getActivity(), getUri()); + String depthFilepath = MpoParser.getDepthmapFilepath(mpoFilepath); + File depthFile = new File(depthFilepath); + if(depthFile.exists()) { + // TODO: read from depth map file and init DDM + // ByteBuffer depthMap = MpoParser.readDepthMapFile(depthFilepath); + // + // DualCameraNativeEngine.getInstance().loadDepthMap( + // mPrimaryMpoImg, primaryWidth, primaryHeight, primaryStride, + // depthMap, depthMapWidth, depthMapHeight, depthMapStride); + + } else { + // read auxiliary image and generate depth map. + Bitmap auxiliaryBm = BitmapFactory.decodeByteArray(auxiliaryMpoData, 0, auxiliaryMpoData.length); + auxiliaryMpoData = null; + + if(auxiliaryBm == null) { + return false; + } + + int auxiliaryWidth = auxiliaryBm.getWidth(); + int auxiliaryHeight = auxiliaryBm.getHeight(); + int auxiliaryStride = auxiliaryBm.getRowBytes(); + + Log.v(LOGTAG, "auxiliary info: " + auxiliaryWidth + "x" + auxiliaryHeight + ", s:" + auxiliaryStride); + + ByteBuffer auxiliaryMpoBuffer = ByteBuffer.allocateDirect(auxiliaryBm.getByteCount()); + auxiliaryBm.copyPixelsToBuffer(auxiliaryMpoBuffer); + auxiliaryBm.recycle(); + auxiliaryBm = null; + + DualCameraNativeEngine.getInstance().initDepthMap( + primaryMpoBuffer, primaryWidth, primaryHeight, primaryStride, + auxiliaryMpoBuffer, auxiliaryWidth, auxiliaryHeight, auxiliaryStride, + mpoFilepath, DualCameraNativeEngine.getInstance().getCalibFilepath(mActivity)); + + Point size = new Point(); + boolean result = DualCameraNativeEngine.getInstance().getDepthMapSize(size); + if(result) { + Log.v(LOGTAG, "get depthmapsize returned true. size: " + size.x + "x" + size.y); + + Bitmap depthMap = Bitmap.createBitmap(size.x, size.y, Config.ALPHA_8); + if(DualCameraNativeEngine.getInstance().getDepthMap(depthMap)) { + loaded = true; + + // TODO: write and read depth map. + // MpoParser.writeDepthMapFile(depthFilepath, depthMap); + } else { + Log.w(LOGTAG, "get depthmap returned false"); + } + + depthMap.recycle(); + depthMap = null; + } else { + Log.w(LOGTAG, "get depthmapsize returned false"); + } + } + } + return loaded; + } + + public void setFusionUnderlay(Bitmap underlay) { + mFusionUnderlay = underlay; + } + + public Bitmap getFusionUnderlay() { + return mFusionUnderlay; + } + + public void setFusionBounds(Canvas canvas, RectF bounds) { + if(mFusionBounds == null) mFusionBounds = new Rect(); + bounds.roundOut(mFusionBounds); + } + + public Rect getFusionBounds() { + return mFusionBounds; + } + + public void setImageBounds(Canvas canvas, Rect bounds) { + mImageBounds = bounds; + } + + public Rect getImageBounds() { + return mImageBounds; + } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java index a487a5d8d..0cdbed76d 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/Buffer.java +++ b/src/com/android/gallery3d/filtershow/pipeline/Buffer.java @@ -18,9 +18,9 @@ package com.android.gallery3d.filtershow.pipeline; import android.graphics.Bitmap; import android.graphics.Canvas; +import android.graphics.PorterDuff; import android.renderscript.Allocation; import android.renderscript.RenderScript; -import android.util.Log; import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.imageshow.MasterImage; @@ -58,6 +58,7 @@ public class Buffer { public synchronized void useBitmap(Bitmap bitmap) { 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/CacheProcessing.java b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java index c2912ed78..f57383a8c 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CacheProcessing.java @@ -28,7 +28,7 @@ import java.util.Vector; public class CacheProcessing { private static final String LOGTAG = "CacheProcessing"; - private static final boolean DEBUG = false; + private static final boolean DEBUG = true; private static final boolean NO_CACHING = false; private Vector<CacheStep> mSteps = new Vector<CacheStep>(); diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java index 1460ad434..51eabe986 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -16,6 +16,13 @@ package com.android.gallery3d.filtershow.pipeline; +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Vector; + import android.graphics.Bitmap; import android.graphics.Rect; import android.renderscript.Allocation; @@ -24,10 +31,11 @@ import android.util.JsonWriter; import android.util.Log; import com.android.gallery3d.R; -import com.android.gallery3d.filtershow.cache.BitmapCache; import com.android.gallery3d.filtershow.cache.ImageLoader; import com.android.gallery3d.filtershow.filters.BaseFiltersManager; import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; +import com.android.gallery3d.filtershow.filters.FilterDualCamFusionRepresentation; +import com.android.gallery3d.filtershow.filters.FilterDualCamSketchRepresentation; import com.android.gallery3d.filtershow.filters.FilterFxRepresentation; import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation; import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; @@ -42,13 +50,6 @@ import com.android.gallery3d.filtershow.imageshow.MasterImage; import com.android.gallery3d.filtershow.state.State; import com.android.gallery3d.filtershow.state.StateAdapter; -import java.io.IOException; -import java.io.StringReader; -import java.io.StringWriter; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Vector; - public class ImagePreset { private static final String LOGTAG = "ImagePreset"; @@ -165,6 +166,10 @@ public class ImagePreset { mDoApplyGeometry = value; } + public boolean getDoApplyGeometry() { + return mDoApplyGeometry; + } + public void setDoApplyFilters(boolean value) { mDoApplyFilters = value; } @@ -327,11 +332,17 @@ public class ImagePreset { } public void removeFilter(FilterRepresentation filterRepresentation) { - if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) { + if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER + || filterRepresentation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) { for (int i = 0; i < mFilters.size(); i++) { - if (mFilters.elementAt(i).getFilterType() - == filterRepresentation.getFilterType()) { + FilterRepresentation filter = mFilters.elementAt(i); + if (filter.getFilterType() == filterRepresentation.getFilterType()) { mFilters.remove(i); + + // reset fusion underlay image. + if(filter instanceof FilterDualCamFusionRepresentation) { + MasterImage.getImage().setFusionUnderlay(null); + } break; } } @@ -350,7 +361,7 @@ public class ImagePreset { if (representation instanceof FilterUserPresetRepresentation) { ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset(); if (preset.nbFilters() == 1 - && preset.contains(FilterRepresentation.TYPE_FX)) { + && preset.contains(FilterRepresentation.TYPE_FX)) { FilterRepresentation rep = preset.getFilterRepresentationForType( FilterRepresentation.TYPE_FX); addFilter(rep); @@ -383,6 +394,11 @@ public class ImagePreset { if (!isNoneBorderFilter(representation)) { mFilters.add(representation); } + } else if (representation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) { + removeFilter(representation); + if (!isNoneDualCamFilter(representation)) { + mFilters.add(representation); + } } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) { boolean replaced = false; for (int i = 0; i < mFilters.size(); i++) { @@ -402,20 +418,36 @@ public class ImagePreset { } else { mFilters.add(representation); } - // Enforces Filter type ordering for borders + + // Enforces Filter type ordering for borders and dual cam FilterRepresentation border = null; + FilterRepresentation dualcam = null; for (int i = 0; i < mFilters.size();) { FilterRepresentation rep = mFilters.elementAt(i); if (rep.getFilterType() == FilterRepresentation.TYPE_BORDER) { border = rep; mFilters.remove(i); continue; + } else if (rep.getFilterType() == FilterRepresentation.TYPE_DUALCAM) { + dualcam = rep; + mFilters.remove(i); + continue; } i++; } if (border != null) { mFilters.add(border); } + if (dualcam != null) { + int i = 0; + for (; i < mFilters.size(); i++) { + FilterRepresentation rep = mFilters.elementAt(i); + if (rep.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) { + break; + } + } + mFilters.add(i, dualcam); + } } private boolean isNoneBorderFilter(FilterRepresentation representation) { @@ -428,6 +460,11 @@ public class ImagePreset { ((FilterFxRepresentation) representation).getNameResource() == R.string.none; } + private boolean isNoneDualCamFilter(FilterRepresentation representation) { + return representation instanceof FilterDualCamSketchRepresentation && + ((FilterDualCamSketchRepresentation) representation).getSketchResId() == 0; + } + public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) { for (int i = 0; i < mFilters.size(); i++) { FilterRepresentation representation = mFilters.elementAt(i); @@ -440,6 +477,7 @@ public class ImagePreset { public Bitmap apply(Bitmap original, FilterEnvironment environment) { Bitmap bitmap = original; + bitmap = applyDualCamera(bitmap, environment); bitmap = applyFilters(bitmap, -1, -1, environment); return applyBorder(bitmap, environment); } @@ -483,6 +521,25 @@ public class ImagePreset { return bitmap; } + public Bitmap applyDualCamera(Bitmap bitmap, FilterEnvironment environment) { + // Apply dual camera filters + // Returns a new bitmap. + for (FilterRepresentation representation:mFilters) { + if (representation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) { + 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( @@ -519,6 +576,10 @@ public class ImagePreset { // TODO: might be worth getting rid of applyBorder. continue; } + if (representation.getFilterType() == FilterRepresentation.TYPE_DUALCAM) { + // skip the dual cam as it's already applied. + continue; + } Bitmap tmp = bitmap; bitmap = environment.applyRepresentation(representation, bitmap); if (tmp != bitmap) { @@ -659,7 +720,7 @@ public class ImagePreset { writer.endObject(); } catch (IOException e) { - Log.e(LOGTAG,"Error encoding JASON",e); + Log.e(LOGTAG,"Error encoding JASON",e); } } diff --git a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java index e334e8798..dbf6a8d88 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java +++ b/src/com/android/gallery3d/filtershow/pipeline/ProcessingService.java @@ -28,6 +28,7 @@ import android.net.Uri; import android.os.Binder; import android.os.IBinder; import android.util.Log; + import com.android.gallery3d.R; import com.android.gallery3d.filtershow.FilterShowActivity; import com.android.gallery3d.filtershow.filters.FiltersManager; @@ -304,6 +305,7 @@ public class ProcessingService extends Service { filtersManager.addBorders(this); filtersManager.addTools(this); filtersManager.addEffects(); + filtersManager.addDualCam(this); filtersManager.addMakeups(this); FiltersManager highresFiltersManager = FiltersManager.getHighresManager(); @@ -311,6 +313,7 @@ public class ProcessingService extends Service { highresFiltersManager.addBorders(this); highresFiltersManager.addTools(this); highresFiltersManager.addEffects(); + highresFiltersManager.addDualCam(this); // highresFiltersManager.addMakeups(this); } diff --git a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java index 4cb9e5ad5..300dfe979 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java +++ b/src/com/android/gallery3d/filtershow/pipeline/RenderingRequest.java @@ -84,6 +84,10 @@ public class RenderingRequest { request.setBounds(bounds); request.setDestination(destination); passedPreset.setPartialRendering(true, bounds); + } else if (type == GEOMETRY_RENDERING || + type == FILTERS_RENDERING) { + passedPreset.setDoApplyGeometry(preset.getDoApplyGeometry()); + passedPreset.setDoApplyFilters(preset.getDoApplyFilters()); } request.setImagePreset(passedPreset); diff --git a/src/com/android/gallery3d/filtershow/tools/DualCameraNativeEngine.java b/src/com/android/gallery3d/filtershow/tools/DualCameraNativeEngine.java new file mode 100644 index 000000000..60b4d67e9 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/tools/DualCameraNativeEngine.java @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2015, 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.io.File; +import java.nio.ByteBuffer; + +import android.content.Context; +import android.graphics.Bitmap; +import android.graphics.Point; +import android.util.Log; + +public class DualCameraNativeEngine { + private static final String TAG = "DualCameraNativeEngine"; + static { + try { + System.loadLibrary("jni_dualcamera"); + mLibLoaded = true; + Log.v(TAG, "successfully loaded dual camera lib"); + } catch (UnsatisfiedLinkError e) { + Log.e(TAG, "failed to load dual camera lib"); + mLibLoaded = false; + } + } + + public static final String DEPTH_MAP_EXT = "dm"; + private static final String CALIBRATION_FILENAME = "ddm_calib_file.dat"; + private static boolean mLibLoaded; + + private static DualCameraNativeEngine mInstance; + + private DualCameraNativeEngine() {} + + public static void createInstance() { + if(mInstance == null) { + mInstance = new DualCameraNativeEngine(); + } + } + + public static DualCameraNativeEngine getInstance() { + createInstance(); + return mInstance; + } + + public boolean isLibLoaded() { + return mLibLoaded; + } + + public String getCalibFilepath(Context context) { + File calibFile = new File(context.getFilesDir(), CALIBRATION_FILENAME); + return calibFile.getAbsolutePath(); + } + + native public void initDepthMap(ByteBuffer primaryRGBA, int primaryWidth, int primaryHeight, int primaryStride, + ByteBuffer auxiliaryRGBA, int auxiliaryWidth, int auxiliaryHeight, int auxiliaryStride, + String mpoFilepath, String calibFilepath); + + native public void loadDepthMap(ByteBuffer primaryRGBA, int primaryWidth, int primaryHeight, int primaryStride, + ByteBuffer depthMap, int depthMapWidth, int depthMapHeight, int depthMapStride); + + native public void releaseDepthMap(); + + native public boolean getDepthMapSize(Point point); + + native public boolean getDepthMap(Bitmap dataBuffer); + + native public boolean applyFocus(int focusPointX, int focusPointY, int intensity, Bitmap outBm); + + native public boolean applyHalo(int focusPointX, int focusPointY, int intensity, Bitmap outBm); + + native public boolean applyBokeh(int focusPointX, int focusPointY, int intensity, Bitmap outBm); + + native public boolean applySketch(Bitmap sketchBm, int focusPointX, int focusPointY, Bitmap outBm); + + native public boolean getForegroundImg(int focusPointX, int focusPointY, Bitmap outBm); +} diff --git a/src/com/android/gallery3d/filtershow/tools/SaveImage.java b/src/com/android/gallery3d/filtershow/tools/SaveImage.java index d4cc3b02a..f04466f1b 100644 --- a/src/com/android/gallery3d/filtershow/tools/SaveImage.java +++ b/src/com/android/gallery3d/filtershow/tools/SaveImage.java @@ -16,12 +16,26 @@ package com.android.gallery3d.filtershow.tools; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FilenameFilter; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.sql.Date; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + import android.content.ContentResolver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.database.Cursor; import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Paint; +import android.graphics.Rect; +import android.graphics.RectF; import android.net.Uri; import android.os.Environment; import android.provider.MediaStore; @@ -35,6 +49,7 @@ import com.android.gallery3d.common.Utils; 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.FilterRepresentation; import com.android.gallery3d.filtershow.filters.FiltersManager; import com.android.gallery3d.filtershow.imageshow.MasterImage; @@ -43,16 +58,6 @@ import com.android.gallery3d.filtershow.pipeline.ImagePreset; import com.android.gallery3d.filtershow.pipeline.ProcessingService; import com.android.gallery3d.util.XmpUtilHelper; -import java.io.File; -import java.io.FileNotFoundException; -import java.io.FilenameFilter; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.TimeZone; - /** * Handles saving edited photo */ @@ -179,12 +184,12 @@ public class SaveImage { querySourceFromContentResolver(contentResolver, srcContentUri, queryProjection, new ContentResolverQueryCallback() { - @Override - public void onCursorResult(Cursor cursor) { - fullPath[0] = cursor.getString(0); - } - } - ); + @Override + public void onCursorResult(Cursor cursor) { + fullPath[0] = cursor.getString(0); + } + }); + if (fullPath[0] != null) { // Construct the auxiliary directory given the source file's path. // Then select and delete all the files starting with the same name @@ -415,6 +420,38 @@ public class SaveImage { "Saving"); 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); + + bitmap.recycle(); + bitmap = underlay; + } + updateProgress(); Object xmp = getPanoramaXMPData(newSourceUri, preset); @@ -542,8 +579,11 @@ public class SaveImage { if (preset.contains(FilterRepresentation.TYPE_TINYPLANET)){ flatten = true; } + + float scaleFactor = 1f; + Intent processIntent = ProcessingService.getSaveIntent(filterShowActivity, preset, - destination, selectedImageUri, sourceImageUri, flatten, 90, 1f, true); + destination, selectedImageUri, sourceImageUri, flatten, 90, scaleFactor, true); filterShowActivity.startService(processIntent); @@ -595,7 +635,7 @@ public class SaveImage { * @return The file object. Return null if srcUri is invalid or not a local * file. */ - private static File getLocalFileFromUri(Context context, Uri srcUri) { + public static File getLocalFileFromUri(Context context, Uri srcUri) { if (srcUri == null) { Log.e(LOGTAG, "srcUri is null."); return null; @@ -615,13 +655,13 @@ public class SaveImage { querySource(context, srcUri, new String[] { ImageColumns.DATA }, - new ContentResolverQueryCallback() { + new ContentResolverQueryCallback() { - @Override - public void onCursorResult(Cursor cursor) { - file[0] = new File(cursor.getString(0)); - } - }); + @Override + public void onCursorResult(Cursor cursor) { + file[0] = new File(cursor.getString(0)); + } + }); } } else if (scheme.equals(ContentResolver.SCHEME_FILE)) { file[0] = new File(srcUri.getPath()); @@ -695,7 +735,7 @@ public class SaveImage { } private static ContentValues getContentValues(Context context, Uri sourceUri, - File file, long time) { + File file, long time) { final ContentValues values = new ContentValues(); time /= 1000; @@ -720,20 +760,20 @@ public class SaveImage { SaveImage.querySource(context, sourceUri, projection, new ContentResolverQueryCallback() { - @Override - public void onCursorResult(Cursor cursor) { - values.put(Images.Media.DATE_TAKEN, cursor.getLong(0)); - - double latitude = cursor.getDouble(1); - double longitude = cursor.getDouble(2); - // TODO: Change || to && after the default location - // issue is fixed. - if ((latitude != 0f) || (longitude != 0f)) { - values.put(Images.Media.LATITUDE, latitude); - values.put(Images.Media.LONGITUDE, longitude); - } - } - }); + @Override + public void onCursorResult(Cursor cursor) { + values.put(Images.Media.DATE_TAKEN, cursor.getLong(0)); + + double latitude = cursor.getDouble(1); + double longitude = cursor.getDouble(2); + // TODO: Change || to && after the default location + // issue is fixed. + if ((latitude != 0f) || (longitude != 0f)) { + values.put(Images.Media.LATITUDE, latitude); + values.put(Images.Media.LONGITUDE, longitude); + } + } + }); return values; } diff --git a/src/com/android/gallery3d/mpo/MpoHeader.java b/src/com/android/gallery3d/mpo/MpoHeader.java new file mode 100644 index 000000000..de8b9be49 --- /dev/null +++ b/src/com/android/gallery3d/mpo/MpoHeader.java @@ -0,0 +1,56 @@ +/* + * Copyright (c) 2015, 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.mpo; + +class MpoHeader { + public static final short SOI = (short) 0xFFD8; + public static final short APP2 = (short) 0xFFE2; + public static final short APP1 = (short) 0xFFE1; + public static final short APP0 = (short) 0xFFE0; + public static final short EOI = (short) 0xFFD9; + + /** + * SOF (start of frame). All value between SOF0 and SOF15 is SOF marker except for DHT, JPG, + * and DAC marker. + */ + public static final short SOF0 = (short) 0xFFC0; + public static final short SOF15 = (short) 0xFFCF; + public static final short DHT = (short) 0xFFC4; + public static final short JPG = (short) 0xFFC8; + public static final short DAC = (short) 0xFFCC; + + public static final int APP2_FIELD_LENGTH_BYTES = 2; + public static final int MP_FORMAT_IDENTIFIER_BYTES = 4; + + public static final boolean isSofMarker(short marker) { + return marker >= SOF0 && marker <= SOF15 && marker != DHT && marker != JPG + && marker != DAC; + } +} diff --git a/src/com/android/gallery3d/mpo/MpoParser.java b/src/com/android/gallery3d/mpo/MpoParser.java new file mode 100644 index 000000000..d859c05b4 --- /dev/null +++ b/src/com/android/gallery3d/mpo/MpoParser.java @@ -0,0 +1,291 @@ +/* + * Copyright (c) 2015, 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.mpo; + +import java.io.ByteArrayOutputStream; +import java.io.FileInputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.ByteOrder; +import java.nio.channels.FileChannel; + +import android.content.ContentResolver; +import android.content.Context; +import android.net.Uri; +import android.util.Log; + +import com.android.gallery3d.common.Utils; +import com.android.gallery3d.exif.CountedDataInputStream; +import com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; + +public class MpoParser { + private static final String LOGTAG = "MpoParser"; + private static final int MP_INDEX_FIELD_SIZE_BYTES = 12; + + protected static final short LITTLE_ENDIAN_TAG = 0x4949; // "II" + protected static final short BIG_ENDIAN_TAG = 0x4d4d; // "MM" + + private ContentResolver mContentResolver; + private Uri mUri; + + private CountedDataInputStream mDataStream; + private ByteOrder mByteOrder; + private int mMpHeaderOffset; + private int mIfd1Offset; + private int mMpEntryOffset; + private MpEntry mPrimaryEntry; + private MpEntry mSecondaryEntry; + + private MpoParser(Context context, Uri uri) { + mContentResolver = context.getContentResolver(); + mUri = uri; + + InputStream is = null; + try { + is = mContentResolver.openInputStream(mUri); + // seek to mp header + if((mMpHeaderOffset = seekToMpData(is)) == -1) + return; + + // read mp header + mDataStream = new CountedDataInputStream(is); + readMpHeader(); + + // read mp index ifd + readMpIndexIfdData(); + + // read mp entries + readMpEntryData(); + } catch (IOException e) { + e.printStackTrace(); + } finally { + Utils.closeSilently(is); + } + } + + public static MpoParser parse(Context context, Uri uri) { + return new MpoParser(context, uri); + } + + private int seekToMpData(InputStream inputStream) throws IOException { + CountedDataInputStream dataStream = new CountedDataInputStream(inputStream); + if (dataStream.readShort() != MpoHeader.SOI) { + return -1; + } + + short marker = dataStream.readShort(); + while (marker != MpoHeader.EOI + && !MpoHeader.isSofMarker(marker)) { + int length = dataStream.readUnsignedShort(); + if (marker == MpoHeader.APP2) { + dataStream.readInt(); // MP Format Identifier + return dataStream.getReadByteCount(); + } + if (length < 2 || (length - 2) != dataStream.skip(length - 2)) { + Log.w(LOGTAG, "Invalid JPEG format."); + return -1; + } + marker = dataStream.readShort(); + } + return -1; + } + + private void readMpHeader() throws IOException { + short byteOrder = mDataStream.readShort(); + mByteOrder = (byteOrder == LITTLE_ENDIAN_TAG)?ByteOrder.LITTLE_ENDIAN:ByteOrder.BIG_ENDIAN; + mDataStream.setByteOrder(mByteOrder); + if(mDataStream.readShort() == 42) { + Log.v(LOGTAG, "correct endian!"); + } else { + Log.w(LOGTAG, "incorrect endian!"); + } + + mIfd1Offset = mDataStream.readInt(); + } + + private void readMpIndexIfdData() throws IOException { + mDataStream.skipTo(mIfd1Offset); + int count = mDataStream.readShort(); + // add 6 (2 for count, 4 for offset to next IFD) + mMpEntryOffset = mIfd1Offset + (count*MP_INDEX_FIELD_SIZE_BYTES) + 6; + } + + private MpEntry readMpEntryData() { + try { + mDataStream.skipTo(mMpEntryOffset); + + mPrimaryEntry = new MpEntry(); + mPrimaryEntry.mImgAttribute = mDataStream.readInt(); + mPrimaryEntry.mImgSize = mDataStream.readInt(); + mPrimaryEntry.mImgDataOffset = mDataStream.readInt(); + mPrimaryEntry.mDepImg1Entry = mDataStream.readShort(); + mPrimaryEntry.mDepImg2Entry = mDataStream.readShort(); + + mSecondaryEntry = new MpEntry(); + mSecondaryEntry.mImgAttribute = mDataStream.readInt(); + mSecondaryEntry.mImgSize = mDataStream.readInt(); + mSecondaryEntry.mImgDataOffset = mDataStream.readInt(); + mSecondaryEntry.mDepImg1Entry = mDataStream.readShort(); + mSecondaryEntry.mDepImg2Entry = mDataStream.readShort(); + } catch (IOException e) { + e.printStackTrace(); + } + + return mPrimaryEntry; + } + + public byte[] readImgData(boolean primary) { + MpEntry mpEntry = null; + byte[] data = null; + + if(primary) { + mpEntry = mPrimaryEntry; + } else { + mpEntry = mSecondaryEntry; + } + + if(mpEntry == null) + return data; + + InputStream is = null; + ByteArrayOutputStream baos = null; + try { + is = mContentResolver.openInputStream(mUri); + data = new byte[mpEntry.mImgSize]; + + is.skip((mpEntry.mImgDataOffset>0)?mpEntry.mImgDataOffset + mMpHeaderOffset : mpEntry.mImgDataOffset); + if(is.read(data) == -1) { + Log.d(LOGTAG, "read EOF. invalid offset/size"); + data = null; + } else { + // verify we have well formed jpeg data + ByteBuffer buffer = ByteBuffer.wrap(data); + if(buffer.getShort(0) != MpoHeader.SOI) { + Log.d(LOGTAG, "non valid SOI. offset incorrect."); + data = null; + } else if(buffer.getShort(buffer.limit() - 2) != MpoHeader.EOI) { + Log.d(LOGTAG, "non valid EOI. size incorrect. attempting to read further till EOI"); + baos = new ByteArrayOutputStream(data.length); + baos.write(data); + + byte[] readArray = new byte[2]; + ByteBuffer readBuf = ByteBuffer.wrap(readArray); + + readArray[0] = data[data.length-2]; + readArray[1] = data[data.length-1]; + + data = null; + + boolean validJpg = true; + while(readBuf.getShort(0) != MpoHeader.EOI) { + int read = is.read(); + if(read == -1) { + Log.d(LOGTAG, "reached EOF before EOI. invalid file"); + validJpg = false; + break; + } + readArray[0] = readArray[1]; + readArray[1] = (byte) (read & 0xFF); + + baos.write(read); + } + + if(validJpg) + data = baos.toByteArray(); + } + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + Utils.closeSilently(is); + Utils.closeSilently(baos); + } + + return data; + } + + public static String getDepthmapFilepath(String mpoFilepath) { + String depthFilepath = mpoFilepath.substring(0, mpoFilepath.lastIndexOf('.')) + + DualCameraNativeEngine.DEPTH_MAP_EXT; + + return depthFilepath; + } + + public static void writeDepthMapFile(String depthMapFilepath, ByteBuffer depthMap) { + FileChannel fc = null; + try { + fc = new FileOutputStream(depthMapFilepath).getChannel(); + fc.write(depthMap); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if(fc != null) { + try { + fc.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + + depthMap.clear(); + } + + public static ByteBuffer readDepthMapFile(String depthMapFilepath) { + FileChannel fc = null; + ByteBuffer depthMap = null; + try { + fc = new FileInputStream(depthMapFilepath).getChannel(); + depthMap = ByteBuffer.allocateDirect((int)fc.size()); + fc.read(depthMap); + } catch (IOException e) { + e.printStackTrace(); + } finally { + if(fc != null) { + try { + fc.close(); + } catch (IOException e) { + e.printStackTrace(); + } + } + } + return depthMap; + } + + class MpEntry { + int mImgAttribute; + int mImgSize; + int mImgDataOffset; + short mDepImg1Entry; + short mDepImg2Entry; + } +}
\ No newline at end of file diff --git a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java index e82d5617c..8c668d482 100644 --- a/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java +++ b/src_pd/com/android/gallery3d/filtershow/editors/EditorManager.java @@ -17,9 +17,6 @@ package com.android.gallery3d.filtershow.editors; import com.android.gallery3d.filtershow.EditorPlaceHolder; -import com.android.gallery3d.filtershow.editors.BasicEditor; -import com.android.gallery3d.filtershow.editors.EditorCurves; -import com.android.gallery3d.filtershow.editors.EditorZoom; public class EditorManager { @@ -36,6 +33,12 @@ public class EditorManager { editorPlaceHolder.addEditor(new EditorRotate()); editorPlaceHolder.addEditor(new EditorStraighten()); editorPlaceHolder.addEditor(new EditorCrop()); + editorPlaceHolder.addEditor(new BasicEditor()); + editorPlaceHolder.addEditor(new ImageOnlyEditor()); + editorPlaceHolder.addEditor(new EditorRedEye()); + editorPlaceHolder.addEditor(new EditorDualCamera()); + editorPlaceHolder.addEditor(new EditorDualCamFusion()); + editorPlaceHolder.addEditor(new EditorDualCamSketch()); } } |