исключение в system.drawing при извлечении изображений из PDF с использованием itextsharp - PullRequest
0 голосов
/ 15 ноября 2011

Я пытаюсь извлечь изображения из PDF-файла, используя itextsharp

пример pdf я использую здесь

Код, который я использую: -

static void Main(string[] args)
    {

        try
        {
            WriteImageFile(); // write image file
            System.Console.WriteLine(AppDomain.CurrentDomain.BaseDirectory);
            System.Console.ReadLine();
        }
        catch (Exception ex)
        {
            System.Console.WriteLine(ex.Message);
        }
    }

    private static List<System.Drawing.Image> ExtractImages(String PDFSourcePath)
    {
        List<System.Drawing.Image> ImgList = new List<System.Drawing.Image>();

        iTextSharp.text.pdf.RandomAccessFileOrArray RAFObj = null;
        iTextSharp.text.pdf.PdfReader PDFReaderObj = null;
        iTextSharp.text.pdf.PdfObject PDFObj = null;
        iTextSharp.text.pdf.PdfStream PDFStremObj = null;

        try
        {
            RAFObj = new iTextSharp.text.pdf.RandomAccessFileOrArray(PDFSourcePath);
            PDFReaderObj = new iTextSharp.text.pdf.PdfReader(RAFObj, null);
            if (PDFReaderObj.IsOpenedWithFullPermissions)
            {
                Debug.Print("this is a test");
            }

            for (int i = 0; i <= PDFReaderObj.XrefSize - 1; i++)
            {
                PDFObj = PDFReaderObj.GetPdfObject(i);

                if ((PDFObj != null) && PDFObj.IsStream())
                {
                    PDFStremObj = (iTextSharp.text.pdf.PdfStream)PDFObj;
                    iTextSharp.text.pdf.PdfObject subtype = PDFStremObj.Get(iTextSharp.text.pdf.PdfName.SUBTYPE);

                    if ((subtype != null) && subtype.ToString() == iTextSharp.text.pdf.PdfName.IMAGE.ToString())
                    {
                        byte[] bytes = iTextSharp.text.pdf.PdfReader.GetStreamBytesRaw((iTextSharp.text.pdf.PRStream)PDFStremObj);

                        if ((bytes != null))
                        {
                            try
                            {
                                System.IO.MemoryStream MS = new System.IO.MemoryStream(bytes);

                                MS.Position = 0;
                                System.Drawing.Image ImgPDF = System.Drawing.Image.FromStream(MS);

                                ImgList.Add(ImgPDF);

                            }
                            catch (Exception e)
                            {
                                Console.WriteLine  ("Exception in extract: " + e);
                            }
                        }
                    }
                }
            }
            PDFReaderObj.Close();
        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
        return ImgList;
    }


    private static void WriteImageFile()
    {
        try
        {
            System.Console.WriteLine("Wait for extracting image from PDF file....");

            // Get a List of Image
            List<System.Drawing.Image> ListImage = ExtractImages(@"C:\Users\pradyut.bhattacharya\Documents\CEVA PDF\more\CS_75.pdf");

            for (int i = 0; i < ListImage.Count; i++)
            {
                try
                {
                    // Write Image File
                    ListImage[i].Save(@"C:\Users\pradyut.bhattacharya\Documents\CEVA PDF\more\Image" + i + ".jpeg", System.Drawing.Imaging.ImageFormat.Jpeg);
                    System.Console.WriteLine("Image" + i + ".jpeg write sucessfully");
                }
                catch (Exception)
                { }
            }

        }
        catch (Exception ex)
        {
            throw new Exception(ex.Message);
        }
    }

Теперь в некоторых случаях я могу получить изображения, но для большинства PDF-файлов, в которых содержатся отсканированные документы, появляется ошибка: -

    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    Exception in extract: System.ArgumentException: Parameter is not valid.
       at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
       at System.Drawing.Image.FromStream(Stream stream)
       at ConsoleApplication1.Program.ExtractImages(String PDFSourcePath) in C:\Users\pradyut.bhattacharya\Documents\Visual Studio 

    2010\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 67
    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    Exception in extract: System.ArgumentException: Parameter is not valid.
       at System.Drawing.Image.FromStream(Stream stream, Boolean useEmbeddedColorManagement, Boolean validateImageData)
       at System.Drawing.Image.FromStream(Stream stream)
       at ConsoleApplication1.Program.ExtractImages(String PDFSourcePath) in C:\Users\pradyut.bhattacharya\Documents\Visual Studio 

    2010\Projects\ConsoleApplication2\ConsoleApplication2\Program.cs:line 67

Любая помощь

Спасибо

Ответы [ 3 ]

1 голос
/ 24 мая 2012

Старый вопрос, я знаю, но я действительно нашел несколько приличное решение для этого.У меня тоже были проблемы с извлечением изображений из PDF-файлов с кодировкой JBig2.Более новые версии (пост 4.1.6) iTextSharp фактически поддерживают его, но эти версии теперь находятся под лицензией AGPL.

Использование JPEdal версии 1 этой библиотеки этой библиотеки (версия 2 небесплатно), вы можете конвертировать изображения в кодировке JBig2 в System.Drawing.Bitmap и сохранять их / изменять их по своему усмотрению Однако , эта библиотека будет только декодировать данные, она не сможет кодировать изображение в формат JBig2.

НебольшаяНо очень незначительно то, что библиотека находится на Java.Это совсем не проблема для пользователя C #, благодаря IKVM .IKVM, если вы еще не знали об этом, имеет полную виртуальную машину Java, которая работает в .NET и имеет собственные реализации .NET библиотек классов Java.Его очень легко настроить, и я буквально только что проверил все это около 2 часов назад.

После того, как вы скачали IKVM и JBig2 jar по вышеуказанной ссылке, вы можете выполнить эту команду, чтобы получить IKVM конвертируйте банку в нативную DLL-библиотеку .NET.

ikvmc -target: library [путь к jbig2.jar]

, которая выведет .NETdll с именем jbig2.dll находится в том же каталоге исполняемого файла jar или ikvmc (который не помню, какой).Затем укажите в своем проекте ссылки jbig2.dll, IKVM.OpenJDK.Core, IKVM.OpenJDK.Media, IKVM.OpenJDK.SwingAWT и IKVM.Runtime.Для извлечения изображения я использовал код, подобный следующему:

// code to iterate over PDF objects and get bytes of a valid image elided
var imageBytes = GetRawImageBytesFromPdf();

if (filterType.Equals(PdfName.JBIG2DECODE))
{
    var jbg2 = new JBIG2Decoder();

    // Some JBig2 will extract without setting the JBig2Globals
    var decodeParams = stream.GetAsDict(PdfName.DECODEPARMS);
    if(decodeParams != null)
    {
        var globalRef = decodeParams.GetAsIndirectObject(
                                        PdfName.JBIG2GLOBALS);
        if(globalRef != null)
        {
            var globals = PdfReader.GetPdfObject(globalRef);
            var globalStream = globals as PRStream;
            var globalBytes = PdfReader.GetStreamBytesRaw(globalStream);

            if (globalBytes != null)
            {
                jbg2.setGlobalData(globalBytes);
            }
        }
    }

    jbg2.decodeJBIG2(imageBytes);

    var pages = jbg2.getNumberOfPages();

    for(int p = 0; p < pages; p++)
    {
        java.awt.image.BufferedImage bufImg = jbg2.getPageAsBufferedImage(p);

        var bitmap = bufImg.getBitmap();
        bitmap.Save(@"c:\path\to\file.tif", ImageFormat.Tiff);
        // note: I am unsure about the need to free the memory of the internal
        //       bitmap used in the BufferedImage class.  The docs for IKVM and
        //       that class should probably be consulted to find out if that
        //       should be done.
    }
}
// handle other formats like CCITTFAXDECODE

Он хорошо работает, хотя библиотека не самая быстрая (это не связано с тем, что она используется в IKVM,разработчики признают, что версия 1 этой библиотеки неэффективна).Я не влюблён в написание / редактирование Java-кода, поэтому, если бы я сам захотел улучшить скорость, я решил, что, вероятно, просто потрудился бы напрямую перенести его на C # -код.Однако в этом проекте github есть еще одна ветвь этого java-кода , требующая увеличения скорости в 2,5-4,5 раза.Возможно, вы могли бы скомпилировать этот jar-файл и использовать с ним ikvmc.

Надеюсь, это поможет любому, кто все еще ищет решение этой проблемы!

1 голос
/ 15 ноября 2011

Изображения в PDF могут быть сохранены различными способами.Ваш код будет работать для всех типов, для которых .Net Framework имеет декодеры, но потерпит неудачу для тех, которые этого не делают.В частности, ваш код не работает, потому что в этом PDF есть изображения, закодированные как JBIG2Decode.Вы можете проверить это, посмотрев свойство PDFStremObj /FILTER.

PdfObject filterType = PDFStremObj.Get(PdfName.FILTER);
if(filterType.Equals(PdfName.JBIG2DECODE)){
    //...
}

Для типов, о которых среда не знает, вам либо понадобится библиотека, либо, к сожалению, вы создадите собственный декодер.1007 *

См. Этот пост для некоторых других библиотек, которые делают это. Вот запись Википедии на JBIG, если вы хотите попробовать запустить свою собственную.И вот еще один пост , в котором показаны некоторые кодировщики, которые также могут поддерживать декодирование, и это то, что вам нужно.

0 голосов
/ 20 марта 2013

Спасибо, что поделились этой идеей.

Его решение было самым элегантным, которое я нашел, используя бесплатную версию iTextsharper .

Как вы и предполагали, я включил библиотеки:

jbig2dec.dll (generated from promt >ikmvc jbig2dec.jar)
ICSharpCode.SharpZipLib
IKVM.Runtime
IKVM.OpenJDK.Core
IKVM.OpenJDK.Media
IKVM.OpenJDK.SwingAWT
...