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