3 Answers, 1 is accepted

Hi Yves,
You can render anything on the view to a png by using native platform capture APIs; this isn't specific to Telerik controls, it can be any UI element.
You can see all the native APIs used in my example CustomXamarinDemos/src/RenderImage. While I originally wrote it for Xamarin, it's exactly the same approach for MAUI because the native APIs are 100% identical. Fortunately, in .NET MAUI it's a little easier to put all the code in one place with #ifdef, instead of partial files in each platform subfolder.
Here's an example to get you started, the highlighted part is showing you that you can pass any Microsoft.Maui.Controls.View object, it doesn't have to be the Telerik UI for MAUI chart.
Note This is not Telerik code, we do not create or maintain these APIs. If you have trouble, please reach out to the .NET MAUI developer community for further assistance. Go to https://learn.microsoft.com/en-us/answers/tags/247/dotnet-maui?wt.mc_id=WDIT-MVP-5000553 for additional help (or use the dotnet Discord)
using MauiDemo.Interfaces;
using MauiDemo.ViewModels;
using Telerik.Maui.Data;
#if ANDROID
using Android.Graphics;
#elif IOS || MACCATALYST
using Foundation;
using UIKit;
#elif WINDOWS
using Microsoft.UI.Xaml;
using Microsoft.UI.Xaml.Media.Imaging;
using System;
using System.Runtime.InteropServices.WindowsRuntime;
using Windows.Graphics.Imaging;
using Windows.Storage.Streams;
#endif
namespace MauiDemo.Views;
public partial class MainPage : ContentPage, IDataGridView
{
public MainPage(MainViewModel vm)
{
InitializeComponent();
}
private async void OnRenderPngClicked(object? sender, EventArgs e)
{
var pngBytes = await CaptureViewAsync(MyChart);
}
public async Task<byte[]> CaptureViewAsync(Microsoft.Maui.Controls.View view)
{
#if ANDROID
var nativeView = view.Handler?.PlatformView as Android.Views.View
?? throw new InvalidOperationException("View must be loaded before capture.");
var width = nativeView.Width > 0 ? nativeView.Width : (int)(view.Width * DeviceDisplay.MainDisplayInfo.Density);
var height = nativeView.Height > 0 ? nativeView.Height : (int)(view.Height * DeviceDisplay.MainDisplayInfo.Density);
nativeView.Measure(
Android.Views.View.MeasureSpec.MakeMeasureSpec(width, Android.Views.MeasureSpecMode.Exactly),
Android.Views.View.MeasureSpec.MakeMeasureSpec(height, Android.Views.MeasureSpecMode.Exactly));
nativeView.Layout(0, 0, width, height);
using var bitmap = Bitmap.CreateBitmap(width, height, Bitmap.Config.Argb8888);
using var canvas = new Canvas(bitmap);
nativeView.Draw(canvas);
using var ms = new MemoryStream();
bitmap.Compress(Bitmap.CompressFormat.Png, 100, ms);
return ms.ToArray();
#elif IOS || MACCATALYST
var nativeView = view.Handler?.PlatformView as UIView
?? throw new InvalidOperationException("View must be loaded before capture.");
nativeView.SetNeedsLayout();
nativeView.LayoutIfNeeded();
UIGraphics.BeginImageContextWithOptions(nativeView.Bounds.Size, false, UIScreen.MainScreen.Scale);
try
{
nativeView.DrawViewHierarchy(nativeView.Bounds, true);
using var image = UIGraphics.GetImageFromCurrentImageContext();
using var imageData = image?.AsPNG();
return imageData?.ToArray() ?? Array.Empty<byte>();
}
finally
{
UIGraphics.EndImageContext();
}
#elif WINDOWS
var nativeView = view.Handler?.PlatformView as FrameworkElement
?? throw new InvalidOperationException("View must be loaded before capture.");
var renderTargetBitmap = new RenderTargetBitmap();
await renderTargetBitmap.RenderAsync(nativeView);
var pixels = (await renderTargetBitmap.GetPixelsAsync()).ToArray();
using var stream = new InMemoryRandomAccessStream();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.PngEncoderId, stream);
encoder.SetPixelData(
BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Premultiplied,
(uint)renderTargetBitmap.PixelWidth,
(uint)renderTargetBitmap.PixelHeight,
96,
96,
pixels);
await encoder.FlushAsync();
stream.Seek(0);
using var reader = new DataReader(stream.GetInputStreamAt(0));
await reader.LoadAsync((uint)stream.Size);
var bytes = new byte[stream.Size];
reader.ReadBytes(bytes);
return bytes;
#else
throw new PlatformNotSupportedException();
#endif
}
}Regards,
Lance | Senior Manager Technical Support
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Edit Note: I've updated CaptureViewAsync to be an async task itself (instead of returning a task) so that you can more easily do something with the result.
For example, save it to the user's Downloads folder:
private async void OnRenderPngClicked(object? sender, EventArgs e)
{
var imageBytes = await CaptureViewAsync(EmployeesGrid);
var imagePath = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads", "MyChart.png");
await File.WriteAllBytesAsync(imagePath, imageBytes);
}
Hi Yves,
To answer the other half of your question about getting a PDF file, I need to make this a separate Answer because it is technically different than my other Answer. To accomplish this, you need to use the Telerik Document Processing Libraries, which comes included with your Maui license.
Please visit the Image object documentation to learn more: Document Processing Libraries RadPdfProcessing Model Image.
Example
First, you generate the png image as I showed you in answer 1, then you can create the PDF with it. Here is some starter code for you:
private async Task GeneratePdf(string imagePath, string pdfPath)
{
// Create a new, blank FixedDocument and add a page to it
var fixedDocument = new Telerik.Windows.Documents.Fixed.Model.RadFixedDocument();
var fixedPage = fixedDocument.Pages.AddPage();
// Create an Image object, set its source to the captured image, and add it to the page
var img = new Telerik.Windows.Documents.Fixed.Model.Objects.Image();
await using (FileStream fileStream = new FileStream(imagePath, FileMode.Open))
{
img.ImageSource = new Telerik.Windows.Documents.Fixed.Model.Resources.ImageSource(fileStream);
// Set image properties
img.AlphaConstant = 0.5;
img.Width = 200;
img.Height = 200;
// Set image location in the document
var simplePosition = new Telerik.Windows.Documents.Fixed.Model.Data.SimplePosition();
simplePosition.Translate(200, 300);
img.Position = simplePosition;
// Finally add the image to the page
fixedPage.Content.Add(img);
}
// Finally, use the PdfFormatProvider and export the FixedDocument to a PDF file
var pdfProvider = new Telerik.Windows.Documents.Fixed.FormatProviders.Pdf.PdfFormatProvider();
await using (var output = File.OpenWrite(pdfPath))
{
pdfProvider.Export(fixedDocument, output, TimeSpan.FromSeconds(10));
}
}If you want to change the size or position of the image inside the PDF, all of the properties you need are in there. Make adjustments as necessary.
Now, going back to my earlier code example's button click event handler, you can also generate the PDF file after the png is created:
private async void OnRenderPngClicked(object? sender, EventArgs e)
{
// Generate png image
var imageBytes = await CaptureViewAsync(EmployeesGrid);
// Option 1 - Save image as a png file
var downloadsFolder = System.IO.Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), "Downloads");
var imagePath = System.IO.Path.Combine(downloadsFolder, "MyChart.png");
await File.WriteAllBytesAsync(imagePath, imageBytes);
// Option 2 - Export as PDF
var pdfPath = System.IO.Path.Combine(downloadsFolder, "MyChart.pdf");
await GeneratePdf(imagePath, pdfPath);
}Note: You do not need to save the image to disk first, you can create ImageSource from multiple sources, with high degree of control over the decoding of the image properties. See Document Processing Libraries RadPdfProcessing Model ImageSource for more information
Regards,
Lance | Senior Manager Technical Support
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
Hello Yves,
Give the approaches Lance suggested.
Regarding to the png option, we have the following feature request: https://feedback.telerik.com/maui/1626858-chart-allow-easy-exporting-of-a-chart-to-a-maui-image-object Please cast your vote for the item.
Regards,
Didi
Progress Telerik
Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.
