package com.tom_roush.pdfbox.pdmodel.graphics.blend; import java.util.HashMap; import java.util.Map; import com.tom_roush.pdfbox.cos.COSArray; import com.tom_roush.pdfbox.cos.COSBase; import com.tom_roush.pdfbox.cos.COSName; /** * Blend mode. * * @author Kühn & Weyh Software, GmbH */ public abstract class BlendMode { /** * Determines the blend mode from the BM entry in the COS ExtGState. * * @param cosBlendMode name or array * @return blending mode */ public static BlendMode getInstance(COSBase cosBlendMode) { BlendMode result = null; if (cosBlendMode instanceof COSName) { result = BLEND_MODES.get(cosBlendMode); } else if (cosBlendMode instanceof COSArray) { COSArray cosBlendModeArray = (COSArray) cosBlendMode; for (int i = 0; i < cosBlendModeArray.size(); i++) { result = BLEND_MODES.get(cosBlendModeArray.get(i)); if (result != null) { break; } } } if (result != null) { return result; } return BlendMode.COMPATIBLE; } public static final SeparableBlendMode NORMAL = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return srcValue; } }; public static final SeparableBlendMode COMPATIBLE = NORMAL; public static final SeparableBlendMode MULTIPLY = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return srcValue * dstValue; } }; public static final SeparableBlendMode SCREEN = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return srcValue + dstValue - srcValue * dstValue; } }; public static final SeparableBlendMode OVERLAY = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return (dstValue <= 0.5) ? 2 * dstValue * srcValue : 2 * (srcValue + dstValue - srcValue * dstValue) - 1; } }; public static final SeparableBlendMode DARKEN = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return Math.min(srcValue, dstValue); } }; public static final SeparableBlendMode LIGHTEN = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return Math.max(srcValue, dstValue); } }; public static final SeparableBlendMode COLOR_DODGE = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return (srcValue < 1) ? Math.min(1, dstValue / (1 - srcValue)) : 1; } }; public static final SeparableBlendMode COLOR_BURN = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return (srcValue > 0) ? 1 - Math.min(1, (1 - dstValue) / srcValue) : 0; } }; public static final SeparableBlendMode HARD_LIGHT = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return (srcValue <= 0.5) ? 2 * dstValue * srcValue : 2 * (srcValue + dstValue - srcValue * dstValue) - 1; } }; public static final SeparableBlendMode SOFT_LIGHT = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { if (srcValue <= 0.5) { return dstValue - (1 - 2 * srcValue) * dstValue * (1 - dstValue); } else { float d = (dstValue <= 0.25) ? ((16 * dstValue - 12) * dstValue + 4) * dstValue : (float) Math .sqrt(dstValue); return dstValue + (2 * srcValue - 1) * (d - dstValue); } } }; public static final SeparableBlendMode DIFFERENCE = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return Math.abs(dstValue - srcValue); } }; public static final SeparableBlendMode EXCLUSION = new SeparableBlendMode() { @Override public float blendChannel(float srcValue, float dstValue) { return dstValue + srcValue - 2 * dstValue * srcValue; } }; private static final Map<COSName, BlendMode> BLEND_MODES = createBlendModeMap(); private static Map<COSName, BlendMode> createBlendModeMap() { Map<COSName, BlendMode> map = new HashMap<COSName, BlendMode>(); map.put(COSName.NORMAL, BlendMode.NORMAL); map.put(COSName.COMPATIBLE, BlendMode.COMPATIBLE); map.put(COSName.MULTIPLY, BlendMode.MULTIPLY); map.put(COSName.SCREEN, BlendMode.SCREEN); map.put(COSName.OVERLAY, BlendMode.OVERLAY); map.put(COSName.DARKEN, BlendMode.DARKEN); map.put(COSName.LIGHTEN, BlendMode.LIGHTEN); map.put(COSName.COLOR_DODGE, BlendMode.COLOR_DODGE); map.put(COSName.COLOR_BURN, BlendMode.COLOR_BURN); map.put(COSName.HARD_LIGHT, BlendMode.HARD_LIGHT); map.put(COSName.SOFT_LIGHT, BlendMode.SOFT_LIGHT); map.put(COSName.DIFFERENCE, BlendMode.DIFFERENCE); map.put(COSName.EXCLUSION, BlendMode.EXCLUSION); // TODO - non-separable blending modes return map; } BlendMode() { } }