这里使用 MemoryStream 两次的替代方案是什么?

问题描述 投票:0回答:1

我正在尝试编写代码,在护照上盖上系统用户姓名、日期和签名图像(我将其作为 varbinary 存储在 sql 数据库中,并在模型中存储为 byte)。

这是我的代码:

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;
}

我收到的错误是“处理护照 PDF 时发生错误:无法访问 MemoryStream 的内部缓冲区”。所以我认为你不能同时使用两个 MemoryStream。为了实现这一目标,我有哪些替代方案?

我所尝试的只是通过 MemorySteam 来实现。

编辑:根据一些评论,我尝试了一些东西。错误就在这里:

                    XImage image = XImage.FromStream(signatureImage);

所以我尝试不显式处理内存流

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
}

但我似乎仍然遇到同样的错误。

c# winforms pdf memorystream pdfsharp
1个回答
0
投票

好的,谢谢您的所有评论,我已经解决了。

错误 System.UnauthorizedAccessException:“无法访问 MemoryStream 的内部缓冲区。”发生的原因是 PdfSharp 中的 XImage.FromStream() 尝试访问 MemoryStream 的内部缓冲区,默认情况下该缓冲区不是公共的。 为了解决这个问题,我创建了一个带有可写缓冲区的新 MemoryStream 并将字节数组复制到其中。这允许 XImage.FromStream() 毫无问题地访问流。解决办法如下:

if (user.Signature != null && user.Signature.Length > 0)
{
    // Create a writable MemoryStream with a public buffer
    MemoryStream signatureImage = new MemoryStream(user.Signature.Length);
    signatureImage.Write(user.Signature, 0, user.Signature.Length);
    signatureImage.Position = 0;  // Reset position to the beginning

    // Load the signature image from the writable MemoryStream
    XImage image = XImage.FromStream(signatureImage);
    gfx.DrawImage(image, 50, 150, 150, 50); // Position and size of the signature
}

这确保 PdfSharp 可以访问内存流的内部缓冲区。

非常感谢所有贡献者!

© www.soinside.com 2019 - 2024. All rights reserved.