Hello @Bharathi Selvam ,
Thank you for the detailed question and all the context you provided.
After reviewing your code and testing the sample, the issue stems from improper resource management and stream handling in the PDF conversion process.
Quickest Fix
If you want to keep most of your existing code, just add garbage collection before rendering:
private async void ConvertAndLoadImage(Stream? pdfStream)
{
if (pdfStream != null)
{
// ... your existing code stays the same ...
PdfPage page = m_document.GetPage(0);
// Add this line to clear any lingering state
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
PdfPageRenderOptions? pdfPageRenderOptions = new PdfPageRenderOptions();
// ... rest of your code unchanged
}
}
I'd recommend trying this first since it requires minimal changes. Keep in mind this is more of a workaround than a proper fix - it might resolve the character rendering issue, but some of the underlying problems could still persist.
If You Want a More Complete Fix
If the quick fix doesn't work or you want to address the root causes, I have tried to break it down:
Stream Handling Issue:
Your current approach creates multiple intermediate streams which can cause memory fragmentation:
InMemoryRandomAccessStream randomAccessStream = new InMemoryRandomAccessStream();
pdfStream.Position = 0;
MemoryStream contentStream = new MemoryStream();
pdfStream.CopyTo(contentStream);
A cleaner approach is to read directly into a byte array:
var pdfBytes = new byte[resourceStream.Length];
await resourceStream.ReadAsync(pdfBytes, 0, pdfBytes.Length);
var randomAccessStream = new InMemoryRandomAccessStream();
using (var outputStream = randomAccessStream.GetOutputStreamAt(0))
{
using (var dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(pdfBytes);
await dataWriter.StoreAsync();
await dataWriter.FlushAsync();
}
}
Async Method Pattern Issue:
The current fire-and-forget pattern can mask exceptions and make debugging harder:
private async void ConvertAndLoadImage(Stream? pdfStream) // async void is mainly for event handlers
It is better to implement proper error handling:
private async Task<bool> ConvertAndLoadImage(string resourceName, string outputName)
{
try
{
await resourceStream.ReadAsync(pdfBytes, 0, pdfBytes.Length);
return true; // lets you know if it worked
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error: {ex.Message}");
return false;
}
}
Hardcoded Dimensions Issue:
Your current approach uses some magic numbers:
pdfPageRenderOptions.DestinationWidth = 956; // where do these come from?
pdfPageRenderOptions.DestinationHeight = 1237;
Using consistent dimensions might help with the rendering inconsistency:
GC.Collect(); GC.WaitForPendingFinalizers(); GC.Collect();
var renderOptions = new PdfPageRenderOptions
{
DestinationWidth = 1200, // consistent fixed dimensions
DestinationHeight = 1600
};
Complete Revised Implementation:
If you want to implement all the improvements, this is what the full method would look like:
private async Task<bool> ConvertAndLoadImage(string resourceName, string outputName)
{
try
{
var assembly = typeof(App).GetTypeInfo().Assembly;
using var resourceStream = assembly.GetManifestResourceStream(resourceName);
if (resourceStream == null) return false;
var pdfBytes = new byte[resourceStream.Length];
await resourceStream.ReadAsync(pdfBytes, 0, pdfBytes.Length);
var randomAccessStream = new InMemoryRandomAccessStream();
using (var outputStream = randomAccessStream.GetOutputStreamAt(0))
using (var dataWriter = new DataWriter(outputStream))
{
dataWriter.WriteBytes(pdfBytes);
await dataWriter.StoreAsync();
await dataWriter.FlushAsync();
}
var pdfDocument = await PdfDocument.LoadFromStreamAsync(randomAccessStream);
var page = pdfDocument.GetPage(0);
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
var renderOptions = new PdfPageRenderOptions
{
DestinationWidth = 1200,
DestinationHeight = 1600
};
var renderStream = new InMemoryRandomAccessStream();
await page.RenderToStreamAsync(renderStream, renderOptions);
var filePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), $"{outputName}.png");
using (var fileStream = new FileStream(filePath, FileMode.Create))
{
renderStream.Seek(0);
using (var readStream = renderStream.AsStreamForRead())
{
await readStream.CopyToAsync(fileStream);
}
}
renderStream?.Dispose();
randomAccessStream?.Dispose();
return true;
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"Error: {ex.Message}");
return false;
}
}
Please test this implementation and let me know:
- If the stream sizes are now consistent across renders
- Whether the character rendering issue persists
I've tested it on my side and it seems to work properly. However, if the character clipping continues after these changes, it might indicate a deeper issue within the WinRT PDF rendering pipeline that requires further investigation.
I hope this helps resolve the issue.