如何将 vaadin 23 元素转换为 itext 7 元素?

问题描述 投票:0回答:3

我的 Vaadin 网站上有传单地图:

enter image description here

我需要将此 DIV 块(作为图片)导出到 PDF 文件(我使用 iText 7 https://kb.itextpdf.com/home):

在这里我找到了资料 * https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml/chapter-1-hello-html-to-pdf*

关于将 HTML 导出为 PDF 文件。

我有问题:

iText 7 需要 IElement,但我只有 vaadin 元素。

请告诉我如何将 vaadin 元素转换为 iText 元素?

我尝试从 vaadin 元素获取 OuterHTML:

        String HTML = this.getElement().getOuterHTML();  
        var elements = HtmlConverter.convertToElements(HTML);
        for (IElement element : elements) {
            pdfExporter.getDocument().add((IBlockElement)element);
        }

结果收到没有图的报告

enter image description here

itext vaadin itext7
3个回答
1
投票

Vaadin 中的元素 API 不会将所有内容保存在服务器端内存中。您应该更多地把它看作是一个代理,它只是将必要的内容传递给客户端并返回。 getOuterHTML 返回的只是浏览器端实际内容的一小部分。元素中的几乎所有内容都由 LeafletJS 呈现,因此服务器端代理对其内容一无所知。这就是为什么你正在尝试的东西永远不会那样工作。

我看到你有两个选择。首先是使用 executeJS 获取完整的 html。但如果 iText 能够以有意义的方式解释 Leaflet 提供的相当复杂的结构,我会感到惊讶。

可能更好的工作解决方案是先使用某些东西将浏览器端的当前视图渲染成图像,然后将该图像转发到 iText。这个 HTMLtoCANVAS 可能会有帮助(免责声明:我自己从未使用过)。


0
投票

如果需要使用传单图,可以使用插件leaflet-simple-map-screenshoterhttps://github.com/grinat/leaflet-simple-map-screenshoter

我为它创建了以下类

import com.vaadin.flow.component.internal.PendingJavaScriptInvocation;
import com.vaadin.flow.component.internal.UIInternals;
import com.vaadin.flow.dom.Element;
import com.vaadin.flow.internal.StateNode;
import org.apache.commons.lang3.StringUtils;
import tetramap.gui.MapView;

import java.util.concurrent.CompletableFuture;

public class HtmlToCanvas {

    MapView mapView;

    public HtmlToCanvas(MapView mapView) {
        this.mapView = mapView;
    }

    public CompletableFuture<String> takeScreenShot(Element e){
        CompletableFuture<String> future = new CompletableFuture<>();
        String id = e.getAttribute("id");
        if (StringUtils.isEmpty(id)) {
            e.setAttribute("id", "elementForScreenShot");
            id = e.getAttribute("id");
        }
        StateNode node = e.getNode();
        getJavaScriptInvoke(node, "let element = document.querySelector('#" + id +  "');\n" +
                "this.simpleMapScreenshoter = L.simpleMapScreenshoter().addTo(" + mapView.getMap().getId() + ")\n" +
                        "let format = 'canvas' \n" +
                        "let overridedPluginOptions = {\n" +
                        "  mimeType: 'image/png'\n" +
                        "}\n" +

                        "function send(canvas) {\n" +
                            "canvasValue = canvas.toDataURL()\n" +
                            "element.dispatchEvent(new Event('canvasReady'));\n" +
                        "}\n" +

                        "this.simpleMapScreenshoter.takeScreen(format, overridedPluginOptions).then(canvas => {\n" +
                            "console.info(canvas)\n" +
                            "send(canvas);\n" +
                        "}).catch(e => {\n" +
                        "   console.error(e)\n" +
                        "})"
        );
        e.addEventListener("canvasReady", l -> getJavaScriptReturn(node, "canvasValue.valueOf()").then(jsonValue -> future.complete(jsonValue.asString())));
        return future;
    }

    public PendingJavaScriptInvocation getJavaScriptInvoke(StateNode node, String expression) {
        UIInternals.JavaScriptInvocation invocation = new UIInternals.JavaScriptInvocation(expression);
        PendingJavaScriptInvocation pending = new PendingJavaScriptInvocation(node, invocation);
        node.runWhenAttached((ui) -> ui.getInternals().getStateTree().beforeClientResponse(node, (context) -> {
            if (!pending.isCanceled()) {
                context.getUI().getInternals().addJavaScriptInvocation(pending);
            }
        }));
        return pending;
    }

    public PendingJavaScriptInvocation getJavaScriptReturn(StateNode node, String expression) {
        return getJavaScriptInvoke(node, "return " + expression);
    }

}

以及如何在 Vaadin 中使用 takeScreenShot()

  HtmlToCanvas htmlToCanvas = new HtmlToCanvas(mapView);

            CompletableFuture<String> completableFuture = htmlToCanvas.takeScreenShot(mapView.getElement());
            completableFuture.thenRun(() -> {
...
    Image image = new Image(completableFuture.get(), "screenshot");

        String immagineBase64 = vaadinImage.getSrc().substring(22);
        byte[] imageBytes = Base64.getDecoder().decode(immagineBase64.getBytes(StandardCharsets.UTF_8));
...
            });

0
投票

非常感谢您提供 HTMLtoCANVAS 插件。

我也遇到了图片保存不正确的问题。几何形状位于地图上的另一个地方。

是:

成为:

我找到了一个解决方案,让 Leaflet 使用 CANVAS 而不是 SVG 来处理形状。

renderer: L.canvas()

现在插件运行良好。非常感谢。

© www.soinside.com 2019 - 2024. All rights reserved.