I’m trying to write code that stamps a passport with the system users name, date and an image of their signature (which I store as a varbinary in the sql database and byte in the model).
Here is my code:
private async void button_ApprovePassport_Click(object sender, EventArgs e)
{
await ProcessPassportPdfAsync();
}
private async Task ProcessPassportPdfAsync()
{
try
{
// Check if a document is selected
if (gridView_PortalDocs.IsSelected())
{
var PortalDoc = gridView_PortalDocs.GetSelectedDataRow<PortalDocumentInfoModel>();
if (PortalDoc != null)
{
EmployeePortalService EPS = new EmployeePortalService();
if (PortalDoc.PortalFileID == null)
{
cGlobal.ShowErrorMessage("PortalFileID is null. Cannot retrieve document.");
return;
}
var Data = await EPS.GetDocument(PortalDoc.PortalFileID);
if (Data != null && !string.IsNullOrEmpty(Data.FileData))
{
// Convert base64 string to byte array
byte[] fileBytes = Convert.FromBase64String(Data.FileData);
// Create a memory stream from the byte array
using (MemoryStream inputStream = new MemoryStream(fileBytes))
{
// Process the PDF (stamp it)
using (MemoryStream processedStream = StampPdf(inputStream))
{
// Save the processed PDF to a temporary file
string tempFilePath = Path.Combine(Path.GetTempPath(), $"StampedPassport_{Guid.NewGuid()}.pdf");
File.WriteAllBytes(tempFilePath, processedStream.ToArray());
// Open the PDF with the default viewer
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo(tempFilePath) { UseShellExecute = true });
// Convert the processed stream back to a base64 string
string processedBase64 = Convert.ToBase64String(processedStream.ToArray());
// Using the API for the document reupload here
// Update the PortalFiles table here
MessageBox.Show("Passport PDF processed and approved successfully.", "Success", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
}
}
else
{
cGlobal.ShowErrorMessage("The document data could not be retrieved from the server or is empty.");
}
}
else
{
cGlobal.ShowErrorMessage("The selected document information is invalid.");
}
}
else
{
cGlobal.ShowInfoMessage("Please select a document to process.");
}
}
catch (Exception ex)
{
cGlobal.ShowErrorMessage($"An error occurred while processing the passport PDF: {ex.Message}");
}
}
private MemoryStream StampPdf(MemoryStream inputStream)
{
// Get the user's signature and first name from the controller
// Use Stefi's for testing then switch to cGlobal.SystemUserID
var SystemUserSignature = Controller.GetSystemUserSignature(345);
// Check if the signature was retrieved successfully
if (SystemUserSignature == null || SystemUserSignature.Count == 0)
{
throw new Exception("User signature not found. Please add one in Access Control.");
}
// Retrieve the first user's details (assuming there's at least one entry)
var user = SystemUserSignature[0];
// Ensure we're using UTF-8 encoding (important for PdfSharp)
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
// Load the existing document
PdfDocument document = PdfReader.Open(inputStream, PdfDocumentOpenMode.Modify);
// Get the first page (you might want to stamp all pages)
PdfPage page = document.Pages[0];
// Create graphics object for drawing
XGraphics gfx = XGraphics.FromPdfPage(page);
// Create fonts using system fonts
XFont font = new XFont("Arial", 12);
XFont largeFont = new XFont("Arial", 24);
// Create a semi-transparent brush for the background of the stamp
XColor stampColor = XColor.FromArgb(128, 255, 0, 0); // Semi-transparent red
XBrush stampBrush = new XSolidBrush(stampColor);
// Draw a rectangle for the stamp background
gfx.DrawRectangle(stampBrush, 50, 50, 250, 100);
// Add text for the stamp
gfx.DrawString("APPROVED", largeFont, XBrushes.White, new XRect(50, 50, 250, 50), XStringFormats.Center);
// Add approval details
gfx.DrawString($"By: {user.Forename}", font, XBrushes.White, new XRect(60, 100, 230, 25), XStringFormats.TopLeft);
gfx.DrawString($"Date: {DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")}", font, XBrushes.White, new XRect(60, 125, 230, 25), XStringFormats.TopLeft);
// If the signature is available, draw it on the PDF
if (user.Signature != null && user.Signature.Length > 0)
{
// Load the signature image from the byte array
using (var signatureImage = new MemoryStream(user.Signature))
{
XImage image = XImage.FromStream(signatureImage);
gfx.DrawImage(image, 50, 150, 150, 50); // Position and size of the signature
}
}
// Save the document to a new MemoryStream
MemoryStream outputStream = new MemoryStream();
document.Save(outputStream, false);
outputStream.Position = 0; // Reset stream position to the beginning
return outputStream;
}
The error I’m getting is "An error occurred while processing the passport PDF: MemoryStream’s internal buffer cannot be accessed". So I don’t think you can use two MemoryStream’s at once. What are my alternatives for achieving this?
All I’ve tried is doing it via MemorySteam really.
Edit: Following some of the comments I’ve tried something. The error is coming here:
XImage image = XImage.FromStream(signatureImage);
So I tried not disposing the memory stream explicitly
if (user.Signature != null && user.Signature.Length > 0)
{
var signatureImage = new MemoryStream(user.Signature);
XImage image = XImage.FromStream(signatureImage);
gfx.DrawImage(image, 50, 150, 150, 50); // Position and size of the signature
}
I still seem to get the same error though.
You need to sign in to view this answers