2014-09-01 11 views
3

В настоящее время я разрабатываю метод, который будет принимать входные данные HTML и преобразовывать его в действительный файл PDF/A. Я знаю, как программно построить действительный файл PDF/A с помощью iText (ссылка: http://itextsupport.com/download/pdfa3.html), но я не могу создать действительный файл PDF/A с использованием HTML в качестве входных данных и использовать XMLWorker для преобразования этого ввода в файл PDF. Проблема, которую я сейчас имею в виду, связана с требованием встроенных шрифтов формата PDF/A. Я всегда получаю это исключение:Как создать действительный файл PDF/A с помощью iText и XMLWorker (HTML to PDF/A)

Исключение из потока «main» com.itextpdf.text.pdf.PdfAConformanceException: все шрифты должны быть встроены. Это не так: Helvetica

Я пытаюсь заставить, какие шрифты будут использовать HTML-ввод, используя файл CSS, и я регистрирую шрифты, которые я хочу использовать в выходном файле PDF, через класс XMLWorkerFontProvider, но, похоже, m делает что-то неправильно, потому что исключение, указанное выше, всегда выбрасывается.

Что еще мне нужно для того, чтобы XMLWorker использовал шрифты, зарегистрированные через класс XMLWorkerFontProvider? Я хочу избежать использования шрифта Helvetica по умолчанию в каждом элементе HTML, присутствующем во входном файле.

Ниже приведен код, я использую для тестирования:

style.css (всего 1 линия):

* { font: normal 100% Arial, sans-serif !important; } 

Main.java:

package com.itextpdf; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.io.Reader; 
import java.io.StringReader; 

import com.itextpdf.text.Document; 
import com.itextpdf.text.pdf.ICC_Profile; 
import com.itextpdf.text.pdf.PdfAConformanceLevel; 
import com.itextpdf.text.pdf.PdfAWriter; 
import com.itextpdf.tool.xml.XMLWorker; 
import com.itextpdf.tool.xml.XMLWorkerFontProvider; 
import com.itextpdf.tool.xml.XMLWorkerHelper; 
import com.itextpdf.tool.xml.css.CssFile; 
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver; 
import com.itextpdf.tool.xml.html.CssAppliers; 
import com.itextpdf.tool.xml.html.CssAppliersImpl; 
import com.itextpdf.tool.xml.html.Tags; 
import com.itextpdf.tool.xml.parser.XMLParser; 
import com.itextpdf.tool.xml.pipeline.css.CSSResolver; 
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline; 
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline; 
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline; 
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext; 

public class Main { 

    /** 
    * @param args 
    */ 
    public static void main(String[] args) { 

     StringBuffer buf = new StringBuffer(); 

     buf.append("<!DOCTYPE html>"); 
     buf.append("<html>"); 
     buf.append("<head>"); 
     buf.append("<title>Test</title>"); 
     buf.append("</head>"); 
     buf.append("<body>"); 
     buf.append("<p>This is a test</p>"); 
     buf.append("</body>"); 
     buf.append("</html>"); 

     OutputStream file = null; 
     Document document = null; 
     PdfAWriter writer = null; 

     try { 

      file = new FileOutputStream(new File("C:\\Users\\amartin\\Desktop\\Test.pdf")); 
      document = new Document(); 
      writer = PdfAWriter.getInstance(document, file, PdfAConformanceLevel.PDF_A_1B); 

      // Create XMP metadata. It's a PDF/A requirement. 
      writer.createXmpMetadata(); 

      document.open(); 

      // Set output intent. PDF/A requirement. 
      ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream("./src/main/resources/com/itextpdf/sRGB Color Space Profile.icm")); 
      writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc); 

      // CSS 
      CSSResolver cssResolver = new StyleAttrCSSResolver(); 
      CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream("./css/style.css")); 
      cssResolver.addCss(cssFile); 

      XMLWorkerFontProvider fontProvider = new XMLWorkerFontProvider(); 
      fontProvider.register("./fonts/arial.ttf"); 
      fontProvider.register("./fonts/sans-serif.ttf"); 
      fontProvider.addFontSubstitute("lowagie", "garamond"); 

      CssAppliers cssAppliers = new CssAppliersImpl(fontProvider); 
      HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers); 
      htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); 

      // Pipelines 
      PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer); 
      HtmlPipeline html = new HtmlPipeline(htmlContext, pdf); 
      CssResolverPipeline css = new CssResolverPipeline(cssResolver, html); 

      XMLWorker worker = new XMLWorker(css, true); 
      XMLParser p = new XMLParser(worker); 

      Reader reader = new StringReader(buf.toString()); 
      p.parse(reader); 

     } catch (Exception e) { 

      e.printStackTrace(); 

     } finally { 

      if (document != null && document.isOpen()) 
       document.close(); 

      try { 

       if (file != null) 
        file.close(); 

      } catch (IOException e) {} 

      if (writer != null && !writer.isCloseStream()) 
       writer.close(); 

     } 

    } 

} 

