Изображения извлечения с помощью iTextSharp

Это назначение не является действительно проблематичным, и компилятор даже в некотором роде знает об этом, потому что следующая реализация компилируется без проблем:

trait F
trait X[A <: F]
def test(x: X[_]): X[_ <: F] = x match { case q: X[t] => q }

Если вы дадите контролеру типов некоторую слабость, позволив Выведите более точные границы для переменной типа t, в конечном итоге выяснится, что t должен быть подтипом F, а затем позволит вам вернуть значение q (которое совпадает с x) без жалоб. Он не делает этого по умолчанию по некоторым нелогичным причинам , что , вероятно, как-то связано с совместимостью с подстановочными символами Java .

(Снова восстановлено; мое первоначальное предположение не показалось слишком далеким, и, учитывая ссылку Дмитрия Митина , по сравнению с ним оно даже не выглядит слишком расплывчатым.) [ 1112]

21
задан Bobrovsky 16 April 2013 в 18:21
поделиться

3 ответа

Я обнаружил, что моя проблема заключалась в том, что я не выполнял рекурсивный поиск изображений внутри форм и групп. По сути, исходный код находит только изображения, встроенные в корень PDF-документа. Вот обновленный метод и новый метод (FindImageInPDFDictionary), который рекурсивно ищет изображения на странице. ПРИМЕЧАНИЕ: недостатки поддержки только JPEG и несжатых изображений по-прежнему применяются. Варианты исправления этих недостатков см. В коде Р. Уббена. Кто-то HTH.

    public static void ExtractImagesFromPDF(string sourcePdf, string outputPath)
    {
        // NOTE:  This will only get the first image it finds per page.
        PdfReader pdf = new PdfReader(sourcePdf);
        RandomAccessFileOrArray raf = new iTextSharp.text.pdf.RandomAccessFileOrArray(sourcePdf);

        try
        {
            for (int pageNumber = 1; pageNumber <= pdf.NumberOfPages; pageNumber++)
            {
                PdfDictionary pg = pdf.GetPageN(pageNumber);

                // recursively search pages, forms and groups for images.
                PdfObject obj = FindImageInPDFDictionary(pg);
                if (obj != null)
                {

                    int XrefIndex = Convert.ToInt32(((PRIndirectReference)obj).Number.ToString(System.Globalization.CultureInfo.InvariantCulture));
                    PdfObject pdfObj = pdf.GetPdfObject(XrefIndex);
                    PdfStream pdfStrem = (PdfStream)pdfObj;
                    byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)pdfStrem);
                    if ((bytes != null))
                    {
                        using (System.IO.MemoryStream memStream = new System.IO.MemoryStream(bytes))
                        {
                            memStream.Position = 0;
                            System.Drawing.Image img = System.Drawing.Image.FromStream(memStream);
                            // must save the file while stream is open.
                            if (!Directory.Exists(outputPath))
                                Directory.CreateDirectory(outputPath);

                            string path = Path.Combine(outputPath, String.Format(@"{0}.jpg", pageNumber));
                            System.Drawing.Imaging.EncoderParameters parms = new System.Drawing.Imaging.EncoderParameters(1);
                            parms.Param[0] = new System.Drawing.Imaging.EncoderParameter(System.Drawing.Imaging.Encoder.Compression, 0);
                            System.Drawing.Imaging.ImageCodecInfo jpegEncoder = Utilities.GetImageEncoder("JPEG");
                            img.Save(path, jpegEncoder, parms);
                        }
                    }
                }
            }
        }
        catch
        {
            throw;
        }
        finally
        {
            pdf.Close();
            raf.Close();
        }


    }

     private static PdfObject FindImageInPDFDictionary(PdfDictionary pg)
    {
        PdfDictionary res =
            (PdfDictionary)PdfReader.GetPdfObject(pg.Get(PdfName.RESOURCES));


        PdfDictionary xobj =
          (PdfDictionary)PdfReader.GetPdfObject(res.Get(PdfName.XOBJECT));
        if (xobj != null)
        {
            foreach (PdfName name in xobj.Keys)
            {

                PdfObject obj = xobj.Get(name);
                if (obj.IsIndirect())
                {
                    PdfDictionary tg = (PdfDictionary)PdfReader.GetPdfObject(obj);

                    PdfName type =
                      (PdfName)PdfReader.GetPdfObject(tg.Get(PdfName.SUBTYPE));

                    //image at the root of the pdf
                    if (PdfName.IMAGE.Equals(type))
                    {
                        return obj;
                    }// image inside a form
                    else if (PdfName.FORM.Equals(type))
                    {
                        return FindImageInPDFDictionary(tg);
                    } //image inside a group
                    else if (PdfName.GROUP.Equals(type))
                    {
                        return FindImageInPDFDictionary(tg);
                    }

                }
            }
        }

        return null;

    }
20
ответ дан 29 November 2019 в 20:17
поделиться

