当前位置: 首页 > 面试题库 >

Java用颜色写入.pdf

金承嗣
2023-03-14
问题内容

我想创建一个.pdf文件,然后用彩色写入。通过控制台,我已经能够使用ansi转义序列做到这一点。例如,如果我想红,我把”\u001b[31m”我的字符串的前面,”\u001b[0m”以删除所有格式。您可以更改背景和前景。我为此设计了自己的有用的类,以帮助显示信息,甚至还用于我仍在从事的基于文本的国际象棋项目。

但是,现在我想用彩色写入文件。我想做与ansi转义类似的事情,但可能不会。

如果我想在.pdf中创建颜色,我该怎么做(不使用外部资源)?有人可以指出我正确的方向吗?


问题答案:

这里是一个非常非常简单的PDF Creator类的快速攻克,除了在彩色背景上用彩色写Courier文本外,它无能为力:

public class SimplePdfCreator
{
    /**
     * Creates a {@link SimplePdfCreator} instance writing to the
     * given {@link OutputStream}.
     */
    public SimplePdfCreator(OutputStream os) throws IOException
    {
        pdfOs = os instanceof BufferedOutputStream ? (BufferedOutputStream) os : new BufferedOutputStream(os);

        writeHeader();
        fontObjectNr = writeFont();
        initPage();
    }

    /**
     * Sets the (fill) color for the upcoming operations on the current page.
     */
    public void color(float r, float g, float b)
    {
        pageBuilder.append(r)
                   .append(' ')
                   .append(g)
                   .append(' ')
                   .append(b)
                   .append(" rg\n");
    }

    /**
     * Sets the background (fill) color for the upcoming operations on the current page.
     */
    public void backColor(float r, float g, float b)
    {
        backBuilder.append(r)
                   .append(' ')
                   .append(g)
                   .append(' ')
                   .append(b)
                   .append(" rg\n");
    }

    /**
     * Prints the given text on a baseline starting at the given coordinates
     * on the current page.
     */
    public void print(int x, int y, String string)
    {
        pageBuilder.append(x - xNow)
                   .append(' ')
                   .append(y - yNow)
                   .append(" Td (")
                   .append(string)
                   .append(") Tj\n");
        xNow = x;
        yNow = y;
        fillBack(string);
    }

    /**
     * Prints the given text on the next line on the current page.
     */
    public void print(String string)
    {
        pageBuilder.append("(")
                   .append(string)
                   .append(") '\n");
        yNow -= leading;
        fillBack(string);
    }

    /**
     * Stores the current page with the printed content in the output
     * and creates a new one.
     */
    public void storePage() throws IOException
    {
        writePageContent();
        initPage();
    }

    /**
     * Returns the width of the given String.
     */
    public double getStringWidth(String string)
    {
        return string.length() * fontSize * .6;
    }

    /**
     * Returns the font size
     */
    public int getFontSize()
    {
        return fontSize;
    }

    /**
     * Returns the leading
     */
    public int getLeading()
    {
        return leading;
    }

    /**
     * Finishes the output writing required data to it and closing the
     * target {@link OutputStream}.
     */
    public void close() throws IOException
    {
        int pagesObjectNr = writePages();
        int catalogObjectNr = writeCatalog(pagesObjectNr);
        long xrefPosition = writeXref();
        writeTrailer(catalogObjectNr);
        writeFooter(xrefPosition);
        pdfOs.close();;
    }

    //
    // helper methods
    //
    void writeHeader() throws IOException
    {
        write("%PDF-1.4\n".getBytes(charSet));
        write(new byte[]{'%', (byte)128, (byte)129, (byte)130, '\n'});
    }

    int writeFont() throws IOException
    {
        return writeObject("<</Type/Font/Subtype/Type1/BaseFont/Courier/Encoding/WinAnsiEncoding>>\n".getBytes(charSet));
    }

    void initPage()
    {
        pageBuilder.setLength(0);
        backBuilder.setLength(0);
        pageBuilder.append("BT/F0 ")
                   .append(fontSize)
                   .append(" Tf ")
                   .append(leading)
                   .append(" TL 0 g\n");
        backBuilder.append("1 g\n");
        xNow = 0;
        yNow = 0;
    }

    void fillBack(String string)
    {
        backBuilder.append(xNow)
                   .append(' ')
                   .append(yNow - leading*.2)
                   .append(' ')
                   .append(getStringWidth(string))
                   .append(' ')
                   .append(leading)
                   .append(" re f\n");
    }

    void writePageContent() throws IOException
    {
        pageBuilder.append("ET\n");
        StringBuilder contents = new StringBuilder();
        contents.append("<</Length ")
                .append(pageBuilder.length() + backBuilder.length())
                .append(">>\nstream\n")
                .append(backBuilder)
                .append(pageBuilder)
                .append("\nendstream\n");
        int contentsObjectNr = writeObject(contents.toString().getBytes(charSet));
        pageContentsObjects.add(contentsObjectNr);
    }

    int writePages() throws IOException
    {
        int pagesObjectNrToBe = xref.size() + pageContentsObjects.size() + 1;
        StringBuilder pages = new StringBuilder();
        pages.append("<</Type /Pages /Count ")
             .append(pageContentsObjects.size())
             .append("/Kids[");
        for (int pageContentObject : pageContentsObjects)
        {
            int pageObjectNr = writeObject(String.format("<</Type/Page/Parent %s 0 R/Contents %s 0 R>>\n", pagesObjectNrToBe, pageContentObject).getBytes(charSet));
            pages.append(pageObjectNr).append(" 0 R ");
        }
        pages.append("]/Resources<</ProcSet[/PDF/Text]/Font<</F0 ")
             .append(fontObjectNr)
             .append(" 0 R>>>>/MediaBox[0 0 612 792]>>\n");
        return writeObject(pages.toString().getBytes(charSet));
    }

    int writeCatalog(int pagesObjectNr) throws IOException
    {
        return writeObject(String.format("<</Type/Catalog/Pages %s 0 R>>\n", pagesObjectNr).getBytes(charSet));
    }

    long writeXref() throws IOException
    {
        long xrefPos = position;
        byte[] eol = new byte[]{'\n'};
        write("xref\n".getBytes(charSet));
        write(String.format("0 %s\n", xref.size() + 1).getBytes(charSet));
        write("0000000000 65535 f ".getBytes(charSet));
        write(eol);
        for(long position: xref)
        {
            write(String.format("%010d 00000 n ", position).getBytes(charSet));
            write(eol);
        }
        return xrefPos;
    }

    void writeTrailer(int catalogObjectNr) throws IOException
    {
        write(String.format("trailer\n<</Size %s/Root %s 0 R>>\n", xref.size() + 1, catalogObjectNr).getBytes(charSet));
    }

    void writeFooter(long xrefPosition) throws IOException
    {
        write(String.format("startxref\n%s\n%%%%EOF\n", xrefPosition).getBytes(charSet));
    }

    int writeObject(byte[] bytes) throws IOException
    {
        int objectNr = startObject();
        write(bytes);
        endObj();
        return objectNr;
    }

    int startObject() throws IOException
    {
        xref.add(position);
        int objectNr = xref.size();
        write(String.format("%s 0 obj\n", objectNr).getBytes(charSet));
        return objectNr;
    }

    void endObj() throws IOException
    {
        write("endobj\n".getBytes(charSet));
    }

    long write(byte[] bytes) throws IOException
    {
        if (bytes != null)
        {
            pdfOs.write(bytes);
            position += bytes.length;
        }
        return position;
    }

    final BufferedOutputStream pdfOs;
    final Charset charSet = Charset.forName("ISO-8859-1");
    final List<Long> xref = new ArrayList<Long>();
    final List<Integer> pageContentsObjects = new ArrayList<Integer>();
    final StringBuilder pageBuilder = new StringBuilder();
    final StringBuilder backBuilder = new StringBuilder();
    final int fontObjectNr;
    long position = 0;

    int xNow = 0;
    int yNow = 0;

    int fontSize = 11;
    int leading = 11;
}

You can use it like this:

public void test() throws IOException
{
    SimplePdfCreator creator = new SimplePdfCreator(new FileOutputStream("target/test-outputs/SimpleGenerated.pdf"));

    creator.print(100, 500, "Test line 1");
    creator.print("Test line 2");

    creator.color(1, 0, 0);
    creator.backColor(0, 1, 1);
    creator.print(100, 450, "Test line red");
    creator.color(0, 1, 0);
    creator.backColor(1, 0, 1);
    creator.print("Test line green");
    creator.color(0, 0, 1);
    creator.backColor(1, 1, 0);
    creator.print("Test line blue");

    creator.color(1, 1, 1);
    creator.backColor(0, 0, 0);

    creator.print(100, 400, "step");
    creator.print(100 + (int)creator.getStringWidth("step"), 400 - creator.getLeading(), "by");
    creator.print(100 + (int)creator.getStringWidth("stepby"), 400 - 2 * creator.getLeading(), "step");

    creator.storePage();

    creator.print(100, 400, "Page 2");

    creator.storePage();

    creator.close();
}

并请记住,如上所述,这是一个快速技巧,可能是
概念的证明,还有很多改进之处,例如,坐标可能应为
双精度而不是int,在添加内容之前应转义字符串
(尤其是括号, …




 类似资料:
  • 问题内容: 我正在从Datatable编写csv文件。在下面检查我的代码 代码对我有用,但我需要在csv的某些单元格中添加颜色代码。 我怎样才能做到这一点 ? 问题答案: CSV是一种纯数据格式,没有任何格式。毕竟是纯文本文件。因此,没有办法增加颜色。

  • 我试图从使用apache POI创建的Excel文件中的给定和复制字体和颜色。后者起作用,但是设置颜色不起作用:虽然我在Excel中的字体在使用直接设置时是绿色的,但是使用创建不起作用(请参见下面的代码)。如何获得(最接近的),或者更好地使用POI字体中的原始值? 当前代码段:

  • 问题内容: 我希望在Java中实现一项功能,该功能可以读取图像并能够检测红色,蓝色,绿色,黄色等阴影,作为卫星图像分析程序的一部分。因此,例如在标准卫星图像中,蓝色将是水,因此我希望程序读取多少像素是蓝色的,然后它可以说图像的x%是水。 我知道通过读取每个像素的RGB值可以使用整个逻辑语句负载,但是有没有更简单的方法呢?否则,将有数百个if语句,这些语句将花费很长时间来编写,但执行起来也会很长。理

  • 通过RGB值设置输入线的颜色。关于连接线定义,请参考这里: 连接线。 默认的输入线颜色是 0x154492: // 颜色的参数可以是字符串 "#00FF00" 或者是十六进制数值 0x00FF00 controller.setImportColor("#00FF00"); //controller.setImportColor(0x00FF00);

  • 原文:Specifying Colors 在 matplotlib 的几乎所有地方,用户都可以指定颜色,它可以以如下形式提供: RGB 或者 RGBA 浮点值元组,[0, 1]之间,例如(0.1, 0.2, 0.5)或者(0.1, 0.2, 0.5, 0.3)。 RGB 或者 RGBA 十六进制字符串,例如#0F0F0F或者#0F0F0F0F。 [0, 1]之间的浮点值的字符串表示,用于表示灰度,

  • 问题内容: 我正在使用NET Beans IDE在LINUX中开发应用程序。我已经使用了Synthesisa软件包来生成新的外观。到目前为止一切都很好。 现在,我的下一个阶段是在某些数据库状态更改时为按钮添加颜色。 例如: 在一家餐厅,我有2张桌子,当有8个人进餐时,由于人们无人值守,我将在我的软件中创建2张桌子,我希望这2张桌子的按钮呈绿色。处理这些表中的任何一个表的订单时,已处理表的按钮颜色应