2 * Copyright (C) 2012 The Android Open Source Project
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.android.gallery3d.filtershow.pipeline;
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;
26 import com.android.gallery3d.R;
27 import com.android.gallery3d.filtershow.cache.BitmapCache;
28 import com.android.gallery3d.filtershow.cache.ImageLoader;
29 import com.android.gallery3d.filtershow.filters.BaseFiltersManager;
30 import com.android.gallery3d.filtershow.filters.FilterCropRepresentation;
31 import com.android.gallery3d.filtershow.filters.FilterFxRepresentation;
32 import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation;
33 import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation;
34 import com.android.gallery3d.filtershow.filters.FilterRepresentation;
35 import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation;
36 import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation;
37 import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation;
38 import com.android.gallery3d.filtershow.filters.FiltersManager;
39 import com.android.gallery3d.filtershow.filters.ImageFilter;
40 import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils;
41 import com.android.gallery3d.filtershow.imageshow.MasterImage;
42 import com.android.gallery3d.filtershow.state.State;
43 import com.android.gallery3d.filtershow.state.StateAdapter;
44 import com.android.gallery3d.util.UsageStatistics;
46 import java.io.IOException;
47 import java.io.StringReader;
48 import java.io.StringWriter;
49 import java.util.ArrayList;
50 import java.util.Collection;
51 import java.util.Vector;
53 public class ImagePreset {
55 private static final String LOGTAG = "ImagePreset";
57 private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>();
59 private boolean mDoApplyGeometry = true;
60 private boolean mDoApplyFilters = true;
62 private boolean mPartialRendering = false;
63 private Rect mPartialRenderingBounds;
64 private static final boolean DEBUG = false;
66 public ImagePreset() {
69 public ImagePreset(ImagePreset source) {
70 for (int i = 0; i < source.mFilters.size(); i++) {
71 FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i);
72 mFilters.add(sourceRepresentation.copy());
76 public Vector<FilterRepresentation> getFilters() {
80 public FilterRepresentation getFilterRepresentation(int position) {
81 FilterRepresentation representation = null;
83 representation = mFilters.elementAt(position).copy();
85 return representation;
88 private static boolean sameSerializationName(String a, String b) {
89 if (a != null && b != null) {
92 return a == null && b == null;
96 public static boolean sameSerializationName(FilterRepresentation a, FilterRepresentation b) {
97 if (a == null || b == null) {
100 return sameSerializationName(a.getSerializationName(), b.getSerializationName());
103 public int getPositionForRepresentation(FilterRepresentation representation) {
104 for (int i = 0; i < mFilters.size(); i++) {
105 if (sameSerializationName(mFilters.elementAt(i), representation)) {
112 private FilterRepresentation getFilterRepresentationForType(int type) {
113 for (int i = 0; i < mFilters.size(); i++) {
114 if (mFilters.elementAt(i).getFilterType() == type) {
115 return mFilters.elementAt(i);
121 public int getPositionForType(int type) {
122 for (int i = 0; i < mFilters.size(); i++) {
123 if (mFilters.elementAt(i).getFilterType() == type) {
130 public FilterRepresentation getFilterRepresentationCopyFrom(
131 FilterRepresentation filterRepresentation) {
132 // TODO: add concept of position in the filters (to allow multiple instances)
133 if (filterRepresentation == null) {
136 int position = getPositionForRepresentation(filterRepresentation);
137 if (position == -1) {
140 FilterRepresentation representation = mFilters.elementAt(position);
141 if (representation != null) {
142 representation = representation.copy();
144 return representation;
147 public void updateFilterRepresentations(Collection<FilterRepresentation> reps) {
148 for (FilterRepresentation r : reps) {
149 updateOrAddFilterRepresentation(r);
153 public void updateOrAddFilterRepresentation(FilterRepresentation rep) {
154 int pos = getPositionForRepresentation(rep);
156 mFilters.elementAt(pos).useParametersFrom(rep);
158 addFilter(rep.copy());
162 public void setDoApplyGeometry(boolean value) {
163 mDoApplyGeometry = value;
166 public void setDoApplyFilters(boolean value) {
167 mDoApplyFilters = value;
170 public boolean getDoApplyFilters() {
171 return mDoApplyFilters;
174 public boolean hasModifications() {
175 for (int i = 0; i < mFilters.size(); i++) {
176 FilterRepresentation filter = mFilters.elementAt(i);
177 if (!filter.isNil()) {
184 public boolean contains(byte type) {
185 for (FilterRepresentation representation : mFilters) {
186 if (representation.getFilterType() == type
187 && !representation.isNil()) {
194 public boolean isPanoramaSafe() {
195 for (FilterRepresentation representation : mFilters) {
196 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
197 && !representation.isNil()) {
200 if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER
201 && !representation.isNil()) {
204 if (representation.getFilterType() == FilterRepresentation.TYPE_VIGNETTE
205 && !representation.isNil()) {
208 if (representation.getFilterType() == FilterRepresentation.TYPE_TINYPLANET
209 && !representation.isNil()) {
216 public boolean same(ImagePreset preset) {
217 if (preset == null) {
221 if (preset.mFilters.size() != mFilters.size()) {
225 if (mDoApplyGeometry != preset.mDoApplyGeometry) {
229 if (mDoApplyFilters != preset.mDoApplyFilters) {
230 if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
235 if (mDoApplyFilters && preset.mDoApplyFilters) {
236 for (int i = 0; i < preset.mFilters.size(); i++) {
237 FilterRepresentation a = preset.mFilters.elementAt(i);
238 FilterRepresentation b = mFilters.elementAt(i);
249 public boolean equals(ImagePreset preset) {
250 if (preset == null) {
254 if (preset.mFilters.size() != mFilters.size()) {
258 if (mDoApplyGeometry != preset.mDoApplyGeometry) {
262 if (mDoApplyFilters != preset.mDoApplyFilters) {
263 if (mFilters.size() > 0 || preset.mFilters.size() > 0) {
268 for (int i = 0; i < preset.mFilters.size(); i++) {
269 FilterRepresentation a = preset.mFilters.elementAt(i);
270 FilterRepresentation b = mFilters.elementAt(i);
280 public int similarUpTo(ImagePreset preset) {
281 for (int i = 0; i < preset.mFilters.size(); i++) {
282 FilterRepresentation a = preset.mFilters.elementAt(i);
283 if (i < mFilters.size()) {
284 FilterRepresentation b = mFilters.elementAt(i);
295 return preset.mFilters.size();
298 public void showFilters() {
299 Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters");
301 for (FilterRepresentation representation : mFilters) {
302 Log.v(LOGTAG, " filter " + n + " : " + representation.toString());
305 Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters");
308 public FilterRepresentation getLastRepresentation() {
309 if (mFilters.size() > 0) {
310 return mFilters.lastElement();
315 public void removeFilter(FilterRepresentation filterRepresentation) {
316 if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
317 for (int i = 0; i < mFilters.size(); i++) {
318 if (mFilters.elementAt(i).getFilterType()
319 == filterRepresentation.getFilterType()) {
325 for (int i = 0; i < mFilters.size(); i++) {
326 if (sameSerializationName(mFilters.elementAt(i), filterRepresentation)) {
334 // If the filter is an "None" effect or border, then just don't add this filter.
335 public void addFilter(FilterRepresentation representation) {
336 if (representation instanceof FilterUserPresetRepresentation) {
337 ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset();
338 // user preset replace everything but geometry
340 for (int i = 0; i < preset.nbFilters(); i++) {
341 addFilter(preset.getFilterRepresentation(i));
343 mFilters.add(representation);
344 } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
345 // Add geometry filter, removing duplicates and do-nothing operations.
346 for (int i = 0; i < mFilters.size(); i++) {
347 if (sameSerializationName(representation, mFilters.elementAt(i))) {
352 for (; index < mFilters.size(); index++) {
353 FilterRepresentation rep = mFilters.elementAt(index);
354 if (rep.getFilterType() != FilterRepresentation.TYPE_GEOMETRY) {
358 if (!representation.isNil()) {
359 mFilters.insertElementAt(representation, index);
361 } else if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
362 removeFilter(representation);
363 if (!isNoneBorderFilter(representation)) {
364 mFilters.add(representation);
366 } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) {
367 boolean found = false;
368 for (int i = 0; i < mFilters.size(); i++) {
369 FilterRepresentation current = mFilters.elementAt(i);
370 int type = current.getFilterType();
372 if (type != FilterRepresentation.TYPE_VIGNETTE) {
377 if (type == FilterRepresentation.TYPE_FX) {
378 if (current instanceof FilterUserPresetRepresentation) {
379 ImagePreset preset = ((FilterUserPresetRepresentation) current)
381 // If we had an existing user preset, let's remove all the presets that
383 for (int j = 0; j < preset.nbFilters(); j++) {
384 FilterRepresentation rep = preset.getFilterRepresentation(j);
385 int pos = getPositionForRepresentation(rep);
387 mFilters.remove(pos);
390 int pos = getPositionForRepresentation(current);
392 mFilters.remove(pos);
396 if (!isNoneFxFilter(representation)) {
397 mFilters.add(pos, representation);
402 if (!isNoneFxFilter(representation)) {
403 mFilters.add(i, representation);
410 if (!isNoneFxFilter(representation)) {
411 mFilters.add(representation);
415 mFilters.add(representation);
419 private boolean isNoneBorderFilter(FilterRepresentation representation) {
420 return representation instanceof FilterImageBorderRepresentation &&
421 ((FilterImageBorderRepresentation) representation).getDrawableResource() == 0;
424 private boolean isNoneFxFilter(FilterRepresentation representation) {
425 return representation instanceof FilterFxRepresentation &&
426 ((FilterFxRepresentation) representation).getNameResource() == R.string.none;
429 public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) {
430 for (int i = 0; i < mFilters.size(); i++) {
431 FilterRepresentation representation = mFilters.elementAt(i);
432 if (sameSerializationName(representation, filterRepresentation)) {
433 return representation;
439 public Bitmap apply(Bitmap original, FilterEnvironment environment) {
440 Bitmap bitmap = original;
441 bitmap = applyFilters(bitmap, -1, -1, environment);
442 return applyBorder(bitmap, environment);
445 public Collection<FilterRepresentation> getGeometryFilters() {
446 ArrayList<FilterRepresentation> geometry = new ArrayList<FilterRepresentation>();
447 for (FilterRepresentation r : mFilters) {
448 if (r.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
455 public FilterRepresentation getFilterWithSerializationName(String serializationName) {
456 for (FilterRepresentation r : mFilters) {
458 if (sameSerializationName(r.getSerializationName(), serializationName)) {
466 public Rect finalGeometryRect(int width, int height) {
467 return GeometryMathUtils.finalGeometryRect(width, height, getGeometryFilters());
470 public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) {
471 // Apply any transform -- 90 rotate, flip, straighten, crop
472 // Returns a new bitmap.
473 if (mDoApplyGeometry) {
474 Bitmap bmp = GeometryMathUtils.applyGeometryRepresentations(
475 getGeometryFilters(), bitmap);
477 environment.cache(bitmap);
484 public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) {
485 // get the border from the list of filters.
486 FilterRepresentation border = getFilterRepresentationForType(
487 FilterRepresentation.TYPE_BORDER);
488 if (border != null && mDoApplyGeometry) {
489 bitmap = environment.applyRepresentation(border, bitmap);
490 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
491 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
492 "SaveBorder", border.getSerializationName(), 1);
498 public int nbFilters() {
499 return mFilters.size();
502 public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) {
503 if (mDoApplyFilters) {
508 to = mFilters.size();
510 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
511 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
512 "SaveFilters", "Total", to - from + 1);
514 for (int i = from; i < to; i++) {
515 FilterRepresentation representation = mFilters.elementAt(i);
516 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) {
517 // skip the geometry as it's already applied.
520 if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
521 // for now, let's skip the border as it will be applied in
523 // TODO: might be worth getting rid of applyBorder.
527 bitmap = environment.applyRepresentation(representation, bitmap);
529 environment.cache(tmp);
531 if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) {
532 UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR,
533 "SaveFilter", representation.getSerializationName(), 1);
535 if (environment.needsStop()) {
544 public void applyBorder(Allocation in, Allocation out,
545 boolean copyOut, FilterEnvironment environment) {
546 FilterRepresentation border = getFilterRepresentationForType(
547 FilterRepresentation.TYPE_BORDER);
548 if (border != null && mDoApplyGeometry) {
549 // TODO: should keep the bitmap around
550 Allocation bitmapIn = in;
552 bitmapIn = Allocation.createTyped(
553 CachingPipeline.getRenderScriptContext(), in.getType());
554 bitmapIn.copyFrom(out);
556 environment.applyRepresentation(border, bitmapIn, out);
560 public void applyFilters(int from, int to, Allocation in, Allocation out,
561 FilterEnvironment environment) {
562 if (mDoApplyFilters) {
567 to = mFilters.size();
569 for (int i = from; i < to; i++) {
570 FilterRepresentation representation = mFilters.elementAt(i);
571 if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY
572 || representation.getFilterType() == FilterRepresentation.TYPE_BORDER) {
578 environment.applyRepresentation(representation, in, out);
583 public boolean canDoPartialRendering() {
584 if (MasterImage.getImage().getZoomOrientation() != ImageLoader.ORI_NORMAL) {
587 for (int i = 0; i < mFilters.size(); i++) {
588 FilterRepresentation representation = mFilters.elementAt(i);
589 if (!representation.supportsPartialRendering()) {
596 public void fillImageStateAdapter(StateAdapter imageStateAdapter) {
597 if (imageStateAdapter == null) {
600 Vector<State> states = new Vector<State>();
601 for (FilterRepresentation filter : mFilters) {
602 if (filter instanceof FilterUserPresetRepresentation) {
603 // do not show the user preset itself in the state panel
606 State state = new State(filter.getName());
607 state.setFilterRepresentation(filter);
610 imageStateAdapter.fill(states);
613 public void setPartialRendering(boolean partialRendering, Rect bounds) {
614 mPartialRendering = partialRendering;
615 mPartialRenderingBounds = bounds;
618 public boolean isPartialRendering() {
619 return mPartialRendering;
622 public Rect getPartialRenderingBounds() {
623 return mPartialRenderingBounds;
626 public Vector<ImageFilter> getUsedFilters(BaseFiltersManager filtersManager) {
627 Vector<ImageFilter> usedFilters = new Vector<ImageFilter>();
628 for (int i = 0; i < mFilters.size(); i++) {
629 FilterRepresentation representation = mFilters.elementAt(i);
630 ImageFilter filter = filtersManager.getFilterForRepresentation(representation);
631 usedFilters.add(filter);
636 public String getJsonString(String name) {
637 StringWriter swriter = new StringWriter();
639 JsonWriter writer = new JsonWriter(swriter);
640 writeJson(writer, name);
642 } catch (IOException e) {
645 return swriter.toString();
648 public void writeJson(JsonWriter writer, String name) {
649 int numFilters = mFilters.size();
651 writer.beginObject();
652 for (int i = 0; i < numFilters; i++) {
653 FilterRepresentation filter = mFilters.get(i);
654 if (filter instanceof FilterUserPresetRepresentation) {
657 String sname = filter.getSerializationName();
659 Log.v(LOGTAG, "Serialization: " + sname);
661 Log.v(LOGTAG, "Serialization name null for filter: " + filter);
665 filter.serializeRepresentation(writer);
669 } catch (IOException e) {
670 Log.e(LOGTAG,"Error encoding JASON",e);
675 * populates preset from JSON string
677 * @param filterString a JSON string
678 * @return true on success if false ImagePreset is undefined
680 public boolean readJsonFromString(String filterString) {
682 Log.v(LOGTAG, "reading preset: \"" + filterString + "\"");
684 StringReader sreader = new StringReader(filterString);
686 JsonReader reader = new JsonReader(sreader);
687 boolean ok = readJson(reader);
693 } catch (Exception e) {
694 Log.e(LOGTAG, "parsing the filter parameters:", e);
701 * populates preset from JSON stream
703 * @param sreader a JSON string
704 * @return true on success if false ImagePreset is undefined
706 public boolean readJson(JsonReader sreader) throws IOException {
707 sreader.beginObject();
709 while (sreader.hasNext()) {
710 String name = sreader.nextName();
711 FilterRepresentation filter = creatFilterFromName(name);
712 if (filter == null) {
713 Log.w(LOGTAG, "UNKNOWN FILTER! " + name);
716 filter.deSerializeRepresentation(sreader);
723 FilterRepresentation creatFilterFromName(String name) {
724 if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) {
725 return new FilterRotateRepresentation();
726 } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) {
727 return new FilterMirrorRepresentation();
728 } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) {
729 return new FilterStraightenRepresentation();
730 } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) {
731 return new FilterCropRepresentation();
733 FiltersManager filtersManager = FiltersManager.getManager();
734 return filtersManager.createFilterFromName(name);
737 public void updateWith(ImagePreset preset) {
738 if (preset.mFilters.size() != mFilters.size()) {
739 Log.e(LOGTAG, "Updating a preset with an incompatible one");
742 for (int i = 0; i < mFilters.size(); i++) {
743 FilterRepresentation destRepresentation = mFilters.elementAt(i);
744 FilterRepresentation sourceRepresentation = preset.mFilters.elementAt(i);
745 destRepresentation.useParametersFrom(sourceRepresentation);