in pdfbox/src/main/java/org/apache/pdfbox/pdmodel/graphics/blend/BlendComposite.java [111:269]
public void compose(Raster src, Raster dstIn, WritableRaster dstOut)
{
int x0 = src.getMinX();
int y0 = src.getMinY();
int width = Math.min(Math.min(src.getWidth(), dstIn.getWidth()), dstOut.getWidth());
int height = Math.min(Math.min(src.getHeight(), dstIn.getHeight()), dstOut.getHeight());
int x1 = x0 + width;
int y1 = y0 + height;
int dstInXShift = dstIn.getMinX() - x0;
int dstInYShift = dstIn.getMinY() - y0;
int dstOutXShift = dstOut.getMinX() - x0;
int dstOutYShift = dstOut.getMinY() - y0;
ColorSpace srcColorSpace = srcColorModel.getColorSpace();
int numSrcColorComponents = srcColorModel.getNumColorComponents();
int numSrcComponents = src.getNumBands();
boolean srcHasAlpha = (numSrcComponents > numSrcColorComponents);
ColorSpace dstColorSpace = dstColorModel.getColorSpace();
int numDstColorComponents = dstColorModel.getNumColorComponents();
int numDstComponents = dstIn.getNumBands();
boolean dstHasAlpha = (numDstComponents > numDstColorComponents);
int srcColorSpaceType = srcColorSpace.getType();
int dstColorSpaceType = dstColorSpace.getType();
boolean subtractive = (dstColorSpaceType != ColorSpace.TYPE_RGB)
&& (dstColorSpaceType != ColorSpace.TYPE_GRAY);
boolean blendModeIsSeparable = blendMode.isSeparableBlendMode();
boolean needsColorConversion = !srcColorSpace.equals(dstColorSpace);
Object srcPixel = null;
Object dstPixel = null;
float[] srcComponents = new float[numSrcComponents];
// PDFBOX-3501 let getNormalizedComponents allocate to avoid
// ArrayIndexOutOfBoundsException for bitonal target
float[] dstComponents = null;
float[] srcColor = new float[numSrcColorComponents];
float[] srcConverted;
float[] dstConverted;
float[] rgbResult = blendModeIsSeparable ? null : new float[dstHasAlpha ? 4 : 3];
for (int y = y0; y < y1; y++)
{
for (int x = x0; x < x1; x++)
{
srcPixel = src.getDataElements(x, y, srcPixel);
dstPixel = dstIn.getDataElements(dstInXShift + x, dstInYShift + y, dstPixel);
srcComponents = srcColorModel.getNormalizedComponents(srcPixel, srcComponents,
0);
dstComponents = dstColorModel.getNormalizedComponents(dstPixel, dstComponents,
0);
float srcAlpha = srcHasAlpha ? srcComponents[numSrcColorComponents] : 1.0f;
float dstAlpha = dstHasAlpha ? dstComponents[numDstColorComponents] : 1.0f;
srcAlpha = srcAlpha * constantAlpha;
float resultAlpha = dstAlpha + srcAlpha - srcAlpha * dstAlpha;
float srcAlphaRatio = (resultAlpha > 0) ? srcAlpha / resultAlpha : 0;
if (blendModeIsSeparable)
{
// convert color
System.arraycopy(srcComponents, 0, srcColor, 0, numSrcColorComponents);
if (needsColorConversion)
{
// TODO - very very slow - Hash results???
float[] cieXYZ = srcColorSpace.toCIEXYZ(srcColor);
srcConverted = dstColorSpace.fromCIEXYZ(cieXYZ);
}
else
{
srcConverted = srcColor;
}
for (int k = 0; k < numDstColorComponents; k++)
{
float srcValue = srcConverted[k];
float dstValue = dstComponents[k];
if (subtractive)
{
srcValue = 1 - srcValue;
dstValue = 1 - dstValue;
}
float value = blendMode.getBlendChannelFunction().blendChannel(srcValue,
dstValue);
value = srcValue + dstAlpha * (value - srcValue);
value = dstValue + srcAlphaRatio * (value - dstValue);
if (subtractive)
{
value = 1 - value;
}
dstComponents[k] = value;
}
}
else
{
// Nonseparable blend modes are computed in RGB color space.
// TODO - CMYK color spaces need special treatment.
if (srcColorSpaceType == ColorSpace.TYPE_RGB)
{
srcConverted = srcComponents;
}
else
{
srcConverted = srcColorSpace.toRGB(srcComponents);
}
if (dstColorSpaceType == ColorSpace.TYPE_RGB)
{
dstConverted = dstComponents;
}
else
{
dstConverted = dstColorSpace.toRGB(dstComponents);
}
blendMode.getBlendFunction().blend(srcConverted, dstConverted, rgbResult);
for (int k = 0; k < 3; k++)
{
float srcValue = srcConverted[k];
float dstValue = dstConverted[k];
float value = rgbResult[k];
value = Math.max(Math.min(value, 1.0f), 0.0f);
value = srcValue + dstAlpha * (value - srcValue);
value = dstValue + srcAlphaRatio * (value - dstValue);
rgbResult[k] = value;
}
if (dstColorSpaceType == ColorSpace.TYPE_RGB)
{
System.arraycopy(rgbResult, 0, dstComponents, 0, dstComponents.length);
}
else
{
float[] temp = dstColorSpace.fromRGB(rgbResult);
System.arraycopy(temp, 0, dstComponents, 0,
Math.min(dstComponents.length, temp.length));
}
}
if (dstHasAlpha)
{
dstComponents[numDstColorComponents] = resultAlpha;
}
dstPixel = dstColorModel.getDataElements(dstComponents, 0, dstPixel);
dstOut.setDataElements(dstOutXShift + x, dstOutYShift + y, dstPixel);
}
}
}