BlendComposite.java revision c0edf09b80fc3180e29632e208775e58a24e04fb
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 { 40c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta MULTIPLY(Multiply), 41c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta SCREEN(Screen), 42c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta DARKEN(Darken), 43c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta LIGHTEN(Lighten), 44c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta OVERLAY(Overlay), 45c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta ADD(Add); 46c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 47c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta private BlendComposite mComposite; 48c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 49c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta BlendingMode(BlendComposite composite) { 50c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta mComposite = composite; 51c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 52c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 53c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta BlendComposite getBlendComposite() { 54c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mComposite; 55c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 56f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 57f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 58f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Multiply = new BlendComposite(BlendingMode.MULTIPLY); 59f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Screen = new BlendComposite(BlendingMode.SCREEN); 60f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Darken = new BlendComposite(BlendingMode.DARKEN); 61f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Lighten = new BlendComposite(BlendingMode.LIGHTEN); 62f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Overlay = new BlendComposite(BlendingMode.OVERLAY); 63f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static final BlendComposite Add = new BlendComposite(BlendingMode.ADD); 64f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 65f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private float alpha; 66f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendingMode mode; 67f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 68f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendComposite(BlendingMode mode) { 69f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this(mode, 1.0f); 70f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 71f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 72f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendComposite(BlendingMode mode, float alpha) { 73f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.mode = mode; 74f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta setAlpha(alpha); 75f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 76f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 77f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode) { 78c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mode.getBlendComposite(); 79f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 80f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 81f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode, float alpha) { 82c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta if (alpha > 0.9999f) { 83c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return getInstance(mode); 84c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta } 85f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new BlendComposite(mode, alpha); 86f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 87f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 88f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public float getAlpha() { 89f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return alpha; 90f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 91f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 92f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public BlendingMode getMode() { 93f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return mode; 94f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 95f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 96f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private void setAlpha(float alpha) { 97f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (alpha < 0.0f || alpha > 1.0f) { 98f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta throw new IllegalArgumentException( 99f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta "alpha must be comprised between 0.0f and 1.0f"); 100f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 101f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 102f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.alpha = alpha; 103f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 104f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 105f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 106f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public int hashCode() { 107f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return Float.floatToIntBits(alpha) * 31 + mode.ordinal(); 108f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 109f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 110f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 111f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public boolean equals(Object obj) { 112f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (!(obj instanceof BlendComposite)) { 113f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return false; 114f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 115f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 116f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta BlendComposite bc = (BlendComposite) obj; 117f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 118c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta return mode == bc.mode && alpha == bc.alpha; 119f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 120f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 121f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public CompositeContext createContext(ColorModel srcColorModel, 122f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta ColorModel dstColorModel, 123f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta RenderingHints hints) { 124f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new BlendingContext(this); 125f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 126f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 127f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private static final class BlendingContext implements CompositeContext { 128f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private final Blender blender; 129f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private final BlendComposite composite; 130f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 131f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private BlendingContext(BlendComposite composite) { 132f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.composite = composite; 133f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta this.blender = Blender.getBlenderFor(composite); 134f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 135f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 136f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public void dispose() { 137f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 138f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 139f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 140f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 141f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 142f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) { 143f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta throw new IllegalStateException( 144f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta "Source and destination must store pixels as INT."); 145f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 146f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 147f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int width = Math.min(src.getWidth(), dstIn.getWidth()); 148f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int height = Math.min(src.getHeight(), dstIn.getHeight()); 149f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 150f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta float alpha = composite.getAlpha(); 151f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 152f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] srcPixel = new int[4]; 153f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] dstPixel = new int[4]; 154bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta int[] result = new int[4]; 155f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] srcPixels = new int[width]; 156f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta int[] dstPixels = new int[width]; 157f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 158f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta for (int y = 0; y < height; y++) { 159f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstIn.getDataElements(0, y, width, 1, dstPixels); 160bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta if (alpha != 0) { 161bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta src.getDataElements(0, y, width, 1, srcPixels); 162bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int x = 0; x < width; x++) { 163bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // pixels are stored as INT_ARGB 164bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // our arrays are [R, G, B, A] 165bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta int pixel = srcPixels[x]; 166bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[0] = (pixel >> 16) & 0xFF; 167bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[1] = (pixel >> 8) & 0xFF; 168bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[2] = (pixel ) & 0xFF; 169bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta srcPixel[3] = (pixel >> 24) & 0xFF; 170bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 171bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta pixel = dstPixels[x]; 172bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[0] = (pixel >> 16) & 0xFF; 173bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[1] = (pixel >> 8) & 0xFF; 174bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[2] = (pixel ) & 0xFF; 175bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixel[3] = (pixel >> 24) & 0xFF; 176bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 177c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // ---- Modified from original ---- 178c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // recompute src pixel for transparency. 179c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta srcPixel[3] *= dstPixel[3] / 0xFF; 180c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta // ---- Modification ends ---- 181c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta 182bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result = blender.blend(srcPixel, dstPixel, result); 183bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 184bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta // mixes the result with the opacity 185bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta if (alpha == 1) { 186bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixels[x] = (result[3] & 0xFF) << 24 | 187bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta (result[0] & 0xFF) << 16 | 188bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta (result[1] & 0xFF) << 8 | 189bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[2] & 0xFF; 190bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } else { 191bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta dstPixels[x] = 192bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 | 193bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 | 194bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 | 195f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF; 196bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 197bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 198bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 199bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 200f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta dstOut.setDataElements(0, y, width, 1, dstPixels); 201f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 202f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 203f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 204f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 205f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta private static abstract class Blender { 206bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public abstract int[] blend(int[] src, int[] dst, int[] result); 207f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta 208f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta public static Blender getBlenderFor(BlendComposite composite) { 209f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta switch (composite.getMode()) { 210f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case ADD: 211f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 212f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 213bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 214bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 4; i++) { 215bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.min(255, src[i] + dst[i]); 216bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 217bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 218f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 219f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 220f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case DARKEN: 221f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 222f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 223bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 224bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 225bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.min(src[i], dst[i]); 226bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 227bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 228bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 229f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 230f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 231f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case LIGHTEN: 232f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 233f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 234bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 235bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 236bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = Math.max(src[i], dst[i]); 237bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 238bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 239bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 240f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 241f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 242f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case MULTIPLY: 243f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 244f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 245bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 246bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 247bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = (src[i] * dst[i]) >> 8; 248bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 249c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255); 250bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 251f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 252f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 253f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta case OVERLAY: 254f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 255f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 256bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 257bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta for (int i = 0; i < 3; i++) { 258bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 : 259bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta 255 - ((255 - dst[i]) * (255 - src[i]) >> 7); 260bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta } 261bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 262bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta return result; 263f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 264f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 265c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta case SCREEN: 266f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return new Blender() { 267f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta @Override 268bcf72b14d7b10bda2a62e7b714ee8858e5fa0036Deepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 269c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8); 270c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8); 271c0edf09b80fc3180e29632e208775e58a24e04fbDeepanshu Gupta result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8); 272f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 273f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta return result; 274f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 275f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta }; 276f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 277f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta throw new IllegalArgumentException("Blender not implement for " + 278f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta composite.getMode().name()); 279f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 280f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta } 281f39dce266913d50b9b484b29fddf655b14cddef6Deepanshu Gupta} 282