0

I'm currently working on a project using C# and have been implementing PDF file creation with iText. Everything works well under normal circumstances, but I've run into a peculiar issue I can't seem to resolve.

When I start my program after booting up Windows and run the code that generates a PDF, it creates a PDF file with zero bytes - essentially an empty file. However, when I close the program and run it again, the PDF file is created without any issues.

I've tried a variety of methods to troubleshoot this problem but haven't found a solution yet. Has anyone experienced a similar issue or does anyone know what might be causing this? Any help on this matter would be greatly appreciated.

Here's a snippet of my code for reference:

string strPDFFileFullName = "D:\\PDF\\Test.pdf";

iText.Kernel.Pdf.PdfDocument pdfDocument;
Document document;

PdfWriter writer = null;
FileStream fs = null;

string mutexName = "MyMutex";
bool createdNew;

using (var mutex = new Mutex(true, mutexName, out createdNew))
{
   if (createdNew)
   {
       try
       {
           fs = new FileStream(strPDFFileFullName, FileMode.Create);
           writer = new PdfWriter(fs);
           pdfDocument = new iText.Kernel.Pdf.PdfDocument(writer);
           document = new Document(pdfDocument);
       }
       catch (Exception ex)
       {
           writeLog(ex.ToString());
           return;
       }

       document.SetLeftMargin(fDocuMargin);
       document.SetRightMargin(fDocuMargin);
       document.SetTopMargin(fDocuMargin);
       document.SetBottomMargin(fDocuMargin);

       MemoryStream ms = new MemoryStream();
       byte[] bytes;

       INV_TestReport.Properties.Resources.Logo.Save(ms,
             System.Drawing.Imaging.ImageFormat.Bmp);
       bytes = ms.ToArray();

       iText.IO.Image.ImageData imData = iText.IO.Image.ImageDataFactory.Create(bytes);
       iText.Layout.Element.Image im = new iText.Layout.Element.Image(imData);

       float newWidth = 140;
       float newHeight = im.GetImageHeight() * (newWidth / im.GetImageWidth());
       im.SetWidth(newWidth).SetHeight(newHeight);

       im.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.RIGHT);
       document.Add(im);

       Table table = new Table(new float[] { 5, 2, 7, 7, 12 })
            .SetWidth(UnitValue.CreatePercentValue(100))
            .SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER)
            .UseAllAvailableWidth();

       Cell cell = new Cell(1, 5)
            .Add(new Paragraph("TEST REPORT")
            .SetFont(koreanFont).SetBold()
            .SetFontSize(30))
            .SetTextAlignment(TextAlignment.CENTER)
            .SetVerticalAlignment(VerticalAlignment.MIDDLE);
       table.AddCell(cell);

       document.Add(table);

       try
       {
            document.Close();
       }
       catch (Exception ex)
       {
            writeLog(ex.ToString());
            return;
       }
       finally
       {
            document.Flush();
            pdfDocument.Close();
            writer.Close();
            //fs.Flush();
       }
   }
}

I'm particularly interested in any possible reasons why this could be happening only on the first run, and how I might go about fixing it.

Thank you in advance for your help!

Ashuro
  • 9
  • 2
  • It seems that the mutex part of the code is from https://stackoverflow.com/a/52070502/10024425. – Tu deschizi eu inchid Jun 02 '23 at 04:10
  • Maybe an AntiVirus app (or similar) running on the PC could be interfering with the file writing ? (e.g. holding a lock). I've also seen problems when Bitlocker was enabled on a PC, where first time after boot, I would have to restart SqlServer (otherwise it couldn't load the database files properly) - maybe there was some hardware/configuration issue with that PC. Do you see anything in the logs (from your writeLog calls) ? You could try writing to a MemoryStream instread of FileStream, and save the resulting bytes to a file in one go at the end ? – Moe Sisko Jun 02 '23 at 06:57
  • Also - can the problem be reproduced on another PC ? – Moe Sisko Jun 02 '23 at 07:03
  • @MoeSisko, Thank you for your advice. I will check the antivirus program currently running on my system, and also verify if the same issue occurs on different PC environments. – Ashuro Jun 03 '23 at 08:49

1 Answers1

0

In the code in the OP, there are some objects that haven't been properly disposed. The following seems to work:

Pre-requisites

  • Download/install NuGet package: iText7 (version: 7.2.5)

Create a class (name: HelperiText7.cs)

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Diagnostics;
using iText.IO.Image;
using iText.Kernel.Pdf;
using iText.Layout;
using iText.Layout.Element;
using System.IO;
using System.Drawing;
using iText.Layout.Properties;

