MasterImage.java revision c031ffc8c8c54f292e30532146c46b5bbbb27eef
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 17package com.android.gallery3d.filtershow.imageshow; 18 19import android.graphics.*; 20import android.os.Handler; 21import android.os.Message; 22 23import android.util.Log; 24import com.android.gallery3d.filtershow.FilterShowActivity; 25import com.android.gallery3d.filtershow.HistoryAdapter; 26import com.android.gallery3d.filtershow.cache.*; 27import com.android.gallery3d.filtershow.filters.FilterRepresentation; 28import com.android.gallery3d.filtershow.filters.ImageFilter; 29import com.android.gallery3d.filtershow.presets.ImagePreset; 30import com.android.gallery3d.filtershow.state.StateAdapter; 31 32import java.util.Vector; 33 34public 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} 529