OSDN Git Service

Pinch to zoom refine
authornicolasroard <nicolasroard@google.com>
Thu, 21 Feb 2013 23:52:49 +0000 (15:52 -0800)
committernicolasroard <nicolasroard@google.com>
Fri, 22 Feb 2013 01:43:58 +0000 (17:43 -0800)
Change-Id: I538defa55a4ed898dd7c936ec813f052ac1b9e0a

24 files changed:
src/com/android/gallery3d/filtershow/PanelController.java
src/com/android/gallery3d/filtershow/cache/FilteringPipeline.java
src/com/android/gallery3d/filtershow/cache/ImageLoader.java
src/com/android/gallery3d/filtershow/cache/RenderingRequest.java
src/com/android/gallery3d/filtershow/filters/FilterCurvesRepresentation.java
src/com/android/gallery3d/filtershow/filters/FilterFxRepresentation.java
src/com/android/gallery3d/filtershow/filters/FilterRepresentation.java
src/com/android/gallery3d/filtershow/filters/ImageFilterBwFilter.java
src/com/android/gallery3d/filtershow/filters/ImageFilterContrast.java
src/com/android/gallery3d/filtershow/filters/ImageFilterEdge.java
src/com/android/gallery3d/filtershow/filters/ImageFilterExposure.java
src/com/android/gallery3d/filtershow/filters/ImageFilterHighlights.java
src/com/android/gallery3d/filtershow/filters/ImageFilterHue.java
src/com/android/gallery3d/filtershow/filters/ImageFilterKMeans.java
src/com/android/gallery3d/filtershow/filters/ImageFilterNegative.java
src/com/android/gallery3d/filtershow/filters/ImageFilterSaturated.java
src/com/android/gallery3d/filtershow/filters/ImageFilterShadows.java
src/com/android/gallery3d/filtershow/filters/ImageFilterSharpen.java
src/com/android/gallery3d/filtershow/filters/ImageFilterVibrance.java
src/com/android/gallery3d/filtershow/filters/ImageFilterWBalance.java
src/com/android/gallery3d/filtershow/imageshow/ImageShow.java
src/com/android/gallery3d/filtershow/imageshow/ImageZoom.java
src/com/android/gallery3d/filtershow/imageshow/MasterImage.java
src/com/android/gallery3d/filtershow/presets/ImagePreset.java

