我在我的Vaadin网站上有传单地图:
在此处输入图像描述
我需要将此DIV块(作为图片)导出到PDF文件(我使用iText 7https://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*
关于导出超文本标记语言到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);
}
结果,我收到了没有图形的报告
在此处输入图像描述
Vaadin中的元素API并不保存服务器端内存中的所有内容。您应该将其视为一个代理,它只是将必要的内容传达给客户端并返回。getOuterHTML返回的只是浏览器端实际内容的一小部分。您元素中的几乎所有内容都由LeafletJS呈现,因此服务器端代理对其内容一无所知。这就是为什么您正在尝试的事情永远不会以这种方式工作。
我看到你有两个选择。首先是使用执行JS获取完整的html。但是如果iText能够以有意义的方式解释Leaflet提供的相当复杂的结构,我会感到惊讶。
也许一个更好的工作解决方案是首先使用一些东西将浏览器端的当前视图渲染成图像,然后将该图像转发到iText。这个HTMLtoCANVAS可能会有所帮助(免责声明:我自己从未使用过)。
如果您需要使用传单地图,您可以使用插件传单-简单-地图-屏幕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);
}
}
以及如何使用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));
...
});
非常感谢您的HTMLtoCANVAS插件。
我还有一个问题,那就是图片保存不正确。几何形态位于地图上的另一个地方。
它是:
成为:
我找到了一个解决方案,让Leaflet使用CANVAS而不是SVG来制作形状。
renderer: L.canvas()
现在插件工作得很好。非常感谢。