0

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

hello_earth
  • 1,442
  • 1
  • 25
  • 39
  • with some searching i find that FreeImage has a SetOutputMessage method that maps to FreeImageAPI.FreeImage.OutputMessageProc C# wrapper method - but it's not very clear to me how to use it - since it doesn't appear to be a delegate / take a function as parameter ... here's another link that touches the problem http://sourceforge.net/p/freeimage/discussion/36111/thread/8ccaebf8/ – hello_earth Dec 04 '14 at 16:42
  • 1
    there seems to exist a delegate method FreeImageAPI.FreeImageEngine.Message which accepts functions in the usual way via +=, but it doesn't seem to be called in my case - by the way the direct output of imgBytes (which are the raw bytes of the PDF Image object) to disk gives something that even IrfanView doesn't recognize as image – hello_earth Dec 05 '14 at 12:57
  • ok, as far as I understood freeimage API will also look for the header of the image data to determine the image format - therefore it is not exactly better for what i want to do than the standard System.Drawing objects like Bitmap. besides, I had to do a FlateDecode on the raw bytes, if it is specified in the Filter "attribute" of the pdfStream - afterwards I resorted to copying line by line the raw image data to a new Bitmap object, aligning properly using Stride etc. as pointed out below – hello_earth Dec 10 '14 at 10:59
  • https://stackoverflow.com/questions/8493559/why-is-my-image-distorted-when-decoding-as-flatedecode-using-itextsharp/8517377#8517377 the fact that i still don't know how to trap an exception given by FreeImage while loading an image is still annoying, but it may be trivial since in the majority of such cases FreeImage just can't read the header of the image, i.e. image data is not in the right format / or unsupported format... – hello_earth Dec 10 '14 at 11:02

1 Answers1

0

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

   }
}
Eliott
  • 332
  • 3
  • 13