OSDN Git Service

am af65d7ba: Merge "Add HTC One picture resolutions" into gb-ub-photos-bryce
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / filtershow / imageshow / MasterImage.java
1 /*
2  * Copyright (C) 2013 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.android.gallery3d.filtershow.imageshow;
18
19 import android.graphics.*;
20 import android.os.Handler;
21 import android.os.Message;
22
23 import android.util.Log;
24 import com.android.gallery3d.filtershow.FilterShowActivity;
25 import com.android.gallery3d.filtershow.HistoryAdapter;
26 import com.android.gallery3d.filtershow.cache.*;
27 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
28 import com.android.gallery3d.filtershow.filters.ImageFilter;
29 import com.android.gallery3d.filtershow.presets.ImagePreset;
30 import com.android.gallery3d.filtershow.state.StateAdapter;
31
32 import java.util.Vector;
33
34 public class MasterImage implements RenderingRequestCaller {
35
36     private static final String LOGTAG = "MasterImage";
37     private boolean DEBUG  = false;
38     private static final boolean DISABLEZOOM = false;
39     private static MasterImage sMasterImage = null;
40     private static int sIconSeedSize = 128;
41     private static float sHistoryPreviewSize = 128.0f;
42
43     private boolean mSupportsHighRes = false;
44
45     private ImageFilter mCurrentFilter = null;
46     private ImagePreset mPreset = null;
47     private ImagePreset mGeometryOnlyPreset = null;
48     private ImagePreset mFiltersOnlyPreset = null;
49
50     private TripleBufferBitmap mFilteredPreview = new TripleBufferBitmap();
51
52     private Bitmap mGeometryOnlyBitmap = null;
53     private Bitmap mFiltersOnlyBitmap = null;
54     private Bitmap mPartialBitmap = null;
55     private Bitmap mHighresBitmap = null;
56
57     private ImageLoader mLoader = null;
58     private HistoryAdapter mHistory = null;
59     private StateAdapter mState = null;
60
61     private FilterShowActivity mActivity = null;
62
63     private Vector<ImageShow> mObservers = new Vector<ImageShow>();
64     private FilterRepresentation mCurrentFilterRepresentation;
65     private Vector<GeometryListener> mGeometryListeners = new Vector<GeometryListener>();
66
67     private GeometryMetadata mPreviousGeometry = null;
68
69     private float mScaleFactor = 1.0f;
70     private float mMaxScaleFactor = 3.0f; // TODO: base this on the current view / image
71     private Point mTranslation = new Point();
72     private Point mOriginalTranslation = new Point();
73
74     private Point mImageShowSize = new Point();
75
76     private boolean mShowsOriginal;
77
78     final private static int NEW_GEOMETRY = 1;
79
80     private final Handler mHandler = new Handler() {
81             @Override
82         public void handleMessage(Message msg) {
83             switch (msg.what) {
84                 case NEW_GEOMETRY: {
85                 hasNewGeometry();
86                 break;
87             }
88             }
89         }
90     };
91
92     private MasterImage() {
93     }
94
95     // TODO: remove singleton
96     public static void setMaster(MasterImage master) {
97         sMasterImage = master;
98     }
99
100     public static MasterImage getImage() {
101         if (sMasterImage == null) {
102             sMasterImage = new MasterImage();
103         }
104         return sMasterImage;
105     }
106
107     public void setSupportsHighRes(boolean value) {
108         mSupportsHighRes = value;
109     }
110
111     public static void setIconSeedSize(int iconSeedSize) {
112         sIconSeedSize = iconSeedSize;
113     }
114
115     public void addObserver(ImageShow observer) {
116         if (mObservers.contains(observer)) {
117             return;
118         }
119         mObservers.add(observer);
120     }
121
122     public void setActivity(FilterShowActivity activity) {
123         mActivity = activity;
124     }
125
126     public ImageLoader getLoader() {
127         return mLoader;
128     }
129
130     public synchronized ImagePreset getPreset() {
131         return mPreset;
132     }
133
134     public synchronized ImagePreset getGeometryPreset() {
135         return mGeometryOnlyPreset;
136     }
137
138     public synchronized ImagePreset getFiltersOnlyPreset() {
139         return mFiltersOnlyPreset;
140     }
141
142     public synchronized void setPreset(ImagePreset preset, boolean addToHistory) {
143         preset.showFilters();
144         mPreset = preset;
145         mPreset.setImageLoader(mLoader);
146         setGeometry();
147         mPreset.fillImageStateAdapter(mState);
148         if (addToHistory) {
149             mHistory.addHistoryItem(mPreset);
150         }
151         updatePresets(true);
152         GeometryMetadata geo = mPreset.mGeoData;
153         if (!geo.equals(mPreviousGeometry)) {
154             notifyGeometryChange();
155         }
156         mPreviousGeometry = new GeometryMetadata(geo);
157     }
158
159     private void renderHistoryPreview() {
160         ImagePreset historyPreset = mPreset;
161         if (historyPreset != null) {
162             Bitmap preview = mLoader.getOriginalBitmapSmall();
163             if (preview != null) {
164                 float s = Math.min(preview.getWidth(), preview.getHeight());
165                 float f = sHistoryPreviewSize / s;
166                 int w = (int) (preview.getWidth() * f);
167                 int h = (int) (preview.getHeight() * f);
168                 Bitmap historyPreview = Bitmap.createScaledBitmap(preview, w, h, true);
169                 historyPreset.setPreviewImage(historyPreview);
170                 RenderingRequest.post(historyPreview,
171                         historyPreset, RenderingRequest.ICON_RENDERING, this);
172             }
173         }
174     }
175
176     private void setGeometry() {
177         Bitmap image = mLoader.getOriginalBitmapLarge();
178         if (image == null) {
179             return;
180         }
181         float w = image.getWidth();
182         float h = image.getHeight();
183         GeometryMetadata geo = mPreset.mGeoData;
184         RectF pb = geo.getPhotoBounds();
185         if (w == pb.width() && h == pb.height()) {
186             return;
187         }
188         RectF r = new RectF(0, 0, w, h);
189         geo.setPhotoBounds(r);
190         geo.setCropBounds(r);
191     }
192
193     public void onHistoryItemClick(int position) {
194         setPreset(new ImagePreset(mHistory.getItem(position)), false);
195         // We need a copy from the history
196         mHistory.setCurrentPreset(position);
197     }
198
199     public HistoryAdapter getHistory() {
200         return mHistory;
201     }
202
203     public StateAdapter getState() {
204         return mState;
205     }
206
207     public void setHistoryAdapter(HistoryAdapter adapter) {
208         mHistory = adapter;
209     }
210
211     public void setStateAdapter(StateAdapter adapter) {
212         mState = adapter;
213     }
214
215     public void setImageLoader(ImageLoader loader) {
216         mLoader = loader;
217     }
218
219     public ImageLoader getImageLoader() {
220         return mLoader;
221     }
222
223     public void setCurrentFilter(ImageFilter filter) {
224         mCurrentFilter = filter;
225     }
226
227     public ImageFilter getCurrentFilter() {
228         return mCurrentFilter;
229     }
230
231     public synchronized boolean hasModifications() {
232         if (mPreset == null) {
233             return false;
234         }
235         return mPreset.hasModifications();
236     }
237
238     public TripleBufferBitmap getDoubleBuffer() {
239         return mFilteredPreview;
240     }
241
242     public void setOriginalGeometry(Bitmap originalBitmapLarge) {
243         GeometryMetadata geo = getPreset().mGeoData;
244         float w = originalBitmapLarge.getWidth();
245         float h = originalBitmapLarge.getHeight();
246         RectF r = new RectF(0, 0, w, h);
247         geo.setPhotoBounds(r);
248         geo.setCropBounds(r);
249         getPreset().setGeometry(geo);
250     }
251
252     public Bitmap getFilteredImage() {
253         return mFilteredPreview.getConsumer();
254     }
255
256     public Bitmap getFiltersOnlyImage() {
257         return mFiltersOnlyBitmap;
258     }
259
260     public Bitmap getGeometryOnlyImage() {
261         return mGeometryOnlyBitmap;
262     }
263
264     public Bitmap getPartialImage() {
265         return mPartialBitmap;
266     }
267
268     public Bitmap getHighresImage() {
269         return mHighresBitmap;
270     }
271
272     public void notifyObservers() {
273         for (ImageShow observer : mObservers) {
274             observer.invalidate();
275         }
276     }
277
278     public void updatePresets(boolean force) {
279         if (force || mGeometryOnlyPreset == null) {
280             ImagePreset newPreset = new ImagePreset(mPreset);
281             newPreset.setDoApplyFilters(false);
282             newPreset.setDoApplyGeometry(true);
283             if (force || mGeometryOnlyPreset == null
284                     || !newPreset.same(mGeometryOnlyPreset)) {
285                 mGeometryOnlyPreset = newPreset;
286                 RenderingRequest.post(mLoader.getOriginalBitmapLarge(),
287                         mGeometryOnlyPreset, RenderingRequest.GEOMETRY_RENDERING, this);
288             }
289         }
290         if (force || mFiltersOnlyPreset == null) {
291             ImagePreset newPreset = new ImagePreset(mPreset);
292             newPreset.setDoApplyFilters(true);
293             newPreset.setDoApplyGeometry(false);
294             if (force || mFiltersOnlyPreset == null
295                     || !newPreset.same(mFiltersOnlyPreset)) {
296                 mFiltersOnlyPreset = newPreset;
297                 RenderingRequest.post(mLoader.getOriginalBitmapLarge(),
298                         mFiltersOnlyPreset, RenderingRequest.FILTERS_RENDERING, this);
299             }
300         }
301         invalidatePreview();
302         mActivity.enableSave(hasModifications());
303     }
304
305     public FilterRepresentation getCurrentFilterRepresentation() {
306         return mCurrentFilterRepresentation;
307     }
308
309     public void setCurrentFilterRepresentation(FilterRepresentation currentFilterRepresentation) {
310         mCurrentFilterRepresentation = currentFilterRepresentation;
311     }
312
313     public void invalidateFiltersOnly() {
314         mFiltersOnlyPreset = null;
315         updatePresets(false);
316     }
317
318     public void invalidatePartialPreview() {
319         if (mPartialBitmap != null) {
320             mPartialBitmap = null;
321             notifyObservers();
322         }
323     }
324
325     public void invalidateHighresPreview() {
326         if (mHighresBitmap != null) {
327             mHighresBitmap = null;
328             notifyObservers();
329         }
330     }
331
332     public void invalidatePreview() {
333         mFilteredPreview.invalidate();
334         invalidatePartialPreview();
335         invalidateHighresPreview();
336         needsUpdatePartialPreview();
337         needsUpdateHighResPreview();
338         FilteringPipeline.getPipeline().updatePreviewBuffer();
339     }
340
341     public void setImageShowSize(int w, int h) {
342         if (mImageShowSize.x != w || mImageShowSize.y != h) {
343             mImageShowSize.set(w, h);
344             needsUpdatePartialPreview();
345             needsUpdateHighResPreview();
346         }
347     }
348
349     private Matrix getImageToScreenMatrix(boolean reflectRotation) {
350         GeometryMetadata geo = mPreset.mGeoData;
351         if (geo == null || mLoader == null
352                 || mLoader.getOriginalBounds() == null
353                 || mImageShowSize.x == 0) {
354             return new Matrix();
355         }
356         Matrix m = geo.getOriginalToScreen(reflectRotation,
357                 mLoader.getOriginalBounds().width(),
358                 mLoader.getOriginalBounds().height(), mImageShowSize.x, mImageShowSize.y);
359         Point translate = getTranslation();
360         float scaleFactor = getScaleFactor();
361         m.postTranslate(translate.x, translate.y);
362         m.postScale(scaleFactor, scaleFactor, mImageShowSize.x/2.0f, mImageShowSize.y/2.0f);
363         return m;
364     }
365
366     private Matrix getScreenToImageMatrix(boolean reflectRotation) {
367         Matrix m = getImageToScreenMatrix(reflectRotation);
368         Matrix invert = new Matrix();
369         m.invert(invert);
370         return invert;
371     }
372
373     public void needsUpdateHighResPreview() {
374         if (!mSupportsHighRes) {
375             return;
376         }
377         RenderingRequest.post(null, mPreset, RenderingRequest.HIGHRES_RENDERING, this);
378         invalidateHighresPreview();
379     }
380
381     public void needsUpdatePartialPreview() {
382         if (!mPreset.canDoPartialRendering()) {
383             invalidatePartialPreview();
384             return;
385         }
386         Matrix m = getScreenToImageMatrix(true);
387         RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y);
388         RectF dest = new RectF();
389         m.mapRect(dest, r);
390         Rect bounds = new Rect();
391         dest.roundOut(bounds);
392         RenderingRequest.post(null, mPreset, RenderingRequest.PARTIAL_RENDERING,
393                 this, bounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y));
394         invalidatePartialPreview();
395     }
396
397     @Override
398     public void available(RenderingRequest request) {
399         if (request.getBitmap() == null) {
400             return;
401         }
402         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
403             mGeometryOnlyBitmap = request.getBitmap();
404         }
405         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
406             mFiltersOnlyBitmap = request.getBitmap();
407         }
408         if (request.getType() == RenderingRequest.PARTIAL_RENDERING
409                 && request.getScaleFactor() == getScaleFactor()) {
410             mPartialBitmap = request.getBitmap();
411             notifyObservers();
412         }
413         if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
414             mHighresBitmap = request.getBitmap();
415             notifyObservers();
416         }
417
418         if (request.getType() == RenderingRequest.ICON_RENDERING) {
419             // History preview images
420             ImagePreset preset = request.getOriginalImagePreset();
421             preset.setPreviewImage(request.getBitmap());
422             mHistory.notifyDataSetChanged();
423         }
424     }
425
426     public static void reset() {
427         sMasterImage = null;
428     }
429
430     public void addGeometryListener(GeometryListener listener) {
431         mGeometryListeners.add(listener);
432     }
433
434     public void notifyGeometryChange() {
435         if (mHandler.hasMessages(NEW_GEOMETRY)) {
436             return;
437         }
438         mHandler.sendEmptyMessage(NEW_GEOMETRY);
439     }
440
441     public void hasNewGeometry() {
442         updatePresets(true);
443         for (GeometryListener listener : mGeometryListeners) {
444             listener.geometryChanged();
445         }
446     }
447
448
449     public float getScaleFactor() {
450         return mScaleFactor;
451     }
452
453     public void setScaleFactor(float scaleFactor) {
454         if (DISABLEZOOM) {
455             return;
456         }
457         if (scaleFactor == mScaleFactor) {
458             return;
459         }
460         mScaleFactor = scaleFactor;
461         invalidatePartialPreview();
462     }
463
464     public Point getTranslation() {
465         return mTranslation;
466     }
467
468     public void setTranslation(Point translation) {
469         if (DISABLEZOOM) {
470             mTranslation.x = 0;
471             mTranslation.y = 0;
472             return;
473         }
474         mTranslation.x = translation.x;
475         mTranslation.y = translation.y;
476         needsUpdatePartialPreview();
477     }
478
479     public Point getOriginalTranslation() {
480         return mOriginalTranslation;
481     }
482
483     public void setOriginalTranslation(Point originalTranslation) {
484         if (DISABLEZOOM) {
485             return;
486         }
487         mOriginalTranslation.x = originalTranslation.x;
488         mOriginalTranslation.y = originalTranslation.y;
489     }
490
491     public void resetTranslation() {
492         mTranslation.x = 0;
493         mTranslation.y = 0;
494         needsUpdatePartialPreview();
495     }
496
497     public Bitmap getThumbnailBitmap() {
498         return mLoader.getOriginalBitmapSmall();
499     }
500
501     public Bitmap getLargeThumbnailBitmap() {
502         return mLoader.getOriginalBitmapLarge();
503     }
504
505     public float getMaxScaleFactor() {
506         if (DISABLEZOOM) {
507             return 1;
508         }
509         return mMaxScaleFactor;
510     }
511
512     public void setMaxScaleFactor(float maxScaleFactor) {
513         mMaxScaleFactor = maxScaleFactor;
514     }
515
516     public boolean supportsHighRes() {
517         return mSupportsHighRes;
518     }
519
520     public void setShowsOriginal(boolean value) {
521         mShowsOriginal = value;
522         notifyObservers();
523     }
524
525     public boolean showsOriginal() {
526         return mShowsOriginal;
527     }
528 }