diff options
Diffstat (limited to 'src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java')
-rw-r--r-- | src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java | 694 |
1 files changed, 694 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java new file mode 100644 index 000000000..d34216ad6 --- /dev/null +++ b/src/com/android/gallery3d/filtershow/pipeline/ImagePreset.java @@ -0,0 +1,694 @@ +/* + * Copyright (C) 2012 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.gallery3d.filtershow.pipeline; + +import android.graphics.Bitmap; +import android.graphics.Rect; +import android.support.v8.renderscript.Allocation; +import android.util.JsonReader; +import android.util.JsonWriter; +import android.util.Log; + +import com.android.gallery3d.R; +import com.android.gallery3d.filtershow.cache.ImageLoader; +import com.android.gallery3d.filtershow.filters.BaseFiltersManager; +import com.android.gallery3d.filtershow.filters.FilterCropRepresentation; +import com.android.gallery3d.filtershow.filters.FilterFxRepresentation; +import com.android.gallery3d.filtershow.filters.FilterImageBorderRepresentation; +import com.android.gallery3d.filtershow.filters.FilterMirrorRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRepresentation; +import com.android.gallery3d.filtershow.filters.FilterRotateRepresentation; +import com.android.gallery3d.filtershow.filters.FilterStraightenRepresentation; +import com.android.gallery3d.filtershow.filters.FilterUserPresetRepresentation; +import com.android.gallery3d.filtershow.filters.FiltersManager; +import com.android.gallery3d.filtershow.filters.ImageFilter; +import com.android.gallery3d.filtershow.imageshow.GeometryMathUtils; +import com.android.gallery3d.filtershow.imageshow.MasterImage; +import com.android.gallery3d.filtershow.state.State; +import com.android.gallery3d.filtershow.state.StateAdapter; +import com.android.gallery3d.util.UsageStatistics; + +import java.io.IOException; +import java.io.StringReader; +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Vector; + +public class ImagePreset { + + private static final String LOGTAG = "ImagePreset"; + + private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); + + private boolean mDoApplyGeometry = true; + private boolean mDoApplyFilters = true; + + private boolean mPartialRendering = false; + private Rect mPartialRenderingBounds; + private static final boolean DEBUG = false; + + public ImagePreset() { + } + + public ImagePreset(ImagePreset source) { + for (int i = 0; i < source.mFilters.size(); i++) { + FilterRepresentation sourceRepresentation = source.mFilters.elementAt(i); + mFilters.add(sourceRepresentation.copy()); + } + } + + public Vector<FilterRepresentation> getFilters() { + return mFilters; + } + + public FilterRepresentation getFilterRepresentation(int position) { + FilterRepresentation representation = null; + + representation = mFilters.elementAt(position).copy(); + + return representation; + } + + private static boolean sameSerializationName(String a, String b) { + if (a != null && b != null) { + return a.equals(b); + } else { + return a == null && b == null; + } + } + + public static boolean sameSerializationName(FilterRepresentation a, FilterRepresentation b) { + if (a == null || b == null) { + return false; + } + return sameSerializationName(a.getSerializationName(), b.getSerializationName()); + } + + public int getPositionForRepresentation(FilterRepresentation representation) { + for (int i = 0; i < mFilters.size(); i++) { + if (sameSerializationName(mFilters.elementAt(i), representation)) { + return i; + } + } + return -1; + } + + private FilterRepresentation getFilterRepresentationForType(int type) { + for (int i = 0; i < mFilters.size(); i++) { + if (mFilters.elementAt(i).getFilterType() == type) { + return mFilters.elementAt(i); + } + } + return null; + } + + public int getPositionForType(int type) { + for (int i = 0; i < mFilters.size(); i++) { + if (mFilters.elementAt(i).getFilterType() == type) { + return i; + } + } + return -1; + } + + public FilterRepresentation getFilterRepresentationCopyFrom( + FilterRepresentation filterRepresentation) { + // TODO: add concept of position in the filters (to allow multiple instances) + if (filterRepresentation == null) { + return null; + } + int position = getPositionForRepresentation(filterRepresentation); + if (position == -1) { + return null; + } + FilterRepresentation representation = mFilters.elementAt(position); + if (representation != null) { + representation = representation.copy(); + } + return representation; + } + + public void updateFilterRepresentations(Collection<FilterRepresentation> reps) { + for (FilterRepresentation r : reps) { + updateOrAddFilterRepresentation(r); + } + } + + public void updateOrAddFilterRepresentation(FilterRepresentation rep) { + int pos = getPositionForRepresentation(rep); + if (pos != -1) { + mFilters.elementAt(pos).useParametersFrom(rep); + } else { + addFilter(rep.copy()); + } + } + + public void setDoApplyGeometry(boolean value) { + mDoApplyGeometry = value; + } + + public void setDoApplyFilters(boolean value) { + mDoApplyFilters = value; + } + + public boolean getDoApplyFilters() { + return mDoApplyFilters; + } + + public boolean hasModifications() { + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation filter = mFilters.elementAt(i); + if (!filter.isNil()) { + return true; + } + } + return false; + } + + public boolean isPanoramaSafe() { + for (FilterRepresentation representation : mFilters) { + if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY + && !representation.isNil()) { + return false; + } + if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER + && !representation.isNil()) { + return false; + } + if (representation.getFilterType() == FilterRepresentation.TYPE_VIGNETTE + && !representation.isNil()) { + return false; + } + if (representation.getFilterType() == FilterRepresentation.TYPE_TINYPLANET + && !representation.isNil()) { + return false; + } + } + return true; + } + + public boolean same(ImagePreset preset) { + if (preset == null) { + return false; + } + + if (preset.mFilters.size() != mFilters.size()) { + return false; + } + + if (mDoApplyGeometry != preset.mDoApplyGeometry) { + return false; + } + + if (mDoApplyFilters != preset.mDoApplyFilters) { + if (mFilters.size() > 0 || preset.mFilters.size() > 0) { + return false; + } + } + + if (mDoApplyFilters && preset.mDoApplyFilters) { + for (int i = 0; i < preset.mFilters.size(); i++) { + FilterRepresentation a = preset.mFilters.elementAt(i); + FilterRepresentation b = mFilters.elementAt(i); + + if (!a.same(b)) { + return false; + } + } + } + + return true; + } + + public int similarUpTo(ImagePreset preset) { + for (int i = 0; i < preset.mFilters.size(); i++) { + FilterRepresentation a = preset.mFilters.elementAt(i); + if (i < mFilters.size()) { + FilterRepresentation b = mFilters.elementAt(i); + if (!a.same(b)) { + return i; + } + if (!a.equals(b)) { + return i; + } + } else { + return i; + } + } + return preset.mFilters.size(); + } + + public void showFilters() { + Log.v(LOGTAG, "\\\\\\ showFilters -- " + mFilters.size() + " filters"); + int n = 0; + for (FilterRepresentation representation : mFilters) { + Log.v(LOGTAG, " filter " + n + " : " + representation.toString()); + n++; + } + Log.v(LOGTAG, "/// showFilters -- " + mFilters.size() + " filters"); + } + + public FilterRepresentation getLastRepresentation() { + if (mFilters.size() > 0) { + return mFilters.lastElement(); + } + return null; + } + + public void removeFilter(FilterRepresentation filterRepresentation) { + if (filterRepresentation.getFilterType() == FilterRepresentation.TYPE_BORDER) { + for (int i = 0; i < mFilters.size(); i++) { + if (mFilters.elementAt(i).getFilterType() + == filterRepresentation.getFilterType()) { + mFilters.remove(i); + break; + } + } + } else { + for (int i = 0; i < mFilters.size(); i++) { + if (sameSerializationName(mFilters.elementAt(i), filterRepresentation)) { + mFilters.remove(i); + break; + } + } + } + } + + // If the filter is an "None" effect or border, then just don't add this filter. + public void addFilter(FilterRepresentation representation) { + if (representation instanceof FilterUserPresetRepresentation) { + ImagePreset preset = ((FilterUserPresetRepresentation) representation).getImagePreset(); + // user preset replace everything but geometry + mFilters.clear(); + for (int i = 0; i < preset.nbFilters(); i++) { + addFilter(preset.getFilterRepresentation(i)); + } + mFilters.add(representation); + } else if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + // Add geometry filter, removing duplicates and do-nothing operations. + for (int i = 0; i < mFilters.size(); i++) { + if (sameSerializationName(representation, mFilters.elementAt(i))) { + mFilters.remove(i); + } + } + if (!representation.isNil()) { + mFilters.add(representation); + } + } else if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { + removeFilter(representation); + if (!isNoneBorderFilter(representation)) { + mFilters.add(representation); + } + } else if (representation.getFilterType() == FilterRepresentation.TYPE_FX) { + boolean found = false; + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation current = mFilters.elementAt(i); + int type = current.getFilterType(); + if (found) { + if (type != FilterRepresentation.TYPE_VIGNETTE) { + mFilters.remove(i); + continue; + } + } + if (type == FilterRepresentation.TYPE_FX) { + if (current instanceof FilterUserPresetRepresentation) { + ImagePreset preset = ((FilterUserPresetRepresentation) current) + .getImagePreset(); + // If we had an existing user preset, let's remove all the presets that + // were added by it + for (int j = 0; j < preset.nbFilters(); j++) { + FilterRepresentation rep = preset.getFilterRepresentation(j); + int pos = getPositionForRepresentation(rep); + if (pos != -1) { + mFilters.remove(pos); + } + } + int pos = getPositionForRepresentation(current); + if (pos != -1) { + mFilters.remove(pos); + } else { + pos = 0; + } + if (!isNoneFxFilter(representation)) { + mFilters.add(pos, representation); + } + + } else { + mFilters.remove(i); + if (!isNoneFxFilter(representation)) { + mFilters.add(i, representation); + } + } + found = true; + } + } + if (!found) { + if (!isNoneFxFilter(representation)) { + mFilters.add(representation); + } + } + } else { + mFilters.add(representation); + } + } + + private boolean isNoneBorderFilter(FilterRepresentation representation) { + return representation instanceof FilterImageBorderRepresentation && + ((FilterImageBorderRepresentation) representation).getDrawableResource() == 0; + } + + private boolean isNoneFxFilter(FilterRepresentation representation) { + return representation instanceof FilterFxRepresentation && + ((FilterFxRepresentation) representation).getNameResource() == R.string.none; + } + + public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) { + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation representation = mFilters.elementAt(i); + if (sameSerializationName(representation, filterRepresentation)) { + return representation; + } + } + return null; + } + + public Bitmap apply(Bitmap original, FilterEnvironment environment) { + Bitmap bitmap = original; + bitmap = applyFilters(bitmap, -1, -1, environment); + return applyBorder(bitmap, environment); + } + + public Collection<FilterRepresentation> getGeometryFilters() { + ArrayList<FilterRepresentation> geometry = new ArrayList<FilterRepresentation>(); + for (FilterRepresentation r : mFilters) { + if (r.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + geometry.add(r); + } + } + return geometry; + } + + public FilterRepresentation getFilterWithSerializationName(String serializationName) { + for (FilterRepresentation r : mFilters) { + if (r != null) { + if (sameSerializationName(r.getSerializationName(), serializationName)) { + return r.copy(); + } + } + } + return null; + } + + public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) { + // Apply any transform -- 90 rotate, flip, straighten, crop + // Returns a new bitmap. + if (mDoApplyGeometry) { + bitmap = GeometryMathUtils.applyGeometryRepresentations(getGeometryFilters(), bitmap); + } + return bitmap; + } + + public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) { + // get the border from the list of filters. + FilterRepresentation border = getFilterRepresentationForType( + FilterRepresentation.TYPE_BORDER); + if (border != null && mDoApplyGeometry) { + bitmap = environment.applyRepresentation(border, bitmap); + if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + "SaveBorder", border.getSerializationName(), 1); + } + } + return bitmap; + } + + public int nbFilters() { + return mFilters.size(); + } + + public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) { + if (mDoApplyFilters) { + if (from < 0) { + from = 0; + } + if (to == -1) { + to = mFilters.size(); + } + if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + "SaveFilters", "Total", to - from + 1); + } + for (int i = from; i < to; i++) { + FilterRepresentation representation = mFilters.elementAt(i); + if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + // skip the geometry as it's already applied. + continue; + } + if (representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { + // for now, let's skip the border as it will be applied in + // applyBorder() + // TODO: might be worth getting rid of applyBorder. + continue; + } + bitmap = environment.applyRepresentation(representation, bitmap); + if (environment.getQuality() == FilterEnvironment.QUALITY_FINAL) { + UsageStatistics.onEvent(UsageStatistics.COMPONENT_EDITOR, + "SaveFilter", representation.getSerializationName(), 1); + } + if (environment.needsStop()) { + return bitmap; + } + } + } + + return bitmap; + } + + public void applyBorder(Allocation in, Allocation out, + boolean copyOut, FilterEnvironment environment) { + FilterRepresentation border = getFilterRepresentationForType( + FilterRepresentation.TYPE_BORDER); + if (border != null && mDoApplyGeometry) { + // TODO: should keep the bitmap around + Allocation bitmapIn = in; + if (copyOut) { + bitmapIn = Allocation.createTyped( + CachingPipeline.getRenderScriptContext(), in.getType()); + bitmapIn.copyFrom(out); + } + environment.applyRepresentation(border, bitmapIn, out); + } + } + + public void applyFilters(int from, int to, Allocation in, Allocation out, + FilterEnvironment environment) { + if (mDoApplyFilters) { + if (from < 0) { + from = 0; + } + if (to == -1) { + to = mFilters.size(); + } + for (int i = from; i < to; i++) { + FilterRepresentation representation = mFilters.elementAt(i); + if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY + || representation.getFilterType() == FilterRepresentation.TYPE_BORDER) { + continue; + } + if (i > from) { + in.copyFrom(out); + } + environment.applyRepresentation(representation, in, out); + } + } + } + + public boolean canDoPartialRendering() { + if (MasterImage.getImage().getZoomOrientation() != ImageLoader.ORI_NORMAL) { + return false; + } + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation representation = mFilters.elementAt(i); + if (representation.getFilterType() == FilterRepresentation.TYPE_GEOMETRY + && !representation.isNil()) { + return false; + } + if (!representation.supportsPartialRendering()) { + return false; + } + } + return true; + } + + public void fillImageStateAdapter(StateAdapter imageStateAdapter) { + if (imageStateAdapter == null) { + return; + } + Vector<State> states = new Vector<State>(); + for (FilterRepresentation filter : mFilters) { + if (filter.getFilterType() == FilterRepresentation.TYPE_GEOMETRY) { + // TODO: supports Geometry representations in the state panel. + continue; + } + if (filter instanceof FilterUserPresetRepresentation) { + // do not show the user preset itself in the state panel + continue; + } + State state = new State(filter.getName()); + state.setFilterRepresentation(filter); + states.add(state); + } + imageStateAdapter.fill(states); + } + + public void setPartialRendering(boolean partialRendering, Rect bounds) { + mPartialRendering = partialRendering; + mPartialRenderingBounds = bounds; + } + + public boolean isPartialRendering() { + return mPartialRendering; + } + + public Rect getPartialRenderingBounds() { + return mPartialRenderingBounds; + } + + public Vector<ImageFilter> getUsedFilters(BaseFiltersManager filtersManager) { + Vector<ImageFilter> usedFilters = new Vector<ImageFilter>(); + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation representation = mFilters.elementAt(i); + ImageFilter filter = filtersManager.getFilterForRepresentation(representation); + usedFilters.add(filter); + } + return usedFilters; + } + + public String getJsonString(String name) { + StringWriter swriter = new StringWriter(); + try { + JsonWriter writer = new JsonWriter(swriter); + writeJson(writer, name); + writer.close(); + } catch (IOException e) { + return null; + } + return swriter.toString(); + } + + public void writeJson(JsonWriter writer, String name) { + int numFilters = mFilters.size(); + try { + writer.beginObject(); + for (int i = 0; i < numFilters; i++) { + FilterRepresentation filter = mFilters.get(i); + if (filter instanceof FilterUserPresetRepresentation) { + continue; + } + String sname = filter.getSerializationName(); + if (DEBUG) { + Log.v(LOGTAG, "Serialization: " + sname); + if (sname == null) { + Log.v(LOGTAG, "Serialization name null for filter: " + filter); + } + } + writer.name(sname); + filter.serializeRepresentation(writer); + } + writer.endObject(); + + } catch (IOException e) { + Log.e(LOGTAG,"Error encoding JASON",e); + } + } + + /** + * populates preset from JSON string + * + * @param filterString a JSON string + * @return true on success if false ImagePreset is undefined + */ + public boolean readJsonFromString(String filterString) { + if (DEBUG) { + Log.v(LOGTAG, "reading preset: \"" + filterString + "\""); + } + StringReader sreader = new StringReader(filterString); + try { + JsonReader reader = new JsonReader(sreader); + boolean ok = readJson(reader); + if (!ok) { + reader.close(); + return false; + } + reader.close(); + } catch (Exception e) { + Log.e(LOGTAG, "parsing the filter parameters:", e); + return false; + } + return true; + } + + /** + * populates preset from JSON stream + * + * @param sreader a JSON string + * @return true on success if false ImagePreset is undefined + */ + public boolean readJson(JsonReader sreader) throws IOException { + sreader.beginObject(); + + while (sreader.hasNext()) { + String name = sreader.nextName(); + FilterRepresentation filter = creatFilterFromName(name); + if (filter == null) { + Log.w(LOGTAG, "UNKNOWN FILTER! " + name); + return false; + } + filter.deSerializeRepresentation(sreader); + addFilter(filter); + } + sreader.endObject(); + return true; + } + + FilterRepresentation creatFilterFromName(String name) { + if (FilterRotateRepresentation.SERIALIZATION_NAME.equals(name)) { + return new FilterRotateRepresentation(); + } else if (FilterMirrorRepresentation.SERIALIZATION_NAME.equals(name)) { + return new FilterMirrorRepresentation(); + } else if (FilterStraightenRepresentation.SERIALIZATION_NAME.equals(name)) { + return new FilterStraightenRepresentation(); + } else if (FilterCropRepresentation.SERIALIZATION_NAME.equals(name)) { + return new FilterCropRepresentation(); + } + FiltersManager filtersManager = FiltersManager.getManager(); + return filtersManager.createFilterFromName(name); + } + + public void updateWith(ImagePreset preset) { + if (preset.mFilters.size() != mFilters.size()) { + Log.e(LOGTAG, "Updating a preset with an incompatible one"); + return; + } + for (int i = 0; i < mFilters.size(); i++) { + FilterRepresentation destRepresentation = mFilters.elementAt(i); + FilterRepresentation sourceRepresentation = preset.mFilters.elementAt(i); + destRepresentation.useParametersFrom(sourceRepresentation); + } + } +} |