Search code examples
c#pdffreeimage

how to diagnose freeimage loadfromstream errors


I am using a C# FreeImage wrapper. I am trying to open a PDF file containing images, and "extract" those images into windows Bitmap objects. I am following the guidelines described in articles on the internet, following loosely the following pattern:

byte[] bytes = GetPdfFile();

iTextSharp.text.pdf.PdfReader reader = new iTextSharp.text.pdf.PdfReader(bytes);

int pageNumber = 0;
for (int i = 0; i <= reader.XrefSize - 1; i++)
{
    pdfObj = reader.GetPdfObject(i);
    if ((pdfObj != null) && pdfObj.IsStream())
    {
        pdfStream = (iTextSharp.text.pdf.PdfStream)pdfObj;
        iTextSharp.text.pdf.PdfObject subtype = pdfStream.Get(iTextSharp.text.pdf.PdfName.SUBTYPE);
        if ((subtype != null) && subtype.ToString().Equals(iTextSharp.text.pdf.PdfName.IMAGE.ToString()))
        {
            pageNumber++;
            byte[] imgBytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)pdfStream);
            if ((imgBytes != null))
            {
                // in my case images are in TIF Group 4 format
                using (MemoryStream ms = new MemoryStream(imgBytes))
                {
                    FreeImageAPI.FIBITMAP bmp = FreeImageAPI.FreeImage.LoadFromStream(ms);

                    // in my case bmp with IsNull = true is returned
                    if (!bmp.IsNull)
                    {
                        using (MemoryStream msOut = new MemoryStream())
                        {
                            FreeImageAPI.FreeImage.SaveToStream(bmp, msOut, ... ); // etc.
                        }
                    }
                }
            }
        }
    }
}

Does anybody have a suggestion on how to troubleshoot this, given that no exception is returned - some kind of GetLastError FreeImage function? Thank you


Solution

  • Although it doesn't appear that the SetOutputMessage function was added to the .NET wrapper library, it is possible to call it directly from the FreeImage library.

    That is, adding the function to your code using:

      [DllImport("FreeImage", EntryPoint = "FreeImage_SetOutputMessage")]
      internal static extern void SetOutputMessage(OutputMessageFunction outputMessageFunction);
    

    The following code shows an Exception being thrown from the Save function, rather than returning false (with the following console output):

    Test 1... Success
    Test 2...
    Unhandled Exception: System.Exception: only 24-bit highcolor or 8-bit greyscale/palette bitmaps can be saved as JPEG
    at ConsoleApplication1.Program.OutputMessage(FREE_IMAGE_FORMAT format, String message) ...\ConsoleApplication1\Program.cs:line 35
    at FreeImageAPI.FreeImage.Save(FREE_IMAGE_FORMAT fif, FIBITMAP dib, String filename, FREE_IMAGE_SAVE_FLAGS flags)
    at ConsoleApplication1.Program.Main(String[] args) in ...\ConsoleApplication1\Program.cs:line 28

    using System;
    using System.Drawing;
    using System.Drawing.Imaging;
    using System.Runtime.InteropServices;
    using FreeImageAPI;
    
    namespace ConsoleApplication1
    {
       class Program
       {
          static void Main(string[] args)
          {  FIBITMAP bitmap;
             bool    success;
    
             SetOutputMessage(OutputMessage);
    
             Console.Write("Test 1... ");
             bitmap = FreeImage.CreateFromBitmap(new Bitmap(320, 240, PixelFormat.Format24bppRgb));
             success = FreeImage.Save(FREE_IMAGE_FORMAT.FIF_JPEG, bitmap, "output.jpg",   FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYNORMAL);
             FreeImage.Unload(bitmap);
             Console.WriteLine("Success");
    
             Console.Write("Test 2... ");
             bitmap = FreeImage.CreateFromBitmap(new Bitmap(320, 240));
             success = FreeImage.Save(FREE_IMAGE_FORMAT.FIF_JPEG, bitmap, "output.jpg",   FREE_IMAGE_SAVE_FLAGS.JPEG_QUALITYNORMAL);
             FreeImage.Unload(bitmap);
             Console.WriteLine("Success");
    
          }
    
          static void OutputMessage(FREE_IMAGE_FORMAT format, string message)
          {  throw new Exception(message);
          }
    
          [DllImport("FreeImage", EntryPoint = "FreeImage_SetOutputMessage")]
          internal static extern void SetOutputMessage(OutputMessageFunction outputMessageFunction);
    
       }
    }