1f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta/* 2f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 3f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * 4f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 5f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * you may not use this file except in compliance with the License. 6f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * You may obtain a copy of the License at 7f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * 8f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 9f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * 10f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 11f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 12f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * See the License for the specific language governing permissions and 14f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * limitations under the License. 15f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta */ 16f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 17f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptapackage android.graphics; 18f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 19f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.Composite; 20f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.CompositeContext; 21f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.RenderingHints; 22f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.image.ColorModel; 23f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.image.DataBuffer; 24f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.image.Raster; 25f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptaimport java.awt.image.WritableRaster; 26f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 27f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta/* 28f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * (non-Javadoc) 29f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * The class is adapted from a demo tool for Blending Modes written by 30f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * Romain Guy (romainguy@android.com). The tool is available at 31f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta * http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/ 32c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta * 33c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta * This class has been adapted for applying color filters. When applying color filters, the src 34c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta * image should not extend beyond the dest image, but in our implementation of the filters, it does. 35c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta * To compensate for the effect, we recompute the alpha value of the src image before applying 36c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta * the color filter as it should have been applied. 37f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta */ 38f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Guptapublic final class BlendComposite implements Composite { 39f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public enum BlendingMode { 40f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta MULTIPLY(), 41f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta SCREEN(), 42f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta DARKEN(), 43f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta LIGHTEN(), 44f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta OVERLAY(), 45f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta ADD(); 46c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 47f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta private final BlendComposite mComposite; 48c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 49f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta BlendingMode() { 50f0fcede48a2a054991e500ea3f10d3f7df913b4fDeepanshu Gupta mComposite = new BlendComposite(this); 51c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 52c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 53c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta BlendComposite getBlendComposite() { 54c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mComposite; 55c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 56f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 57f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 58f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private float alpha; 59f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendingMode mode; 60f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 61f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendComposite(BlendingMode mode) { 62f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this(mode, 1.0f); 63f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 64f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 65f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendComposite(BlendingMode mode, float alpha) { 66f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.mode = mode; 67f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta setAlpha(alpha); 68f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 69f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 70f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode) { 71c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mode.getBlendComposite(); 72f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 73f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 74f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode, float alpha) { 75c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta if (alpha > 0.9999f) { 76c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return getInstance(mode); 77c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 78f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new BlendComposite(mode, alpha); 79f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 80f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 81f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public float getAlpha() { 82f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return alpha; 83f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 84f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 85f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public BlendingMode getMode() { 86f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return mode; 87f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 88f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 89f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private void setAlpha(float alpha) { 90f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (alpha < 0.0f || alpha > 1.0f) { 910609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez assert false : "alpha must be comprised between 0.0f and 1.0f"; 920609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez alpha = Math.min(alpha, 1.0f); 930609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez alpha = Math.max(alpha, 0.0f); 94f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 95f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 96f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.alpha = alpha; 97f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 98f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 99f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 100f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public int hashCode() { 101f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return Float.floatToIntBits(alpha) * 31 + mode.ordinal(); 102f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 103f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 104f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 105f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public boolean equals(Object obj) { 106f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (!(obj instanceof BlendComposite)) { 107f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return false; 108f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 109f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 110f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta BlendComposite bc = (BlendComposite) obj; 111f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 112c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mode == bc.mode && alpha == bc.alpha; 113f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 114f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 115f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public CompositeContext createContext(ColorModel srcColorModel, 116f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta ColorModel dstColorModel, 117f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta RenderingHints hints) { 118f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new BlendingContext(this); 119f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 120f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 121f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private static final class BlendingContext implements CompositeContext { 122f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private final Blender blender; 123f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private final BlendComposite composite; 124f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 125f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendingContext(BlendComposite composite) { 126f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.composite = composite; 127f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.blender = Blender.getBlenderFor(composite); 128f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 129f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 130f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public void dispose() { 131f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 132f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 133f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 134f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 135f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 136f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) { 137f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta throw new IllegalStateException( 138f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta "Source and destination must store pixels as INT."); 139f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 140f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 141f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int width = Math.min(src.getWidth(), dstIn.getWidth()); 142f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int height = Math.min(src.getHeight(), dstIn.getHeight()); 143f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 144f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta float alpha = composite.getAlpha(); 145f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 146f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] srcPixel = new int[4]; 147f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] dstPixel = new int[4]; 148bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta int[] result = new int[4]; 149f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] srcPixels = new int[width]; 150f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] dstPixels = new int[width]; 151f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 152f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta for (int y = 0; y < height; y++) { 153f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstIn.getDataElements(0, y, width, 1, dstPixels); 154bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta if (alpha != 0) { 155bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta src.getDataElements(0, y, width, 1, srcPixels); 156bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int x = 0; x < width; x++) { 157bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // pixels are stored as INT_ARGB 158bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // our arrays are [R, G, B, A] 159bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta int pixel = srcPixels[x]; 160bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[0] = (pixel >> 16) & 0xFF; 161bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[1] = (pixel >> 8) & 0xFF; 162bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[2] = (pixel ) & 0xFF; 163bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[3] = (pixel >> 24) & 0xFF; 164bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 165bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta pixel = dstPixels[x]; 166bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[0] = (pixel >> 16) & 0xFF; 167bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[1] = (pixel >> 8) & 0xFF; 168bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[2] = (pixel ) & 0xFF; 169bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[3] = (pixel >> 24) & 0xFF; 170bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 171c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // ---- Modified from original ---- 172c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // recompute src pixel for transparency. 173c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta srcPixel[3] *= dstPixel[3] / 0xFF; 174c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // ---- Modification ends ---- 175c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 176bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result = blender.blend(srcPixel, dstPixel, result); 177bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 178bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // mixes the result with the opacity 179bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta if (alpha == 1) { 180bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixels[x] = (result[3] & 0xFF) << 24 | 181bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta (result[0] & 0xFF) << 16 | 182bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta (result[1] & 0xFF) << 8 | 183bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[2] & 0xFF; 184bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } else { 185bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixels[x] = 186bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 | 187bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 | 188bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 | 189f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF; 190bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 191bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 192bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 193bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 194f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstOut.setDataElements(0, y, width, 1, dstPixels); 195f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 196f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 197f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 198f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 199f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private static abstract class Blender { 200bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public abstract int[] blend(int[] src, int[] dst, int[] result); 201f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 202f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static Blender getBlenderFor(BlendComposite composite) { 203f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta switch (composite.getMode()) { 204f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case ADD: 205f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 206f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 207bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 208bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 4; i++) { 209bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.min(255, src[i] + dst[i]); 210bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 211bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 212f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 213f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 214f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case DARKEN: 215f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 216f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 217bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 218bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 219bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.min(src[i], dst[i]); 220bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 221bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 222bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 223f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 224f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 225f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case LIGHTEN: 226f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 227f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 228bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 229bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 230bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.max(src[i], dst[i]); 231bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 232bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 233bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 234f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 235f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 236f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case MULTIPLY: 237f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 238f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 239bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 240bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 241bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = (src[i] * dst[i]) >> 8; 242bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 243c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255); 244bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 245f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 246f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 247f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case OVERLAY: 248f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 249f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 250bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 251bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 252bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 : 253bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 255 - ((255 - dst[i]) * (255 - src[i]) >> 7); 254bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 255bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 256bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 257f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 258f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 259c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta case SCREEN: 260f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 261f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 262bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 263c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8); 264c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8); 265c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8); 266f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 267f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return result; 268f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 269f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 2700609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez default: 2710609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez assert false : "Blender not implement for " + composite.getMode().name(); 2720609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez 2730609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez // Ignore the blend 2740609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez return new Blender() { 2750609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez @Override 2760609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez public int[] blend(int[] src, int[] dst, int[] result) { 2770609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez result[0] = dst[0]; 2780609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez result[1] = dst[1]; 2790609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez result[2] = dst[2]; 2800609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez result[3] = dst[3]; 2810609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez return result; 2820609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez } 2830609785e6f839bfd27e33fa2630e6a1c12be9a20Diego Perez }; 284f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 285f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 286f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 287f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta} 288