Вышеуказанное будет работать только с JPEG. Исключая встроенные изображения и внедренные файлы, вам нужно пройти через объекты подтипа IMAGE, затем посмотреть на фильтр и предпринять соответствующие действия. Вот пример, предполагая, что у нас есть PdfObject подтипа IMAGE:

            PdfReader pdf = new PdfReader("c:\\temp\\exp0.pdf");
        int xo=pdf.XrefSize;
        for (int i=0;i<xo;i++)
        {
            PdfObject obj=pdf.GetPdfObject(i);
            if (obj!=null && obj.IsStream())
            {
                PdfDictionary pd=(PdfDictionary)obj;
                if (pd.Contains(PdfName.SUBTYPE) && pd.Get(PdfName.SUBTYPE).ToString()=="/Image")
                {
                    string filter=pd.Get(PdfName.FILTER).ToString();
                    string width=pd.Get(PdfName.WIDTH).ToString();
                    string height=pd.Get(PdfName.HEIGHT).ToString();
                    string bpp=pd.Get(PdfName.BITSPERCOMPONENT).ToString();
                    string extent=".";
                    byte [] img=null;
                    switch (filter)
                    {
                        case "/FlateDecode":
                            byte[] arr=PdfReader.FlateDecode(PdfReader.GetStreamBytesRaw((PRStream)obj),true);
                            Bitmap bmp=new Bitmap(Int32.Parse(width),Int32.Parse(height),PixelFormat.Format24bppRgb);
                            BitmapData bmd=bmp.LockBits(new Rectangle(0,0,Int32.Parse(width),Int32.Parse(height)),ImageLockMode.WriteOnly,
                                PixelFormat.Format24bppRgb);
                            Marshal.Copy(arr,0,bmd.Scan0,arr.Length);
                            bmp.UnlockBits(bmd);
                            bmp.Save("c:\\temp\\bmp1.png",ImageFormat.Png);
                            break;
                        default:
                            break;
                    }
                }
            }
        }

Это, конечно, испортит цвет из-за Microsoft BGR, но я хотел, чтобы он был коротким. Сделайте что-то подобное для "/ CCITTFaxDecode" и т. Д.

3
ответ дан 29 November 2019 в 20:17
поделиться

Следующий код включает в себя все идеи Дэйва и Р. Уббена, приведенные выше, плюс он возвращает полный список всех изображений, а также имеет дело с несколькими битовыми глубинами. Мне пришлось преобразовать его в VB для проекта, над которым я работаю, извините за это ...

Private Sub getAllImages(ByVal dict As pdf.PdfDictionary, ByVal images As List(Of Byte()), ByVal doc As pdf.PdfReader)
    Dim res As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(dict.Get(pdf.PdfName.RESOURCES)), pdf.PdfDictionary)
    Dim xobj As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(res.Get(pdf.PdfName.XOBJECT)), pdf.PdfDictionary)

    If xobj IsNot Nothing Then
        For Each name As pdf.PdfName In xobj.Keys
            Dim obj As pdf.PdfObject = xobj.Get(name)
            If (obj.IsIndirect) Then
                Dim tg As pdf.PdfDictionary = CType(pdf.PdfReader.GetPdfObject(obj), pdf.PdfDictionary)
                Dim subtype As pdf.PdfName = CType(pdf.PdfReader.GetPdfObject(tg.Get(pdf.PdfName.SUBTYPE)), pdf.PdfName)
                If pdf.PdfName.IMAGE.Equals(subtype) Then
                    Dim xrefIdx As Integer = CType(obj, pdf.PRIndirectReference).Number
                    Dim pdfObj As pdf.PdfObject = doc.GetPdfObject(xrefIdx)
                    Dim str As pdf.PdfStream = CType(pdfObj, pdf.PdfStream)
                    Dim bytes As Byte() = pdf.PdfReader.GetStreamBytesRaw(CType(str, pdf.PRStream))

                    Dim filter As String = tg.Get(pdf.PdfName.FILTER).ToString
                    Dim width As String = tg.Get(pdf.PdfName.WIDTH).ToString
                    Dim height As String = tg.Get(pdf.PdfName.HEIGHT).ToString
                    Dim bpp As String = tg.Get(pdf.PdfName.BITSPERCOMPONENT).ToString

                    If filter = "/FlateDecode" Then
                        bytes = pdf.PdfReader.FlateDecode(bytes, True)
                        Dim pixelFormat As System.Drawing.Imaging.PixelFormat
                        Select Case Integer.Parse(bpp)
                            Case 1
                                pixelFormat = Drawing.Imaging.PixelFormat.Format1bppIndexed
                            Case 24
                                pixelFormat = Drawing.Imaging.PixelFormat.Format24bppRgb
                            Case Else
                                Throw New Exception("Unknown pixel format " + bpp)
                        End Select
                        Dim bmp As New System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat)
                        Dim bmd As System.Drawing.Imaging.BitmapData = bmp.LockBits(New System.Drawing.Rectangle(0, 0, Int32.Parse(width), Int32.Parse(height)), System.Drawing.Imaging.ImageLockMode.WriteOnly, pixelFormat)
                        Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length)
                        bmp.UnlockBits(bmd)
                        Using ms As New MemoryStream
                            bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Png)
                            bytes = ms.GetBuffer
                        End Using
                    End If
                    images.Add(bytes)
                ElseIf pdf.PdfName.FORM.Equals(subtype) Or pdf.PdfName.GROUP.Equals(subtype) Then
                    getAllImages(tg, images, doc)
                End If
            End If
        Next
    End If
End Sub
6
ответ дан 29 November 2019 в 20:17
поделиться