| /* |
| * 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.presets; |
| |
| import android.graphics.Bitmap; |
| import android.graphics.Rect; |
| import android.support.v8.renderscript.Allocation; |
| import android.util.Log; |
| |
| import com.android.gallery3d.filtershow.cache.CachingPipeline; |
| import com.android.gallery3d.filtershow.cache.ImageLoader; |
| import com.android.gallery3d.filtershow.filters.BaseFiltersManager; |
| import com.android.gallery3d.filtershow.filters.FilterRepresentation; |
| import com.android.gallery3d.filtershow.filters.ImageFilter; |
| import com.android.gallery3d.filtershow.imageshow.GeometryMetadata; |
| import com.android.gallery3d.filtershow.imageshow.MasterImage; |
| import com.android.gallery3d.filtershow.state.StateAdapter; |
| |
| import java.util.Vector; |
| |
| public class ImagePreset { |
| |
| private static final String LOGTAG = "ImagePreset"; |
| |
| private FilterRepresentation mBorder = null; |
| public static final int QUALITY_ICON = 0; |
| public static final int QUALITY_PREVIEW = 1; |
| public static final int QUALITY_FINAL = 2; |
| public static final int STYLE_ICON = 3; |
| |
| private ImageLoader mImageLoader = null; |
| |
| private Vector<FilterRepresentation> mFilters = new Vector<FilterRepresentation>(); |
| |
| protected String mName = "Original"; |
| private String mHistoryName = "Original"; |
| protected boolean mIsFxPreset = false; |
| |
| private boolean mDoApplyGeometry = true; |
| private boolean mDoApplyFilters = true; |
| |
| public final GeometryMetadata mGeoData = new GeometryMetadata(); |
| private boolean mPartialRendering = false; |
| private Rect mPartialRenderingBounds; |
| |
| private Bitmap mPreviewImage; |
| |
| public ImagePreset() { |
| setup(); |
| } |
| |
| public ImagePreset(String historyName) { |
| setHistoryName(historyName); |
| setup(); |
| } |
| |
| public ImagePreset(ImagePreset source, String historyName) { |
| this(source); |
| if (historyName != null) { |
| setHistoryName(historyName); |
| } |
| } |
| |
| public ImagePreset(ImagePreset source) { |
| try { |
| if (source.mBorder != null) { |
| mBorder = source.mBorder.clone(); |
| } |
| for (int i = 0; i < source.mFilters.size(); i++) { |
| FilterRepresentation representation = source.mFilters.elementAt(i).clone(); |
| addFilter(representation); |
| } |
| } catch (java.lang.CloneNotSupportedException e) { |
| Log.v(LOGTAG, "Exception trying to clone: " + e); |
| } |
| mName = source.name(); |
| mHistoryName = source.name(); |
| mIsFxPreset = source.isFx(); |
| mImageLoader = source.getImageLoader(); |
| mPreviewImage = source.getPreviewImage(); |
| |
| mGeoData.set(source.mGeoData); |
| } |
| |
| public FilterRepresentation getFilterRepresentation(int position) { |
| FilterRepresentation representation = null; |
| try { |
| representation = mFilters.elementAt(position).clone(); |
| } catch (CloneNotSupportedException e) { |
| e.printStackTrace(); |
| } |
| return representation; |
| } |
| |
| public int getPositionForRepresentation(FilterRepresentation representation) { |
| for (int i = 0; i < mFilters.size(); i++) { |
| if (mFilters.elementAt(i).getFilterClass() == representation.getFilterClass()) { |
| 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; |
| } |
| FilterRepresentation representation = null; |
| if ((mBorder != null) |
| && (mBorder.getFilterClass() == filterRepresentation.getFilterClass())) { |
| // TODO: instead of special casing for border, we should correctly implements "filters priority set" |
| representation = mBorder; |
| } else { |
| int position = getPositionForRepresentation(filterRepresentation); |
| if (position == -1) { |
| return null; |
| } |
| representation = mFilters.elementAt(position); |
| } |
| if (representation != null) { |
| try { |
| representation = representation.clone(); |
| } catch (CloneNotSupportedException e) { |
| e.printStackTrace(); |
| } |
| } |
| return representation; |
| } |
| |
| public void updateFilterRepresentation(FilterRepresentation representation) { |
| if (representation == null) { |
| return; |
| } |
| synchronized (mFilters) { |
| if (representation instanceof GeometryMetadata) { |
| setGeometry((GeometryMetadata) representation); |
| } else { |
| if ((mBorder != null) |
| && (mBorder.getFilterClass() == representation.getFilterClass())) { |
| mBorder.updateTempParametersFrom(representation); |
| } else { |
| int position = getPositionForRepresentation(representation); |
| if (position == -1) { |
| return; |
| } |
| FilterRepresentation old = mFilters.elementAt(position); |
| old.updateTempParametersFrom(representation); |
| } |
| } |
| } |
| MasterImage.getImage().invalidatePreview(); |
| fillImageStateAdapter(MasterImage.getImage().getState()); |
| } |
| |
| public void setDoApplyGeometry(boolean value) { |
| mDoApplyGeometry = value; |
| } |
| |
| public void setDoApplyFilters(boolean value) { |
| mDoApplyFilters = value; |
| } |
| |
| public boolean getDoApplyFilters() { |
| return mDoApplyFilters; |
| } |
| |
| public synchronized GeometryMetadata getGeometry() { |
| return mGeoData; |
| } |
| |
| public boolean hasModifications() { |
| if (mBorder != null && !mBorder.isNil()) { |
| return true; |
| } |
| if (mGeoData.hasModifications()) { |
| return true; |
| } |
| for (int i = 0; i < mFilters.size(); i++) { |
| FilterRepresentation filter = mFilters.elementAt(i); |
| if (!filter.isNil()) { |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| public boolean isPanoramaSafe() { |
| if (mBorder != null && !mBorder.isNil()) { |
| return false; |
| } |
| if (mGeoData.hasModifications()) { |
| return false; |
| } |
| for (FilterRepresentation representation : mFilters) { |
| if (representation.getPriority() == FilterRepresentation.TYPE_VIGNETTE |
| && !representation.isNil()) { |
| return false; |
| } |
| if (representation.getPriority() == FilterRepresentation.TYPE_TINYPLANET |
| && !representation.isNil()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public synchronized void setGeometry(GeometryMetadata m) { |
| mGeoData.set(m); |
| MasterImage.getImage().notifyGeometryChange(); |
| } |
| |
| private void setBorder(FilterRepresentation filter) { |
| mBorder = filter; |
| } |
| |
| public void resetBorder() { |
| mBorder = null; |
| } |
| |
| public boolean isFx() { |
| return mIsFxPreset; |
| } |
| |
| public void setIsFx(boolean value) { |
| mIsFxPreset = value; |
| } |
| |
| public void setName(String name) { |
| mName = name; |
| mHistoryName = name; |
| } |
| |
| public void setHistoryName(String name) { |
| mHistoryName = name; |
| } |
| |
| public ImageLoader getImageLoader() { |
| return mImageLoader; |
| } |
| |
| public void setImageLoader(ImageLoader mImageLoader) { |
| this.mImageLoader = mImageLoader; |
| } |
| |
| public boolean equals(ImagePreset preset) { |
| if (!same(preset)) { |
| 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.equals(b)) { |
| return false; |
| } |
| } |
| } |
| return true; |
| } |
| |
| public boolean same(ImagePreset preset) { |
| if (preset == null) { |
| return false; |
| } |
| |
| if (preset.mFilters.size() != mFilters.size()) { |
| return false; |
| } |
| |
| if (!mName.equalsIgnoreCase(preset.name())) { |
| return false; |
| } |
| |
| if (mDoApplyGeometry != preset.mDoApplyGeometry) { |
| return false; |
| } |
| |
| if (mDoApplyGeometry && !mGeoData.equals(preset.mGeoData)) { |
| return false; |
| } |
| |
| if (mDoApplyGeometry && mBorder != preset.mBorder) { |
| return false; |
| } |
| |
| if (mBorder != null && !mBorder.equals(preset.mBorder)) { |
| 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) { |
| if (!mGeoData.equals(preset.mGeoData)) { |
| return -1; |
| } |
| |
| 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 String name() { |
| return mName; |
| } |
| |
| public String historyName() { |
| return mHistoryName; |
| } |
| |
| 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) { |
| for (int i = 0; i < mFilters.size(); i++) { |
| if (mFilters.elementAt(i).getFilterClass() == filterRepresentation.getFilterClass()) { |
| mFilters.remove(i); |
| setHistoryName("Remove"); |
| return; |
| } |
| } |
| } |
| |
| public void addFilter(FilterRepresentation representation) { |
| if (representation instanceof GeometryMetadata) { |
| setGeometry((GeometryMetadata) representation); |
| return; |
| } |
| if (representation.getPriority() == FilterRepresentation.TYPE_BORDER) { |
| setHistoryName(representation.getName()); |
| setBorder(representation); |
| } else if (representation.getPriority() == FilterRepresentation.TYPE_FX) { |
| boolean found = false; |
| for (int i = 0; i < mFilters.size(); i++) { |
| int type = mFilters.elementAt(i).getPriority(); |
| if (found) { |
| if (type != FilterRepresentation.TYPE_VIGNETTE) { |
| mFilters.remove(i); |
| continue; |
| } |
| } |
| if (type == FilterRepresentation.TYPE_FX) { |
| mFilters.remove(i); |
| mFilters.add(i, representation); |
| setHistoryName(representation.getName()); |
| found = true; |
| } |
| } |
| if (!found) { |
| mFilters.add(representation); |
| setHistoryName(representation.getName()); |
| } |
| } else { |
| mFilters.add(representation); |
| setHistoryName(representation.getName()); |
| } |
| } |
| |
| public FilterRepresentation getRepresentation(FilterRepresentation filterRepresentation) { |
| if (filterRepresentation instanceof GeometryMetadata) { |
| return mGeoData; |
| } |
| for (int i = 0; i < mFilters.size(); i++) { |
| FilterRepresentation representation = mFilters.elementAt(i); |
| if (representation.getFilterClass() == filterRepresentation.getFilterClass()) { |
| return representation; |
| } |
| } |
| if (mBorder != null && mBorder.getFilterClass() == filterRepresentation.getFilterClass()) { |
| return mBorder; |
| } |
| return null; |
| } |
| |
| public void setup() { |
| // do nothing here |
| } |
| |
| public Bitmap apply(Bitmap original, FilterEnvironment environment) { |
| Bitmap bitmap = original; |
| bitmap = applyFilters(bitmap, -1, -1, environment); |
| return applyBorder(bitmap, environment); |
| } |
| |
| public Bitmap applyGeometry(Bitmap bitmap, FilterEnvironment environment) { |
| // Apply any transform -- 90 rotate, flip, straighten, crop |
| // Returns a new bitmap. |
| if (mDoApplyGeometry) { |
| mGeoData.synchronizeRepresentation(); |
| bitmap = environment.applyRepresentation(mGeoData, bitmap); |
| } |
| return bitmap; |
| } |
| |
| public Bitmap applyBorder(Bitmap bitmap, FilterEnvironment environment) { |
| if (mBorder != null && mDoApplyGeometry) { |
| mBorder.synchronizeRepresentation(); |
| bitmap = environment.applyRepresentation(mBorder, bitmap); |
| } |
| return bitmap; |
| } |
| |
| public Bitmap applyFilters(Bitmap bitmap, int from, int to, FilterEnvironment environment) { |
| if (mDoApplyFilters) { |
| if (from < 0) { |
| from = 0; |
| } |
| if (to == -1) { |
| to = mFilters.size(); |
| } |
| for (int i = from; i < to; i++) { |
| FilterRepresentation representation = null; |
| synchronized (mFilters) { |
| representation = mFilters.elementAt(i); |
| representation.synchronizeRepresentation(); |
| } |
| bitmap = environment.applyRepresentation(representation, bitmap); |
| if (environment.needsStop()) { |
| return bitmap; |
| } |
| } |
| } |
| |
| return bitmap; |
| } |
| |
| public void applyBorder(Allocation in, Allocation out, FilterEnvironment environment) { |
| if (mBorder != null && mDoApplyGeometry) { |
| mBorder.synchronizeRepresentation(); |
| // TODO: should keep the bitmap around |
| Allocation bitmapIn = Allocation.createTyped(CachingPipeline.getRenderScriptContext(), in.getType()); |
| bitmapIn.copyFrom(out); |
| environment.applyRepresentation(mBorder, 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 = null; |
| synchronized (mFilters) { |
| representation = mFilters.elementAt(i); |
| representation.synchronizeRepresentation(); |
| } |
| if (i > from) { |
| in.copyFrom(out); |
| } |
| environment.applyRepresentation(representation, in, out); |
| } |
| } |
| } |
| |
| public boolean canDoPartialRendering() { |
| if (mGeoData.hasModifications()) { |
| return false; |
| } |
| if (mBorder != null && !mBorder.supportsPartialRendering()) { |
| return false; |
| } |
| if (ImageLoader.getZoomOrientation() != ImageLoader.ORI_NORMAL) { |
| return false; |
| } |
| for (int i = 0; i < mFilters.size(); i++) { |
| FilterRepresentation representation = null; |
| synchronized (mFilters) { |
| representation = mFilters.elementAt(i); |
| } |
| if (!representation.supportsPartialRendering()) { |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| public void fillImageStateAdapter(StateAdapter imageStateAdapter) { |
| if (imageStateAdapter == null) { |
| return; |
| } |
| imageStateAdapter.addAll(mFilters); |
| } |
| |
| public void setPartialRendering(boolean partialRendering, Rect bounds) { |
| mPartialRendering = partialRendering; |
| mPartialRenderingBounds = bounds; |
| } |
| |
| public boolean isPartialRendering() { |
| return mPartialRendering; |
| } |
| |
| public Rect getPartialRenderingBounds() { |
| return mPartialRenderingBounds; |
| } |
| |
| public Bitmap getPreviewImage() { |
| return mPreviewImage; |
| } |
| |
| public void setPreviewImage(Bitmap previewImage) { |
| mPreviewImage = previewImage; |
| } |
| |
| 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; |
| } |
| |
| } |