OSDN Git Service

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