如何将Vaadin 23元素转换为iText 7元素?

huangapple go评论62阅读模式
英文:

How convert vaadin 23 element to itext 7 element?

问题

I have leaflet map in my Vaadin site:

enter image description here

I need export this DIV block (as a picture) into PDF file (i use iText 7 https://kb.itextpdf.com/home):

Here I found the information
*
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml/chapter-1-hello-html-to-pdf*

about export HTML to PDF file.

I have problem:

iText 7 need IElement, but I have only vaadin element.

Please tell me how to convert vaadin element to iText element?

I try get OuterHTML from vaadin element:

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

As a result, I received report without graphics

enter image description here

英文:

I have leaflet map in my Vaadin site:

enter image description here

I need export this DIV block (as a picture) into PDF file (i use iText 7 https://kb.itextpdf.com/home):

Here I found the information
*
https://kb.itextpdf.com/home/it7kb/ebooks/itext-7-converting-html-to-pdf-with-pdfhtml/chapter-1-hello-html-to-pdf*

about export HTML to PDF file.

I have problem:

iText 7 need IElement, but I have only vaadin element.

Please tell me how to convert vaadin element to iText element?

I try get OuterHTML from vaadin element:

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

As a result , I received report without graphics

enter image description here

答案1

得分: 1

Vaadin中的Element API不会将所有内容保存在服务器端内存中。您应该将其视为一种代理,只传递对客户端和返回客户端所需的内容。getOuterHTML返回的只是浏览器端实际内容的一部分。几乎您元素内的所有内容都是由LeafletJS渲染的,因此服务器端代理对其内容一无所知。这就是为什么您尝试的方法永远不会起作用的原因。

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

可能更好的解决方案是首先使用某种方式在浏览器端将当前视图渲染为图像,然后将该图像转发给iText。这个HTMLtoCANVAS可能会有所帮助(免责声明:我自己从未使用过)。

英文:

The Element API in Vaadin does not hold everything on the server-side memory. You should think of it more as a proxy that just communicates what is necessary to the client side and back. What the getOuterHTML returns is just a fraction of the actual content on the browser side. Pretty much everything inside your element is rendered by LeafletJS, so the server side proxy knows nothing about its contents. That's why the thing you are trying will never work that way.

I see you have two options. First would be to fetch the full html with executeJS instead. But I would be surprised if iText can interpret the rather complex structure provided by Leaflet in a meaningful way.

Probably a better working solution would be to use something to render the current view on the browser side into an image first and then forward that image to iText. This HTMLtoCANVAS might be helpful (disclaimer: I have never used it myself).

答案2

得分: 0

非常感谢HTMLtoCANVAS插件。

我也遇到了一个问题,图片保存时出现错误。几何形状在地图上的位置不正确。

原来是:

如何将Vaadin 23元素转换为iText 7元素?

现在是:

如何将Vaadin 23元素转换为iText 7元素?

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

renderer: L.canvas()

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

英文:

Thank you very much for the HTMLtoCANVAS plugin.

I also had a problem that the picture was incorrect saved.The geometric shapes were located in another place on the map.

It was:

如何将Vaadin 23元素转换为iText 7元素?

Become:

如何将Vaadin 23元素转换为iText 7元素?

I found a solution to let Leaflet use CANVAS instead of SVG for shapes.

renderer: L.canvas()

如何将Vaadin 23元素转换为iText 7元素?

Now the plugin works great. Many thanks.

答案3

得分: 0

如果您需要使用Leaflet地图,可以使用Leaflet-Simple-Map-Screenshoter插件 https://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);
    }

}

如何使用takeScreenShot()与Vaadin

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));
    // ...
});
英文:

If you need to use a leaflet map, you can use the plugin leaflet-simple-map-screenshoter https://github.com/grinat/leaflet-simple-map-screenshoter

I created the following class for it

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&lt;String&gt; takeScreenShot(Element e){
CompletableFuture&lt;String&gt; future = new CompletableFuture&lt;&gt;();
String id = e.getAttribute(&quot;id&quot;);
if (StringUtils.isEmpty(id)) {
e.setAttribute(&quot;id&quot;, &quot;elementForScreenShot&quot;);
id = e.getAttribute(&quot;id&quot;);
}
StateNode node = e.getNode();
getJavaScriptInvoke(node, &quot;let element = document.querySelector(&#39;#&quot; + id +  &quot;&#39;);\n&quot; +
&quot;this.simpleMapScreenshoter = L.simpleMapScreenshoter().addTo(&quot; + mapView.getMap().getId() + &quot;)\n&quot; +
&quot;let format = &#39;canvas&#39; \n&quot; +
&quot;let overridedPluginOptions = {\n&quot; +
&quot;  mimeType: &#39;image/png&#39;\n&quot; +
&quot;}\n&quot; +
&quot;function send(canvas) {\n&quot; +
&quot;canvasValue = canvas.toDataURL()\n&quot; +
&quot;element.dispatchEvent(new Event(&#39;canvasReady&#39;));\n&quot; +
&quot;}\n&quot; +
&quot;this.simpleMapScreenshoter.takeScreen(format, overridedPluginOptions).then(canvas =&gt; {\n&quot; +
&quot;console.info(canvas)\n&quot; +
&quot;send(canvas);\n&quot; +
&quot;}).catch(e =&gt; {\n&quot; +
&quot;   console.error(e)\n&quot; +
&quot;})&quot;
);
e.addEventListener(&quot;canvasReady&quot;, l -&gt; getJavaScriptReturn(node, &quot;canvasValue.valueOf()&quot;).then(jsonValue -&gt; 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) -&gt; ui.getInternals().getStateTree().beforeClientResponse(node, (context) -&gt; {
if (!pending.isCanceled()) {
context.getUI().getInternals().addJavaScriptInvocation(pending);
}
}));
return pending;
}
public PendingJavaScriptInvocation getJavaScriptReturn(StateNode node, String expression) {
return getJavaScriptInvoke(node, &quot;return &quot; + expression);
}
}

And how to use takeScreenShot() with Vaadin

  HtmlToCanvas htmlToCanvas = new HtmlToCanvas(mapView);
CompletableFuture&lt;String&gt; completableFuture = htmlToCanvas.takeScreenShot(mapView.getElement());
completableFuture.thenRun(() -&gt; {
...
Image image = new Image(completableFuture.get(), &quot;screenshot&quot;);
String immagineBase64 = vaadinImage.getSrc().substring(22);
byte[] imageBytes = Base64.getDecoder().decode(immagineBase64.getBytes(StandardCharsets.UTF_8));
...
});

huangapple
  • 本文由 发表于 2023年3月3日 18:14:18
  • 转载请务必保留本文链接:https://go.coder-hub.com/75625748.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定