OSDN Git Service

64643e4551b2a429c18a6e44f5ccb5e629f168f8
[android-x86/packages-apps-Gallery2.git] / src / com / android / gallery3d / filtershow / pipeline / ImagePreset.java
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.pipeline;
18
19 import android.graphics.Bitmap;
20 import android.graphics.Rect;
21 import android.support.v8.renderscript.Allocation;
22 import android.util.JsonReader;
23 import android.util.JsonWriter;
24 import android.util.Log;
25
26 import com.android.gallery3d.R;
27 import com.android.gallery3d.filtershow.cache.ImageLoader;
28 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
29 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
30 import com.android.gallery3d.filtershow.filters.FilterFxRepresentation;
31 import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation;
32 import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
33 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
34 import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
35 import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
36 import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
37 import com.android.gallery3d.filtershow.filters.FiltersManager;
38 import com.android.gallery3d.filtershow.filters.ImageFilter;
39 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
40 import com.android.gallery3d.filtershow.imageshow.MasterImage;
41 import com.android.gallery3d.filtershow.state.State;
42 import com.android.gallery3d.filtershow.state.StateAdapter;
43 import com.android.gallery3d.util.UsageStatistics;
44
45 import java.io.IOException;
46 import java.io.StringReader;
47 import java.io.StringWriter;
48 import java.util.ArrayList;
49 import java.util.Collection;
50 import java.util.Vector;
51
52 public class ImagePreset {
53
54     private static final String LOGTAG = "ImagePreset";
55
56     private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>();
57
58     private boolean mDoApplyGeometry = true;
59     private boolean mDoApplyFilters = true;
60
61     private boolean mPartialRendering = false;
62     private Rect mPartialRenderingBounds;
63     private static final boolean DEBUG = false;
64
65     public ImagePreset() {
66     }
67
68     public ImagePreset(ImagePreset source) {
69         for (int i = 0; i < source.mFilters.size(); i++) {
70             FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i);
71             mFilters.add(sourceRepresentation.copy());
72         }
73     }
74
75     public Vector<FilterRepresentation> getFilters() {
76         return mFilters;
77     }
78
79     public FilterRepresentation getFilterRepresentation(int position) {
80         FilterRepresentation representation = null;
81
82         representation = mFilters.elementAt(position).copy();
83
84         return representation;
85     }
86
87     private static boolean sameSerializationName(String a, String b) {
88         if (a != null && b != null) {
89             return a.equals(b);
90         } else {
91             return a == null && b == null;
92         }
93     }
94
95     public static boolean sameSerializationName(FilterRepresentation a, FilterRepresentation b) {
96         if (a == null || b == null) {
97             return false;
98         }
99         return sameSerializationName(a.getSerializationName(), b.getSerializationName());
100     }
101
102     public int getPositionForRepresentation(FilterRepresentation representation) {
103         for (int i = 0; i < mFilters.size(); i++) {
104             if (sameSerializationName(mFilters.elementAt(i), representation)) {
105                 return i;
106             }
107         }
108         return -1;
109     }
110
111     private FilterRepresentation getFilterRepresentationForType(int type) {
112         for (int i = 0; i < mFilters.size(); i++) {
113             if (mFilters.elementAt(i).getFilterType() == type) {
114                 return mFilters.elementAt(i);
115             }
116         }
117         return null;
118     }
119
120     public int getPositionForType(int type) {
121         for (int i = 0; i < mFilters.size(); i++) {
122             if (mFilters.elementAt(i).getFilterType() == type) {
123                 return i;
124             }
125         }
126         return -1;
127     }
128
129     public FilterRepresentation getFilterRepresentationCopyFrom(
130             FilterRepresentation filterRepresentation) {
131         // TODO: add concept of position in the filters (to allow multiple instances)
132         if (filterRepresentation == null) {
133             return null;
134         }
135         int position = getPositionForRepresentation(filterRepresentation);
136         if (position == -1) {
137             return null;
138         }
139         FilterRepresentation representation = mFilters.elementAt(position);
140         if (representation != null) {
141             representation = representation.copy();
142         }
143         return representation;
144     }
145
146     public void updateFilterRepresentations(Collection<FilterRepresentation> reps) {
147         for (FilterRepresentation r : reps) {
148             updateOrAddFilterRepresentation(r);
149         }
150     }
151
152     public void updateOrAddFilterRepresentation(FilterRepresentation rep) {
153         int pos = getPositionForRepresentation(rep);
154         if (pos != -1) {
155             mFilters.elementAt(pos).useParametersFrom(rep);
156         } else {
157             addFilter(rep.copy());
158         }
159     }
160
161     public void setDoApplyGeometry(boolean value) {
162         mDoApplyGeometry = value;
163     }
164
165     public void setDoApplyFilters(boolean value) {
166         mDoApplyFilters = value;
167     }
168
169     public boolean getDoApplyFilters() {
170         return mDoApplyFilters;
171     }
172
173     public boolean hasModifications() {
174         for (int i = 0; i < mFilters.size(); i++) {
175             FilterRepresentation filter = mFilters.elementAt(i);
176             if (!filter.isNil()) {
177                 return true;
178             }
179         }
180         return false;
181     }
182
183     public boolean isPanoramaSafe() {
184         for (FilterRepresentation representation : mFilters) {
185             if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
186                     && !representation.isNil()) {
187                 return false;
188             }
189             if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER
190                     && !representation.isNil()) {
191                 return false;
192             }
193             if (representation.getFilterType() == FilterRepresentation.TYPE_VIGNETTE
194                     && !representation.isNil()) {
195                 return false;
196             }
197             if (representation.getFilterType() == FilterRepresentation.TYPE_TINYPLANET
198                     && !representation.isNil()) {
199                 return false;
200             }
201         }
202         return true;
203     }
204
205     public boolean same(ImagePreset preset) {
206         if (preset == null) {
207             return false;
208         }
209
210         if (preset.mFilters.size() != mFilters.size()) {
211             return false;
212         }
213
214         if (mDoApplyGeometry != preset.mDoApplyGeometry) {
215             return false;
216         }
217
218         if (mDoApplyFilters != preset.mDoApplyFilters) {
219             if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
220                 return false;
221             }
222         }
223
224         if (mDoApplyFilters && preset.mDoApplyFilters) {
225             for (int i = 0; i < preset.mFilters.size(); i++) {
226                 FilterRepresentation a = preset.mFilters.elementAt(i);
227                 FilterRepresentation b = mFilters.elementAt(i);
228
229                 if (!a.same(b)) {
230                     return false;
231                 }
232             }
233         }
234
235         return true;
236     }
237
238     public int similarUpTo(ImagePreset preset) {
239         for (int i = 0; i < preset.mFilters.size(); i++) {
240             FilterRepresentation a = preset.mFilters.elementAt(i);
241             if (i < mFilters.size()) {
242                 FilterRepresentation b = mFilters.elementAt(i);
243                 if (!a.same(b)) {
244                     return i;
245                 }
246                 if (!a.equals(b)) {
247                     return i;
248                 }
249             } else {
250                 return i;
251             }
252         }
253         return preset.mFilters.size();
254     }
255
256     public void showFilters() {
257         Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters");
258         int n = 0;
259         for (FilterRepresentation representation : mFilters) {
260             Log.v(LOGTAG, " filter " + n + " : " + representation.toString());
261             n++;
262         }
263         Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters");
264     }
265
266     public FilterRepresentation getLastRepresentation() {
267         if (mFilters.size() > 0) {
268             return mFilters.lastElement();
269         }
270         return null;
271     }
272
273     public void removeFilter(FilterRepresentation filterRepresentation) {
274         if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
275             for (int i = 0; i < mFilters.size(); i++) {
276                 if (mFilters.elementAt(i).getFilterType()
277                 == filterRepresentation.getFilterType()) {
278                     mFilters.remove(i);
279                     break;
280                 }
281             }
282         } else {
283             for (int i = 0; i < mFilters.size(); i++) {
284                 if (sameSerializationName(mFilters.elementAt(i), filterRepresentation)) {
285                     mFilters.remove(i);
286                     break;
287                 }
288             }
289         }
290     }
291
292     // If the filter is an "None" effect or border, then just don't add this filter.
293     public void addFilter(FilterRepresentation representation) {
294         if (representation instanceof FilterUserPresetRepresentation) {
295             ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset();
296             // user preset replace everything but geometry
297             mFilters.clear();
298             for (int i = 0; i < preset.nbFilters(); i++) {
299                 addFilter(preset.getFilterRepresentation(i));
300             }
301             mFilters.add(representation);
302         } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
303             // Add geometry filter, removing duplicates and do-nothing operations.
304             for (int i = 0; i < mFilters.size(); i++) {
305                 if (sameSerializationName(representation, mFilters.elementAt(i))) {
306                     mFilters.remove(i);
307                 }
308             }
309             if (!representation.isNil()) {
310                 mFilters.add(representation);
311             }
312         } else if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
313             removeFilter(representation);
314             if (!isNoneBorderFilter(representation)) {
315                 mFilters.add(representation);
316             }
317         } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) {
318             boolean found = false;
319             for (int i = 0; i < mFilters.size(); i++) {
320                 FilterRepresentation current = mFilters.elementAt(i);
321                 int type = current.getFilterType();
322                 if (found) {
323                     if (type != FilterRepresentation.TYPE_VIGNETTE) {
324                         mFilters.remove(i);
325                         continue;
326                     }
327                 }
328                 if (type == FilterRepresentation.TYPE_FX) {
329                     if (current instanceof FilterUserPresetRepresentation) {
330                         ImagePreset preset = ((FilterUserPresetRepresentation) current)
331                                 .getImagePreset();
332                         // If we had an existing user preset, let's remove all the presets that
333                         // were added by it
334                         for (int j = 0; j < preset.nbFilters(); j++) {
335                             FilterRepresentation rep = preset.getFilterRepresentation(j);
336                             int pos = getPositionForRepresentation(rep);
337                             if (pos != -1) {
338                                 mFilters.remove(pos);
339                             }
340                         }
341                         int pos = getPositionForRepresentation(current);
342                         if (pos != -1) {
343                             mFilters.remove(pos);
344                         } else {
345                             pos = 0;
346                         }
347                         if (!isNoneFxFilter(representation)) {
348                             mFilters.add(pos, representation);
349                         }
350
351                     } else {
352                         mFilters.remove(i);
353                         if (!isNoneFxFilter(representation)) {
354                             mFilters.add(i, representation);
355                         }
356                     }
357                     found = true;
358                 }
359             }
360             if (!found) {
361                 if (!isNoneFxFilter(representation)) {
362                     mFilters.add(representation);
363                 }
364             }
365         } else {
366             mFilters.add(representation);
367         }
368     }
369
370     private boolean isNoneBorderFilter(FilterRepresentation representation) {
371         return representation instanceof FilterImageBorderRepresentation &&
372                 ((FilterImageBorderRepresentation) representation).getDrawableResource() == 0;
373     }
374
375     private boolean isNoneFxFilter(FilterRepresentation representation) {
376         return representation instanceof FilterFxRepresentation &&
377                 ((FilterFxRepresentation) representation).getNameResource() == R.string.none;
378     }
379
380     public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
381         for (int i = 0; i < mFilters.size(); i++) {
382             FilterRepresentation representation = mFilters.elementAt(i);
383             if (sameSerializationName(representation, filterRepresentation)) {
384                 return representation;
385             }
386         }
387         return null;
388     }
389
390     public Bitmap apply(Bitmap original, FilterEnvironment environment) {
391         Bitmap bitmap = original;
392         bitmap = applyFilters(bitmap, -1, -1, environment);
393         return applyBorder(bitmap, environment);
394     }
395
396     public Collection<FilterRepresentation> getGeometryFilters() {
397         ArrayList<FilterRepresentation> geometry = new ArrayList<FilterRepresentation>();
398         for (FilterRepresentation r : mFilters) {
399             if (r.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
400                 geometry.add(r);
401             }
402         }
403         return geometry;
404     }
405
406     public FilterRepresentation getFilterWithSerializationName(String serializationName) {
407         for (FilterRepresentation r : mFilters) {
408             if (r != null) {
409                 if (sameSerializationName(r.getSerializationName(), serializationName)) {
410                     return r.copy();
411                 }
412             }
413         }
414         return null;
415     }
416
417     public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) {
418         // Apply any transform -- 90 rotate, flip, straighten, crop
419         // Returns a new bitmap.
420         if (mDoApplyGeometry) {
421             bitmap = GeometryMathUtils.applyGeometryRepresentations(getGeometryFilters(), bitmap);
422         }
423         return bitmap;
424     }
425
426     public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) {
427         // get the border from the list of filters.
428         FilterRepresentation border = getFilterRepresentationForType(
429                 FilterRepresentation.TYPE_BORDER);
430         if (border != null && mDoApplyGeometry) {
431             bitmap = environment.applyRepresentation(border, bitmap);
432             if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
433                 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
434                         "SaveBorder", border.getSerializationName(), 1);
435             }
436         }
437         return bitmap;
438     }
439
440     public int nbFilters() {
441         return mFilters.size();
442     }
443
444     public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) {
445         if (mDoApplyFilters) {
446             if (from < 0) {
447                 from = 0;
448             }
449             if (to == -1) {
450                 to = mFilters.size();
451             }
452             if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
453                 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
454                         "SaveFilters", "Total", to - from + 1);
455             }
456             for (int i = from; i < to; i++) {
457                 FilterRepresentation representation = mFilters.elementAt(i);
458                 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
459                     // skip the geometry as it's already applied.
460                     continue;
461                 }
462                 if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
463                     // for now, let's skip the border as it will be applied in
464                     // applyBorder()
465                     // TODO: might be worth getting rid of applyBorder.
466                     continue;
467                 }
468                 bitmap = environment.applyRepresentation(representation, bitmap);
469                 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
470                     UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
471                             "SaveFilter", representation.getSerializationName(), 1);
472                 }
473                 if (environment.needsStop()) {
474                     return bitmap;
475                 }
476             }
477         }
478
479         return bitmap;
480     }
481
482     public void applyBorder(Allocation in, Allocation out,
483             boolean copyOut, FilterEnvironment environment) {
484         FilterRepresentation border = getFilterRepresentationForType(
485                 FilterRepresentation.TYPE_BORDER);
486         if (border != null && mDoApplyGeometry) {
487             // TODO: should keep the bitmap around
488             Allocation bitmapIn = in;
489             if (copyOut) {
490                 bitmapIn = Allocation.createTyped(
491                         CachingPipeline.getRenderScriptContext(), in.getType());
492                 bitmapIn.copyFrom(out);
493             }
494             environment.applyRepresentation(border, bitmapIn, out);
495         }
496     }
497
498     public void applyFilters(int from, int to, Allocation in, Allocation out,
499             FilterEnvironment environment) {
500         if (mDoApplyFilters) {
501             if (from < 0) {
502                 from = 0;
503             }
504             if (to == -1) {
505                 to = mFilters.size();
506             }
507             for (int i = from; i < to; i++) {
508                 FilterRepresentation representation = mFilters.elementAt(i);
509                 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
510                         || representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
511                     continue;
512                 }
513                 if (i > from) {
514                     in.copyFrom(out);
515                 }
516                 environment.applyRepresentation(representation, in, out);
517             }
518         }
519     }
520
521     public boolean canDoPartialRendering() {
522         if (MasterImage.getImage().getZoomOrientation() != ImageLoader.ORI_NORMAL) {
523             return false;
524         }
525         for (int i = 0; i < mFilters.size(); i++) {
526             FilterRepresentation representation = mFilters.elementAt(i);
527             if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
528                     && !representation.isNil()) {
529                 return false;
530             }
531             if (!representation.supportsPartialRendering()) {
532                 return false;
533             }
534         }
535         return true;
536     }
537
538     public void fillImageStateAdapter(StateAdapter imageStateAdapter) {
539         if (imageStateAdapter == null) {
540             return;
541         }
542         Vector<State> states = new Vector<State>();
543         for (FilterRepresentation filter : mFilters) {
544             if (filter.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
545                 // TODO: supports Geometry representations in the state panel.
546                 continue;
547             }
548             if (filter instanceof FilterUserPresetRepresentation) {
549                 // do not show the user preset itself in the state panel
550                 continue;
551             }
552             State state = new State(filter.getName());
553             state.setFilterRepresentation(filter);
554             states.add(state);
555         }
556         imageStateAdapter.fill(states);
557     }
558
559     public void setPartialRendering(boolean partialRendering, Rect bounds) {
560         mPartialRendering = partialRendering;
561         mPartialRenderingBounds = bounds;
562     }
563
564     public boolean isPartialRendering() {
565         return mPartialRendering;
566     }
567
568     public Rect getPartialRenderingBounds() {
569         return mPartialRenderingBounds;
570     }
571
572     public Vector<ImageFilter> getUsedFilters(BaseFiltersManager filtersManager) {
573         Vector<ImageFilter> usedFilters = new Vector<ImageFilter>();
574         for (int i = 0; i < mFilters.size(); i++) {
575             FilterRepresentation representation = mFilters.elementAt(i);
576             ImageFilter filter = filtersManager.getFilterForRepresentation(representation);
577             usedFilters.add(filter);
578         }
579         return usedFilters;
580     }
581
582     public String getJsonString(String name) {
583         StringWriter swriter = new StringWriter();
584         try {
585             JsonWriter writer = new JsonWriter(swriter);
586             writeJson(writer, name);
587             writer.close();
588         } catch (IOException e) {
589             return null;
590         }
591         return swriter.toString();
592     }
593
594     public void writeJson(JsonWriter writer, String name) {
595         int numFilters = mFilters.size();
596         try {
597             writer.beginObject();
598             for (int i = 0; i < numFilters; i++) {
599                 FilterRepresentation filter = mFilters.get(i);
600                 if (filter instanceof FilterUserPresetRepresentation) {
601                     continue;
602                 }
603                 String sname = filter.getSerializationName();
604                 if (DEBUG) {
605                     Log.v(LOGTAG, "Serialization: " + sname);
606                     if (sname == null) {
607                         Log.v(LOGTAG, "Serialization name null for filter: " + filter);
608                     }
609                 }
610                 writer.name(sname);
611                 filter.serializeRepresentation(writer);
612             }
613             writer.endObject();
614
615         } catch (IOException e) {
616             e.printStackTrace();
617         }
618     }
619
620     /**
621      * populates preset from JSON string
622      *
623      * @param filterString a JSON string
624      * @return true on success if false ImagePreset is undefined
625      */
626     public boolean readJsonFromString(String filterString) {
627         if (DEBUG) {
628             Log.v(LOGTAG, "reading preset: \"" + filterString + "\"");
629         }
630         StringReader sreader = new StringReader(filterString);
631         try {
632             JsonReader reader = new JsonReader(sreader);
633             boolean ok = readJson(reader);
634             if (!ok) {
635                 reader.close();
636                 return false;
637             }
638             reader.close();
639         } catch (Exception e) {
640             Log.e(LOGTAG, "parsing the filter parameters:", e);
641             return false;
642         }
643         return true;
644     }
645
646     /**
647      * populates preset from JSON stream
648      *
649      * @param sreader a JSON string
650      * @return true on success if false ImagePreset is undefined
651      */
652     public boolean readJson(JsonReader sreader) throws IOException {
653         sreader.beginObject();
654
655         while (sreader.hasNext()) {
656             String name = sreader.nextName();
657             FilterRepresentation filter = creatFilterFromName(name);
658             if (filter == null) {
659                 Log.w(LOGTAG, "UNKNOWN FILTER! " + name);
660                 return false;
661             }
662             filter.deSerializeRepresentation(sreader);
663             addFilter(filter);
664         }
665         sreader.endObject();
666         return true;
667     }
668
669     FilterRepresentation creatFilterFromName(String name) {
670         if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
671             return new FilterRotateRepresentation();
672         } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) {
673             return new FilterMirrorRepresentation();
674         } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) {
675             return new FilterStraightenRepresentation();
676         } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) {
677             return new FilterCropRepresentation();
678         }
679         FiltersManager filtersManager = FiltersManager.getManager();
680         return filtersManager.createFilterFromName(name);
681     }
682
683     public void updateWith(ImagePreset preset) {
684         if (preset.mFilters.size() != mFilters.size()) {
685             Log.e(LOGTAG, "Updating a preset with an incompatible one");
686             return;
687         }
688         for (int i = 0; i < mFilters.size(); i++) {
689             FilterRepresentation destRepresentation = mFilters.elementAt(i);
690             FilterRepresentation sourceRepresentation = preset.mFilters.elementAt(i);
691             destRepresentation.useParametersFrom(sourceRepresentation);
692         }
693     }
694 }