public void compose()

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);
                }
            }
        }