index cff07ff..5bda246 100644 (file)
@@ -375,11 +375,13 @@ public class PanelController implements OnClickListener {
         ImageShow image = null;
         mActivity.hideImageViews();
         for (View view : mImageViews) {
+            image = (ImageShow) view;
             if (view.getId() == id) {
                 view.setVisibility(View.VISIBLE);
-                image = (ImageShow) view;
+                image.select();
             } else {
                 view.setVisibility(View.GONE);
+                image.unselect();
             }
         }
         return image;
@@ -498,7 +500,7 @@ public class PanelController implements OnClickListener {
         }
         mUtilityPanel.hideAccessoryViews();
 
-        if (view instanceof FilterIconButton) {
+        if (view instanceof FilterIconButton && view.getId() != R.id.applyEffect) {
             mCurrentEditor = null;
             FilterIconButton component = (FilterIconButton) view;
             FilterRepresentation representation = component.getFilterRepresentation();
@@ -555,8 +557,8 @@ public class PanelController implements OnClickListener {
                 if (mCurrentImage instanceof ImageCrop && mUtilityPanel.firstTimeCropDisplayed) {
                     ((ImageCrop) mCurrentImage).clear();
                     mUtilityPanel.firstTimeCropDisplayed = false;
+                    ((ImageCrop) mCurrentImage).setFixedAspect(mFixedAspect);
                 }
-                ((ImageCrop) mCurrentImage).setFixedAspect(mFixedAspect);
                 break;
             }
             case R.id.rotateButton: {
index 419abe8..7d5b529 100644 (file)
@@ -48,6 +48,7 @@ public class FilteringPipeline implements Handler.Callback {
     private final static int NEW_RENDERING_REQUEST = 1;
     private final static int COMPUTE_PRESET = 2;
     private final static int COMPUTE_RENDERING_REQUEST = 3;
+    private final static int COMPUTE_PARTIAL_RENDERING_REQUEST = 4;
 
     private Handler mProcessingHandler = null;
     private final Handler mUIHandler = new Handler() {
@@ -81,7 +82,13 @@ public class FilteringPipeline implements Handler.Callback {
                 mUIHandler.sendMessage(uimsg);
                 break;
             }
-            case COMPUTE_RENDERING_REQUEST: {
+            case COMPUTE_RENDERING_REQUEST:
+            case COMPUTE_PARTIAL_RENDERING_REQUEST: {
+                if (msg.what == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+                    if (mProcessingHandler.hasMessages(COMPUTE_PARTIAL_RENDERING_REQUEST)) {
+                        return false;
+                    }
+                }
                 RenderingRequest request = (RenderingRequest) msg.obj;
                 render(request);
                 Message uimsg = mUIHandler.obtainMessage(NEW_RENDERING_REQUEST);
@@ -95,6 +102,7 @@ public class FilteringPipeline implements Handler.Callback {
 
     private static float RESIZE_FACTOR = 0.8f;
     private static float MAX_PROCESS_TIME = 100; // in ms
+    private static long HIRES_DELAY = 100; // in ms
     private float mResizeFactor = 1.0f;
     private long mResizeTime = 0;
 
@@ -165,9 +173,17 @@ public class FilteringPipeline implements Handler.Callback {
         if (mOriginalAllocation == null) {
             return;
         }
-        Message msg = mProcessingHandler.obtainMessage(COMPUTE_RENDERING_REQUEST);
+        int type = COMPUTE_RENDERING_REQUEST;
+        if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+            type = COMPUTE_PARTIAL_RENDERING_REQUEST;
+        }
+        Message msg = mProcessingHandler.obtainMessage(type);
         msg.obj = request;
-        mProcessingHandler.sendMessage(msg);
+        if (type == COMPUTE_PARTIAL_RENDERING_REQUEST) {
+            mProcessingHandler.sendMessageDelayed(msg, HIRES_DELAY);
+        } else {
+            mProcessingHandler.sendMessage(msg);
+        }
     }
 
     public synchronized void updatePreviewBuffer() {
@@ -210,11 +226,15 @@ public class FilteringPipeline implements Handler.Callback {
         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
             return "GEOMETRY_RENDERING";
         }
+        if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+            return "PARTIAL_RENDERING";
+        }
         return "UNKNOWN TYPE!";
     }
 
     private void render(RenderingRequest request) {
-        if (request.getBitmap() == null
+        if ((request.getType() != RenderingRequest.PARTIAL_RENDERING
+                && request.getBitmap() == null)
                 || request.getImagePreset() == null) {
             return;
         }
@@ -225,11 +245,21 @@ public class FilteringPipeline implements Handler.Callback {
         Bitmap bitmap = request.getBitmap();
         ImagePreset preset = request.getImagePreset();
         setPresetParameters(preset);
+
+        if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+            bitmap = MasterImage.getImage().getImageLoader().getScaleOneImageForPreset(null, preset, request.getBounds(), request.getDestination(), false);
+            if (bitmap == null) {
+                return;
+            }
+            bitmap = preset.applyGeometry(bitmap);
+        }
+
         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
             FiltersManager.getManager().resetBitmapsRS();
         }
 
-        if (request.getType() != RenderingRequest.ICON_RENDERING) {
+        if (request.getType() != RenderingRequest.ICON_RENDERING
+                && request.getType() != RenderingRequest.PARTIAL_RENDERING) {
             updateOriginalAllocation(preset);
         }
         if (DEBUG) {
@@ -243,9 +273,11 @@ public class FilteringPipeline implements Handler.Callback {
         } else if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
             mFiltersOnlyOriginalAllocation.copyTo(bitmap);
         }
+
         if (request.getType() == RenderingRequest.FULL_RENDERING
                 || request.getType() == RenderingRequest.FILTERS_RENDERING
-                || request.getType() == RenderingRequest.ICON_RENDERING) {
+                || request.getType() == RenderingRequest.ICON_RENDERING
+                || request.getType() == RenderingRequest.PARTIAL_RENDERING) {
             Bitmap bmp = preset.apply(bitmap);
             request.setBitmap(bmp);
         }
index 42e72e6..25bb6b6 100644 (file)
@@ -265,12 +265,12 @@ public class ImageLoader {
                 bitmap.getHeight(), matrix, true);
     }
 
-    private Bitmap loadRegionBitmap(Uri uri, Rect bounds) {
+    private Bitmap loadRegionBitmap(Uri uri, BitmapFactory.Options options, Rect bounds) {
         InputStream is = null;
         try {
             is = mContext.getContentResolver().openInputStream(uri);
             BitmapRegionDecoder decoder = BitmapRegionDecoder.newInstance(is, false);
-            return decoder.decodeRegion(bounds, null);
+            return decoder.decodeRegion(bounds, options);
         } catch (FileNotFoundException e) {
             Log.e(LOGTAG, "FileNotFoundException: " + uri);
         } catch (Exception e) {
@@ -370,11 +370,24 @@ public class ImageLoader {
     // FIXME: this currently does the loading + filtering on the UI thread --
     // need to move this to a background thread.
     public Bitmap getScaleOneImageForPreset(ImageShow caller, ImagePreset imagePreset, Rect bounds,
-            boolean force) {
+                                            Rect destination, boolean force) {
         mLoadingLock.lock();
         Bitmap bmp = mZoomCache.getImage(imagePreset, bounds);
         if (force || bmp == null) {
-            bmp = loadRegionBitmap(mUri, bounds);
+            BitmapFactory.Options options = null;
+            if (destination != null) {
+                options = new BitmapFactory.Options();
+                if (bounds.width() > destination.width()) {
+                    int sampleSize = 1;
+                    int w = bounds.width();
+                    while (w > destination.width()) {
+                        sampleSize *= 2;
+                        w /= sampleSize;
+                    }
+                    options.inSampleSize = sampleSize;
+                }
+            }
+            bmp = loadRegionBitmap(mUri, options, bounds);
             if (bmp != null) {
                 // TODO: this workaround for RS might not be needed ultimately
                 Bitmap bmp2 = bmp.copy(Bitmap.Config.ARGB_8888, true);
index 1e9f6b8..3ec74e2 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.gallery3d.filtershow.cache;
 
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import com.android.gallery3d.app.Log;
 import com.android.gallery3d.filtershow.imageshow.MasterImage;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
@@ -27,29 +28,46 @@ public class RenderingRequest {
     private Bitmap mBitmap = null;
     private ImagePreset mImagePreset = null;
     private RenderingRequestCaller mCaller = null;
+    private Rect mBounds = null;
+    private Rect mDestination = null;
     private int mType = FULL_RENDERING;
-    public static int FULL_RENDERING = 0;
-    public static int FILTERS_RENDERING = 1;
-    public static int GEOMETRY_RENDERING = 2;
-    public static int ICON_RENDERING = 3;
+    public static final int FULL_RENDERING = 0;
+    public static final int FILTERS_RENDERING = 1;
+    public static final int GEOMETRY_RENDERING = 2;
+    public static final int ICON_RENDERING = 3;
+    public static final int PARTIAL_RENDERING = 4;
     private static final Bitmap.Config mConfig = Bitmap.Config.ARGB_8888;
 
+    public static void post(Bitmap source, ImagePreset preset, int type, RenderingRequestCaller caller) {
+        RenderingRequest.post(source, preset, type, caller, null, null);
+    }
+
     public static void post(Bitmap source, ImagePreset preset, int type,
-                            RenderingRequestCaller caller) {
-        if (source == null || preset == null || caller == null) {
+                            RenderingRequestCaller caller, Rect bounds, Rect destination) {
+        if ((type != PARTIAL_RENDERING && source == null) || preset == null || caller == null) {
             Log.v(LOGTAG, "something null: source: " + source + " or preset: " + preset + " or caller: " + caller);
             return;
         }
         RenderingRequest request = new RenderingRequest();
         Bitmap bitmap = null;
-        if (type == FULL_RENDERING || type == GEOMETRY_RENDERING || type == ICON_RENDERING) {
+        if (type == FULL_RENDERING
+                || type == GEOMETRY_RENDERING
+                || type == ICON_RENDERING) {
             bitmap = preset.applyGeometry(source);
-        } else {
+        } else if (type != PARTIAL_RENDERING) {
             bitmap = Bitmap.createBitmap(source.getWidth(), source.getHeight(), mConfig);
         }
+
         request.setBitmap(bitmap);
         ImagePreset passedPreset = new ImagePreset(preset);
         passedPreset.setImageLoader(MasterImage.getImage().getImageLoader());
+
+        if (type == PARTIAL_RENDERING) {
+            request.setBounds(bounds);
+            request.setDestination(destination);
+            passedPreset.setPartialRendering(true, bounds);
+        }
+
         request.setImagePreset(passedPreset);
         request.setType(type);
         request.setCaller(caller);
@@ -103,4 +121,20 @@ public class RenderingRequest {
     public void setCaller(RenderingRequestCaller caller) {
         mCaller = caller;
     }
+
+    public Rect getBounds() {
+        return mBounds;
+    }
+
+    public void setBounds(Rect bounds) {
+        mBounds = bounds;
+    }
+
+    public Rect getDestination() {
+        return mDestination;
+    }
+
+    public void setDestination(Rect destination) {
+        mDestination = destination;
+    }
 }
index 6c83170..3511c67 100644 (file)
@@ -19,6 +19,7 @@ public class FilterCurvesRepresentation extends FilterRepresentation {
         setShowEditingControls(false);
         setShowParameterValue(false);
         setShowUtilityPanel(true);
+        setSupportsPartialRendering(true);
         for (int i = 0; i < mSplines.length; i++) {
             mSplines[i] = new Spline();
             mSplines[i].reset();
index 859bf32..d4128dc 100644 (file)
@@ -37,6 +37,7 @@ public class FilterFxRepresentation extends FilterRepresentation {
         setShowEditingControls(false);
         setShowParameterValue(false);
         setShowUtilityPanel(false);
+        setSupportsPartialRendering(true);
     }
 
     public String toString() {
index 513cdcd..83f2a1b 100644 (file)
@@ -25,6 +25,7 @@ public class FilterRepresentation implements Cloneable {
     private String mName;
     private int mPriority = TYPE_NORMAL;
     private Class mFilterClass;
+    private boolean mSupportsPartialRendering = false;
     private int mTextId = 0;
     private int mEditorId = BasicEditor.ID;
     private int mButtonId = 0;
@@ -52,6 +53,7 @@ public class FilterRepresentation implements Cloneable {
         representation.setName(getName());
         representation.setPriority(getPriority());
         representation.setFilterClass(getFilterClass());
+        representation.setSupportsPartialRendering(supportsPartialRendering());
         representation.setTextId(getTextId());
         representation.setEditorId(getEditorId());
         representation.setButtonId(getButtonId());
@@ -70,6 +72,7 @@ public class FilterRepresentation implements Cloneable {
         if (representation.mFilterClass == representation.mFilterClass
                 && representation.mName.equalsIgnoreCase(mName)
                 && representation.mPriority == mPriority
+                && representation.mSupportsPartialRendering == mSupportsPartialRendering
                 && representation.mTextId == mTextId
                 && representation.mEditorId == mEditorId
                 && representation.mButtonId == mButtonId
@@ -106,6 +109,14 @@ public class FilterRepresentation implements Cloneable {
         return false;
     }
 
+    public boolean supportsPartialRendering() {
+        return mSupportsPartialRendering;
+    }
+
+    public void setSupportsPartialRendering(boolean value) {
+        mSupportsPartialRendering = value;
+    }
+
     public void useParametersFrom(FilterRepresentation a) {
     }
 
index c92ac01..a4626cd 100644 (file)
@@ -36,6 +36,7 @@ public class ImageFilterBwFilter extends SimpleImageFilter {
         representation.setMinimum(-180);
         representation.setTextId(R.string.bwfilter);
         representation.setButtonId(R.id.bwfilterButton);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 2f94e3d..2097f0d 100644 (file)
@@ -37,6 +37,7 @@ public class ImageFilterContrast extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 55c7095..46a9a29 100644 (file)
@@ -32,6 +32,7 @@ public class ImageFilterEdge extends SimpleImageFilter {
         representation.setFilterClass(ImageFilterEdge.class);
         representation.setTextId(R.string.edge);
         representation.setButtonId(R.id.edgeButton);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 7a8df71..b0b0b2d 100644 (file)
@@ -36,6 +36,7 @@ public class ImageFilterExposure extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index b9a1465..12f032d 100644 (file)
@@ -41,6 +41,7 @@ public class ImageFilterHighlights extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 8c484c7..b1f9f73 100644 (file)
@@ -39,6 +39,7 @@ public class ImageFilterHue extends SimpleImageFilter {
         representation.setTextId(R.string.hue);
         representation.setButtonId(R.id.hueButton);
         representation.setEditorId(BasicEditor.ID);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index f48bd04..6f785ef 100644 (file)
@@ -45,6 +45,7 @@ public class ImageFilterKMeans extends SimpleImageFilter {
         representation.setPreviewValue(4);
         representation.setTextId(R.string.kmeans);
         representation.setButtonId(R.id.kmeansButton);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 841c5c9..c256686 100644 (file)
@@ -19,6 +19,7 @@ public class ImageFilterNegative extends ImageFilter {
         representation.setShowEditingControls(false);
         representation.setShowParameterValue(false);
         representation.setEditorId(ImageOnlyEditor.ID);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 6cd8332..0febe49 100644 (file)
@@ -37,6 +37,7 @@ public class ImageFilterSaturated extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index e178239..fd67ee8 100644 (file)
@@ -37,6 +37,7 @@ public class ImageFilterShadows extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 9c99d57..8afa474 100644 (file)
@@ -37,7 +37,8 @@ public class ImageFilterSharpen extends ImageFilterRS {
         representation.setTextId(R.string.sharpness);
         representation.setButtonId(R.id.sharpenButton);
         representation.setOverlayId(R.drawable.filtershow_button_colors_sharpen);
-        representation.setEditorId(R.id.imageZoom);
+        representation.setEditorId(R.id.imageShow);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index a57af71..ea315d3 100644 (file)
@@ -36,6 +36,7 @@ public class ImageFilterVibrance extends SimpleImageFilter {
         representation.setMinimum(-100);
         representation.setMaximum(100);
         representation.setDefaultValue(0);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index 2f48523..c4c293a 100644 (file)
@@ -37,6 +37,7 @@ public class ImageFilterWBalance extends ImageFilter {
         representation.setShowEditingControls(false);
         representation.setShowParameterValue(false);
         representation.setEditorId(ImageOnlyEditor.ID);
+        representation.setSupportsPartialRendering(true);
         return representation;
     }
 
index b91ebd1..39e0cc8 100644 (file)
@@ -21,15 +21,16 @@ import android.graphics.*;
 import android.net.Uri;
 import android.os.Handler;
 import android.util.AttributeSet;
+import android.util.Log;
 import android.view.*;
 import android.view.GestureDetector.OnDoubleTapListener;
 import android.view.GestureDetector.OnGestureListener;
 import android.widget.LinearLayout;
 
-import com.android.gallery3d.app.Log;
 import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.PanelController;
 import com.android.gallery3d.filtershow.cache.ImageLoader;
+import com.android.gallery3d.filtershow.cache.RenderingRequestCaller;
 import com.android.gallery3d.filtershow.filters.ImageFilter;
 import com.android.gallery3d.filtershow.presets.ImagePreset;
 
@@ -229,6 +230,10 @@ public class ImageShow extends View implements OnGestureListener,
      */
     protected Matrix getImageToScreenMatrix(boolean reflectRotation) {
         GeometryMetadata geo = getImagePreset().mGeoData;
+        if (geo == null || mImageLoader == null
+                || mImageLoader.getOriginalBounds() == null) {
+            return new Matrix();
+        }
         Matrix m = geo.getOriginalToScreen(reflectRotation,
                 mImageLoader.getOriginalBounds().width(),
                 mImageLoader.getOriginalBounds().height(), getWidth(), getHeight());
@@ -291,7 +296,7 @@ public class ImageShow extends View implements OnGestureListener,
 
     @Override
     public void onDraw(Canvas canvas) {
-
+        MasterImage.getImage().setImageShowSize(getWidth(), getHeight());
         canvas.save();
         // TODO: center scale on gesture
         float cx = canvas.getWidth()/2.0f;
@@ -315,6 +320,12 @@ public class ImageShow extends View implements OnGestureListener,
                     1.5f * mTextPadding, mPaint);
         }
 
+        Bitmap partialPreview = MasterImage.getImage().getPartialImage();
+        if (partialPreview != null) {
+            Rect src = new Rect(0, 0, partialPreview.getWidth(), partialPreview.getHeight());
+            Rect dest = new Rect(0, 0, getWidth(), getHeight());
+            canvas.drawBitmap(partialPreview, src, dest, mPaint);
+        }
         drawToast(canvas);
     }
 
@@ -547,6 +558,7 @@ public class ImageShow extends View implements OnGestureListener,
                     Point translation = MasterImage.getImage().getTranslation();
                     translation.x = (int) (originalTranslation.x + translateX);
                     translation.y = (int) (originalTranslation.y + translateY);
+                    MasterImage.getImage().setTranslation(translation);
                 }
             } else if (!mOriginalDisabled && !mActivity.isShowingHistoryPanel()
                     && (System.currentTimeMillis() - mTouchShowOriginalDate
@@ -682,4 +694,5 @@ public class ImageShow extends View implements OnGestureListener,
         }
         return false;
     }
+
 }
index 0e32dc1..eb568c3 100644 (file)
@@ -90,7 +90,7 @@ public class ImageZoom extends ImageShow {
         Bitmap filteredImage = null;
         if ((mZoomedIn || mTouchDown) && mImageLoader != null) {
             filteredImage = mImageLoader.getScaleOneImageForPreset(this, getImagePreset(),
-                    mZoomBounds, false);
+                    mZoomBounds, null, false);
         } else {
             filteredImage = getFilteredImage();
         }
index 905d2c3..9eafe22 100644 (file)
@@ -16,9 +16,7 @@
 
 package com.android.gallery3d.filtershow.imageshow;
 
-import android.graphics.Bitmap;
-import android.graphics.Point;
-import android.graphics.RectF;
+import android.graphics.*;
 
 import com.android.gallery3d.filtershow.FilterShowActivity;
 import com.android.gallery3d.filtershow.HistoryAdapter;
@@ -45,6 +43,7 @@ public class MasterImage implements RenderingRequestCaller {
 
     private Bitmap mGeometryOnlyBitmap = null;
     private Bitmap mFiltersOnlyBitmap = null;
+    private Bitmap mPartialBitmap = null;
 
     private ImageLoader mLoader = null;
     private HistoryAdapter mHistory = null;
@@ -62,6 +61,8 @@ public class MasterImage implements RenderingRequestCaller {
     private Point mTranslation = new Point();
     private Point mOriginalTranslation = new Point();
 
+    private Point mImageShowSize = new Point();
+
     private MasterImage() {
     }
 
@@ -193,6 +194,10 @@ public class MasterImage implements RenderingRequestCaller {
         return mGeometryOnlyBitmap;
     }
 
+    public Bitmap getPartialImage() {
+        return mPartialBitmap;
+    }
+
     public void notifyObservers() {
         for (ImageShow observer : mObservers) {
             observer.invalidate();
@@ -221,6 +226,7 @@ public class MasterImage implements RenderingRequestCaller {
             }
         }
         invalidatePreview();
+        needsUpdateFullResPreview();
         mActivity.enableSave(hasModifications());
     }
 
@@ -237,11 +243,67 @@ public class MasterImage implements RenderingRequestCaller {
         updatePresets(false);
     }
 
+    public void invalidatePartialPreview() {
+        if (mPartialBitmap != null) {
+            mPartialBitmap = null;
+            notifyObservers();
+        }
+    }
+
     public void invalidatePreview() {
         mFilteredPreview.invalidate();
+        invalidatePartialPreview();
+        needsUpdateFullResPreview();
         FilteringPipeline.getPipeline().updatePreviewBuffer();
     }
 
+    public void setImageShowSize(int w, int h) {
+        if (mImageShowSize.x != w || mImageShowSize.y != h) {
+            mImageShowSize.set(w, h);
+            needsUpdateFullResPreview();
+        }
+    }
+
+    private Matrix getImageToScreenMatrix(boolean reflectRotation) {
+        GeometryMetadata geo = mPreset.mGeoData;
+        if (geo == null || mLoader == null
+                || mLoader.getOriginalBounds() == null
+                || mImageShowSize.x == 0) {
+            return new Matrix();
+        }
+        Matrix m = geo.getOriginalToScreen(reflectRotation,
+                mLoader.getOriginalBounds().width(),
+                mLoader.getOriginalBounds().height(), mImageShowSize.x, mImageShowSize.y);
+        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 needsUpdateFullResPreview() {
+        if (!mPreset.canDoPartialRendering()) {
+            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);
+        RenderingRequest.post(null, mPreset, RenderingRequest.PARTIAL_RENDERING,
+                this, bounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y));
+        invalidatePartialPreview();
+    }
+
     @Override
     public void available(RenderingRequest request) {
         if (request.getBitmap() == null) {
@@ -253,6 +315,10 @@ public class MasterImage implements RenderingRequestCaller {
         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
             mFiltersOnlyBitmap = request.getBitmap();
         }
+        if (request.getType() == RenderingRequest.PARTIAL_RENDERING) {
+            mPartialBitmap = request.getBitmap();
+            notifyObservers();
+        }
     }
 
     public static void reset() {
@@ -275,6 +341,7 @@ public class MasterImage implements RenderingRequestCaller {
 
     public void setScaleFactor(float scaleFactor) {
         mScaleFactor = scaleFactor;
+        needsUpdateFullResPreview();
     }
 
     public Point getTranslation() {
@@ -282,7 +349,9 @@ public class MasterImage implements RenderingRequestCaller {
     }
 
     public void setTranslation(Point translation) {
-        mTranslation = translation;
+        mTranslation.x = translation.x;
+        mTranslation.y = translation.y;
+        needsUpdateFullResPreview();
     }
 
     public Point getOriginalTranslation() {
@@ -297,5 +366,6 @@ public class MasterImage implements RenderingRequestCaller {
     public void resetTranslation() {
         mTranslation.x = 0;
         mTranslation.y = 0;
+        needsUpdateFullResPreview();
     }
 }
index 84266c5..ae5a034 100644 (file)
@@ -17,6 +17,7 @@
 package com.android.gallery3d.filtershow.presets;
 
 import android.graphics.Bitmap;
+import android.graphics.Rect;
 import android.util.Log;
 
 import com.android.gallery3d.filtershow.ImageStateAdapter;
@@ -52,6 +53,8 @@ public class ImagePreset {
     private boolean mDoApplyFilters = true;
 
     public final GeometryMetadata mGeoData = new GeometryMetadata();
+    private boolean mPartialRendering = false;
+    private Rect mPartialRenderingBounds;
 
     public ImagePreset() {
         setup();
@@ -421,6 +424,22 @@ public class ImagePreset {
         return bitmap;
     }
 
+    public boolean canDoPartialRendering() {
+        if (mGeoData.hasModifications()) {
+            return false;
+        }
+        for (int i = 0; i < mFilters.size(); i++) {
+            FilterRepresentation representation = null;
+            synchronized (mFilters) {
+                representation = mFilters.elementAt(i);
+            }
+            if (!representation.supportsPartialRendering()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
     public void fillImageStateAdapter(ImageStateAdapter imageStateAdapter) {
         if (imageStateAdapter == null) {
             return;
@@ -446,4 +465,17 @@ public class ImagePreset {
     public void setScaleFactor(float value) {
         mScaleFactor = value;
     }
+
+    public void setPartialRendering(boolean partialRendering, Rect bounds) {
+        mPartialRendering = partialRendering;
+        mPartialRenderingBounds = bounds;
+    }
+
+    public boolean isPartialRendering() {
+        return mPartialRendering;
+    }
+
+    public Rect getPartialRenderingBounds() {
+        return mPartialRenderingBounds;
+    }
 }