diff options
author | nicolasroard <nicolasroard@google.com> | 2013-09-10 13:58:30 -0700 |
---|---|---|
committer | nicolasroard <nicolasroard@google.com> | 2013-09-12 08:26:23 -0700 |
commit | 34e8432353acb0c45253cf4ef855512c7472019b (patch) | |
tree | 8ed962acfb79b11746373d65763a9f7c7f10523e /src | |
parent | 5d727d85d58ad03edbcdd62c533bb14fdd5dda19 (diff) | |
download | android_packages_apps_Gallery2-34e8432353acb0c45253cf4ef855512c7472019b.tar.gz android_packages_apps_Gallery2-34e8432353acb0c45253cf4ef855512c7472019b.tar.bz2 android_packages_apps_Gallery2-34e8432353acb0c45253cf4ef855512c7472019b.zip |
Fix full-res geometry
Change-Id: I25f2fde1031ba7d896c82484a3da0ea03bcff7b8
Diffstat (limited to 'src')
4 files changed, 161 insertions, 101 deletions
diff --git a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java index 92942d4fc..3f9df23b6 100644 --- a/src/com/android/gallery3d/filtershow/cache/ImageLoader.java +++ b/src/com/android/gallery3d/filtershow/cache/ImageLoader.java @@ -65,7 +65,7 @@ public final class ImageLoader { public static final int ORI_TRANSVERSE = ExifInterface.Orientation.LEFT_BOTTOM; private static final int BITMAP_LOAD_BACKOUT_ATTEMPTS = 5; - + private static final float OVERDRAW_ZOOM = 1.2f; private ImageLoader() {} /** @@ -235,7 +235,7 @@ public final class ImageLoader { * if it is a subset of the bitmap stored at uri. Otherwise returns * null. */ - public static Bitmap loadRegionBitmap(Context context, FilterEnvironment environment, + public static Bitmap loadRegionBitmap(Context context, BitmapCache cache, Uri uri, BitmapFactory.Options options, Rect bounds) { InputStream is = null; @@ -254,23 +254,15 @@ public final class ImageLoader { // return null if bounds are not entirely within the bitmap if (!r.contains(imageBounds)) { imageBounds.intersect(r); + bounds.left = imageBounds.left; + bounds.top = imageBounds.top; } - Bitmap reuse = environment.getBitmap(imageBounds.width(), + Bitmap reuse = cache.getBitmap(imageBounds.width(), imageBounds.height(), BitmapCache.REGION); options.inBitmap = reuse; Bitmap bitmap = decoder.decodeRegion(imageBounds, options); if (bitmap != reuse) { - environment.cache(reuse); // not reused, put back in cache - } - if (imageBounds.width() != bounds.width() || imageBounds.height() != bounds.height()) { - Bitmap temp = environment.getBitmap(bounds.width(), - bounds.height(), BitmapCache.REGION); - Canvas canvas = new Canvas(temp); - canvas.drawARGB(0, 0, 0, 0); - float dx = imageBounds.left - bounds.left; - float dy = imageBounds.top - bounds.top; - canvas.drawBitmap(bitmap, dx, dy, null); - return temp; + cache.cache(reuse); // not reused, put back in cache } return bitmap; } catch (FileNotFoundException e) { @@ -404,24 +396,24 @@ public final class ImageLoader { } public static Bitmap getScaleOneImageForPreset(Context context, - FilterEnvironment environment, + BitmapCache cache, Uri uri, Rect bounds, Rect destination) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inMutable = true; if (destination != null) { - if (bounds.width() > destination.width()) { + int thresholdWidth = (int) (destination.width() * OVERDRAW_ZOOM); + if (bounds.width() > thresholdWidth) { int sampleSize = 1; int w = bounds.width(); - while (w > destination.width()) { + while (w > thresholdWidth) { sampleSize *= 2; w /= sampleSize; } options.inSampleSize = sampleSize; } } - Bitmap bmp = loadRegionBitmap(context, environment, uri, options, bounds); - return bmp; + return loadRegionBitmap(context, cache, uri, options, bounds); } /** diff --git a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java index 56fdd7d67..3234c2516 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java +++ b/src/com/android/gallery3d/filtershow/imageshow/ImageShow.java @@ -27,10 +27,10 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Point; import android.graphics.Rect; +import android.graphics.RectF; import android.graphics.Shader; import android.graphics.drawable.NinePatchDrawable; import android.util.AttributeSet; -import android.util.Log; import android.view.GestureDetector; import android.view.GestureDetector.OnDoubleTapListener; import android.view.GestureDetector.OnGestureListener; @@ -49,7 +49,6 @@ import com.android.gallery3d.filtershow.tools.SaveImage; import java.io.File; import java.util.ArrayList; -import java.util.Collection; public class ImageShow extends View implements OnGestureListener, ScaleGestureDetector.OnScaleGestureListener, @@ -233,6 +232,9 @@ public class ImageShow extends View implements OnGestureListener, @Override public void onDraw(Canvas canvas) { + mPaint.reset(); + mPaint.setAntiAlias(true); + mPaint.setFilterBitmap(true); MasterImage.getImage().setImageShowSize( getWidth() - 2*mShadowMargin, getHeight() - 2*mShadowMargin); @@ -248,53 +250,43 @@ public class ImageShow extends View implements OnGestureListener, } else if (img.getLoadedPreset() != null) { return; } + mActivity.stopLoadingIndicator(); } - float cx = canvas.getWidth()/2.0f; - float cy = canvas.getHeight()/2.0f; - float scaleFactor = MasterImage.getImage().getScaleFactor(); - Point translation = MasterImage.getImage().getTranslation(); - canvas.save(); mShadowDrawn = false; - canvas.save(); - // TODO: center scale on gesture - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); Bitmap highresPreview = MasterImage.getImage().getHighresImage(); + Bitmap fullHighres = MasterImage.getImage().getPartialImage(); boolean isDoingNewLookAnimation = MasterImage.getImage().onGoingNewLookAnimation(); - if (!isDoingNewLookAnimation && highresPreview != null) { - drawImage(canvas, highresPreview, true); + if (highresPreview == null || isDoingNewLookAnimation) { + drawImageAndAnimate(canvas, getFilteredImage()); } else { - drawImage(canvas, getFilteredImage(), true); + drawImageAndAnimate(canvas, highresPreview); } - canvas.restore(); - Bitmap partialPreview = MasterImage.getImage().getPartialImage(); - if (!isDoingNewLookAnimation && partialPreview != null) { - canvas.save(); - Rect originalBounds = MasterImage.getImage().getOriginalBounds(); - Collection<FilterRepresentation> geo = MasterImage.getImage().getPreset() - .getGeometryFilters(); - - Matrix compensation = GeometryMathUtils.getPartialToScreenMatrix(geo, - originalBounds, getWidth(), getHeight(), - partialPreview.getWidth(), partialPreview.getHeight()); - canvas.drawBitmap(partialPreview, compensation, null); - canvas.restore(); - } + drawHighresImage(canvas, fullHighres); + drawCompareImage(canvas, getGeometryOnlyImage()); - canvas.save(); - canvas.scale(scaleFactor, scaleFactor, cx, cy); - canvas.translate(translation.x, translation.y); - drawPartialImage(canvas, getGeometryOnlyImage()); canvas.restore(); + } - canvas.restore(); + private void drawHighresImage(Canvas canvas, Bitmap fullHighres) { + Matrix originalToScreen = MasterImage.getImage().originalImageToScreen(); + if (fullHighres != null && originalToScreen != null) { + Matrix screenToOriginal = new Matrix(); + originalToScreen.invert(screenToOriginal); + Rect rBounds = new Rect(); + rBounds.set(MasterImage.getImage().getPartialBounds()); + if (fullHighres != null) { + originalToScreen.preTranslate(rBounds.left, rBounds.top); + canvas.clipRect(mImageBounds); + canvas.drawBitmap(fullHighres, originalToScreen, mPaint); + } + } } public void resetImageCaches(ImageShow caller) { @@ -313,56 +305,68 @@ public class ImageShow extends View implements OnGestureListener, return MasterImage.getImage().getFilteredImage(); } - public void drawImage(Canvas canvas, Bitmap image, boolean updateBounds) { + public void drawImageAndAnimate(Canvas canvas, + Bitmap image) { if (image == null) { return; } - - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); - - if (updateBounds) { - mImageBounds = d; + Matrix m = MasterImage.getImage().computeImageToScreen(image, 0, false); + if (m == null) { + return; } - float centerX = mShadowMargin + (getWidth() - 2 * mShadowMargin) / 2; - float centerY = mShadowMargin + (getHeight() - 2 * mShadowMargin) / 2; - - MasterImage master = MasterImage.getImage(); canvas.save(); + MasterImage master = MasterImage.getImage(); + + RectF d = new RectF(0, 0, image.getWidth(), image.getHeight()); + m.mapRect(d); + d.roundOut(mImageBounds); + if (master.onGoingNewLookAnimation() || mDidStartAnimation) { mDidStartAnimation = true; + canvas.save(); + + // Animation uses the image before the change + Bitmap previousImage = master.getPreviousImage(); + Matrix mp = MasterImage.getImage().computeImageToScreen(previousImage, 0, false); + RectF dp = new RectF(0, 0, previousImage.getWidth(), previousImage.getHeight()); + mp.mapRect(dp); + Rect previousBounds = new Rect(); + dp.roundOut(previousBounds); + float centerX = dp.centerX(); + float centerY = dp.centerY(); + boolean needsToDrawImage = true; + if (master.getCurrentLookAnimation() - == MasterImage.CIRCLE_ANIMATION - && MasterImage.getImage().getPreviousImage() != null) { + == MasterImage.CIRCLE_ANIMATION) { float maskScale = MasterImage.getImage().getMaskScale(); if (maskScale >= 0.0f) { float maskW = sMask.getWidth() / 2.0f; float maskH = sMask.getHeight() / 2.0f; - float x = centerX - maskW * maskScale; - float y = centerY - maskH * maskScale; Point point = mActivity.hintTouchPoint(this); - x = point.x - maskW * maskScale; - y = point.y - maskH * maskScale; + float x = point.x - maskW * maskScale; + float y = point.y - maskH * maskScale; // Prepare the shader mShaderMatrix.reset(); mShaderMatrix.setScale(1.0f / maskScale, 1.0f / maskScale); - mShaderMatrix.preTranslate(-x + d.left, -y + d.top); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); + mShaderMatrix.preTranslate(-x + mImageBounds.left, -y + mImageBounds.top); + float scaleImageX = mImageBounds.width() / (float) image.getWidth(); + float scaleImageY = mImageBounds.height() / (float) image.getHeight(); mShaderMatrix.preScale(scaleImageX, scaleImageY); mMaskPaint.reset(); mMaskPaint.setShader(createShader(image)); mMaskPaint.getShader().setLocalMatrix(mShaderMatrix); - drawImage(canvas, MasterImage.getImage().getPreviousImage()); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(previousImage, m, mPaint); + canvas.clipRect(mImageBounds); canvas.translate(x, y); canvas.scale(maskScale, maskScale); canvas.drawBitmap(sMask, 0, 0, mMaskPaint); - } else { - drawImage(canvas, image); + needsToDrawImage = false; } } else if (master.getCurrentLookAnimation() == MasterImage.ROTATE_ANIMATION) { @@ -375,7 +379,6 @@ public class ImageShow extends View implements OnGestureListener, + (finalScale * master.getAnimFraction()); canvas.rotate(master.getAnimRotationValue(), centerX, centerY); canvas.scale(finalScale, finalScale, centerX, centerY); - drawImage(canvas, master.getPreviousImage()); } else if (master.getCurrentLookAnimation() == MasterImage.MIRROR_ANIMATION) { if (master.getCurrentFilterRepresentation() @@ -411,10 +414,17 @@ public class ImageShow extends View implements OnGestureListener, } } } - drawImage(canvas, master.getPreviousImage()); } + + if (needsToDrawImage) { + drawShadow(canvas, previousBounds); // as needed + canvas.drawBitmap(previousImage, mp, mPaint); + } + + canvas.restore(); } else { - drawImage(canvas, image); + drawShadow(canvas, mImageBounds); // as needed + canvas.drawBitmap(image, m, mPaint); } if (!master.onGoingNewLookAnimation() @@ -423,19 +433,8 @@ public class ImageShow extends View implements OnGestureListener, mDidStartAnimation = false; MasterImage.getImage().resetAnimBitmap(); } - canvas.restore(); - } - private void drawImage(Canvas canvas, Bitmap image) { - Rect d = computeImageBounds(image.getWidth(), image.getHeight()); - float scaleImageX = d.width() / (float) image.getWidth(); - float scaleImageY = d.height() / (float) image.getHeight(); - Matrix imageMatrix = new Matrix(); - imageMatrix.postScale(scaleImageX, scaleImageY); - imageMatrix.postTranslate(d.left, d.top); - drawShadow(canvas, d); - canvas.clipRect(d); - canvas.drawBitmap(image, imageMatrix, mPaint); + canvas.restore(); } private Rect computeImageBounds(int imageWidth, int imageHeight) { @@ -462,7 +461,7 @@ public class ImageShow extends View implements OnGestureListener, } } - public void drawPartialImage(Canvas canvas, Bitmap image) { + public void drawCompareImage(Canvas canvas, Bitmap image) { boolean showsOriginal = MasterImage.getImage().showsOriginal(); if (!showsOriginal && !mTouchShowOriginal) return; @@ -503,7 +502,8 @@ public class ImageShow extends View implements OnGestureListener, } } canvas.clipRect(d); - drawImage(canvas, image, false); + Matrix m = MasterImage.getImage().computeImageToScreen(image, 0, false); + canvas.drawBitmap(image, m, mPaint); Paint paint = new Paint(); paint.setColor(Color.BLACK); paint.setStrokeWidth(3); @@ -658,7 +658,6 @@ public class ImageShow extends View implements OnGestureListener, translation.y = (int) (Math.signum(translation.y) * maxTranslationY); } - } } diff --git a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java index e0f328746..bad2012b6 100644 --- a/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java +++ b/src/com/android/gallery3d/filtershow/imageshow/MasterImage.java @@ -25,7 +25,6 @@ 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; @@ -85,6 +84,8 @@ public class MasterImage implements RenderingRequestCaller { private Bitmap mHighresBitmap = null; private Bitmap mPreviousImage = null; private ImagePreset mPreviousPreset = null; + private int mShadowMargin = 15; // not scaled, fixed in the asset + private Rect mPartialBounds = new Rect(); private ValueAnimator mAnimator = null; private float mMaskScale = 1; @@ -360,6 +361,10 @@ public class MasterImage implements RenderingRequestCaller { return mPartialBitmap; } + public Rect getPartialBounds() { + return mPartialBounds; + } + public Bitmap getHighresImage() { if (mHighresBitmap == null) { return getFilteredImage(); @@ -470,6 +475,7 @@ public class MasterImage implements RenderingRequestCaller { mOnGoingNewLookAnimation = false; mCurrentAnimRotationStartValue = 0; mAnimator = null; + notifyObservers(); } @Override @@ -566,11 +572,66 @@ public class MasterImage implements RenderingRequestCaller { 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; + } + private Matrix getImageToScreenMatrix(boolean reflectRotation) { if (getOriginalBounds() == null || mImageShowSize.x == 0 || mImageShowSize.y == 0) { return new Matrix(); @@ -619,14 +680,21 @@ public class MasterImage implements RenderingRequestCaller { invalidatePartialPreview(); return; } - Matrix m = getScreenToImageMatrix(true); - RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y); - RectF dest = new RectF(); - m.mapRect(dest, r); - Rect bounds = new Rect(); - dest.roundOut(bounds); + 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(), bounds, + getScaleFactor(), rBounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y), this); invalidatePartialPreview(); } @@ -653,6 +721,7 @@ public class MasterImage implements RenderingRequestCaller { && request.getScaleFactor() == getScaleFactor()) { mBitmapCache.cache(mPartialBitmap); mPartialBitmap = request.getBitmap(); + mPartialBounds.set(request.getBounds()); notifyObservers(); needsCheckModification = true; } diff --git a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java index 2a4b09952..07ab14ac9 100644 --- a/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java +++ b/src/com/android/gallery3d/filtershow/pipeline/CachingPipeline.java @@ -306,7 +306,7 @@ public class CachingPipeline implements PipelineInterface { if (request.getType() == RenderingRequest.PARTIAL_RENDERING) { MasterImage master = MasterImage.getImage(); bitmap = ImageLoader.getScaleOneImageForPreset(master.getActivity(), - mEnvironment, + mEnvironment.getBimapCache(), master.getUri(), request.getBounds(), request.getDestination()); if (bitmap == null) { |