13dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta/* 23dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * Copyright (C) 2014 The Android Open Source Project 33dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * 43dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * Licensed under the Apache License, Version 2.0 (the "License"); 53dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * you may not use this file except in compliance with the License. 63dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * You may obtain a copy of the License at 73dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * 83dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * http://www.apache.org/licenses/LICENSE-2.0 93dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * 103dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * Unless required by applicable law or agreed to in writing, software 113dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * distributed under the License is distributed on an "AS IS" BASIS, 123dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * See the License for the specific language governing permissions and 143dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * limitations under the License. 153dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta */ 163dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 173dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptapackage android.graphics; 183dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 193dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.Composite; 203dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.CompositeContext; 213dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.RenderingHints; 223dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.image.ColorModel; 233dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.image.DataBuffer; 243dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.image.Raster; 253dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptaimport java.awt.image.WritableRaster; 263dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 273dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta/* 283dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * (non-Javadoc) 293dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * The class is adapted from a demo tool for Blending Modes written by 303dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * Romain Guy (romainguy@android.com). The tool is available at 313dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta * http://www.curious-creature.org/2006/09/20/new-blendings-modes-for-java2d/ 321a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta * 331a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta * This class has been adapted for applying color filters. When applying color filters, the src 341a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta * image should not extend beyond the dest image, but in our implementation of the filters, it does. 351a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta * To compensate for the effect, we recompute the alpha value of the src image before applying 361a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta * the color filter as it should have been applied. 373dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta */ 383dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Guptapublic final class BlendComposite implements Composite { 393dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public enum BlendingMode { 405521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta MULTIPLY(), 415521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta SCREEN(), 425521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta DARKEN(), 435521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta LIGHTEN(), 445521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta OVERLAY(), 455521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta ADD(); 461a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta 475521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta private final BlendComposite mComposite; 481a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta 495521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta BlendingMode() { 505521f65ecb0b91a6847bd78afc4e8c927b6b78efDeepanshu Gupta mComposite = new BlendComposite(this); 511a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta } 521a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta 531a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta BlendComposite getBlendComposite() { 541a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta return mComposite; 551a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta } 563dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 573dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 583dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private float alpha; 593dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private BlendingMode mode; 603dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 613dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private BlendComposite(BlendingMode mode) { 623dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta this(mode, 1.0f); 633dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 643dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 653dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private BlendComposite(BlendingMode mode, float alpha) { 663dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta this.mode = mode; 673dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta setAlpha(alpha); 683dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 693dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 703dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode) { 711a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta return mode.getBlendComposite(); 723dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 733dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 743dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public static BlendComposite getInstance(BlendingMode mode, float alpha) { 751a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta if (alpha > 0.9999f) { 761a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta return getInstance(mode); 771a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta } 783dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new BlendComposite(mode, alpha); 793dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 803dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 813dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public float getAlpha() { 823dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return alpha; 833dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 843dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 853dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public BlendingMode getMode() { 863dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return mode; 873dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 883dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 893dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private void setAlpha(float alpha) { 903dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta if (alpha < 0.0f || alpha > 1.0f) { 913dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta throw new IllegalArgumentException( 923dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta "alpha must be comprised between 0.0f and 1.0f"); 933dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 943dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 953dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta this.alpha = alpha; 963dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 973dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 983dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 993dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public int hashCode() { 1003dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return Float.floatToIntBits(alpha) * 31 + mode.ordinal(); 1013dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1023dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1033dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 1043dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public boolean equals(Object obj) { 1053dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta if (!(obj instanceof BlendComposite)) { 1063dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return false; 1073dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1083dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1093dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta BlendComposite bc = (BlendComposite) obj; 1103dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1111a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta return mode == bc.mode && alpha == bc.alpha; 1123dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1133dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1143dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public CompositeContext createContext(ColorModel srcColorModel, 1153dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta ColorModel dstColorModel, 1163dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta RenderingHints hints) { 1173dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new BlendingContext(this); 1183dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1193dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1203dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private static final class BlendingContext implements CompositeContext { 1213dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private final Blender blender; 1223dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private final BlendComposite composite; 1233dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1243dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private BlendingContext(BlendComposite composite) { 1253dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta this.composite = composite; 1263dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta this.blender = Blender.getBlenderFor(composite); 1273dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1283dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1293dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public void dispose() { 1303dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1313dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1323dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public void compose(Raster src, Raster dstIn, WritableRaster dstOut) { 1333dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta if (src.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 1343dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta dstIn.getSampleModel().getDataType() != DataBuffer.TYPE_INT || 1353dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta dstOut.getSampleModel().getDataType() != DataBuffer.TYPE_INT) { 1363dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta throw new IllegalStateException( 1373dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta "Source and destination must store pixels as INT."); 1383dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1393dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1403dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int width = Math.min(src.getWidth(), dstIn.getWidth()); 1413dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int height = Math.min(src.getHeight(), dstIn.getHeight()); 1423dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1433dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta float alpha = composite.getAlpha(); 1443dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1453dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int[] srcPixel = new int[4]; 1463dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int[] dstPixel = new int[4]; 14747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta int[] result = new int[4]; 1483dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int[] srcPixels = new int[width]; 1493dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta int[] dstPixels = new int[width]; 1503dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1513dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta for (int y = 0; y < height; y++) { 1523dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta dstIn.getDataElements(0, y, width, 1, dstPixels); 15347fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta if (alpha != 0) { 15447fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta src.getDataElements(0, y, width, 1, srcPixels); 15547fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int x = 0; x < width; x++) { 15647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta // pixels are stored as INT_ARGB 15747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta // our arrays are [R, G, B, A] 15847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta int pixel = srcPixels[x]; 15947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta srcPixel[0] = (pixel >> 16) & 0xFF; 16047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta srcPixel[1] = (pixel >> 8) & 0xFF; 16147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta srcPixel[2] = (pixel ) & 0xFF; 16247fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta srcPixel[3] = (pixel >> 24) & 0xFF; 16347fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta 16447fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta pixel = dstPixels[x]; 16547fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixel[0] = (pixel >> 16) & 0xFF; 16647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixel[1] = (pixel >> 8) & 0xFF; 16747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixel[2] = (pixel ) & 0xFF; 16847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixel[3] = (pixel >> 24) & 0xFF; 16947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta 1701a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta // ---- Modified from original ---- 1711a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta // recompute src pixel for transparency. 1721a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta srcPixel[3] *= dstPixel[3] / 0xFF; 1731a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta // ---- Modification ends ---- 1741a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta 17547fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result = blender.blend(srcPixel, dstPixel, result); 17647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta 17747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta // mixes the result with the opacity 17847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta if (alpha == 1) { 17947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixels[x] = (result[3] & 0xFF) << 24 | 18047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta (result[0] & 0xFF) << 16 | 18147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta (result[1] & 0xFF) << 8 | 18247fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[2] & 0xFF; 18347fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } else { 18447fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta dstPixels[x] = 18547fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta ((int) (dstPixel[3] + (result[3] - dstPixel[3]) * alpha) & 0xFF) << 24 | 18647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta ((int) (dstPixel[0] + (result[0] - dstPixel[0]) * alpha) & 0xFF) << 16 | 18747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta ((int) (dstPixel[1] + (result[1] - dstPixel[1]) * alpha) & 0xFF) << 8 | 1883dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta (int) (dstPixel[2] + (result[2] - dstPixel[2]) * alpha) & 0xFF; 18947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 19047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta 19147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 19247fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 1933dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta dstOut.setDataElements(0, y, width, 1, dstPixels); 1943dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1953dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1963dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 1973dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 1983dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta private static abstract class Blender { 19947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public abstract int[] blend(int[] src, int[] dst, int[] result); 2003dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta 2013dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta public static Blender getBlenderFor(BlendComposite composite) { 2023dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta switch (composite.getMode()) { 2033dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta case ADD: 2043dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2053dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 20647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 20747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int i = 0; i < 4; i++) { 20847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[i] = Math.min(255, src[i] + dst[i]); 20947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 21047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta return result; 2113dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2123dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2133dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta case DARKEN: 2143dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2153dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 21647fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 21747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int i = 0; i < 3; i++) { 21847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[i] = Math.min(src[i], dst[i]); 21947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 22047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 22147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta return result; 2223dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2233dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2243dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta case LIGHTEN: 2253dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2263dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 22747fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 22847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int i = 0; i < 3; i++) { 22947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[i] = Math.max(src[i], dst[i]); 23047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 23147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 23247fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta return result; 2333dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2343dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2353dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta case MULTIPLY: 2363dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2373dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 23847fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 23947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int i = 0; i < 3; i++) { 24047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[i] = (src[i] * dst[i]) >> 8; 24147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 2421a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3] - (src[3] * dst[3]) / 255); 24347fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta return result; 2443dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2453dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2463dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta case OVERLAY: 2473dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2483dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 24947fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 25047fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta for (int i = 0; i < 3; i++) { 25147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[i] = dst[i] < 128 ? dst[i] * src[i] >> 7 : 25247fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta 255 - ((255 - dst[i]) * (255 - src[i]) >> 7); 25347fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta } 25447fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 25547fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta return result; 2563dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2573dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2581a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta case SCREEN: 2593dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return new Blender() { 2603dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta @Override 26147fa5c920d6eb93e435794544b96a0e4ede4403aDeepanshu Gupta public int[] blend(int[] src, int[] dst, int[] result) { 2621a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta result[0] = 255 - ((255 - src[0]) * (255 - dst[0]) >> 8); 2631a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta result[1] = 255 - ((255 - src[1]) * (255 - dst[1]) >> 8); 2641a10ca7e526736b4fd143f7c9f3b29643c0062a4Deepanshu Gupta result[2] = 255 - ((255 - src[2]) * (255 - dst[2]) >> 8); 2653dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta result[3] = Math.min(255, src[3] + dst[3]); 2663dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta return result; 2673dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2683dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta }; 2693dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2703dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta throw new IllegalArgumentException("Blender not implement for " + 2713dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta composite.getMode().name()); 2723dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2733dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta } 2743dfc1c21d58a7a6764a436cbf5c3c8ba09db45e5Deepanshu Gupta} 275