Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
148 changes: 137 additions & 11 deletions knowledge-base/qrcode-barcode-chart-export-to-image.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
title: Export QRCode, Barcode, or Chart to Image
description: Learn how to convert and export a Telerik Blazor QRCode, Barcode, or Chart to an image and send it to the .NET runtime.
title: Export QRCode, Barcode, Chart or Diagram to Image
description: Learn how to convert and export a Telerik Blazor QRCode, Barcode, Chart, or Diagram to an image and send it to the .NET runtime.
type: how-to
page_title: How to Export Telerik QRCode, Barcode, or Chart to Image
page_title: How to Export Telerik QRCode, Barcode, Chart, or Diagram to Image
slug: qrcode-barcode-chart-kb-export-to-image
tags: telerik, blazor, qrcode, barcode, chart
ticketid: 1572189, 1588186, 1667798
tags: telerik, blazor, qrcode, barcode, chart, diagram
ticketid: 1572189, 1588186, 1667798, 1697494, 1697884
res_type: kb
---

Expand All @@ -32,6 +32,7 @@ This KB answers the following questions:
* How to create an image from the Telerik QRCode for Blazor?
* How to convert a Barcode, Chart, or QRCode from SVG to an image?
* How to save a Barcode or QRCode as an image?
* How to export a Diagram to a PNG file?

## Solution

Expand All @@ -48,7 +49,11 @@ When using the `SVG` rendering mode:

> When using a Blazor app with **Server** render mode, make sure to [increase the SignalR max message size](slug:common-kb-increase-signalr-max-message-size), otherwise the Base64 data URI may not reach the .NET runtime.

>caption Export QRCode, BarCode, or Chart to Image
> The following examples demonstrates JavaScript APIs, which are not subject to Telerik technical support.

### Export BarCode, Chart and QRCode

>caption Export QRCode, BarCode, or Chart to PNG Image

````RAZOR
@inject IJSRuntime js
Expand All @@ -65,7 +70,7 @@ When using the `SVG` rendering mode:
</TelerikButtonGroup>

<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Success"
OnClick="@OnQrCodeExportButtonClick">Export to PNG</TelerikButton>
OnClick="@OnExportButtonClick">Export to PNG</TelerikButton>

<div style="display: flex; gap: 2em;">
<div style="flex: 1 33%;">
Expand Down Expand Up @@ -186,8 +191,6 @@ When using the `SVG` rendering mode:
</script>

