Векторная графика в iText PDF

Мы используем iText для создания PDF-файлов из Java (частично на основе рекомендаций на этом сайте). Однако встраивание копии нашего логотипа в формат изображения, такой как GIF, приводит к тому, что он выглядит немного странно, когда люди увеличивают и уменьшают масштаб.

В идеале мы хотели бы встроить изображение в векторный формат, такой как EPS, SVG или просто шаблон PDF. На веб-сайте утверждается, что поддержка EPS прекращена, что встраивание PDF или PS в PDF может привести к ошибкам, и даже не упоминается SVG.

Наш код использует Graphics2D API, а не iText напрямую, но мы были бы готовы выйти из режима AWT и использовать сам iText, если бы он достиг результата. Как это может быть сделано?

Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
13
0
31 946
7
Перейти к ответу Данный вопрос помечен как решенный

Ответы 7

Недавно я узнал, что вы можете отправить свой объект Graphics2D прямо в iText, и полученные PDF-файлы ничем не хуже масштабируемой векторной графики. Судя по вашему сообщению, это может решить вашу проблему.

Document document = new Document(PageSize.LETTER);
PdfWriter writer = null;
try {
    writer = PdfWriter.getInstance(document, new FileOutputStream(your file name));
} catch (Exception e) {
    // do something with exception
}

document.open();

PdfContentByte cb = writer.getDirectContent();
PdfTemplate tp = cb.createTemplate(width, height);
Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper());

// Create your graphics here - draw on the g2 Graphics object

g2.dispose();
cb.addTemplate(tp, 0, 100); // 0, 100 = x,y positioning of graphics in PDF page
document.close();

Это то, что мы уже делаем - используем Graphics2D для рисования на странице. Нам нужно добавить изображение в векторном формате.

Marcus Downing 03.01.2009 01:06
Ответ принят как подходящий

Согласно документация iText поддерживает следующие форматы изображений: JPEG, GIF, PNG, TIFF, BMP, WMF и EPS. Я не знаю, может ли это помочь, но я успешно использовал iTextSharp для встраивания векторного изображения WMF в файл pdf:

C#:

using System;
using System.IO;
using iTextSharp.text;
using iTextSharp.text.pdf;

public class Program 
{

    public static void Main() 
    {
        Document document = new Document();
        using (Stream outputPdfStream = new FileStream("output.pdf", FileMode.Create, FileAccess.Write, FileShare.None))
        using (Stream imageStream = new FileStream("test.wmf", FileMode.Open, FileAccess.Read, FileShare.Read))
        {
            PdfWriter.GetInstance(document, outputPdfStream);
            Image wmf = Image.GetInstance(imageStream);
            document.Open();
            document.Add(wmf);
            document.Close();
        }
    }
}

Я получаю исключение, когда пробовал ваш код, это не работает для меня, я недавно прочитал, что eps не поддерживается, вы должны преобразовать его в WMF

RJardines 13.02.2012 01:00

Я нашел пару примеров от автора iText, которые используют Graphics2D API и библиотеку Apache Batik для рисования SVG в PDF.

http://itextpdf.com/examples/iia.php?id=269

http://itextpdf.com/examples/iia.php?id=263

Для моих целей мне нужно было взять строку SVG и нарисовать ее в PDF-файле определенного размера и в определенном месте, сохраняя при этом векторный характер изображения (без растеризации).

Я хотел обойти SVG-файл, который, кажется, преобладает в функциях SAXSVGDocumentFactory.createSVGDocument (). Я нашел следующий пост полезным для использования текстовой строки SVG вместо плоского файла.

http://batik.2283329.n4.nabble.com/Parse-SVG-from-String-td3539080.html

You have to create a StringReader from your String and pass that to the SAXSVGDocumentFactory#createDocument(String, Reader) method. The URI that you pass as the first parameter as a String will be the base document URI of the SVG document. This should only be important if your SVG references any external files.

Best regards,