редактировать:

Отвечая на Bruno, я расширил класс FontFactoryImp, переопределяя метод getFont() (тот, который имеет все аргументы). Она вызывает функцию System.out.println так:

System.out.println("=fontname: " + fontname + " =encoding: " + encoding + " =embedded : " + embedded + " =size: " + size + " =style: " + style + " =BaseColor: " + color) 

, а затем вызывает метод parent.getFont() с теми же аргументами. Единственный выход я вижу это:

= имя_шрифт: нуль = кодировка: cp1252 = встроенное: истина = размер: -1,0 = стиль: -1 = BaseColor: нуль = имя_шрифт: нуль = кодировка: cp1252 = embedded: true = size: -1.0 = style: -1 = BaseColor: null

и исключение, вставленное перед этим кодом.

+1

Создайте собственную реализацию 'FontProvider' и напишите шрифты, которые запрашиваются' System.out'. Убедитесь, что все эти шрифты сопоставлены с программой шрифтов. –

+0

Привет, Бруно. Я сделал то, что вы прокомментировали, и я опубликовал результаты редактирования вопроса. Если бы вы хотели бы получить некоторые отзывы или советы, я был бы очень благодарен. – Arturo

+1

Результат означает, что шрифт, который вы определили в CSS, не был получен XML Worker. Теперь, когда я смотрю на ваш CSS, я знаю, почему. Попробуйте 'font-family:« Arial »вместо использования' font'. –

ответ

2

На основании отзывов, которые вы отправляете на адрес System.out, кажется, что XML Worker не забирает семейство шрифтов, которые вы хотите использовать.

Пожалуйста, укажите семейство шрифтов, как это:

font-family: "Arial" 

Использование «шрифт» в CSS может работать, но это сложно. Я думаю, что iText видит normal и интерпретирует его как Используйте шрифт по умолчанию.

2

Полный код, который делает этот пример работы заключается в следующем:

style.css:

* { 
    font-family: "Arial"; 
    font-style: normal; 
} 

Main.Java:

package com.itextpdf; 

import java.io.File; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.IOException; 
import java.io.OutputStream; 
import java.io.Reader; 
import java.io.StringReader; 

import com.itextpdf.text.Document; 
import com.itextpdf.text.pdf.ICC_Profile; 
import com.itextpdf.text.pdf.PdfAConformanceLevel; 
import com.itextpdf.text.pdf.PdfAWriter; 
import com.itextpdf.tool.xml.XMLWorker; 
import com.itextpdf.tool.xml.XMLWorkerHelper; 
import com.itextpdf.tool.xml.css.CssFile; 
import com.itextpdf.tool.xml.css.StyleAttrCSSResolver; 
import com.itextpdf.tool.xml.html.CssAppliers; 
import com.itextpdf.tool.xml.html.CssAppliersImpl; 
import com.itextpdf.tool.xml.html.Tags; 
import com.itextpdf.tool.xml.parser.XMLParser; 
import com.itextpdf.tool.xml.pipeline.css.CSSResolver; 
import com.itextpdf.tool.xml.pipeline.css.CssResolverPipeline; 
import com.itextpdf.tool.xml.pipeline.end.PdfWriterPipeline; 
import com.itextpdf.tool.xml.pipeline.html.HtmlPipeline; 
import com.itextpdf.tool.xml.pipeline.html.HtmlPipelineContext; 