@code {
#nullable enable

private RenderingMode RenderingMode { get; set; } = RenderingMode.SVG;

private string QrImageDataUrl { get; set; } = string.Empty;
Expand All @@ -196,7 +199,7 @@ When using the `SVG` rendering mode:
private List<ChartModel> SeriesData1 { get; set; } = new();
private List<ChartModel> SeriesData2 { get; set; } = new();

private async Task OnQrCodeExportButtonClick()
private async Task OnExportButtonClick()
{
string jsFunctionName = RenderingMode == RenderingMode.SVG ? "getImageFromSvg" : "getImageFromCanvas";

Expand Down Expand Up @@ -254,10 +257,133 @@ When using the `SVG` rendering mode:
}
````

> The example in this KB article demonstrates JavaScript APIs, which are not subject to Telerik technical support.
### Export Diagram

The required approach with a Telerik Blazor Diagram is the same as described above, with one exception. The `getBlobImage` JavaScript function must receive the exact Diagram width and height, instead of `svgBox.width` and `svgBox.height`. This is because the Diagram supports panning and the `svgBox` is larger than the visible component dimensions. Using `svgBox.width` and `svgBox.height` may result in a clipped PNG image.

>caption Export Diagram to PNG Image

````RAZOR
@inject IJSRuntime js

<TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Success"
OnClick="@OnDiagramExportButtonClick">Export Diagram to PNG</TelerikButton>

<TelerikDiagram Width="@( $"{DiagramWidth}px" )" Height="@( $"{DiagramHeight}px" )" Zoom="0.8" Class="exportable-diagram">
<DiagramConnectionDefaults Type="@DiagramConnectionType.Cascading" />
<DiagramLayout Type="@DiagramLayoutType.Tree" />
<DiagramShapeDefaults Type="@DiagramShapeType.Rectangle" />

<DiagramShapes>
<DiagramShape Id="shape1">
<DiagramShapeContent Text="Shape 1" />
</DiagramShape>
<DiagramShape Id="shape2">
<DiagramShapeContent Text="Shape 2" />
</DiagramShape>
<DiagramShape Id="shape3">
<DiagramShapeContent Text="Shape 3" />
</DiagramShape>
<DiagramShape Id="shape4">
<DiagramShapeContent Text="Shape 4" />
</DiagramShape>
<DiagramShape Id="shape5">
<DiagramShapeContent Text="Shape 5" />
</DiagramShape>
<DiagramShape Id="shape6">
<DiagramShapeContent Text="Shape 6" />
</DiagramShape>
</DiagramShapes>

<DiagramConnections>
<DiagramConnection FromId="shape1" ToId="shape2" />
<DiagramConnection FromId="shape1" ToId="shape3" />
<DiagramConnection FromId="shape2" ToId="shape4" />
<DiagramConnection FromId="shape2" ToId="shape5" />
<DiagramConnection FromId="shape3" ToId="shape6" />
</DiagramConnections>
</TelerikDiagram>

@if (!string.IsNullOrEmpty(DiagramImageDataUrl))
{
<h3>Diagram PNG</h3>
<img src="@DiagramImageDataUrl" style="width: @(DiagramWidth)px; height: @(DiagramHeight)px;" alt="PNG from Diagram" />
}

@* Move JavaScript code to a separate JS file *@
<script suppress-error="BL9992">
function getDiagramFromSvg(selector, diagramWidth, diagramHeight) {
const dpr = window.devicePixelRatio;

const svg = document.querySelector(`${selector} svg`);
if (!svg) {
return;
}

const svgBox = svg.getBBox();
const svgW = diagramWidth; // svgBox.width
const svgH = diagramHeight; // svgBox.height
// Using svgBox.width and svgBox.height may result in a clipped image,
// because the Diagram shapes can overflow their container.

const svgData = (new XMLSerializer()).serializeToString(svg);
const svgBlob = new Blob([svgData], {
type: "image/svg+xml;charset=utf-8"
});
const blobUrl = URL.createObjectURL(svgBlob);

return getBlobImage(blobUrl, svgW, svgH).then((img) => {
const canvas = document.createElement("canvas");
canvas.width = svgW * dpr;
canvas.height = svgH * dpr;

const context = canvas.getContext("2d");
context.imageSmoothingEnabled = false;
context.drawImage(img, 0, 0, svgW * dpr, svgH * dpr);

URL.revokeObjectURL(blobUrl);
img.parentElement.removeChild(img);

return canvas.toDataURL("image/png");
});
}

function getBlobImage(blobUrl, imageWidth, imageHeight) {
return new Promise(function(resolve) {
const img = new Image();

img.addEventListener("load", () => {
setTimeout( () => resolve(img) );
});

img.style.cssText = "visibility:hidden;position:absolute;top:0;left:0;";
img.width = imageWidth;
img.height = imageHeight;
document.body.appendChild(img);

img.src = blobUrl;
});
}
</script>

@code {
private string DiagramImageDataUrl { get; set; } = string.Empty;

private const int DiagramWidth = 480;
private const int DiagramHeight = 400;

private async Task OnDiagramExportButtonClick()
{
string jsFunctionName = "getDiagramFromSvg";

DiagramImageDataUrl = await js.InvokeAsync<string>(jsFunctionName, ".exportable-diagram", DiagramWidth, DiagramHeight);
}
}
````

## See Also

* [Barcode Overview](slug:barcode-overview)
* [Chart Overview](slug:components/chart/overview)
* [Diagram Overview](slug:diagram-overview)
* [QRCore Overview](slug:qrcode-overview)
Loading