Изменить ориентацию страницы только для некоторых страниц в полученном PDF (созданном из HTML) - PullRequest
0 голосов
/ 16 января 2019

Я хотел бы изменить ориентацию страницы только для определенных нескольких страниц в моем документе PDF. Документ PDF создается из HTML-шаблона с использованием html2pdf. Это выглядит так: если содержимое страницы (обычно таблицы) слишком широкое, чтобы правильно отображать его в книжной ориентации, показывать страницу в альбомной ориентации.

Следуя подсказке в [как повернуть страницы в альбомную ориентацию, содержимое страницы должно быть в портретной ориентации iTextpdf] [1]

[1]: как повернуть страницы в альбомную ориентацию, а содержимое страницы должно быть портретным iTextpdf Я создал свой собственный тег и TagWorker.

public class LandscapeTagWorker extends BodyTagWorker {

public LandscapeTagWorker(IElementNode element, ProcessorContext context) {
    super(element, context);
}

/**
 * @param element
 * @param context
 * @see com.itextpdf.html2pdf.attach.ITagWorker#processEnd(com.itextpdf.html2pdf.html.node.IElementNode, com.itextpdf.html2pdf.attach.ProcessorContext)
 */
@Override
public void processEnd(IElementNode element, ProcessorContext context) {
    super.processEnd(element, context);
    String value = element.getAttribute("value");
     if ( "true".equalsIgnoreCase(value) ) {
        PdfDocument doc = context.getPdfDocument();

        doc.setDefaultPageSize(doc.getDefaultPageSize().rotate());
     }
}

}

Проблемы: во-первых, это ничего не делает. Даже если это сработает, я не хочу менять ориентацию всего документа, а только ориентацию страниц, где находится содержимое <landscape value="true">.

Как извлечь текущие страницы из ProcessorContext / PdfDocument и как изменить ориентацию страниц только этих страниц?

1 Ответ

0 голосов
/ 17 января 2019

В ответе ниже я покажу, как таблицы с атрибутом класса, заданным как ландшафт, можно обрабатывать так, как вы хотите.

Прежде всего, давайте создадим собственный аппликатор CSS для таких таблиц. Его целью было бы установить пользовательское свойство для тега таблицы (например, 10001). Затем во время макета мы проверим это свойство и решим, изменять размер страницы или нет.

    class CustomCssApplierFactory extends DefaultCssApplierFactory {
    @Override
    public ICssApplier getCustomCssApplier(IElementNode tag) {
        if ("table".equals(tag.name()) && "landscape".equals(tag.getAttribute(AttributeConstants.CLASS))) {
            return new CustomLandscapeCssApplier();
        }
        return null;
    }
}

class CustomLandscapeCssApplier extends TableTagCssApplier {
    @Override
    public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker) {
        super.apply(context, stylesContainer, tagWorker);
        IPropertyContainer container = tagWorker.getElementResult();
        if (null != container) {
            container.setProperty(10001, true);
        }
    }
}

Теперь давайте преобразуем ваш HTML не в PDF-файл, а в список элементов IE , которые образуют этот HTML (вас особенно интересует последняя строка):

    PdfDocument pdfDocument = new PdfDocument(new PdfWriter(pdfDest));
    Document document = new Document(pdfDocument);

    ConverterProperties converterProperties = new ConverterProperties();
    converterProperties.setCssApplierFactory(new CustomCssApplierFactory());
    List<IElement> list = HtmlConverter.convertToElements(new FileInputStream(htmlSource), converterProperties);

Теперь давайте добавим эти элементы в документ по одному и проверим, имеет ли текущий элемент (добавляемый элемент) свойство magic 10001. Если нет, то просто добавьте элемент. Если она существует, давайте разбиваем страницу и устанавливаем размер следующей страницы при разрыве:

        for (IElement element : list) {
        if (element instanceof IBlockElement) {
            if (!element.hasProperty(10001)) {
                document.add((IBlockElement) element);
            } else {
                document.add(new AreaBreak(new PageSize(PageSize.A4).rotate()));
                document.add((IBlockElement) element);
                document.getPdfDocument().setDefaultPageSize(PageSize.A4);
            }
        }
    }

Как вы можете видеть из приведенного выше фрагмента, я разбил страницу (устанавливая размер следующей страницы), добавил элемент, а затем снова установил размер следующей области макета, чтобы следующая страница после той, которая содержит элемент будет иметь размер страницы по умолчанию).

Вот так выглядит результат: enter image description here

Однако существуют некоторые ограничения:

1) Вообще говоря, PDF-файл - это не просто набор элементов, отображаемых на странице. В разделе HtmlConverter.convertToPdf iText также обрабатывает некоторые другие функции (схемы и т. Д.). Однако, похоже, что для ваших целей метод работает отлично.

2) Как видите, я не проверяю, существуют ли какие-либо таблицы, которые не являются прямыми потомками тега body. На самом деле, для правильной работы в общем случае вам нужно изменить цикл: проверить дочерние элементы всех элементов (возможно, с помощью `AbstractElement # getChildren ()) и поместить в них несколько объектов AreaBreaks. Но это похоже на другой вопрос.

...