Daniel

Исходный код Java, полученный из примеров iText:

// SVG as a text string.
String svg = "<svg>...</svg>";

// Create the PDF document.
// rootPath is the present working directory path.
Document document = new Document();
PdfWriter writer = PdfWriter.getInstance(document, new FileOutputStream(new File(rootPath + "svg.pdf")));
document.open();

// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 1"));
document.add(new Paragraph(" "));

// Boilerplate for drawing the SVG to the PDF.
String parser = XMLResourceDescriptor.getXMLParserClassName();
SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(parser);
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
PdfContentByte cb = writer.getDirectContent();

// Parse the SVG and draw it to the PDF.
Graphics2D g2d = new PdfGraphics2D(cb, 725, 400);
SVGDocument chart = factory.createSVGDocument(rootPath, new StringReader(svg));
GraphicsNode chartGfx = builder.build(ctx, chart);
chartGfx.paint(g2d);
g2d.dispose();

// Add paragraphs to the document...
document.add(new Paragraph("Paragraph 2"));
document.add(new Paragraph(" "));

document.close();

Обратите внимание, что это приведет к отображению SVG в PDF-файле, над которым вы работаете. SVG отображается как плавающий слой над текстом. Я все еще работаю над его перемещением / масштабированием и размещением в тексте, но, надеюсь, это выходит за рамки непосредственного вопроса.

Надеюсь, это помогло.

Ваше здоровье

Обновлено: мне удалось реализовать свой svg как встроенный объект, используя следующее. Прокомментированные строки предназначены для добавления быстрой границы для проверки позиционирования.

SAXSVGDocumentFactory factory = new SAXSVGDocumentFactory(XMLResourceDescriptor.getXMLParserClassName());
UserAgent userAgent = new UserAgentAdapter();
DocumentLoader loader = new DocumentLoader(userAgent);
BridgeContext ctx = new BridgeContext(userAgent, loader);
ctx.setDynamicState(BridgeContext.DYNAMIC);
GVTBuilder builder = new GVTBuilder();
SVGDocument svgDoc = factory.createSVGDocument(rootPath, new StringReader(svg));
PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width")), Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height")));
Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
GraphicsNode chartGfx = builder.build(ctx, svgDoc);
chartGfx.paint(g2d);
g2d.dispose();
Image svgImg = new ImgTemplate(svgTempl);
svgImg.setAlignment(Image.ALIGN_CENTER);
//svgImg.setBorder(Image.BOX);
//svgImg.setBorderColor(new BaseColor(0xff, 0x00, 0x00));
//svgImg.setBorderWidth(1);
document.add(svgImg);

Здравствуйте, я пытаюсь найти способ сделать что-то подобное, чтобы преобразовать файлы SVG в документ PDF. Какую версию Itext вы используете? Я заметил, что конструкторы являются частными для класса com.lowagie.text.pdf.PdfGraphics2D, по крайней мере, в iText 2.1.2, и я не смог найти такой класс в IText 5.5.4. Спасибо! - Хосе Тепедино 6 минут назад

Jose Tepedino 16.03.2016 15:03

@JoseTepedino Мне очень жаль, но я не касался этого годами (с тех пор, как написал ответ). Я могу представить, что использую версию, выпущенную примерно в сентябре 2012 года, так что это, вероятно, будет iText 5.3.2, выпущенная в августе 2012 года в соответствии с их выпусками GitHub - github.com/itext/itextpdf/releases/tag/5.3.2. Надеюсь, это поможет.

clayzermk1 16.03.2016 19:06

Спасибо за твое сообщение! Я добился небольшого прогресса, найдя страницу API, на которой указано, что класс PdfGraphics2D из пакета com.itextpdf.awt существует с iText 5.0.2: developers.itextpdf.com/reference/…. Мне еще предстоит кое-что обсудить, но поиск правильной версии для использования - хорошее начало. Спасибо!

