2 * Copyright (C) 2013 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow.imageshow;
19 import android.graphics.*;
20 import android.os.Handler;
21 import android.os.Message;
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;
32 import java.util.Vector;
34 public class MasterImage implements RenderingRequestCaller {
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;
43 private boolean mSupportsHighRes = false;
45 private ImageFilter mCurrentFilter = null;
46 private ImagePreset mPreset = null;
47 private ImagePreset mGeometryOnlyPreset = null;
48 private ImagePreset mFiltersOnlyPreset = null;
50 private TripleBufferBitmap mFilteredPreview = new TripleBufferBitmap();
52 private Bitmap mGeometryOnlyBitmap = null;
53 private Bitmap mFiltersOnlyBitmap = null;
54 private Bitmap mPartialBitmap = null;
55 private Bitmap mHighresBitmap = null;
57 private ImageLoader mLoader = null;
58 private HistoryAdapter mHistory = null;
59 private StateAdapter mState = null;
61 private FilterShowActivity mActivity = null;
63 private Vector<ImageShow> mObservers = new Vector<ImageShow>();
64 private FilterRepresentation mCurrentFilterRepresentation;
65 private Vector<GeometryListener> mGeometryListeners = new Vector<GeometryListener>();
67 private GeometryMetadata mPreviousGeometry = null;
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();
74 private Point mImageShowSize = new Point();
76 private boolean mShowsOriginal;
78 final private static int NEW_GEOMETRY = 1;
80 private final Handler mHandler = new Handler() {
82 public void handleMessage(Message msg) {
92 private MasterImage() {
95 // TODO: remove singleton
96 public static void setMaster(MasterImage master) {
97 sMasterImage = master;
100 public static MasterImage getImage() {
101 if (sMasterImage == null) {
102 sMasterImage = new MasterImage();
107 public void setSupportsHighRes(boolean value) {
108 mSupportsHighRes = value;
111 public static void setIconSeedSize(int iconSeedSize) {
112 sIconSeedSize = iconSeedSize;
115 public void addObserver(ImageShow observer) {
116 if (mObservers.contains(observer)) {
119 mObservers.add(observer);
122 public void setActivity(FilterShowActivity activity) {
123 mActivity = activity;
126 public ImageLoader getLoader() {
130 public synchronized ImagePreset getPreset() {
134 public synchronized ImagePreset getGeometryPreset() {
135 return mGeometryOnlyPreset;
138 public synchronized ImagePreset getFiltersOnlyPreset() {
139 return mFiltersOnlyPreset;
142 public synchronized void setPreset(ImagePreset preset, boolean addToHistory) {
143 preset.showFilters();
145 mPreset.setImageLoader(mLoader);
147 mPreset.fillImageStateAdapter(mState);
149 mHistory.addHistoryItem(mPreset);
152 GeometryMetadata geo = mPreset.mGeoData;
153 if (!geo.equals(mPreviousGeometry)) {
154 notifyGeometryChange();
156 mPreviousGeometry = new GeometryMetadata(geo);
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);
176 private void setGeometry() {
177 Bitmap image = mLoader.getOriginalBitmapLarge();
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()) {
188 RectF r = new RectF(0, 0, w, h);
189 geo.setPhotoBounds(r);
190 geo.setCropBounds(r);
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);
199 public HistoryAdapter getHistory() {
203 public StateAdapter getState() {
207 public void setHistoryAdapter(HistoryAdapter adapter) {
211 public void setStateAdapter(StateAdapter adapter) {
215 public void setImageLoader(ImageLoader loader) {
219 public ImageLoader getImageLoader() {
223 public void setCurrentFilter(ImageFilter filter) {
224 mCurrentFilter = filter;
227 public ImageFilter getCurrentFilter() {
228 return mCurrentFilter;
231 public synchronized boolean hasModifications() {
232 if (mPreset == null) {
235 return mPreset.hasModifications();
238 public TripleBufferBitmap getDoubleBuffer() {
239 return mFilteredPreview;
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);
252 public Bitmap getFilteredImage() {
253 return mFilteredPreview.getConsumer();
256 public Bitmap getFiltersOnlyImage() {
257 return mFiltersOnlyBitmap;
260 public Bitmap getGeometryOnlyImage() {
261 return mGeometryOnlyBitmap;
264 public Bitmap getPartialImage() {
265 return mPartialBitmap;
268 public Bitmap getHighresImage() {
269 return mHighresBitmap;
272 public void notifyObservers() {
273 for (ImageShow observer : mObservers) {
274 observer.invalidate();
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);
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);
302 mActivity.enableSave(hasModifications());
305 public FilterRepresentation getCurrentFilterRepresentation() {
306 return mCurrentFilterRepresentation;
309 public void setCurrentFilterRepresentation(FilterRepresentation currentFilterRepresentation) {
310 mCurrentFilterRepresentation = currentFilterRepresentation;
313 public void invalidateFiltersOnly() {
314 mFiltersOnlyPreset = null;
315 updatePresets(false);
318 public void invalidatePartialPreview() {
319 if (mPartialBitmap != null) {
320 mPartialBitmap = null;
325 public void invalidateHighresPreview() {
326 if (mHighresBitmap != null) {
327 mHighresBitmap = null;
332 public void invalidatePreview() {
333 mFilteredPreview.invalidate();
334 invalidatePartialPreview();
335 invalidateHighresPreview();
336 needsUpdatePartialPreview();
337 needsUpdateHighResPreview();
338 FilteringPipeline.getPipeline().updatePreviewBuffer();
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();
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) {
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);
366 private Matrix getScreenToImageMatrix(boolean reflectRotation) {
367 Matrix m = getImageToScreenMatrix(reflectRotation);
368 Matrix invert = new Matrix();
373 public void needsUpdateHighResPreview() {
374 if (!mSupportsHighRes) {
377 RenderingRequest.post(null, mPreset, RenderingRequest.HIGHRES_RENDERING, this);
378 invalidateHighresPreview();
381 public void needsUpdatePartialPreview() {
382 if (!mPreset.canDoPartialRendering()) {
383 invalidatePartialPreview();
386 Matrix m = getScreenToImageMatrix(true);
387 RectF r = new RectF(0, 0, mImageShowSize.x, mImageShowSize.y);
388 RectF dest = new RectF();
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();
398 public void available(RenderingRequest request) {
399 if (request.getBitmap() == null) {
402 if (request.getType() == RenderingRequest.GEOMETRY_RENDERING) {
403 mGeometryOnlyBitmap = request.getBitmap();
405 if (request.getType() == RenderingRequest.FILTERS_RENDERING) {
406 mFiltersOnlyBitmap = request.getBitmap();
408 if (request.getType() == RenderingRequest.PARTIAL_RENDERING
409 && request.getScaleFactor() == getScaleFactor()) {
410 mPartialBitmap = request.getBitmap();
413 if (request.getType() == RenderingRequest.HIGHRES_RENDERING) {
414 mHighresBitmap = request.getBitmap();
418 if (request.getType() == RenderingRequest.ICON_RENDERING) {
419 // History preview images
420 ImagePreset preset = request.getOriginalImagePreset();
421 preset.setPreviewImage(request.getBitmap());
422 mHistory.notifyDataSetChanged();
426 public static void reset() {
430 public void addGeometryListener(GeometryListener listener) {
431 mGeometryListeners.add(listener);
434 public void notifyGeometryChange() {
435 if (mHandler.hasMessages(NEW_GEOMETRY)) {
438 mHandler.sendEmptyMessage(NEW_GEOMETRY);
441 public void hasNewGeometry() {
443 for (GeometryListener listener : mGeometryListeners) {
444 listener.geometryChanged();
449 public float getScaleFactor() {
453 public void setScaleFactor(float scaleFactor) {
457 if (scaleFactor == mScaleFactor) {
460 mScaleFactor = scaleFactor;
461 invalidatePartialPreview();
464 public Point getTranslation() {
468 public void setTranslation(Point translation) {
474 mTranslation.x = translation.x;
475 mTranslation.y = translation.y;
476 needsUpdatePartialPreview();
479 public Point getOriginalTranslation() {
480 return mOriginalTranslation;
483 public void setOriginalTranslation(Point originalTranslation) {
487 mOriginalTranslation.x = originalTranslation.x;
488 mOriginalTranslation.y = originalTranslation.y;
491 public void resetTranslation() {
494 needsUpdatePartialPreview();
497 public Bitmap getThumbnailBitmap() {
498 return mLoader.getOriginalBitmapSmall();
501 public Bitmap getLargeThumbnailBitmap() {
502 return mLoader.getOriginalBitmapLarge();
505 public float getMaxScaleFactor() {
509 return mMaxScaleFactor;
512 public void setMaxScaleFactor(float maxScaleFactor) {
513 mMaxScaleFactor = maxScaleFactor;
516 public boolean supportsHighRes() {
517 return mSupportsHighRes;
520 public void setShowsOriginal(boolean value) {
521 mShowsOriginal = value;
525 public boolean showsOriginal() {
526 return mShowsOriginal;