public class Main { 

    public static void main(String[] args) { 

     StringBuffer buf = new StringBuffer(); 

     String title = "Test"; 

     // Sample HTML content. 
     buf.append("<!DOCTYPE html>"); 
     buf.append("<html>"); 
     buf.append("<head>"); 
     buf.append("<title>" + title + "</title>"); 
     buf.append("</head>"); 
     buf.append("<body>"); 
     buf.append("<p>This is a test</p>"); 
     buf.append("</body>"); 
     buf.append("</html>"); 

     OutputStream file = null; 
     Document document = null; 
     PdfAWriter writer = null; 

     try { 

      file = new FileOutputStream(new File("C:\\Users\\amartin\\Desktop\\Test.pdf")); 
      document = new Document(); 
      writer = PdfAWriter.getInstance(document, file, PdfAConformanceLevel.PDF_A_1B); 

      // Avoid discrepances between document title and XMP metadata information. 
      document.addTitle(title); 

      // Create XMP metadata. It's a PDF/A requirement. 
      writer.createXmpMetadata(); 

      document.open(); 

      // Set output intent. PDF/A requirement. 
      ICC_Profile icc = ICC_Profile.getInstance(new FileInputStream("./src/main/resources/com/itextpdf/sRGB Color Space Profile.icm")); 
      writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc); 

      // CSS stylesheet. 
      CSSResolver cssResolver = new StyleAttrCSSResolver(); 
      CssFile cssFile = XMLWorkerHelper.getCSS(new FileInputStream("./css/style.css")); 
      cssResolver.addCss(cssFile); 

      MyFontProvider fontProvider = new MyFontProvider(); 
      fontProvider.register("./fonts/arial.ttf"); 

      /* DEBUG 
      System.out.println("Fonts present in " + fontProvider.getClass().getName()); 
      Set<String> registeredFonts = fontProvider.getRegisteredFonts(); 
      for (String font : registeredFonts) 
       System.out.println(font); 
      */ 

      CssAppliers cssAppliers = new CssAppliersImpl(fontProvider); 
      HtmlPipelineContext htmlContext = new HtmlPipelineContext(cssAppliers); 
      htmlContext.setTagFactory(Tags.getHtmlTagProcessorFactory()); 

      // Pipelines. 
      PdfWriterPipeline pdf = new PdfWriterPipeline(document, writer); 
      HtmlPipeline html = new HtmlPipeline(htmlContext, pdf); 
      CssResolverPipeline css = new CssResolverPipeline(cssResolver, html); 

      XMLWorker worker = new XMLWorker(css, true); 
      XMLParser p = new XMLParser(worker); 

      Reader reader = new StringReader(buf.toString()); 
      p.parse(reader); 

     } catch (Exception e) { 

      e.printStackTrace(); 

     } finally { 

      if (document != null && document.isOpen()) 
       document.close(); 

      try { 

       if (file != null) 
        file.close(); 

      } catch (IOException e) {} 

      if (writer != null && !writer.isCloseStream()) 
       writer.close(); 

     } 

    } 

} 

MyFontProvider.java:

package com.itextpdf; 

import com.itextpdf.text.BaseColor; 
import com.itextpdf.text.Font; 
import com.itextpdf.text.FontFactoryImp; 

public class MyFontProvider extends FontFactoryImp { 

    @Override 
    public Font getFont(String fontname, String encoding, boolean embedded, 
      float size, int style, BaseColor color) { 

     System.out.println("=fontname: " + fontname + " =encoding: " + encoding + " =embedded : " + embedded + " =size: " + size + " =style: " + style + " =BaseColor: " + color); 

     return super.getFont(fontname, encoding, embedded, size, style, color); 

    } 

} 

Опять же, спасибо, Бруно. Я очень рад получить вашу помощь здесь :)

Смежные вопросы