Home | History | Annotate | Download | only in presets
      1 /*
      2  * Copyright (C) 2012 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.presets;
     18 
     19 import android.graphics.Bitmap;
     20 import android.graphics.Rect;
     21 import android.support.v8.renderscript.Allocation;
     22 import android.util.Log;
     23 
     24 import com.android.gallery3d.filtershow.cache.CachingPipeline;
     25 import com.android.gallery3d.filtershow.cache.ImageLoader;
     26 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
     27 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
     28 import com.android.gallery3d.filtershow.filters.ImageFilter;
     29 import com.android.gallery3d.filtershow.imageshow.GeometryMetadata;
     30 import com.android.gallery3d.filtershow.imageshow.MasterImage;
     31 import com.android.gallery3d.filtershow.state.State;
     32 import com.android.gallery3d.filtershow.state.StateAdapter;
     33 import com.android.gallery3d.util.UsageStatistics;
     34 
     35 import java.util.Vector;
     36 
     37 public class ImagePreset {
     38 
     39     private static final String LOGTAG = "ImagePreset";
     40 
     41     private FilterRepresentation mBorder = null;
     42     public static final int QUALITY_ICON = 0;
     43     public static final int QUALITY_PREVIEW = 1;
     44     public static final int QUALITY_FINAL = 2;
     45     public static final int STYLE_ICON = 3;
     46 
     47     private ImageLoader mImageLoader = null;
     48 
     49     private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>();
     50 
     51     protected String mName = "Original";
     52     private String mHistoryName = "Original";
     53     protected boolean mIsFxPreset = false;
     54 
     55     private boolean mDoApplyGeometry = true;
     56     private boolean mDoApplyFilters = true;
     57 
     58     public final GeometryMetadata mGeoData = new GeometryMetadata();
     59     private boolean mPartialRendering = false;
     60     private Rect mPartialRenderingBounds;
     61 
     62     private Bitmap mPreviewImage;
     63 
     64     public ImagePreset() {
     65         setup();
     66     }
     67 
     68     public ImagePreset(String historyName) {
     69         setHistoryName(historyName);
     70         setup();
     71     }
     72 
     73     public ImagePreset(ImagePreset source, String historyName) {
     74         this(source);
     75         if (historyName != null) {
     76             setHistoryName(historyName);
     77         }
     78     }
     79 
     80     public ImagePreset(ImagePreset source) {
     81         try {
     82             if (source.mBorder != null) {
     83                 mBorder = source.mBorder.clone();
     84             }
     85             for (int i = 0; i < source.mFilters.size(); i++) {
     86                 FilterRepresentation representation = source.mFilters.elementAt(i).clone();
     87                 addFilter(representation);
     88             }
     89         } catch (java.lang.CloneNotSupportedException e) {
     90             Log.v(LOGTAG, "Exception trying to clone: " + e);
     91         }
     92         mName = source.name();
     93         mHistoryName = source.name();
     94         mIsFxPreset = source.isFx();
     95         mImageLoader = source.getImageLoader();
     96         mPreviewImage = source.getPreviewImage();
     97 
     98         mGeoData.set(source.mGeoData);
     99     }
    100 
    101     public FilterRepresentation getFilterRepresentation(int position) {
    102         FilterRepresentation representation = null;
    103         try {
    104             representation = mFilters.elementAt(position).clone();
    105         } catch (CloneNotSupportedException e) {
    106             e.printStackTrace();
    107         }
    108         return representation;
    109     }
    110 
    111     public int getPositionForRepresentation(FilterRepresentation representation) {
    112         for (int i = 0; i < mFilters.size(); i++) {
    113             if (mFilters.elementAt(i).getFilterClass() == representation.getFilterClass()) {
    114                 return i;
    115             }
    116         }
    117         return -1;
    118     }
    119 
    120     public FilterRepresentation getFilterRepresentationCopyFrom(FilterRepresentation filterRepresentation) {
    121         // TODO: add concept of position in the filters (to allow multiple instances)
    122         if (filterRepresentation == null) {
    123             return null;
    124         }
    125         FilterRepresentation representation = null;
    126         if ((mBorder != null)
    127                 && (mBorder.getFilterClass() == filterRepresentation.getFilterClass())) {
    128             // TODO: instead of special casing for border, we should correctly implements "filters priority set"
    129             representation = mBorder;
    130         } else {
    131             int position = getPositionForRepresentation(filterRepresentation);
    132             if (position == -1) {
    133                 return null;
    134             }
    135             representation = mFilters.elementAt(position);
    136         }
    137         if (representation != null) {
    138             try {
    139                 representation = representation.clone();
    140             } catch (CloneNotSupportedException e) {
    141                 e.printStackTrace();
    142             }
    143         }
    144         return representation;
    145     }
    146 
    147     public void updateFilterRepresentation(FilterRepresentation representation) {
    148         if (representation == null) {
    149             return;
    150         }
    151         synchronized (mFilters) {
    152             if (representation instanceof GeometryMetadata) {
    153                 setGeometry((GeometryMetadata) representation);
    154             } else {
    155                 if ((mBorder != null)
    156                         && (mBorder.getFilterClass() == representation.getFilterClass())) {
    157                     mBorder.updateTempParametersFrom(representation);
    158                 } else {
    159                     int position = getPositionForRepresentation(representation);
    160                     if (position == -1) {
    161                         return;
    162                     }
    163                     FilterRepresentation old = mFilters.elementAt(position);
    164                     old.updateTempParametersFrom(representation);
    165                 }
    166             }
    167         }
    168         MasterImage.getImage().invalidatePreview();
    169         fillImageStateAdapter(MasterImage.getImage().getState());
    170     }
    171 
    172     public void setDoApplyGeometry(boolean value) {
    173         mDoApplyGeometry = value;
    174     }
    175 
    176     public void setDoApplyFilters(boolean value) {
    177         mDoApplyFilters = value;
    178     }
    179 
    180     public boolean getDoApplyFilters() {
    181         return mDoApplyFilters;
    182     }
    183 
    184     public synchronized GeometryMetadata getGeometry() {
    185         return mGeoData;
    186     }
    187 
    188     public boolean hasModifications() {
    189         if (mBorder != null && !mBorder.isNil()) {
    190             return true;
    191         }
    192         if (mGeoData.hasModifications()) {
    193             return true;
    194         }
    195         for (int i = 0; i < mFilters.size(); i++) {
    196             FilterRepresentation filter = mFilters.elementAt(i);
    197             if (!filter.isNil() && !filter.getName().equalsIgnoreCase("none")) {
    198                 return true;
    199             }
    200         }
    201         return false;
    202     }
    203 
    204     public boolean isPanoramaSafe() {
    205         if (mBorder != null && !mBorder.isNil()) {
    206             return false;
    207         }
    208         if (mGeoData.hasModifications()) {
    209             return false;
    210         }
    211         for (FilterRepresentation representation : mFilters) {
    212             if (representation.getPriority() == FilterRepresentation.TYPE_VIGNETTE
    213                 && !representation.isNil()) {
    214                 return false;
    215             }
    216             if (representation.getPriority() == FilterRepresentation.TYPE_TINYPLANET
    217                 && !representation.isNil()) {
    218                 return false;
    219             }
    220         }
    221         return true;
    222     }
    223 
    224     public synchronized void setGeometry(GeometryMetadata m) {
    225         mGeoData.set(m);
    226         MasterImage.getImage().notifyGeometryChange();
    227     }
    228 
    229     private void setBorder(FilterRepresentation filter) {
    230         mBorder = filter;
    231     }
    232 
    233     public void resetBorder() {
    234         mBorder = null;
    235     }
    236 
    237     public boolean isFx() {
    238         return mIsFxPreset;
    239     }
    240 
    241     public void setIsFx(boolean value) {
    242         mIsFxPreset = value;
    243     }
    244 
    245     public void setName(String name) {
    246         mName = name;
    247         mHistoryName = name;
    248     }
    249 
    250     public void setHistoryName(String name) {
    251         mHistoryName = name;
    252     }
    253 
    254     public ImageLoader getImageLoader() {
    255         return mImageLoader;
    256     }
    257 
    258     public void setImageLoader(ImageLoader mImageLoader) {
    259         this.mImageLoader = mImageLoader;
    260     }
    261 
    262     public boolean equals(ImagePreset preset) {
    263         if (!same(preset)) {
    264             return false;
    265         }
    266         if (mDoApplyFilters && preset.mDoApplyFilters) {
    267             for (int i = 0; i < preset.mFilters.size(); i++) {
    268                 FilterRepresentation a = preset.mFilters.elementAt(i);
    269                 FilterRepresentation b = mFilters.elementAt(i);
    270                 if (!a.equals(b)) {
    271                     return false;
    272                 }
    273             }
    274         }
    275         return true;
    276     }
    277 
    278     public boolean same(ImagePreset preset) {
    279         if (preset == null) {
    280             return false;
    281         }
    282 
    283         if (preset.mFilters.size() != mFilters.size()) {
    284             return false;
    285         }
    286 
    287         if (!mName.equalsIgnoreCase(preset.name())) {
    288             return false;
    289         }
    290 
    291         if (mDoApplyGeometry != preset.mDoApplyGeometry) {
    292             return false;
    293         }
    294 
    295         if (mDoApplyGeometry && !mGeoData.equals(preset.mGeoData)) {
    296             return false;
    297         }
    298 
    299         if (mDoApplyGeometry && mBorder != preset.mBorder) {
    300             return false;
    301         }
    302 
    303         if (mBorder != null && !mBorder.equals(preset.mBorder)) {
    304             return false;
    305         }
    306 
    307         if (mDoApplyFilters != preset.mDoApplyFilters) {
    308             if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
    309                 return false;
    310             }
    311         }
    312 
    313         if (mDoApplyFilters && preset.mDoApplyFilters) {
    314             for (int i = 0; i < preset.mFilters.size(); i++) {
    315                 FilterRepresentation a = preset.mFilters.elementAt(i);
    316                 FilterRepresentation b = mFilters.elementAt(i);
    317                 if (!a.same(b)) {
    318                     return false;
    319                 }
    320             }
    321         }
    322 
    323         return true;
    324     }
    325 
    326     public int similarUpTo(ImagePreset preset) {
    327         if (!mGeoData.equals(preset.mGeoData)) {
    328             return -1;
    329         }
    330 
    331         for (int i = 0; i < preset.mFilters.size(); i++) {
    332             FilterRepresentation a = preset.mFilters.elementAt(i);
    333             if (i < mFilters.size()) {
    334                 FilterRepresentation b = mFilters.elementAt(i);
    335                 if (!a.same(b)) {
    336                     return i;
    337                 }
    338                 if (!a.equals(b)) {
    339                     return i;
    340                 }
    341             } else {
    342                 return i;
    343             }
    344         }
    345         return preset.mFilters.size();
    346     }
    347 
    348     public String name() {
    349         return mName;
    350     }
    351 
    352     public String historyName() {
    353         return mHistoryName;
    354     }
    355 
    356     public void showFilters() {
    357         Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters");
    358         int n = 0;
    359         for (FilterRepresentation representation : mFilters) {
    360             Log.v(LOGTAG, " filter " + n + " : " + representation.toString());
    361             n++;
    362         }
    363         Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters");
    364     }
    365 
    366     public FilterRepresentation getLastRepresentation() {
    367         if (mFilters.size() > 0) {
    368             return mFilters.lastElement();
    369         }
    370         return null;
    371     }
    372 
    373     public void removeFilter(FilterRepresentation filterRepresentation) {
    374         if (filterRepresentation.getPriority() == FilterRepresentation.TYPE_BORDER) {
    375             setBorder(null);
    376             setHistoryName("Remove");
    377             return;
    378         }
    379         for (int i = 0; i < mFilters.size(); i++) {
    380             if (mFilters.elementAt(i).getFilterClass() == filterRepresentation.getFilterClass()) {
    381                 mFilters.remove(i);
    382                 setHistoryName("Remove");
    383                 return;
    384             }
    385         }
    386     }
    387 
    388     public void addFilter(FilterRepresentation representation) {
    389         if (representation instanceof GeometryMetadata) {
    390             setGeometry((GeometryMetadata) representation);
    391             return;
    392         }
    393         if (representation.getPriority() == FilterRepresentation.TYPE_BORDER) {
    394             setHistoryName(representation.getName());
    395             setBorder(representation);
    396         } else if (representation.getPriority() == FilterRepresentation.TYPE_FX) {
    397             boolean found = false;
    398             for (int i = 0; i < mFilters.size(); i++) {
    399                 int type = mFilters.elementAt(i).getPriority();
    400                 if (found) {
    401                     if (type != FilterRepresentation.TYPE_VIGNETTE) {
    402                         mFilters.remove(i);
    403                         continue;
    404                     }
    405                 }
    406                 if (type == FilterRepresentation.TYPE_FX) {
    407                     mFilters.remove(i);
    408                     mFilters.add(i, representation);
    409                     setHistoryName(representation.getName());
    410                     found = true;
    411                 }
    412             }
    413             if (!found) {
    414                 mFilters.add(representation);
    415                 setHistoryName(representation.getName());
    416             }
    417         } else {
    418             mFilters.add(representation);
    419             setHistoryName(representation.getName());
    420         }
    421     }
    422 
    423     public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
    424         if (filterRepresentation instanceof GeometryMetadata) {
    425             return mGeoData;
    426         }
    427         for (int i = 0; i < mFilters.size(); i++) {
    428             FilterRepresentation representation = mFilters.elementAt(i);
    429             if (representation.getFilterClass() == filterRepresentation.getFilterClass()) {
    430                 return representation;
    431             }
    432         }
    433         if (mBorder != null && mBorder.getFilterClass() == filterRepresentation.getFilterClass()) {
    434             return mBorder;
    435         }
    436         return null;
    437     }
    438 
    439     public void setup() {
    440         // do nothing here
    441     }
    442 
    443     public Bitmap apply(Bitmap original, FilterEnvironment environment) {
    444         Bitmap bitmap = original;
    445         bitmap = applyFilters(bitmap, -1, -1, environment);
    446         return applyBorder(bitmap, environment);
    447     }
    448 
    449     public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) {
    450         // Apply any transform -- 90 rotate, flip, straighten, crop
    451         // Returns a new bitmap.
    452         if (mDoApplyGeometry) {
    453             mGeoData.synchronizeRepresentation();
    454             bitmap = environment.applyRepresentation(mGeoData, bitmap);
    455         }
    456         return bitmap;
    457     }
    458 
    459     public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) {
    460         if (mBorder != null && mDoApplyGeometry) {
    461             mBorder.synchronizeRepresentation();
    462             bitmap = environment.applyRepresentation(mBorder, bitmap);
    463             if (environment.getQuality() == QUALITY_FINAL) {
    464                 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
    465                         "SaveBorder", mBorder.getName(), 1);
    466             }
    467         }
    468         return bitmap;
    469     }
    470 
    471     public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) {
    472         if (mDoApplyFilters) {
    473             if (from < 0) {
    474                 from = 0;
    475             }
    476             if (to == -1) {
    477                 to = mFilters.size();
    478             }
    479             for (int i = from; i < to; i++) {
    480                 FilterRepresentation representation = null;
    481                 synchronized (mFilters) {
    482                     representation = mFilters.elementAt(i);
    483                     representation.synchronizeRepresentation();
    484                 }
    485                 bitmap = environment.applyRepresentation(representation, bitmap);
    486                 if (environment.getQuality() == QUALITY_FINAL) {
    487                     UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
    488                             "SaveFilter", representation.getName(), 1);
    489                 }
    490                 if (environment.needsStop()) {
    491                     return bitmap;
    492                 }
    493             }
    494         }
    495 
    496         return bitmap;
    497     }
    498 
    499     public void applyBorder(Allocation in, Allocation out, FilterEnvironment environment) {
    500         if (mBorder != null && mDoApplyGeometry) {
    501             mBorder.synchronizeRepresentation();
    502             // TODO: should keep the bitmap around
    503             Allocation bitmapIn = Allocation.createTyped(CachingPipeline.getRenderScriptContext(), in.getType());
    504             bitmapIn.copyFrom(out);
    505             environment.applyRepresentation(mBorder, bitmapIn, out);
    506         }
    507     }
    508 
    509     public void applyFilters(int from, int to, Allocation in, Allocation out, FilterEnvironment environment) {
    510         if (mDoApplyFilters) {
    511             if (from < 0) {
    512                 from = 0;
    513             }
    514             if (to == -1) {
    515                 to = mFilters.size();
    516             }
    517             for (int i = from; i < to; i++) {
    518                 FilterRepresentation representation = null;
    519                 synchronized (mFilters) {
    520                     representation = mFilters.elementAt(i);
    521                     representation.synchronizeRepresentation();
    522                 }
    523                 if (i > from) {
    524                     in.copyFrom(out);
    525                 }
    526                 environment.applyRepresentation(representation, in, out);
    527             }
    528         }
    529     }
    530 
    531     public boolean canDoPartialRendering() {
    532         if (mGeoData.hasModifications()) {
    533             return false;
    534         }
    535         if (mBorder != null && !mBorder.supportsPartialRendering()) {
    536             return false;
    537         }
    538         if (ImageLoader.getZoomOrientation() != ImageLoader.ORI_NORMAL) {
    539             return false;
    540         }
    541         for (int i = 0; i < mFilters.size(); i++) {
    542             FilterRepresentation representation = null;
    543             synchronized (mFilters) {
    544                 representation = mFilters.elementAt(i);
    545             }
    546             if (!representation.supportsPartialRendering()) {
    547                 return false;
    548             }
    549         }
    550         return true;
    551     }
    552 
    553     public void fillImageStateAdapter(StateAdapter imageStateAdapter) {
    554         if (imageStateAdapter == null) {
    555             return;
    556         }
    557         Vector<State> states = new Vector<State>();
    558         // TODO: supports Geometry representations in the state panel.
    559         if (false && mGeoData != null && mGeoData.hasModifications()) {
    560             State geo = new State("Geometry");
    561             geo.setFilterRepresentation(mGeoData);
    562             states.add(geo);
    563         }
    564         for (FilterRepresentation filter : mFilters) {
    565             State state = new State(filter.getName());
    566             state.setFilterRepresentation(filter);
    567             states.add(state);
    568         }
    569         if (mBorder != null) {
    570             State border = new State(mBorder.getName());
    571             border.setFilterRepresentation(mBorder);
    572             states.add(border);
    573         }
    574         imageStateAdapter.fill(states);
    575     }
    576 
    577     public void setPartialRendering(boolean partialRendering, Rect bounds) {
    578         mPartialRendering = partialRendering;
    579         mPartialRenderingBounds = bounds;
    580     }
    581 
    582     public boolean isPartialRendering() {
    583         return mPartialRendering;
    584     }
    585 
    586     public Rect getPartialRenderingBounds() {
    587         return mPartialRenderingBounds;
    588     }
    589 
    590     public Bitmap getPreviewImage() {
    591         return mPreviewImage;
    592     }
    593 
    594     public void setPreviewImage(Bitmap previewImage) {
    595         mPreviewImage = previewImage;
    596     }
    597 
    598     public Vector<ImageFilter> getUsedFilters(BaseFiltersManager filtersManager) {
    599         Vector<ImageFilter> usedFilters = new Vector<ImageFilter>();
    600         for (int i = 0; i < mFilters.size(); i++) {
    601             FilterRepresentation representation = mFilters.elementAt(i);
    602             ImageFilter filter = filtersManager.getFilterForRepresentation(representation);
    603             usedFilters.add(filter);
    604         }
    605         return usedFilters;
    606     }
    607 
    608 }
    609