使用PDFBox在背景中创建渐变

时间:2016-11-19 19:39:22

标签: java pdf gradient pdfbox

如何在PDFBox中创建渐变?或者“我可以吗?”。

我不想创建它们并导出到jpeg或其他东西。我需要一个轻量级的文档,所以必须以某种方式进行编程。

有什么想法吗?

2 个答案:

答案 0 :(得分:2)

经过大量的研究,我终于创造了一个自己渐变的小型创作者"!它看起来像这样:

{{1}}

我会把这个留给别人。留下您的意见并随意向我展示一些改进此代码的聪明主意:)

答案 1 :(得分:0)

这是我制作的一门课,旨在简化渐变的创建。它支持多种颜色的轴向渐变。它使用java.awt.Color指定颜色,但可以轻松替换。

public class PDGradient extends PDShadingType2 {

    public PDGradient(List<GradientPart> parts) {
        super(new COSDictionary());

        // PDF 1.7 - 8.7.4.5.3 Type 2 (Axial) Shadings
        setColorSpace(PDDeviceRGB.INSTANCE);
        setShadingType(PDShadingType2.SHADING_TYPE2);
        setFunction(createGradientFunction(parts));
    }

    private static PDFunction createGradientFunction(List<GradientPart> parts) {
        if (parts.size() < 2) {
            throw new IllegalArgumentException("Gradient must have at least 2 colors.");
        }

        GradientPart first = parts.get(0);
        GradientPart last = parts.get(parts.size() - 1);
        if (first.ratio != 0f) {
            throw new IllegalArgumentException("Gradient first color ratio must be 0.");
        } else if (last.ratio != 1f) {
            throw new IllegalArgumentException("Gradient last color ratio must be 1.");
        }
        if (parts.size() == 2) {
            // Only two colors, use exponential function.
            return createColorFunction(first.color, last.color);
        }

        // Multiple colors, use stitching function to combine exponential functions
        // PDF 1.7 - 7.10.4 Type 3 (Stitching) Functions
        COSDictionary dict = new COSDictionary();
        COSArray functions = new COSArray();
        COSArray bounds = new COSArray();
        COSArray encode = new COSArray();
        GradientPart lastPart = first;
        for (int i = 1; i < parts.size(); i++) {
            GradientPart part = parts.get(i);

            // Add exponential function for interpolating between these two colors.
            functions.add(createColorFunction(lastPart.color, part.color));

            // Specify function bounds, except for first and last, which are specified by domain.
            if (i != parts.size() - 1) {
                bounds.add(new COSFloat(part.ratio));
            }

            // Used to interpolate stitching function subdomain (eg: [0.2 0.5] 
            // to the exponential function domain, which is always [0.0 1.0].
            encode.add(COSInteger.ZERO);
            encode.add(COSInteger.ONE);

            lastPart = part;
        }

        dict.setInt(COSName.FUNCTION_TYPE, 3);
        dict.setItem(COSName.DOMAIN, new PDRange());  // [0.0 1.0]
        dict.setItem(COSName.FUNCTIONS, functions);
        dict.setItem(COSName.BOUNDS, bounds);
        dict.setItem(COSName.ENCODE, encode);

        return new PDFunctionType3(dict);
    }

    private static PDFunction createColorFunction(Color start, Color end) {
        // PDF 1.7 - 7.10.3 Type 2 (Exponential Interpolation) Functions
        COSDictionary dict = new COSDictionary();
        dict.setInt(COSName.FUNCTION_TYPE, 2);
        dict.setItem(COSName.DOMAIN, new PDRange());  // [0.0 1.0]
        dict.setItem(COSName.C0, createColorCOSArray(start));
        dict.setItem(COSName.C1, createColorCOSArray(end));
        dict.setInt(COSName.N, 1);  // Linear interpolation
        return new PDFunctionType2(dict);
    }

    private static COSArray createColorCOSArray(Color color) {
        // Create a COSArray for a color. 
        // java.awt.Color uses 0-255 values while PDF uses 0-1.
        COSArray a = new COSArray();
        a.add(new COSFloat(color.getRed() / 255f));
        a.add(new COSFloat(color.getGreen() / 255f));
        a.add(new COSFloat(color.getBlue() / 255f));
        return a;
    }

    /**
     * Specifies a color and its position in a {@link PDGradient}.
     */
    public static class GradientPart {

        public final Color color;
        public final float ratio;

        public GradientPart(Color color, float ratio) {
            this.color = color;
            this.ratio = ratio;
        }
    }
}

用法示例:

List<GradientPart> parts = new ArrayList<>();
parts.add(new GradientPart(Color.RED, 0.0f));
parts.add(new GradientPart(Color.YELLOW, 0.5f));
parts.add(new GradientPart(Color.GREEN, 1.0f));
PDGradient gradient = new PDGradient(parts);
gradient.setCoords(...);
pdfStream.shadingFill(gradient)

这与两种颜色渐变的其他答案基本相同,使用指数函数(类型2)在两种颜色之间线性插值。如果有更多颜色,则可以使用拼接(类型3)功能将具有不同子域的多个指数功能组合在一起。