【问题标题】:Creating a gradient in background with PDFBox使用 PDFBox 在背景中创建渐变
【发布时间】:2016-11-19 19:39:21
【问题描述】:

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

我不想创建它们并导出为 jpeg 或其他格式。我需要一个简单的文档,所以必须以某种方式对其进行编程。

有什么想法吗?

【问题讨论】:

  • 你想要什么样的渐变?轴向还是径向?什么境界?什么颜色?您是否尝试过源代码下载中的 CreateGradientShadingPDF.java?
  • 从网站下载的 jar 中好像没有。我应该从外部网站下载它吗?
  • 应该在源码下载中。如果没有,请在此处获取svn.apache.org/viewvc/pdfbox/trunk/examples/src/main/java/org/…
  • 我刚看了,源码下载的zip也有,在pdfbox-2.0.3\examples\src\main\java\org\apache\pdfbox\examples\pdmodel
  • 我想我明白了。感谢您的帮助!

标签: java pdf gradient pdfbox


【解决方案1】:

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

COSDictionary fdict = new COSDictionary();

fdict.setInt(COSName.FUNCTION_TYPE, 2); // still not understaning that...

COSArray domain = new COSArray();
domain.add(COSInteger.get(0));
domain.add(COSInteger.get(1));

COSArray c0 = new COSArray();
c0.add(COSFloat.get("0.64176"));
c0.add(COSFloat.get("0.72588"));
c0.add(COSFloat.get("0.78078"));

COSArray c1 = new COSArray();
c1.add(COSFloat.get("0.57176"));
c1.add(COSFloat.get("0.62588"));
c1.add(COSFloat.get("0.70078"));

fdict.setItem(COSName.DOMAIN, domain);
fdict.setItem(COSName.C0, c0);
fdict.setItem(COSName.C1, c1);
fdict.setInt(COSName.N, 1);

PDFunctionType2 func = new PDFunctionType2(fdict);

PDShadingType2 axialShading = new PDShadingType2(new COSDictionary());

axialShading.setColorSpace(PDDeviceRGB.INSTANCE);
axialShading.setShadingType(PDShading.SHADING_TYPE2);

COSArray coords1 = new COSArray();
coords1.add(COSInteger.get(0));
coords1.add(COSInteger.get(0));
coords1.add(COSInteger.get(850)); // size of my page
coords1.add(COSInteger.get(600));

axialShading.setCoords(coords1); // so this sets the bounds of my gradient
axialShading.setFunction(func); // and this determines all the curves etc?

CStr.shadingFill(axialShading); // where CStr is a ContentStream for my PDDocument

我会把这个留给其他人。留下您的意见,并随时向我展示一些改进此代码的聪明想法:)

【讨论】:

  • 该函数根据轴上的输入值计算颜色(此处为 RGB 颜色空间,但也可以是 CMYK 或其他)。类型 2 函数是指数插值函数并且是最常用的。 PDF 规范的 7.10.3 对此进行了解释。想象一下,结果值介于两个边界 C0 和 C1 之间,实际上并不需要理解数学。
  • 我有一个想法,这些 0-1 之间的颜色值与 RGB 中 0-255 之间的颜色值成正比。这让我更接近了。这是一个非常有用的库,我喜欢它!
  • 确实如此。在 PDF 中,颜色介于 0 和 1 之间。所以 1 0 0 是完美的红色。
  • 绘制三角形的解决方案是什么?我只能找到使用过时方法的代码,例如 appendRawCommands()。 “q\n”或“B*\n”不要告诉我太多......
  • 使用 moveTo()、LineTo()、LineTo()、closePath()、stroke()。不要忘记设置描边颜色。
【解决方案2】:

这是我为使创建渐变更容易而创建的一个类。它支持多种颜色的轴向渐变。它使用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)函数将多个指数函数与不同的子域组合起来。

【讨论】:

  • 谢谢,我可以使用它在我的页脚上创建渐变:pdfStream.addRect(0, 0, pageWidth, 20f) pdfStream.clip() 但是,我该怎么做撤消剪切区域以便能够绘制到整个页面?我尝试了所有我能想到的方法,但都没有奏效。
  • 从 Adob​​e PDF 参考中找到答案。裁剪和绘图之后需要调用 saveGraphicsState() 和 restoreGraphicsState()。
猜你喜欢
  • 2012-08-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2022-08-07
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多