| /* |
| * Copyright (C) 2013 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.gallery3d.filtershow.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; |
| import android.graphics.Rect; |
| import android.graphics.RectF; |
| import android.net.Uri; |
| import android.util.Log; |
| |
| 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; |
| import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; |
| import com.android.gallery3d.filtershow.filters.ImageFilter; |
| import com.android.gallery3d.filtershow.history.HistoryItem; |
| import com.android.gallery3d.filtershow.history.HistoryManager; |
| import com.android.gallery3d.filtershow.pipeline.Buffer; |
| import com.android.gallery3d.filtershow.pipeline.ImagePreset; |
| import com.android.gallery3d.filtershow.pipeline.RenderingRequest; |
| 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 com.android.gallery3d.filtershow.tools.DualCameraNativeEngine; |
| import com.android.gallery3d.mpo.MpoParser; |
| |
| public class MasterImage implements RenderingRequestCaller { |
| |
| private static final String LOGTAG = "MasterImage"; |
| private boolean DEBUG = false; |
| private static final boolean DISABLEZOOM = false; |
| public static final int SMALL_BITMAP_DIM = 160; |
| public static final int MAX_BITMAP_DIM = 900; |
| private static MasterImage sMasterImage = null; |
| |
| private boolean mSupportsHighRes = false; |
| |
| private ImageFilter mCurrentFilter = null; |
| private ImagePreset mPreset = null; |
| private ImagePreset mLoadedPreset = null; |
| private ImagePreset mGeometryOnlyPreset = null; |
| private ImagePreset mFiltersOnlyPreset = null; |
| |
| private SharedBuffer mPreviewBuffer = new SharedBuffer(); |
| private SharedPreset mPreviewPreset = new SharedPreset(); |
| |
| private Bitmap mOriginalBitmapSmall = null; |
| 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>(); |
| private Uri mUri = null; |
| private int mZoomOrientation = ImageLoader.ORI_NORMAL; |
| |
| private Bitmap mGeometryOnlyBitmap = null; |
| private Bitmap mFiltersOnlyBitmap = null; |
| private Bitmap mPartialBitmap = null; |
| private Bitmap mHighresBitmap = null; |
| private Bitmap mPreviousImage = null; |
| 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; |
| private float mAnimRotationValue = 0; |
| private float mCurrentAnimRotationStartValue = 0; |
| private float mAnimFraction = 0; |
| private int mCurrentLookAnimation = 0; |
| public static final int CIRCLE_ANIMATION = 1; |
| public static final int ROTATE_ANIMATION = 2; |
| public static final int MIRROR_ANIMATION = 3; |
| |
| private HistoryManager mHistory = null; |
| private StateAdapter mState = null; |
| |
| private FilterShowActivity mActivity = null; |
| |
| private Vector<ImageShow> mObservers = new Vector<ImageShow>(); |
| private FilterRepresentation mCurrentFilterRepresentation; |
| |
| private float mScaleFactor = 1.0f; |
| private float mMaxScaleFactor = 3.0f; // TODO: base this on the current view / image |
| private Point mTranslation = new Point(); |
| private Point mOriginalTranslation = new Point(); |
| |
| private Point mImageShowSize = new Point(); |
| |
| private boolean mShowsOriginal; |
| private List<ExifTag> mEXIF; |
| private BitmapCache mBitmapCache = new BitmapCache(); |
| |
| private MasterImage() { |
| } |
| |
| // TODO: remove singleton |
| public static void setMaster(MasterImage master) { |
| sMasterImage = master; |
| } |
| |
| public static MasterImage getImage() { |
| if (sMasterImage == null) { |
| sMasterImage = new MasterImage(); |
| } |
| return sMasterImage; |
| } |
| |
| public Bitmap getOriginalBitmapSmall() { |
| return mOriginalBitmapSmall; |
| } |
| |
| public Bitmap getOriginalBitmapLarge() { |
| return mOriginalBitmapLarge; |
| } |
| |
| public Bitmap getOriginalBitmapHighres() { |
| if (mOriginalBitmapHighres == null) { |
| return mOriginalBitmapLarge; |
| } |
| return mOriginalBitmapHighres; |
| } |
| |
| public void setOriginalBitmapHighres(Bitmap mOriginalBitmapHighres) { |
| this.mOriginalBitmapHighres = mOriginalBitmapHighres; |
| } |
| |
| public int getOrientation() { |
| return mOrientation; |
| } |
| |
| public Rect getOriginalBounds() { |
| return mOriginalBounds; |
| } |
| |
| public void setOriginalBounds(Rect r) { |
| mOriginalBounds = r; |
| } |
| |
| public Uri getUri() { |
| return mUri; |
| } |
| |
| public void setUri(Uri uri) { |
| mUri = uri; |
| } |
| |
| public int getZoomOrientation() { |
| return mZoomOrientation; |
| } |
| |
| public void addListener(ImageShow imageShow) { |
| if (!mLoadListeners.contains(imageShow)) { |
| mLoadListeners.add(imageShow); |
| } |
| } |
| |
| public void warnListeners() { |
| mActivity.runOnUiThread(mWarnListenersRunnable); |
| } |
| |
| private Runnable mWarnListenersRunnable = new Runnable() { |
| @Override |
| public void run() { |
| for (int i = 0; i < mLoadListeners.size(); i++) { |
| ImageShow imageShow = mLoadListeners.elementAt(i); |
| imageShow.imageLoaded(); |
| } |
| invalidatePreview(); |
| } |
| }; |
| |
| public boolean loadBitmap(Uri uri, int size) { |
| setUri(uri); |
| mEXIF = ImageLoader.getExif(getActivity(), uri); |
| mOrientation = ImageLoader.getMetadataOrientation(mActivity, uri); |
| Rect originalBounds = new Rect(); |
| mOriginalBitmapLarge = ImageLoader.loadOrientedConstrainedBitmap(uri, mActivity, |
| Math.min(MAX_BITMAP_DIM, size), |
| mOrientation, originalBounds); |
| setOriginalBounds(originalBounds); |
| if (mOriginalBitmapLarge == null) { |
| return false; |
| } |
| int sw = SMALL_BITMAP_DIM; |
| int sh = (int) (sw * (float) mOriginalBitmapLarge.getHeight() / mOriginalBitmapLarge |
| .getWidth()); |
| mOriginalBitmapSmall = Bitmap.createScaledBitmap(mOriginalBitmapLarge, sw, sh, true); |
| Log.d(LOGTAG, "MasterImage.loadBitmap(): OriginalBitmapLarge.WH is (" + mOriginalBitmapLarge.getWidth() + ", " |
| + mOriginalBitmapLarge.getHeight() + "), OriginalBitmapSmall.WH is (" + sw + ", " + sh + "), originalBounds is " |
| + originalBounds.toString()); |
| mZoomOrientation = mOrientation; |
| warnListeners(); |
| return true; |
| } |
| |
| public void setSupportsHighRes(boolean value) { |
| mSupportsHighRes = value; |
| } |
| |
| public void addObserver(ImageShow observer) { |
| if (mObservers.contains(observer)) { |
| return; |
| } |
| mObservers.add(observer); |
| } |
| |
| public void removeObserver(ImageShow observer) { |
| mObservers.remove(observer); |
| } |
| |
| public void setActivity(FilterShowActivity activity) { |
| mActivity = activity; |
| } |
| |
| public FilterShowActivity getActivity() { |
| return mActivity; |
| } |
| |
| public synchronized ImagePreset getPreset() { |
| return mPreset; |
| } |
| |
| public synchronized ImagePreset getGeometryPreset() { |
| return mGeometryOnlyPreset; |
| } |
| |
| public synchronized ImagePreset getFiltersOnlyPreset() { |
| return mFiltersOnlyPreset; |
| } |
| |
| public synchronized void setPreset(ImagePreset preset, |
| FilterRepresentation change, |
| boolean addToHistory) { |
| if (DEBUG) { |
| preset.showFilters(); |
| } |
| mPreset = preset; |
| mPreset.fillImageStateAdapter(mState); |
| if (addToHistory) { |
| HistoryItem historyItem = new HistoryItem(mPreset, change); |
| mHistory.addHistoryItem(historyItem); |
| } |
| updatePresets(true); |
| resetGeometryImages(false); |
| mActivity.updateCategories(); |
| } |
| |
| public void onHistoryItemClick(int position) { |
| HistoryItem historyItem = mHistory.getItem(position); |
| // We need a copy from the history |
| if (historyItem == null) { |
| return; |
| } |
| ImagePreset newPreset = new ImagePreset(historyItem.getImagePreset()); |
| // don't need to add it to the history |
| setPreset(newPreset, historyItem.getFilterRepresentation(), false); |
| mHistory.setCurrentPreset(position); |
| } |
| |
| public HistoryManager getHistory() { |
| return mHistory; |
| } |
| |
| public StateAdapter getState() { |
| return mState; |
| } |
| |
| public void setHistoryManager(HistoryManager adapter) { |
| mHistory = adapter; |
| } |
| |
| public void setStateAdapter(StateAdapter adapter) { |
| mState = adapter; |
| } |
| |
| public void setCurrentFilter(ImageFilter filter) { |
| mCurrentFilter = filter; |
| } |
| |
| public ImageFilter getCurrentFilter() { |
| return mCurrentFilter; |
| } |
| |
| public synchronized boolean hasModifications() { |
| // TODO: We need to have a better same effects check to see if two |
| // presets are functionally the same. Right now, we are relying on a |
| // stricter check as equals(). |
| ImagePreset loadedPreset = getLoadedPreset(); |
| if (mPreset == null) { |
| if (loadedPreset == null) { |
| return false; |
| } else { |
| return loadedPreset.hasModifications(); |
| } |
| } else { |
| if (loadedPreset == null) { |
| return mPreset.hasModifications(); |
| } else { |
| return !mPreset.equals(loadedPreset); |
| } |
| } |
| } |
| |
| public synchronized boolean hasFusionApplied() { |
| FilterRepresentation representation = |
| mPreset.getFilterWithSerializationName(FilterDualCamFusionRepresentation.SERIALIZATION_NAME); |
| if(representation instanceof FilterDualCamFusionRepresentation) { |
| return true; |
| } |
| return false; |
| } |
| |
| public SharedBuffer getPreviewBuffer() { |
| return mPreviewBuffer; |
| } |
| |
| public SharedPreset getPreviewPreset() { |
| return mPreviewPreset; |
| } |
| |
| public Bitmap getFilteredImage() { |
| mPreviewBuffer.swapConsumerIfNeeded(); // get latest bitmap |
| Buffer consumer = mPreviewBuffer.getConsumer(); |
| if (consumer != null) { |
| return consumer.getBitmap(); |
| } |
| return null; |
| } |
| |
| public Bitmap getFiltersOnlyImage() { |
| return mFiltersOnlyBitmap; |
| } |
| |
| public Bitmap getGeometryOnlyImage() { |
| return mGeometryOnlyBitmap; |
| } |
| |
| public Bitmap getPartialImage() { |
| return mPartialBitmap; |
| } |
| |
| public Rect getPartialBounds() { |
| return mPartialBounds; |
| } |
| |
| public Bitmap getHighresImage() { |
| if (mHighresBitmap == null) { |
| return getFilteredImage(); |
| } |
| return mHighresBitmap; |
| } |
| |
| public Bitmap getPreviousImage() { |
| return mPreviousImage; |
| } |
| |
| public ImagePreset getCurrentPreset() { |
| return getPreviewBuffer().getConsumer().getPreset(); |
| } |
| |
| public float getMaskScale() { |
| return mMaskScale; |
| } |
| |
| public void setMaskScale(float scale) { |
| mMaskScale = scale; |
| notifyObservers(); |
| } |
| |
| public float getAnimRotationValue() { |
| return mAnimRotationValue; |
| } |
| |
| public void setAnimRotation(float rotation) { |
| mAnimRotationValue = mCurrentAnimRotationStartValue + rotation; |
| notifyObservers(); |
| } |
| |
| public void setAnimFraction(float fraction) { |
| mAnimFraction = fraction; |
| } |
| |
| public float getAnimFraction() { |
| return mAnimFraction; |
| } |
| |
| public boolean onGoingNewLookAnimation() { |
| return mOnGoingNewLookAnimation; |
| } |
| |
| public int getCurrentLookAnimation() { |
| return mCurrentLookAnimation; |
| } |
| |
| public void resetAnimBitmap() { |
| mBitmapCache.cache(mPreviousImage); |
| mPreviousImage = null; |
| } |
| |
| public void onNewLook(FilterRepresentation newRepresentation) { |
| if (getFilteredImage() == null) { |
| return; |
| } |
| if (mAnimator != null) { |
| mAnimator.cancel(); |
| if (mCurrentLookAnimation == ROTATE_ANIMATION) { |
| mCurrentAnimRotationStartValue += 90; |
| } |
| } else { |
| resetAnimBitmap(); |
| mPreviousImage = mBitmapCache.getBitmapCopy(getFilteredImage(), BitmapCache.NEW_LOOK); |
| } |
| if (newRepresentation instanceof FilterUserPresetRepresentation) { |
| mCurrentLookAnimation = CIRCLE_ANIMATION; |
| mAnimator = ValueAnimator.ofFloat(0, 1); |
| mAnimator.setDuration(650); |
| } |
| if (newRepresentation instanceof FilterRotateRepresentation) { |
| mCurrentLookAnimation = ROTATE_ANIMATION; |
| mAnimator = ValueAnimator.ofFloat(0, 90); |
| mAnimator.setDuration(500); |
| } |
| if (newRepresentation instanceof FilterMirrorRepresentation) { |
| mCurrentLookAnimation = MIRROR_ANIMATION; |
| mAnimator = ValueAnimator.ofFloat(1, 0, -1); |
| mAnimator.setDuration(500); |
| } |
| mAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
| @Override |
| public void onAnimationUpdate(ValueAnimator animation) { |
| if (mCurrentLookAnimation == CIRCLE_ANIMATION) { |
| setMaskScale((Float) animation.getAnimatedValue()); |
| } else if (mCurrentLookAnimation == ROTATE_ANIMATION |
| || mCurrentLookAnimation == MIRROR_ANIMATION) { |
| setAnimRotation((Float) animation.getAnimatedValue()); |
| setAnimFraction(animation.getAnimatedFraction()); |
| } |
| } |
| }); |
| mAnimator.addListener(new Animator.AnimatorListener() { |
| @Override |
| public void onAnimationStart(Animator animation) { |
| mOnGoingNewLookAnimation = true; |
| } |
| |
| @Override |
| public void onAnimationEnd(Animator animation) { |
| mOnGoingNewLookAnimation = false; |
| mCurrentAnimRotationStartValue = 0; |
| mAnimator = null; |
| notifyObservers(); |
| } |
| |
| @Override |
| public void onAnimationCancel(Animator animation) { |
| |
| } |
| |
| @Override |
| public void onAnimationRepeat(Animator animation) { |
| |
| } |
| }); |
| mAnimator.start(); |
| notifyObservers(); |
| } |
| |
| public void notifyObservers() { |
| for (ImageShow observer : mObservers) { |
| observer.invalidate(); |
| } |
| } |
| |
| public void resetGeometryImages(boolean force) { |
| if (mPreset == null) { |
| return; |
| } |
| ImagePreset newPresetGeometryOnly = new ImagePreset(mPreset); |
| newPresetGeometryOnly.setDoApplyFilters(false); |
| newPresetGeometryOnly.setDoApplyGeometry(true); |
| if (force || mGeometryOnlyPreset == null |
| || !newPresetGeometryOnly.equals(mGeometryOnlyPreset)) { |
| mGeometryOnlyPreset = newPresetGeometryOnly; |
| RenderingRequest.post(mActivity, null, |
| mGeometryOnlyPreset, RenderingRequest.GEOMETRY_RENDERING, this); |
| } |
| ImagePreset newPresetFiltersOnly = new ImagePreset(mPreset); |
| newPresetFiltersOnly.setDoApplyFilters(true); |
| newPresetFiltersOnly.setDoApplyGeometry(false); |
| if (force || mFiltersOnlyPreset == null |
| || !newPresetFiltersOnly.same(mFiltersOnlyPreset)) { |
| mFiltersOnlyPreset = newPresetFiltersOnly; |
| RenderingRequest.post(mActivity, null, |
| mFiltersOnlyPreset, RenderingRequest.FILTERS_RENDERING, this); |
| } |
| } |
| |
| public void updatePresets(boolean force) { |
| invalidatePreview(); |
| } |
| |
| public FilterRepresentation getCurrentFilterRepresentation() { |
| return mCurrentFilterRepresentation; |
| } |
| |
| public void setCurrentFilterRepresentation(FilterRepresentation currentFilterRepresentation) { |
| mCurrentFilterRepresentation = currentFilterRepresentation; |
| } |
| |
| public void invalidateFiltersOnly() { |
| mFiltersOnlyPreset = null; |
| invalidatePreview(); |
| } |
| |
| public void invalidatePartialPreview() { |
| if (mPartialBitmap != null) { |
| mBitmapCache.cache(mPartialBitmap); |
| mPartialBitmap = null; |
| notifyObservers(); |
| } |
| } |
| |
| public void invalidateHighresPreview() { |
| if (mHighresBitmap != null) { |
| mBitmapCache.cache(mHighresBitmap); |
| mHighresBitmap = null; |
| notifyObservers(); |
| } |
| } |
| |
| public void invalidatePreview() { |
| if (mPreset == null) { |
| return; |
| } |
| |
| mPreviewPreset.enqueuePreset(mPreset); |
| mPreviewBuffer.invalidate(); |
| invalidatePartialPreview(); |
| invalidateHighresPreview(); |
| needsUpdatePartialPreview(); |
| needsUpdateHighResPreview(); |
| mActivity.getProcessingService().updatePreviewBuffer(); |
| } |
| |
| public void setImageShowSize(int w, int h) { |
| if (mImageShowSize.x != w || mImageShowSize.y != h) { |
| mImageShowSize.set(w, h); |
| float maxWidth = mOriginalBounds.width() / (float) w; |
| float maxHeight = mOriginalBounds.height() / (float) h; |
| mMaxScaleFactor = Math.max(3.f, Math.max(maxWidth, maxHeight)); |
| needsUpdatePartialPreview(); |
| needsUpdateHighResPreview(); |
| } |
| } |
| |
| public Matrix originalImageToScreen() { |
| return computeImageToScreen(null, 0, true); |
| } |
| |
| public Matrix computeImageToScreen(Bitmap bitmapToDraw, |
| float rotate, |
| boolean applyGeometry) { |
| if (getOriginalBounds() == null |
| || mImageShowSize.x == 0 |
| || mImageShowSize.y == 0) { |
| return null; |
| } |
| |
| Matrix m = null; |
| float scale = 1f; |
| float translateX = 0; |
| float translateY = 0; |
| |
| if (applyGeometry) { |
| GeometryMathUtils.GeometryHolder holder = GeometryMathUtils.unpackGeometry( |
| mPreset.getGeometryFilters()); |
| m = GeometryMathUtils.getCropSelectionToScreenMatrix(null, holder, |
| getOriginalBounds().width(), getOriginalBounds().height(), |
| mImageShowSize.x, mImageShowSize.y); |
| } else if (bitmapToDraw != null) { |
| m = new Matrix(); |
| RectF size = new RectF(0, 0, |
| bitmapToDraw.getWidth(), |
| bitmapToDraw.getHeight()); |
| scale = mImageShowSize.x / size.width(); |
| if (size.width() < size.height()) { |
| scale = mImageShowSize.y / size.height(); |
| } |
| translateX = (mImageShowSize.x - (size.width() * scale)) / 2.0f; |
| translateY = (mImageShowSize.y - (size.height() * scale)) / 2.0f; |
| } else { |
| return null; |
| } |
| |
| Point translation = getTranslation(); |
| m.postScale(scale, scale); |
| m.postRotate(rotate, mImageShowSize.x / 2.0f, mImageShowSize.y / 2.0f); |
| m.postTranslate(translateX, translateY); |
| m.postTranslate(mShadowMargin, mShadowMargin); |
| m.postScale(getScaleFactor(), getScaleFactor(), |
| mImageShowSize.x / 2.0f, |
| mImageShowSize.y / 2.0f); |
| m.postTranslate(translation.x * getScaleFactor(), |
| translation.y * getScaleFactor()); |
| return m; |
| } |
| |
| public Matrix getImageToScreenMatrix(boolean reflectRotation) { |
| if (getOriginalBounds() == null || mImageShowSize.x == 0 || mImageShowSize.y == 0) { |
| return new Matrix(); |
| } |
| Matrix m = GeometryMathUtils.getImageToScreenMatrix(mPreset.getGeometryFilters(), |
| reflectRotation, getOriginalBounds(), mImageShowSize.x, mImageShowSize.y); |
| if (m == null) { |
| m = new Matrix(); |
| m.reset(); |
| return m; |
| } |
| Point translate = getTranslation(); |
| float scaleFactor = getScaleFactor(); |
| m.postTranslate(translate.x, translate.y); |
| m.postScale(scaleFactor, scaleFactor, mImageShowSize.x / 2.0f, mImageShowSize.y / 2.0f); |
| return m; |
| } |
| |
| private Matrix getScreenToImageMatrix(boolean reflectRotation) { |
| Matrix m = getImageToScreenMatrix(reflectRotation); |
| Matrix invert = new Matrix(); |
| m.invert(invert); |
| return invert; |
| } |
| |
| public void needsUpdateHighResPreview() { |
| if (!mSupportsHighRes) { |
| return; |
| } |
| if (mActivity.getProcessingService() == null) { |
| return; |
| } |
| if (mPreset == null) { |
| return; |
| } |
| mActivity.getProcessingService().postHighresRenderingRequest(mPreset, |
| getScaleFactor(), this); |
| invalidateHighresPreview(); |
| } |
| |
| public void needsUpdatePartialPreview() { |
| if (mPreset == null) { |
| return; |
| } |
| if (!mPreset.canDoPartialRendering()) { |
| invalidatePartialPreview(); |
| return; |
| } |
| Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); |
| if (originalToScreen == null) { |
| return; |
| } |
| Matrix screenToOriginal = new Matrix(); |
| originalToScreen.invert(screenToOriginal); |
| RectF bounds = new RectF(0, 0, |
| mImageShowSize.x + 2 * mShadowMargin, |
| mImageShowSize.y + 2 * mShadowMargin); |
| screenToOriginal.mapRect(bounds); |
| Rect rBounds = new Rect(); |
| bounds.roundOut(rBounds); |
| |
| mActivity.getProcessingService().postFullresRenderingRequest(mPreset, |
| getScaleFactor(), rBounds, |
| new Rect(0, 0, mImageShowSize.x, mImageShowSize.y), this); |
| invalidatePartialPreview(); |
| } |
| |
| @Override |
| public void available(RenderingRequest request) { |
| if (request.getBitmap() == null) { |
| return; |
| } |
| |
| boolean needsCheckModification = false; |
| if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) { |
| mBitmapCache.cache(mGeometryOnlyBitmap); |
| mGeometryOnlyBitmap = request.getBitmap(); |
| needsCheckModification = true; |
| } |
| if (request.getType() == RenderingRequest.FILTERS_RENDERING) { |
| mBitmapCache.cache(mFiltersOnlyBitmap); |
| mFiltersOnlyBitmap = request.getBitmap(); |
| notifyObservers(); |
| needsCheckModification = true; |
| } |
| if (request.getType() == RenderingRequest.PARTIAL_RENDERING |
| && request.getScaleFactor() == getScaleFactor()) { |
| mBitmapCache.cache(mPartialBitmap); |
| mPartialBitmap = request.getBitmap(); |
| mPartialBounds.set(request.getBounds()); |
| notifyObservers(); |
| needsCheckModification = true; |
| } |
| if (request.getType() == RenderingRequest.HIGHRES_RENDERING) { |
| mBitmapCache.cache(mHighresBitmap); |
| mHighresBitmap = request.getBitmap(); |
| notifyObservers(); |
| needsCheckModification = true; |
| } |
| if (needsCheckModification) { |
| mActivity.enableSave(hasModifications()); |
| } |
| } |
| |
| public static void reset() { |
| sMasterImage = null; |
| } |
| |
| public float getScaleFactor() { |
| return mScaleFactor; |
| } |
| |
| public void setScaleFactor(float scaleFactor) { |
| if (DISABLEZOOM) { |
| return; |
| } |
| if (scaleFactor == mScaleFactor) { |
| return; |
| } |
| mScaleFactor = scaleFactor; |
| invalidatePartialPreview(); |
| } |
| |
| public Point getTranslation() { |
| return mTranslation; |
| } |
| |
| public void setTranslation(Point translation) { |
| if (DISABLEZOOM) { |
| mTranslation.x = 0; |
| mTranslation.y = 0; |
| return; |
| } |
| mTranslation.x = translation.x; |
| mTranslation.y = translation.y; |
| needsUpdatePartialPreview(); |
| } |
| |
| public Point getOriginalTranslation() { |
| return mOriginalTranslation; |
| } |
| |
| public void setOriginalTranslation(Point originalTranslation) { |
| if (DISABLEZOOM) { |
| return; |
| } |
| mOriginalTranslation.x = originalTranslation.x; |
| mOriginalTranslation.y = originalTranslation.y; |
| } |
| |
| public void resetTranslation() { |
| mTranslation.x = 0; |
| mTranslation.y = 0; |
| needsUpdatePartialPreview(); |
| } |
| |
| public Bitmap getTemporaryThumbnailBitmap() { |
| if (mTemporaryThumbnail == null |
| && getOriginalBitmapSmall() != null) { |
| mTemporaryThumbnail = getOriginalBitmapSmall().copy(Bitmap.Config.ARGB_8888, true); |
| Canvas canvas = new Canvas(mTemporaryThumbnail); |
| canvas.drawARGB(200, 80, 80, 80); |
| } |
| return mTemporaryThumbnail; |
| } |
| |
| public Bitmap getThumbnailBitmap() { |
| return getOriginalBitmapSmall(); |
| } |
| |
| public Bitmap getLargeThumbnailBitmap() { |
| return getOriginalBitmapLarge(); |
| } |
| |
| public float getMaxScaleFactor() { |
| if (DISABLEZOOM) { |
| return 1; |
| } |
| return mMaxScaleFactor; |
| } |
| |
| public void setMaxScaleFactor(float maxScaleFactor) { |
| mMaxScaleFactor = maxScaleFactor; |
| } |
| |
| public boolean supportsHighRes() { |
| return mSupportsHighRes; |
| } |
| |
| public void setShowsOriginal(boolean value) { |
| mShowsOriginal = value; |
| notifyObservers(); |
| } |
| |
| public boolean showsOriginal() { |
| return mShowsOriginal; |
| } |
| |
| public void setLoadedPreset(ImagePreset preset) { |
| mLoadedPreset = preset; |
| } |
| |
| public ImagePreset getLoadedPreset() { |
| return mLoadedPreset; |
| } |
| |
| public List<ExifTag> getEXIF() { |
| return mEXIF; |
| } |
| |
| public BitmapCache getBitmapCache() { |
| return mBitmapCache; |
| } |
| |
| 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; |
| } |
| |
| // 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) { |
| primaryBm.recycle(); |
| primaryBm = null; |
| return false; |
| } |
| |
| DualCameraNativeEngine.getInstance().initDepthMap( |
| primaryBm, auxiliaryBm, mpoFilepath, |
| DualCameraNativeEngine.getInstance().getCalibFilepath(mActivity)); |
| |
| primaryBm.recycle(); |
| primaryBm = null; |
| auxiliaryBm.recycle(); |
| auxiliaryBm = null; |
| |
| 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; |
| } |
| } |