Jose Tepedino 17.03.2016 05:46

Это то, что я извлек из сообщений, которые я нашел здесь, и официальных примеров:

/**
 * Reads an SVG Image file into an com.itextpdf.text.Image instance to embed it into a PDF
 * @param svgPath SVG filepath
 * @param writer PdfWriter instance 
 * @return Instance of com.itextpdf.text.Image holding the SVG file
 * @throws IOException
 * @throws BadElementException
 */
private static Image getSVGImage(String svgPath, PdfWriter writer) throws IOException, BadElementException {
    SVGDocument svgDoc = new SAXSVGDocumentFactory(null).createSVGDocument(null, new FileReader(svgPath));

    // Try to read embedded height and width
    float svgWidth = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("width").replaceAll("[^0-9.,]",""));
    float svgHeight = Float.parseFloat(svgDoc.getDocumentElement().getAttribute("height").replaceAll("[^0-9.,]",""));

    PdfTemplate svgTempl = PdfTemplate.createTemplate(writer, svgWidth, svgHeight);
    Graphics2D g2d = new PdfGraphics2D(svgTempl, svgTempl.getWidth(), svgTempl.getHeight());
    GraphicsNode chartGfx = (new GVTBuilder()).build(new BridgeContext(new UserAgentAdapter()), svgDoc);
    chartGfx.paint(g2d);
    g2d.dispose();

    return new ImgTemplate(svgTempl);
}

Экземпляр изображения можно легко добавить в pdf (в моем случае в качестве подписи).

Классы в приведенном выше коде могут быть импортированы с использованием следующей зависимости maven: <dependency> <groupId>org.apache.xmlgraphics</groupId> <artifactId>batik-gvt</artifactId> <version>1.7</version> </dependency>

Serhii Maksymchuk 28.03.2017 13:35

Это сработало для меня, используя itext 7.1.3 для рендеринга изображения SVG с помощью SVGConverter.

PdfWriter writer = new PdfWriter(new FileOutputStream("/home/users/Documents/pdf/new.pdf"));

        PdfDocument pdfDoc = new PdfDocument(writer);

        Document doc = new Document(pdfDoc);

        URL svgUrl = new File(svg).toURI().toURL();

        doc.add(new Paragraph("new pikachu"));                      

        Image image = SvgConverter.convertToImage(svgUrl.openStream(), pdfDoc);                 
        doc.add(image);

        doc.close();

Новая версия iText также поддерживает файлы SVG. См. Страницу это.

Согласовано. Добавьте в этот ответ полезные подробности, и я с радостью проголосую за него.

Marcus Downing 23.04.2019 15:05

Единственный способ заставить его работать - это преобразование векторного файла SVG в векторный файл PDF, прежде чем вставлять его в мой PDF-файл itext / openpdf.

Вы правильно поняли: я вставляю векторный PDF-файл в свой PDF-файл и работает как шарм. Вы можете увеличить масштаб и все работает хорошо.

Я использую этот код в приложении Spring Boot:

public void addVectorToPDF(PdfWriter writer) throws IOException {

    // My SVG image that I converted to PDF format, keeping the vectorial format.
    URL resource = this.getClass().getResource("/resources/my-vectorial-image-pdf-format.pdf");

    PdfReader reader = new PdfReader(resource);

    // Getting the page 01 of the PDF. The PDF has only the
    // SVG image inside, so the page 01 is everything.
    PdfImportedPage page = writer.getImportedPage(reader, 1);

    float posX = 50;
    float posY = 300;
    float scale = 0.75F;
    PdfContentByte canvas = writer.getDirectContent();

    // adding vectorial image pdf to my pdf
    canvas.addTemplate(page, scale, 0, 0, scale, posX, posY);

}

Вы можете использовать zamzar.com для преобразования вашего векторного SVG в PDF. У меня это сработало.

Решения с Batik и Graphics2D в моем случае не сохранили векторный формат.

Другие вопросы по теме