OSDN Git Service

ffd69a662594955163b514fc8ad53f8ebbeac41c
[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.Bitmap;
20 import android.graphics.Matrix;
21 import android.graphics.Point;
22 import android.graphics.Rect;
23 import android.graphics.RectF;
24 import android.os.Handler;
25 import android.os.Message;
26
27 import com.android.gallery3d.filtershow.FilterShowActivity;
28 import com.android.gallery3d.filtershow.history.HistoryManager;
29 import com.android.gallery3d.filtershow.history.HistoryItem;
30 import com.android.gallery3d.filtershow.pipeline.FilteringPipeline;
31 import com.android.gallery3d.filtershow.cache.ImageLoader;
32 import com.android.gallery3d.filtershow.pipeline.RenderingRequest;
33 import com.android.gallery3d.filtershow.pipeline.RenderingRequestCaller;
34 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
35 import com.android.gallery3d.filtershow.filters.ImageFilter;
36 import com.android.gallery3d.filtershow.pipeline.Buffer;
37 import com.android.gallery3d.filtershow.pipeline.SharedBuffer;
38 import com.android.gallery3d.filtershow.pipeline.SharedPreset;
39 import com.android.gallery3d.filtershow.pipeline.ImagePreset;
40 import com.android.gallery3d.filtershow.state.StateAdapter;
41
42 import java.util.Vector;
43
44 public class MasterImage implements RenderingRequestCaller {
45
46     private static final String LOGTAG = "MasterImage";
47     private boolean DEBUG  = false;
48     private static final boolean DISABLEZOOM = false;
49     private static MasterImage sMasterImage = null;
50     private static int sIconSeedSize = 128;
51     private static float sHistoryPreviewSize = 128.0f;
52
53     private boolean mSupportsHighRes = false;
54
55     private ImageFilter mCurrentFilter = null;
56     private ImagePreset mPreset = null;
57     private ImagePreset mLoadedPreset = null;
58     private ImagePreset mGeometryOnlyPreset = null;
59     private ImagePreset mFiltersOnlyPreset = null;
60
61     private SharedBuffer mPreviewBuffer = new SharedBuffer();
62     private SharedPreset mPreviewPreset = new SharedPreset();
63
64     private Bitmap mGeometryOnlyBitmap = null;
65     private Bitmap mFiltersOnlyBitmap = null;
66     private Bitmap mPartialBitmap = null;
67     private Bitmap mHighresBitmap = null;
68
69     private ImageLoader mLoader = null;
70     private HistoryManager mHistory = null;
71     private StateAdapter mState = null;
72
73     private FilterShowActivity mActivity = null;
74
75     private Vector<ImageShow> mObservers = new Vector<ImageShow>();
76     private FilterRepresentation mCurrentFilterRepresentation;
77     private Vector<GeometryListener> mGeometryListeners = new Vector<GeometryListener>();
78
79     private GeometryMetadata mPreviousGeometry = null;
80
81     private float mScaleFactor = 1.0f;
82     private float mMaxScaleFactor = 3.0f; // TODO: base this on the current view / image
83     private Point mTranslation = new Point();
84     private Point mOriginalTranslation = new Point();
85
86     private Point mImageShowSize = new Point();
87
88     private boolean mShowsOriginal;
89
90     final private static int NEW_GEOMETRY = 1;
91
92     private final Handler mHandler = new Handler() {
93             @Override
94         public void handleMessage(Message msg) {
95             switch (msg.what) {
96                 case NEW_GEOMETRY: {
97                 hasNewGeometry();
98                 break;
99             }
100             }
101         }
102     };
103
104     private MasterImage() {
105     }
106
107     // TODO: remove singleton
108     public static void setMaster(MasterImage master) {
109         sMasterImage = master;
110     }
111
112     public static MasterImage getImage() {
113         if (sMasterImage == null) {
114             sMasterImage = new MasterImage();
115         }
116         return sMasterImage;
117     }
118
119     public void setSupportsHighRes(boolean value) {
120         mSupportsHighRes = value;
121     }
122
123     public static void setIconSeedSize(int iconSeedSize) {
124         sIconSeedSize = iconSeedSize;
125     }
126
127     public void addObserver(ImageShow observer) {
128         if (mObservers.contains(observer)) {
129             return;
130         }
131         mObservers.add(observer);
132     }
133
134     public void setActivity(FilterShowActivity activity) {
135         mActivity = activity;
136     }
137
138     public ImageLoader getLoader() {
139         return mLoader;
140     }
141
142     public synchronized ImagePreset getPreset() {
143         return mPreset;
144     }
145
146     public synchronized ImagePreset getGeometryPreset() {
147         return mGeometryOnlyPreset;
148     }
149
150     public synchronized ImagePreset getFiltersOnlyPreset() {
151         return mFiltersOnlyPreset;
152     }
153
154     public synchronized void setPreset(ImagePreset preset,
155                                        FilterRepresentation change,
156                                        boolean addToHistory) {
157         if (DEBUG) {
158             preset.showFilters();
159         }
160         mPreset = preset;
161         mPreset.setImageLoader(mLoader);
162         setGeometry();
163         mPreset.fillImageStateAdapter(mState);
164         if (addToHistory) {
165             HistoryItem historyItem = new HistoryItem(mPreset, change);
166             mHistory.addHistoryItem(historyItem);
167         }
168         updatePresets(true);
169         GeometryMetadata geo = mPreset.getGeometry();
170         if (!geo.equals(mPreviousGeometry)) {
171             notifyGeometryChange();
172         }
173         mPreviousGeometry = new GeometryMetadata(geo);
174         mActivity.updateCategories();
175     }
176
177     private void setGeometry() {
178         Bitmap image = mLoader.getOriginalBitmapLarge();
179         if (image == null) {
180             return;
181         }
182         float w = image.getWidth();
183         float h = image.getHeight();
184         GeometryMetadata geo = mPreset.getGeometry();
185         RectF pb = geo.getPhotoBounds();
186         if (w == pb.width() && h == pb.height()) {
187             return;
188         }
189         RectF r = new RectF(0, 0, w, h);
190         geo.setPhotoBounds(r);
191         geo.setCropBounds(r);
192         mPreset.setGeometry(geo);
193     }
194
195     public void onHistoryItemClick(int position) {
196         HistoryItem historyItem = mHistory.getItem(position);
197         // We need a copy from the history
198         ImagePreset newPreset = new ImagePreset(historyItem.getImagePreset());
199         // don't need to add it to the history
200         setPreset(newPreset, historyItem.getFilterRepresentation(), false);
201         mHistory.setCurrentPreset(position);
202     }
203
204     public HistoryManager getHistory() {
205         return mHistory;
206     }
207
208     public StateAdapter getState() {
209         return mState;
210     }
211
212     public void setHistoryManager(HistoryManager adapter) {
213         mHistory = adapter;
214     }
215
216     public void setStateAdapter(StateAdapter adapter) {
217         mState = adapter;
218     }
219
220     public void setImageLoader(ImageLoader loader) {
221         mLoader = loader;
222     }
223
224     public ImageLoader getImageLoader() {
225         return mLoader;
226     }
227
228     public void setCurrentFilter(ImageFilter filter) {
229         mCurrentFilter = filter;
230     }
231
232     public ImageFilter getCurrentFilter() {
233         return mCurrentFilter;
234     }
235
236     public synchronized boolean hasModifications() {
237         // TODO: We need to have a better same effects check to see if two
238         // presets are functionally the same. Right now, we are relying on a
239         // stricter check as equals().
240         ImagePreset loadedPreset = getLoadedPreset();
241         if (mPreset == null) {
242             if (loadedPreset == null) {
243                 return false;
244             } else {
245                 return loadedPreset.hasModifications();
246             }
247         } else {
248             if (loadedPreset == null) {
249                 return mPreset.hasModifications();
250             } else {
251                 return !mPreset.equals(getLoadedPreset());
252             }
253         }
254     }
255
256     public SharedBuffer getPreviewBuffer() {
257         return mPreviewBuffer;
258     }
259
260     public SharedPreset getPreviewPreset() {
261         return mPreviewPreset;
262     }
263
264     public void setOriginalGeometry(Bitmap originalBitmapLarge) {
265         GeometryMetadata geo = getPreset().getGeometry();
266         float w = originalBitmapLarge.getWidth();
267         float h = originalBitmapLarge.getHeight();
268         RectF r = new RectF(0, 0, w, h);
269         geo.setPhotoBounds(r);
270         geo.setCropBounds(r);
271         getPreset().setGeometry(geo);
272     }
273
274     public Bitmap getFilteredImage() {
275         mPreviewBuffer.swapConsumerIfNeeded(); // get latest bitmap
276         Buffer consumer = mPreviewBuffer.getConsumer();
277         if (consumer != null) {
278             return consumer.getBitmap();
279         }
280         return null;
281     }
282
283     public Bitmap getFiltersOnlyImage() {
284         return mFiltersOnlyBitmap;
285     }
286
287     public Bitmap getGeometryOnlyImage() {
288         return mGeometryOnlyBitmap;
289     }
290
291     public Bitmap getPartialImage() {
292         return mPartialBitmap;
293     }
294
295     public Bitmap getHighresImage() {
296         return mHighresBitmap;
297     }
298
299     public void notifyObservers() {
300         for (ImageShow observer : mObservers) {
301             observer.invalidate();
302         }
303     }
304
305     public void updatePresets(boolean force) {
306         if (force || mGeometryOnlyPreset == null) {
307             ImagePreset newPreset = new ImagePreset(mPreset);
308             newPreset.setDoApplyFilters(false);
309             newPreset.setDoApplyGeometry(true);
310             if (force || mGeometryOnlyPreset == null
311                     || !newPreset.same(mGeometryOnlyPreset)) {
312                 mGeometryOnlyPreset = newPreset;
313                 RenderingRequest.post(mLoader.getOriginalBitmapLarge(),
314                         mGeometryOnlyPreset, RenderingRequest.GEOMETRY_RENDERING, this);
315             }
316         }
317         if (force || mFiltersOnlyPreset == null) {
318             ImagePreset newPreset = new ImagePreset(mPreset);
319             newPreset.setDoApplyFilters(true);
320             newPreset.setDoApplyGeometry(false);
321             if (force || mFiltersOnlyPreset == null
322                     || !newPreset.same(mFiltersOnlyPreset)) {
323                 mFiltersOnlyPreset = newPreset;
324                 RenderingRequest.post(mLoader.getOriginalBitmapLarge(),
325                         mFiltersOnlyPreset, RenderingRequest.FILTERS_RENDERING, this);
326             }
327         }
328         invalidatePreview();
329     }
330
331     public FilterRepresentation getCurrentFilterRepresentation() {
332         return mCurrentFilterRepresentation;
333     }
334
335     public void setCurrentFilterRepresentation(FilterRepresentation currentFilterRepresentation) {
336         mCurrentFilterRepresentation = currentFilterRepresentation;
337     }
338
339     public void invalidateFiltersOnly() {
340         mFiltersOnlyPreset = null;
341         updatePresets(false);
342     }
343
344     public void invalidatePartialPreview() {
345         if (mPartialBitmap != null) {
346             mPartialBitmap = null;
347             notifyObservers();
348         }
349     }
350
351     public void invalidateHighresPreview() {
352         if (mHighresBitmap != null) {
353             mHighresBitmap = null;
354             notifyObservers();
355         }
356     }
357
358     public void invalidatePreview() {
359         mPreviewPreset.enqueuePreset(mPreset);
360         mPreviewBuffer.invalidate();
361         invalidatePartialPreview();
362         invalidateHighresPreview();
363         needsUpdatePartialPreview();
364         needsUpdateHighResPreview();
365         FilteringPipeline.getPipeline().updatePreviewBuffer();
366     }
367
368     public void setImageShowSize(int w, int h) {
369         if (mImageShowSize.x != w || mImageShowSize.y != h) {
370             mImageShowSize.set(w, h);
371             needsUpdatePartialPreview();
372             needsUpdateHighResPreview();
373         }
374     }
375
376     private Matrix getImageToScreenMatrix(boolean reflectRotation) {
377         GeometryMetadata geo = mPreset.getGeometry();
378         if (geo == null || mLoader == null
379                 || mLoader.getOriginalBounds() == null
380                 || mImageShowSize.x == 0) {
381             return new Matrix();
382         }
383         Matrix m = geo.getOriginalToScreen(reflectRotation,
384                 mLoader.getOriginalBounds().width(),
385                 mLoader.getOriginalBounds().height(), mImageShowSize.x, mImageShowSize.y);
386         Point translate = getTranslation();
387         float scaleFactor = getScaleFactor();
388         m.postTranslate(translate.x, translate.y);
389         m.postScale(scaleFactor, scaleFactor, mImageShowSize.x / 2.0f, mImageShowSize.y / 2.0f);
390         return m;
391     }
392
393     private Matrix getScreenToImageMatrix(boolean reflectRotation) {
394         Matrix m = getImageToScreenMatrix(reflectRotation);
395         Matrix invert = new Matrix();
396         m.invert(invert);
397         return invert;
398     }
399
400     public void needsUpdateHighResPreview() {
401         if (!mSupportsHighRes) {
402             return;
403         }
404         RenderingRequest.post(null, mPreset, RenderingRequest.HIGHRES_RENDERING, this);
405         invalidateHighresPreview();
406     }
407
408     public void needsUpdatePartialPreview() {
409         if (!mPreset.canDoPartialRendering()) {
410             invalidatePartialPreview();
411             return;
412         }
413         Matrix m = getScreenToImageMatrix(true);
414         RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y);
415         RectF dest = new RectF();
416         m.mapRect(dest, r);
417         Rect bounds = new Rect();
418         dest.roundOut(bounds);
419         RenderingRequest.post(null, mPreset, RenderingRequest.PARTIAL_RENDERING,
420                 this, bounds, new Rect(0, 0, mImageShowSize.x, mImageShowSize.y));
421         invalidatePartialPreview();
422     }
423
424     @Override
425     public void available(RenderingRequest request) {
426         if (request.getBitmap() == null) {
427             return;
428         }
429
430         boolean needsCheckModification = false;
431         if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
432             mGeometryOnlyBitmap = request.getBitmap();
433             needsCheckModification = true;
434         }
435         if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
436             mFiltersOnlyBitmap = request.getBitmap();
437             needsCheckModification = true;
438         }
439         if (request.getType() == RenderingRequest.PARTIAL_RENDERING
440                 && request.getScaleFactor() == getScaleFactor()) {
441             mPartialBitmap = request.getBitmap();
442             notifyObservers();
443             needsCheckModification = true;
444         }
445         if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
446             mHighresBitmap = request.getBitmap();
447             notifyObservers();
448             needsCheckModification = true;
449         }
450         if (needsCheckModification) {
451             mActivity.enableSave(hasModifications());
452         }
453     }
454
455     public static void reset() {
456         sMasterImage = null;
457     }
458
459     public void addGeometryListener(GeometryListener listener) {
460         mGeometryListeners.add(listener);
461     }
462
463     public void notifyGeometryChange() {
464         if (mHandler.hasMessages(NEW_GEOMETRY)) {
465             return;
466         }
467         mHandler.sendEmptyMessage(NEW_GEOMETRY);
468     }
469
470     public void hasNewGeometry() {
471         updatePresets(true);
472         for (GeometryListener listener : mGeometryListeners) {
473             listener.geometryChanged();
474         }
475     }
476
477
478     public float getScaleFactor() {
479         return mScaleFactor;
480     }
481
482     public void setScaleFactor(float scaleFactor) {
483         if (DISABLEZOOM) {
484             return;
485         }
486         if (scaleFactor == mScaleFactor) {
487             return;
488         }
489         mScaleFactor = scaleFactor;
490         invalidatePartialPreview();
491     }
492
493     public Point getTranslation() {
494         return mTranslation;
495     }
496
497     public void setTranslation(Point translation) {
498         if (DISABLEZOOM) {
499             mTranslation.x = 0;
500             mTranslation.y = 0;
501             return;
502         }
503         mTranslation.x = translation.x;
504         mTranslation.y = translation.y;
505         needsUpdatePartialPreview();
506     }
507
508     public Point getOriginalTranslation() {
509         return mOriginalTranslation;
510     }
511
512     public void setOriginalTranslation(Point originalTranslation) {
513         if (DISABLEZOOM) {
514             return;
515         }
516         mOriginalTranslation.x = originalTranslation.x;
517         mOriginalTranslation.y = originalTranslation.y;
518     }
519
520     public void resetTranslation() {
521         mTranslation.x = 0;
522         mTranslation.y = 0;
523         needsUpdatePartialPreview();
524     }
525
526     public Bitmap getThumbnailBitmap() {
527         return mLoader.getOriginalBitmapSmall();
528     }
529
530     public Bitmap getLargeThumbnailBitmap() {
531         return mLoader.getOriginalBitmapLarge();
532     }
533
534     public float getMaxScaleFactor() {
535         if (DISABLEZOOM) {
536             return 1;
537         }
538         return mMaxScaleFactor;
539     }
540
541     public void setMaxScaleFactor(float maxScaleFactor) {
542         mMaxScaleFactor = maxScaleFactor;
543     }
544
545     public boolean supportsHighRes() {
546         return mSupportsHighRes;
547     }
548
549     public void setShowsOriginal(boolean value) {
550         mShowsOriginal = value;
551         notifyObservers();
552     }
553
554     public boolean showsOriginal() {
555         return mShowsOriginal;
556     }
557
558     public void setLoadedPreset(ImagePreset preset) {
559         mLoadedPreset = preset;
560     }
561
562     public ImagePreset getLoadedPreset() {
563         return mLoadedPreset;
564     }
565
566 }