/* * Copyright (C) 2015 Jorge Ruesga * * 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.ruesga.android.wallpapers.photophase.effects; import android.content.Context; import android.graphics.Color; import android.media.effect.Effect; import android.media.effect.EffectContext; import android.media.effect.EffectFactory; import com.ruesga.android.wallpapers.photophase.preferences.PreferencesProvider.Preferences; import com.ruesga.android.wallpapers.photophase.utils.Utils; import java.util.HashMap; import java.util.Map; import java.util.NoSuchElementException; /** * A class that manages all the supported effects */ public class Effects { public static class Settings { public final int mMin; public final int mMax; public final int mDef; public Settings(int min, int max, int def) { mMin = min; mMax = max; mDef = def; } } /** * Enumeration of the supported effects */ public enum EFFECTS { /** * @see PhotoPhaseEffectFactory#EFFECT_NULL */ NO_EFFECT(0, null), /** * @see EffectFactory#EFFECT_AUTOFIX */ AUTOFIX(1, new Settings(0, 20, 5)), /** * @see PhotoPhaseEffectFactory#EFFECT_BLUR */ BLUR(2, new Settings(0, 20, 5)), /** * @see EffectFactory#EFFECT_CROSSPROCESS */ CROSSPROCESS(3, null), /** * @see EffectFactory#EFFECT_DOCUMENTARY */ DOCUMENTARY(4, null), /** * @see EffectFactory#EFFECT_DUOTONE */ DUOTONE(5, new Settings(0, 8, 0)), /** * @see PhotoPhaseEffectFactory#EFFECT_EMBOSS */ EMBOSS(6, null), /** * @see PhotoPhaseEffectFactory#EFFECT_FISHEYE */ FISHEYE(7, null), /** * @see PhotoPhaseEffectFactory#EFFECT_GLOW */ GLOW(8, null), /** * @see EffectFactory#EFFECT_GRAIN */ GRAIN(9, new Settings(0, 20, 13)), /** * @see EffectFactory#EFFECT_GRAYSCALE */ GRAYSCALE(10, null), /** * @see PhotoPhaseEffectFactory#EFFECT_HALFTONE */ HALFTONE(11, new Settings(0, 20, 10)), /** * @see EffectFactory#EFFECT_LOMOISH */ LOMOISH(12, null), /** * @see PhotoPhaseEffectFactory#EFFECT_MIRROR */ MIRROR(13, null), /** * @see EffectFactory#EFFECT_NEGATIVE */ NEGATIVE(14, null), /** * @see PhotoPhaseEffectFactory#EFFECT_OUTLINE */ OUTLINE(15, null), /** * @see PhotoPhaseEffectFactory#EFFECT_PIXELATE */ PIXELATE(16, new Settings(0, 20, 8)), /** * @see PhotoPhaseEffectFactory#EFFECT_POPART */ POPART(17, null), /** * @see EffectFactory#EFFECT_POSTERIZE */ POSTERIZE(18, null), /** * @see EffectFactory#EFFECT_SATURATE */ SATURATE(19, new Settings(0, 20, 8)), /** * @see PhotoPhaseEffectFactory#EFFECT_SCANLINES */ SCANLINES(20, new Settings(0, 20, 10)), /** * @see EffectFactory#EFFECT_SEPIA */ SEPIA(21, null), /** * @see EffectFactory#EFFECT_TEMPERATURE */ TEMPERATURE(22, new Settings(0, 20, 15)), /** * @see EffectFactory#EFFECT_TINT */ TINT(23, new Settings(0, 12, 0)), /** * @see EffectFactory#EFFECT_VIGNETTE */ VIGNETTE(24, new Settings(0, 20, 15)), /** * @see PhotoPhaseEffectFactory#EFFECT_NOISE */ NOISE(25, new Settings(0, 20, 9)), /** * @see PhotoPhaseEffectFactory#EFFECT_FROSTED */ FROSTED(26, new Settings(0, 20, 9)), /** * @see PhotoPhaseEffectFactory#EFFECT_CROSSHATCHING */ CROSSHATCHING(27, null), /** * @see PhotoPhaseEffectFactory#EFFECT_THERMALVISION */ THERMALVISION(28, null), /** * @see PhotoPhaseEffectFactory#EFFECT_SWIRL */ SWIRL(29, new Settings(0, 20, 4)), /** * @see PhotoPhaseEffectFactory#EFFECT_DOF */ DOF(30, new Settings(0, 20, 15)), /** * @see PhotoPhaseEffectFactory#EFFECT_WARHOL */ WARHOL(31, null), /** * @see PhotoPhaseEffectFactory#EFFECT_TOON */ TOON(32, null), /** * @see PhotoPhaseEffectFactory#EFFECT_SOBEL */ SOBEL(33, null); public final int mId; public final Settings mSettings; EFFECTS(int id, Settings settings) { mId = id; mSettings = settings; } public static EFFECTS fromId(int id) { for (EFFECTS effect : EFFECTS.values()) { if (effect.mId == id) { return effect; } } return null; } } private final Map<EFFECTS, Effect> mCachedEffects; private final EffectContext mEffectContext; private final Context mContext; /** * Constructor of <code>Effects</code> * * @param effectContext The current effect context */ public Effects(Context context, EffectContext effectContext) { super(); mCachedEffects = new HashMap<>(); mEffectContext = effectContext; mContext = context; } /** * Method that that release the cached data */ public void release() { if (mCachedEffects != null) { for (Effect effect : mCachedEffects.values()) { try { effect.release(); } catch (NoSuchElementException ex) { // Catching a runtime exception is not ideally, but releasing // the effect causes a fc it the effect is not a valid state. // Since we are releasing the effect we can ignore it to avoid // crash the app } } mCachedEffects.clear(); } } /** * Method that return the next effect to use with the picture. * * @return Effect The next effect to use or null if no need to apply any effect */ @SuppressWarnings("boxing") public Effect getNextEffect() { // Get an effect based on the user preference EFFECTS[] effects = Preferences.General.Effects.toEFFECTS( Preferences.General.Effects.getSelectedEffects(mContext)); EFFECTS nextEffect = null; if (effects.length > 0) { int low = 0; int high = effects.length - 1; int pos = Utils.getNextRandom(low, high); nextEffect = effects[pos]; } return getEffect(nextEffect); } public Effect getEffect(EFFECTS nextEffect) { EffectFactory effectFactory = mEffectContext.getFactory(); Effect effect = null; // Ensure we apply at least an effect (a null one) if (nextEffect == null) { nextEffect = EFFECTS.NO_EFFECT; } // The effect was cached previously? if (mCachedEffects.containsKey(nextEffect)) { effect = mCachedEffects.get(nextEffect); updateParameters(nextEffect, effect); return effect; } // Select the effect if is available if (nextEffect.compareTo(EFFECTS.NO_EFFECT) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_NULL)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_NULL); } } else if (nextEffect.compareTo(EFFECTS.AUTOFIX) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_AUTOFIX)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_AUTOFIX); } } else if (nextEffect.compareTo(EFFECTS.BLUR) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_BLUR)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_BLUR); } } else if (nextEffect.compareTo(EFFECTS.CROSSPROCESS) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_CROSSPROCESS)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_CROSSPROCESS); } } else if (nextEffect.compareTo(EFFECTS.DOCUMENTARY) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_DOCUMENTARY)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_DOCUMENTARY); } } else if (nextEffect.compareTo(EFFECTS.DUOTONE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_DUOTONE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_DUOTONE); } } else if (nextEffect.compareTo(EFFECTS.EMBOSS) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_EMBOSS)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_EMBOSS); } } else if (nextEffect.compareTo(EFFECTS.FISHEYE) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_FISHEYE)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_FISHEYE); } } else if (nextEffect.compareTo(EFFECTS.GLOW) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_GLOW)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_GLOW); } } else if (nextEffect.compareTo(EFFECTS.GRAIN) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_GRAIN)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_GRAIN); } } else if (nextEffect.compareTo(EFFECTS.GRAYSCALE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_GRAYSCALE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_GRAYSCALE); } } else if (nextEffect.compareTo(EFFECTS.HALFTONE) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_HALFTONE)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_HALFTONE); } } else if (nextEffect.compareTo(EFFECTS.MIRROR) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_MIRROR)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_MIRROR); } } else if (nextEffect.compareTo(EFFECTS.LOMOISH) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_LOMOISH)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_LOMOISH); } } else if (nextEffect.compareTo(EFFECTS.NEGATIVE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_NEGATIVE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_NEGATIVE); } } else if (nextEffect.compareTo(EFFECTS.OUTLINE) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_OUTLINE)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_OUTLINE); } } else if (nextEffect.compareTo(EFFECTS.PIXELATE) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_PIXELATE)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_PIXELATE); } } else if (nextEffect.compareTo(EFFECTS.POPART) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_POPART)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_POPART); } } else if (nextEffect.compareTo(EFFECTS.POSTERIZE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_POSTERIZE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_POSTERIZE); } } else if (nextEffect.compareTo(EFFECTS.SATURATE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_SATURATE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_SATURATE); } } else if (nextEffect.compareTo(EFFECTS.SCANLINES) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_SCANLINES)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_SCANLINES); } } else if (nextEffect.compareTo(EFFECTS.SEPIA) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_SEPIA)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_SEPIA); } } else if (nextEffect.compareTo(EFFECTS.TEMPERATURE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_TEMPERATURE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_TEMPERATURE); } } else if (nextEffect.compareTo(EFFECTS.TINT) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_TINT)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_TINT); } } else if (nextEffect.compareTo(EFFECTS.VIGNETTE) == 0) { if (EffectFactory.isEffectSupported(EffectFactory.EFFECT_VIGNETTE)) { effect = effectFactory.createEffect(EffectFactory.EFFECT_VIGNETTE); } } else if (nextEffect.compareTo(EFFECTS.NOISE) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_NOISE)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_NOISE); } } else if (nextEffect.compareTo(EFFECTS.FROSTED) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_FROSTED)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_FROSTED); } } else if (nextEffect.compareTo(EFFECTS.CROSSHATCHING) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_CROSSHATCHING)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_CROSSHATCHING); } } else if (nextEffect.compareTo(EFFECTS.THERMALVISION) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_THERMALVISION)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_THERMALVISION); } } else if (nextEffect.compareTo(EFFECTS.SWIRL) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_SWIRL)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_SWIRL); } } else if (nextEffect.compareTo(EFFECTS.DOF) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_DOF)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_DOF); } } else if (nextEffect.compareTo(EFFECTS.WARHOL) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_WARHOL)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_WARHOL); } } else if (nextEffect.compareTo(EFFECTS.TOON) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_TOON)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_TOON); } } else if (nextEffect.compareTo(EFFECTS.SOBEL) == 0) { if (EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_SOBEL)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_SOBEL); } } // Instead of not to apply any effect, just use one null effect to follow the same // effect model. This allow to use the same height when Effect.apply is applied for all // the frames if (effect == null && EffectFactory.isEffectSupported(PhotoPhaseEffectFactory.EFFECT_NULL)) { effect = effectFactory.createEffect(PhotoPhaseEffectFactory.EFFECT_NULL); nextEffect = EFFECTS.NO_EFFECT; } if (effect != null) { // Cache the effects mCachedEffects.put(nextEffect, effect); } updateParameters(nextEffect, effect); return effect; } private void updateParameters(EFFECTS type, Effect effect) { Settings settings = type.mSettings; if (settings == null) { return; } int val = Preferences.General.Effects.getEffectSettings(mContext, type.mId, settings.mDef); // Update the parameters if (type.compareTo(EFFECTS.AUTOFIX) == 0) { effect.setParameter("scale", (val * 0.05f)); } else if (type.compareTo(EFFECTS.BLUR) == 0) { effect.setParameter(BlurEffect.STRENGTH_PARAMETER, (val * 0.2f) + 1.0f); } else if (type.compareTo(EFFECTS.FROSTED) == 0) { effect.setParameter(FrostedEffect.STRENGTH_PARAMETER, (val * 0.005f) + 0.005f); } else if (type.compareTo(EFFECTS.GRAIN) == 0) { effect.setParameter("strength", (val * 0.075f) + 0.075f); } else if (type.compareTo(EFFECTS.DOF) == 0) { effect.setParameter(DoFEffect.STRENGTH_PARAMETER, (val * 0.05f)); } else if (type.compareTo(EFFECTS.SCANLINES) == 0) { effect.setParameter(ScanlinesEffect.STRENGTH_PARAMETER, (val * 0.3f) + 3f); } else if (type.compareTo(EFFECTS.HALFTONE) == 0) { effect.setParameter(HalftoneEffect.STRENGTH_PARAMETER, (val * 4f) + 40f); } else if (type.compareTo(EFFECTS.NOISE) == 0) { effect.setParameter(NoiseEffect.STRENGTH_PARAMETER, (val * 0.00175) + 0.00175); } else if (type.compareTo(EFFECTS.PIXELATE) == 0) { effect.setParameter(PixelateEffect.STRENGTH_PARAMETER, (val * 0.075) + 0.5); } else if (type.compareTo(EFFECTS.SATURATE) == 0) { effect.setParameter("scale", (val * 0.04f) + 0.1f); } else if (type.compareTo(EFFECTS.TEMPERATURE) == 0) { effect.setParameter("scale", (val * 0.04f) + 0.1f); } else if (type.compareTo(EFFECTS.VIGNETTE) == 0) { effect.setParameter("scale", (val * 0.04f) + 0.1f); } else if (type.compareTo(EFFECTS.SWIRL) == 0) { effect.setParameter(SwirlEffect.STRENGTH_PARAMETER, (val * 0.15f) + 1.0f); } else if (type.compareTo(EFFECTS.DUOTONE) == 0) { final String[] firstColors = {"#ff4a61c6", "#ffc64a50", "#ff4ac65b"}; final int[] secondColors = {Color.WHITE, Color.BLACK, Color.LTGRAY}; effect.setParameter("first_color", Color.parseColor(firstColors[val % firstColors.length])); effect.setParameter("second_color", secondColors[(val / secondColors.length)]); } else if (type.compareTo(EFFECTS.TINT) == 0) { final int[] colors = { Color.WHITE, Color.BLACK, Color.LTGRAY, Color.LTGRAY, Color.DKGRAY, Color.parseColor("#ff4a61c6"), Color.parseColor("#ffc64a50"), Color.parseColor("#ff4ac65b"), Color.parseColor("#ffc64ab6"), Color.parseColor("#ffc6c54a"), Color.parseColor("#ffc69f4a"), Color.parseColor("#ff934ac6"), Color.parseColor("#ffffa500")}; effect.setParameter("tint", colors[val]); } } }