-
Notifications
You must be signed in to change notification settings - Fork 80
kb(qrcode): Add KB for Barcode, QRCode and Chart export to image #2512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 1 commit
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
11599ad
docs(qrcode): Add KB for Barcode, QRCode and Chart export to image
dimodi 4740c9c
Update knowledge-base/qrcode-barcode-chart-export-to-image.md
dimodi 6b4c5eb
Update knowledge-base/qrcode-barcode-chart-export-to-image.md
dimodi c3dd9cd
Update knowledge-base/qrcode-barcode-chart-export-to-image.md
dimodi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,263 @@ | ||
| --- | ||
| 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. | ||
| type: how-to | ||
| page_title: How to Export Telerik QRCode, Barcode, or Chart to Image | ||
| slug: qrcode-barcode-chart-kb-export-to-image | ||
| tags: telerik, blazor, qrcode, barcode, chart | ||
| ticketid: 1572189, 1588186, 1667798 | ||
| res_type: kb | ||
| --- | ||
|
|
||
| ## Environment | ||
|
|
||
| <table> | ||
| <tbody> | ||
| <tr> | ||
| <td>Product</td> | ||
| <td> | ||
| QRCode for Blazor, <br /> | ||
| Barcode for Blazor, <br /> | ||
| Chart for Blazor | ||
| </td> | ||
| </tr> | ||
| </tbody> | ||
| </table> | ||
|
|
||
| ## Description | ||
|
|
||
| This KB answers the following questions: | ||
|
|
||
| * How to export a generated QRCode to a PNG or JPG image for saving on the server or download? | ||
| * 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? | ||
|
|
||
| ## Solution | ||
|
|
||
| Use `JSInterop` and JavaScript APIs to convert the Telerik component to a Base64 string and send it to the server. | ||
|
|
||
| When using the `Canvas` `RenderingMode` of the Telerik component (Barcode, Chart, QRCode), use the [`toDataURL`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) method of the `canvas` HTML element to obtain a Base64 data URI for the image. | ||
|
|
||
| When using the `SVG` rendering mode: | ||
|
|
||
| 1. Use an [`XMLSerializer`](https://developer.mozilla.org/en-US/docs/Web/API/XMLSerializer) to create an image [`Blob`](https://developer.mozilla.org/en-US/docs/Web/API/Blob). | ||
| 1. Create a `canvas` element and [get its 2D context](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/getContext). | ||
| 1. [Draw the image](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) into the `canvas` element. | ||
| 1. Use the [`toDataURL`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL) method of the `canvas` HTML element to obtain a Base64 data URI for the image. | ||
|
|
||
| > 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 | ||
|
|
||
| ````CSHTML | ||
dimodi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
dimodi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| @inject IJSRuntime js | ||
|
|
||
| <TelerikButtonGroup SelectionMode="@ButtonGroupSelectionMode.Single"> | ||
| <ButtonGroupToggleButton Selected="@(RenderingMode == RenderingMode.SVG)" | ||
| OnClick="@( () => ToggleRenderingMode(RenderingMode.SVG) )"> | ||
| Use SVG | ||
| </ButtonGroupToggleButton> | ||
| <ButtonGroupToggleButton Selected="@(RenderingMode == RenderingMode.Canvas)" | ||
| OnClick="@( () => ToggleRenderingMode(RenderingMode.Canvas) )"> | ||
| Use Canvas | ||
| </ButtonGroupToggleButton> | ||
| </TelerikButtonGroup> | ||
|
|
||
| <TelerikButton ThemeColor="@ThemeConstants.Button.ThemeColor.Success" | ||
| OnClick="@OnQrCodeExportButtonClick">Export to PNG</TelerikButton> | ||
|
|
||
| <div style="display: flex; gap: 2em;"> | ||
| <div style="flex: 1 33%;"> | ||
| <h3>@RenderingMode QR Code</h3> | ||
| <TelerikQRCode RenderAs="@RenderingMode" | ||
| Size="240px" | ||
| Value="https://docs.telerik.com/blazor-ui/introduction" | ||
| Class="exportable-qrcode"> | ||
| </TelerikQRCode> | ||
|
|
||
| @if (!string.IsNullOrEmpty(QrImageDataUrl)) | ||
| { | ||
| <h3>QR Code PNG</h3> | ||
| <img src="@QrImageDataUrl" style="width: 240px;" alt="PNG from QR Code" /> | ||
| } | ||
|
|
||
| </div> | ||
| <div style="flex: 1 66%;"> | ||
| <h3>@RenderingMode Chart</h3> | ||
| <TelerikChart RenderAs="@RenderingMode" | ||
| Height="240px" | ||
| Class="exportable-chart"> | ||
| <ChartSeriesItems> | ||
| <ChartSeries Type="ChartSeriesType.Column" | ||
| Data="@SeriesData1" | ||
| Field="@nameof(ChartModel.Revenue)" | ||
| CategoryField="@nameof(ChartModel.TimePeriod)" | ||
| Name="Product 1"> | ||
| </ChartSeries> | ||
| <ChartSeries Type="ChartSeriesType.Line" | ||
| Data="@SeriesData2" | ||
| Field="@nameof(ChartModel.Revenue)" | ||
| CategoryField="@nameof(ChartModel.TimePeriod)" | ||
| Name="Product 2"> | ||
| </ChartSeries> | ||
| </ChartSeriesItems> | ||
|
|
||
| <ChartCategoryAxes> | ||
| <ChartCategoryAxis Type="@ChartCategoryAxisType.Date"></ChartCategoryAxis> | ||
| </ChartCategoryAxes> | ||
|
|
||
| <ChartValueAxes> | ||
| <ChartValueAxis Max="1000" /> | ||
| </ChartValueAxes> | ||
|
|
||
| <ChartTitle Text="Chart"></ChartTitle> | ||
|
|
||
| <ChartLegend Position="ChartLegendPosition.Bottom"> | ||
| </ChartLegend> | ||
| </TelerikChart> | ||
| @if (!string.IsNullOrEmpty(ChartImageDataUrl)) | ||
| { | ||
| <h3>Chart PNG</h3> | ||
| <img src="@ChartImageDataUrl" style="width: 100%;" alt="PNG from Chart" /> | ||
| } | ||
| </div> | ||
| </div> | ||
|
|
||
| @* Move JavaScript code to a separate JS file *@ | ||
| <script suppress-error="BL9992"> | ||
| function getImageFromCanvas(selector) { | ||
| const canvas = document.querySelector(`${selector} canvas`); | ||
| if (canvas) { | ||
| return canvas.toDataURL("image/png"); | ||
| } | ||
| } | ||
|
|
||
| function getImageFromSvg(selector) { | ||
| const dpr = window.devicePixelRatio; | ||
|
|
||
| const svg = document.querySelector(`${selector} svg`); | ||
| if (!svg) { | ||
| return; | ||
| } | ||
|
|
||
| const svgBox = svg.getBBox(); | ||
| const svgW = svgBox.width; | ||
| const svgH = svgBox.height; | ||
|
|
||
| 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 { | ||
| #nullable enable | ||
|
|
||
| private RenderingMode RenderingMode { get; set; } = RenderingMode.SVG; | ||
|
|
||
| private string QrImageDataUrl { get; set; } = string.Empty; | ||
| private string ChartImageDataUrl { get; set; } = string.Empty; | ||
|
|
||
| private List<ChartModel> SeriesData1 { get; set; } = new(); | ||
| private List<ChartModel> SeriesData2 { get; set; } = new(); | ||
|
|
||
| private async Task OnQrCodeExportButtonClick() | ||
| { | ||
| string jsFunctionName = RenderingMode == RenderingMode.SVG ? "getImageFromSvg" : "getImageFromCanvas"; | ||
|
|
||
| QrImageDataUrl = await js.InvokeAsync<string>(jsFunctionName, ".exportable-qrcode"); | ||
| ChartImageDataUrl = await js.InvokeAsync<string>(jsFunctionName, ".exportable-chart"); | ||
| } | ||
|
|
||
| private void ToggleRenderingMode(RenderingMode newMode) | ||
| { | ||
| RenderingMode = newMode; | ||
|
|
||
| QrImageDataUrl = ChartImageDataUrl = string.Empty; | ||
| } | ||
|
|
||
| #region Data Generation | ||
|
|
||
| protected override async Task OnInitializedAsync() | ||
| { | ||
| var now = DateTime.Today; | ||
| var monthsBack = 6; | ||
|
|
||
| for (int i = 1; i <= monthsBack; i++) | ||
| { | ||
| var dateTimeValue = now.AddMonths(-monthsBack + i); | ||
|
|
||
| SeriesData1.Add(new ChartModel() | ||
| { | ||
| Id = i, | ||
| Product = "Product 1", | ||
| Revenue = Random.Shared.Next(1, 900), | ||
| TimePeriod = dateTimeValue | ||
| }); | ||
|
|
||
| SeriesData2.Add(new ChartModel() | ||
| { | ||
| Id = i, | ||
| Product = "Product 2", | ||
| Revenue = Random.Shared.Next(1, 900), | ||
| TimePeriod = dateTimeValue | ||
| }); | ||
| } | ||
|
|
||
| await base.OnInitializedAsync(); | ||
| } | ||
|
|
||
| public class ChartModel | ||
| { | ||
| public int Id { get; set; } | ||
| public string Product { get; set; } = string.Empty; | ||
| public DateTime TimePeriod { get; set; } | ||
| public decimal Revenue { get; set; } | ||
| } | ||
|
|
||
| #endregion Data Generation | ||
| } | ||
| ```` | ||
|
|
||
| > The example in this KB article demonstrates non-Telerik JavaScript APIs, which are not subject to Telerik technical support. | ||
dimodi marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
|
|
||
| ## See Also | ||
|
|
||
| * [Barcode Overview]({%slug barcode-overview%}) | ||
| * [Chart Overview]({%slug components/chart/overview%}) | ||
| * [QRCore Overview]({%slug qrcode-overview%}) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.