namespace PdfiTextMutex
{
    public class HelperiText7
    {
        //add 'Local\' for compatibility with TerminalServices
        //see https://learn.microsoft.com/en-us/dotnet/api/system.threading.mutex?view=net-7.0
        private static string _mutexName = System.IO.Path.Combine("Local",System.IO.Path.GetFileNameWithoutExtension(System.Reflection.Assembly.GetExecutingAssembly().Location));
        private static bool _createdNew = false;

        public static void CreatePdf(string filename, float margin = 0.5f)
        {
            using (var mutex = new Mutex(true, _mutexName, out _createdNew))
            {
                if (!_createdNew)
                {
                    throw new Exception("Error: CreatePdf is already executing. Please try again later.");
                }

                Debug.WriteLine($"_mutexName: '{_mutexName}'");

                //for testing, pause
                System.Threading.Thread.Sleep(10000);

                //create new instance
                using (PdfWriter writer = new PdfWriter(filename))
                {
                    //create new PDF document
                    PdfDocument pdfDoc = new PdfDocument(writer);

                    //create reference
                    PdfDocumentInfo pdfDocInfo = pdfDoc.GetDocumentInfo();

                    DateTime creationDateTime = PdfDate.Decode(pdfDocInfo.GetMoreInfo("CreationDate"));
                    Debug.WriteLine($"creationDateTime: {creationDateTime.ToString()}");

                    //create new instance
                    //Document doc = new Document(pdfDoc, new iText.Kernel.Geom.PageSize(iText.Kernel.Geom.PageSize.A4.GetWidth(), iText.Kernel.Geom.PageSize.A4.GetHeight()));
                    Document doc = new Document(pdfDoc);

                    //set margins
                    doc.SetLeftMargin(margin);
                    doc.SetRightMargin(margin);
                    doc.SetTopMargin(margin);
                    doc.SetBottomMargin(margin);

                    //get image
                    byte[] imageBytes = GetResourceImage("logo");

                    //add image to PDF
                    ImageData imData = iText.IO.Image.ImageDataFactory.Create(imageBytes);
                    iText.Layout.Element.Image im = new iText.Layout.Element.Image(imData);

                    float newWidth = 140;
                    float newHeight = im.GetImageHeight() * (newWidth / im.GetImageWidth());
                    im.SetWidth(newWidth).SetHeight(newHeight);

                    im.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.RIGHT);

                    doc.Add(im);

                    Table table = new Table(new float[] { 5, 2, 7, 7, 12 })
                         .SetWidth(UnitValue.CreatePercentValue(100))
                         .SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER)
                         .UseAllAvailableWidth();

                    /*
                    Cell cell = new Cell(1, 5)
                         .Add(new Paragraph("TEST REPORT")
                         .SetFont(kor).SetBold()
                         .SetFontSize(30))
                         .SetTextAlignment(TextAlignment.CENTER)
                         .SetVerticalAlignment(VerticalAlignment.MIDDLE);
                    */

                    Cell cell = new Cell(1, 5)
                         .Add(new Paragraph($"TEST REPORT - {DateTime.Now.ToString("HH:mm:ss.fff")}")
                         .SetFontSize(30))
                         .SetTextAlignment(TextAlignment.CENTER)
                         .SetVerticalAlignment(VerticalAlignment.MIDDLE);

                    //add Cell
                    table.AddCell(cell);

                    //add Table
                    doc.Add(table);

                    //close
                    doc.Close();
                    pdfDoc.Close();
                }
            }
        }

        public static void CreatePdf2(string filename, float margin = 0.5f)
        {
            using (var mutex = new Mutex(true, _mutexName, out _createdNew)) 
            {
                if (!_createdNew)
                {
                    throw new Exception("Error: CreatePdf is already executing. Please try again later.");
                }
                    
                Debug.WriteLine($"_mutexName: '{_mutexName}'");

                if (mutex.WaitOne())
                {
                    //for testing, pause
                    System.Threading.Thread.Sleep(10000);

                    //create new instance
                    using (PdfWriter writer = new PdfWriter(filename))
                    {
                        //create new PDF document
                        PdfDocument pdfDoc = new PdfDocument(writer);

                        //create reference
                        PdfDocumentInfo pdfDocInfo = pdfDoc.GetDocumentInfo();

                        DateTime creationDateTime = PdfDate.Decode(pdfDocInfo.GetMoreInfo("CreationDate"));
                        Debug.WriteLine($"creationDateTime: {creationDateTime.ToString()}");

                        //create new instance
                        //Document doc = new Document(pdfDoc, new iText.Kernel.Geom.PageSize(iText.Kernel.Geom.PageSize.A4.GetWidth(), iText.Kernel.Geom.PageSize.A4.GetHeight()));
                        Document doc = new Document(pdfDoc);

                        //set margins
                        doc.SetLeftMargin(margin);
                        doc.SetRightMargin(margin);
                        doc.SetTopMargin(margin);
                        doc.SetBottomMargin(margin);

                        //get image
                        byte[] imageBytes = GetResourceImage("logo");

                        //add image to PDF
                        ImageData imData = iText.IO.Image.ImageDataFactory.Create(imageBytes);
                        iText.Layout.Element.Image im = new iText.Layout.Element.Image(imData);

                        float newWidth = 140;
                        float newHeight = im.GetImageHeight() * (newWidth / im.GetImageWidth());
                        im.SetWidth(newWidth).SetHeight(newHeight);

                        im.SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.RIGHT);
                        
                        doc.Add(im);

                        Table table = new Table(new float[] { 5, 2, 7, 7, 12 })
                             .SetWidth(UnitValue.CreatePercentValue(100))
                             .SetHorizontalAlignment(iText.Layout.Properties.HorizontalAlignment.CENTER)
                             .UseAllAvailableWidth();

                        /*
                        Cell cell = new Cell(1, 5)
                             .Add(new Paragraph("TEST REPORT")
                             .SetFont(kor).SetBold()
                             .SetFontSize(30))
                             .SetTextAlignment(TextAlignment.CENTER)
                             .SetVerticalAlignment(VerticalAlignment.MIDDLE);
                        */

                        Cell cell = new Cell(1, 5)
                             .Add(new Paragraph($"TEST REPORT - {DateTime.Now.ToString("HH:mm:ss.fff")}")
                             .SetFontSize(30))
                             .SetTextAlignment(TextAlignment.CENTER)
                             .SetVerticalAlignment(VerticalAlignment.MIDDLE);

                        //add Cell
                        table.AddCell(cell);

                        //add Table
                        doc.Add(table);

                        //close
                        doc.Close();
                        pdfDoc.Close();
                    }

                    //release mutex
                    mutex.ReleaseMutex();
                }
            }
        }

        

        public static async Task CreatePdfAsync(string filename, float margin = 0.5f)
        {
            await Task.Run(() => { CreatePdf(filename, margin); });
            //await Task.Run(() => { CreatePdf2(filename, margin); });
        }

        private static byte[] GetResourceImage(string imageName)
        {
            //https://stackoverflow.com/questions/1192054/load-image-from-resources-area-of-project-in-c-sharp
            System.Reflection.Assembly asm = System.Reflection.Assembly.GetExecutingAssembly();
            string resourceName = asm.GetName().Name + ".Properties.Resources";
            System.Resources.ResourceManager rm = new System.Resources.ResourceManager(resourceName, asm);
           
            using (MemoryStream ms = new MemoryStream())
            {
                using (Bitmap bmp = (Bitmap)rm.GetObject(imageName))
                {
                    bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
                    return ms.ToArray();
                }
            }
        }
    }
}

Usage 1:

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "PDF File (*.pdf)|*.pdf";

    sfd.FileName = "Test.pdf";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        try
        {
            HelperiText7.CreatePdf(sfd.FileName);
        }
        catch(Exception ex) 
        {
            if (ex.Message == "Error: CreatePdf is already executing. Please try again later.")
                MessageBox.Show(ex.Message, "Error - Method In Use", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

Usage 2:

using (SaveFileDialog sfd = new SaveFileDialog())
{
    sfd.Filter = "PDF File (*.pdf)|*.pdf";

    sfd.FileName = "Test.pdf";

    if (sfd.ShowDialog() == DialogResult.OK)
    {
        try
        {
            await HelperiText7.CreatePdfAsync(sfd.FileName);
        }
        catch (Exception ex)
        {
            if (ex.Message == "Error: CreatePdf is already executing. Please try again later.")
                MessageBox.Show(ex.Message, "Error - Method In Use", MessageBoxButtons.OK, MessageBoxIcon.Error);
            else
                MessageBox.Show(ex.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
        }
    }
}

Resources:

Tu deschizi eu inchid
  • 4,117
  • 3
  • 13
  • 24