Правильный способ реализации пользовательских атрибутов Css с Itext и html2Pdf - PullRequest
0 голосов
/ 20 ноября 2018

Я использую Itext 7 и их html2Pdf lib.Есть ли способ реализовать, например, цвета CMYK.

.wootWorkingCMYK-color{
  color: cmyk( 1 , 0.69 , 0.08 , 0.54);
}

Я знаю, что основная часть itext довольно хорошо, ища, чтобы использовать сторону html2Pdf.Я знаю о CssApplierFactory, но, похоже, это далеко зацепило цепочку.

1 Ответ

0 голосов
/ 20 ноября 2018

Ну, конечно, есть способ обработки пользовательских свойств CSS, таких как cmyk цвета, но, к сожалению, код будет довольно громоздким, и вам придется написать довольно много кода для разных случаев.Я покажу, как применять пользовательский цвет для шрифта, но, например, для фона, границ или других случаев вам нужно будет написать отдельный код аналогичным образом.Причиной этого является то, что структура макета iText, хотя и разработана с учетом HTML / CSS, не на 100% похожа и имеет некоторые различия, которые вы должны кодировать.

Имея это в виду, если вы можете разбирать, строить ииспользуйте вашу пользовательскую версию из источников, так я бы посоветовал.Хотя у него есть недостатки, такие как необходимость перебазирования для получения обновлений, решение будет более простым и более общим.Для этого выполните поиск значений CssUtils.parseRgbaColor в модуле pdfHTML, и вы обнаружите, что он используется в BackgroundApplierUtil, BorderStyleApplierUtil, FontStyleApplierUtil, OutlineApplierUtil.Там вы найдете код, подобный

if (!CssConstants.TRANSPARENT.equals(cssColorPropValue)) {
    float[] rgbaColor = CssUtils.parseRgbaColor(cssColorPropValue);
    Color color = new DeviceRgb(rgbaColor[0], rgbaColor[1], rgbaColor[2]);
    float opacity = rgbaColor[3];
    transparentColor = new TransparentColor(color, opacity);
} else {
    transparentColor = new TransparentColor(ColorConstants.BLACK, 0f);
}

, который, как я полагаю, вы также можете настроить для обработки cmyk, зная, что вы достаточно хорошо знаете основную часть.

Теперь решение без пользовательскихВерсия pdfHTML действительно должна начинаться с реализации ICssApplierFactory или реализации по умолчанию подкласса DefaultCssApplierFactory.В основном мы заинтересованы в настройке реализации SpanTagCssApplier и BlockCssApplier, но вы можете проконсультироваться с DefaultTagCssApplierMapping, чтобы получить полный список поставщиков и случаев, в которых они используются, чтобы вы могли решить, какой из них вы хотите обработатьв вашем коде.

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

private static class CustomCssApplierFactory implements ICssApplierFactory {
    private static final ICssApplierFactory DEFAULT_FACTORY = new DefaultCssApplierFactory();

    @Override
    public ICssApplier getCssApplier(IElementNode tag) {
        ICssApplier defaultApplier = DEFAULT_FACTORY.getCssApplier(tag);
        if (defaultApplier instanceof SpanTagCssApplier) {
            return new CustomSpanTagCssApplier();
        } else if (defaultApplier instanceof BlockCssApplier) {
            return new CustomBlockCssApplier();
        } else {
            return defaultApplier;
        }
    }
}

private static class CustomSpanTagCssApplier extends SpanTagCssApplier {
    @Override
    protected void applyChildElementStyles(IPropertyContainer element, Map<String, String> css, ProcessorContext context, IStylesContainer stylesContainer) {
        super.applyChildElementStyles(element, css, context, stylesContainer);
        String color = css.get("color2");
        if (color != null) {
            color = color.trim();
            if (color.startsWith("cmyk")) {
                element.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
            }
        }
    }
}

private static class CustomBlockCssApplier extends BlockCssApplier {
    @Override
    public void apply(ProcessorContext context, IStylesContainer stylesContainer, ITagWorker tagWorker) {
        super.apply(context, stylesContainer, tagWorker);
        IPropertyContainer container = tagWorker.getElementResult();
        if (container != null) {
            String color = stylesContainer.getStyles().get("color2");
            if (color != null) {
                color = color.trim();
                if (color.startsWith("cmyk")) {
                    container.setProperty(Property.FONT_COLOR, new TransparentColor(parseCmykColor(color)));
                }
            }
        }
    }
}

// You might want a safer implementation with better handling of corner cases
private static DeviceCmyk parseCmykColor(String color) {
    final String delim = "cmyk(), \t\r\n\f";
    StringTokenizer tok = new StringTokenizer(color, delim);
    float[] res = new float[]{0, 0, 0, 0};
    for (int k = 0; k < 3; ++k) {
        if (tok.hasMoreTokens()) {
            res[k] = Float.parseFloat(tok.nextToken());
        }
    }
    return new DeviceCmyk(res[0], res[1], res[2], res[3]);
}

Имеяэтот пользовательский код, вы должны соответствующим образом настроить ConverterProperties и передать его HtmlConverter:

ConverterProperties properties = new ConverterProperties();
properties.setCssApplierFactory(new CustomCssApplierFactory());
HtmlConverter.convertToPdf(..., properties);

Возможно, вы заметили, что я использовал color2 вместо color, и это не просто так.В pdfHTML есть механизм проверки свойств CSS (как это делают и браузеры), позволяющий отбрасывать недействительные свойства CSS при расчете эффективных свойств элемента.К сожалению, в настоящее время нет механизма настройки этой логики проверки, и, конечно, в настоящее время он обрабатывает cmyk цветов как недопустимые объявления.Таким образом, если вы действительно хотите иметь собственное свойство color, вам придется предварительно обработать HTML-код и заменить объявления вроде color: cmyk... на color2: cmyk.. или любое другое имя свойства, которое вы можете использовать.

КакЯ упоминал в начале ответа, я рекомендую создать свою собственную версию:)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...