Pdf ITextFax使用GetDrawingImage()对提取的数据进行解码

Pdf ITextFax使用GetDrawingImage()对提取的数据进行解码,pdf,itextsharp,Pdf,Itextsharp,在某些图像上,当我调用: PdfImageObject pimg = new PdfImageObject(stream); Image bmp = pimg.GetDrawingImage(); 返回的图像被扭曲。我以前见过这种情况,通常与字节对齐有关,但我不确定如何解决这个问题 此对象的/decodeparm是/EndOfLine true/K 0/Columns 3300 我曾尝试将GetStreamBytesRaw与BitMiracle.LibTiff一起使用,使用它可以正确格式化数据

在某些图像上,当我调用:

PdfImageObject pimg = new PdfImageObject(stream);
Image bmp = pimg.GetDrawingImage();
返回的图像被扭曲。我以前见过这种情况,通常与字节对齐有关,但我不确定如何解决这个问题

此对象的/decodeparm是/EndOfLine true/K 0/Columns 3300

我曾尝试将GetStreamBytesRaw与BitMiracle.LibTiff一起使用,使用它可以正确格式化数据,尽管图像是旋转的。如果可能的话,我希望GetDrawingImage能够正确解码数据,假设这就是问题所在

如果需要,我可以通过电子邮件提供PDF

谢谢,
Darren

对于遇到此场景的任何其他人,这里是我的解决方案。这个谜题的关键是理解/k0是G3,/K-1或者任何小于0的东西都是G4/k1或者任何大于0的东西都是G3-2D

当您试图使G3压缩数据适合G4图像时,就会发生扭曲,这似乎是iTextSharp可能正在做的事情。我知道它肯定与我在项目中实施iTextSharp的方式不符。我承认我无法破译iTextSharp正在进行的所有解码工作,因此我可能也遗漏了一些东西

EndOfLine并没有参与这个谜题,但我仍然认为在二进制数据中输入换行符是一种奇怪的做法

99%的代码来自BitMiracle.LibTiff.Net-谢谢

int nK = 0;// Default to 0 like the PDF Spec
PdfObject oDecodeParms = stream.Get(PdfName.DECODEPARMS);
if (oDecodeParms is PdfDictionary)
{
    PdfObject oK0 = ((PdfDictionary)oDecodeParms).Get(PdfName.K);
    if (oK0 != null)
        nK = ((PdfNumber)oK0).IntValue;
}

using (MemoryStream ms = new MemoryStream())
{
    using (Tiff tiff = Tiff.ClientOpen("custom", "w", ms, new TiffStream()))
    {
        tiff.SetField(TiffTag.IMAGEWIDTH, width);
        tiff.SetField(TiffTag.IMAGELENGTH, height);
        if (nK == 0 || nK > 0) // 0 = Group 3, > 0 = Group 3 2D
            tiff.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX3);
        else if (nK < 0) // < 0 = Group 4
            tiff.SetField(TiffTag.COMPRESSION, Compression.CCITTFAX4);
        tiff.SetField(TiffTag.BITSPERSAMPLE, bpc);
        tiff.SetField(TiffTag.SAMPLESPERPIXEL, 1);
        tiff.WriteRawStrip(0, rawBytes, rawBytes.Length); //saving the tiff file using the raw bytes retrieved from the PDF.
        tiff.Close();
    }

    TiffStreamForBytes byteStream = new TiffStreamForBytes(ms.ToArray());

    using (Tiff input = Tiff.ClientOpen("bytes", "r", null, byteStream))
    {
        int stride = input.ScanlineSize();

        Bitmap result = new Bitmap(width, height, pixelFormat);
        ColorPalette palette = result.Palette;
        palette.Entries[0] = System.Drawing.Color.White;
        palette.Entries[1] = System.Drawing.Color.Black;
        result.Palette = palette;

        for (int i = 0; i < height; i++)
        {
            Rectangle imgRect = new Rectangle(0, i, width, 1);
            BitmapData imgData = result.LockBits(imgRect, ImageLockMode.WriteOnly, pixelFormat);

            byte[] buffer = new byte[stride];
            input.ReadScanline(buffer, i);

            System.Runtime.InteropServices.Marshal.Copy(buffer, 0, imgData.Scan0, buffer.Length);
            result.UnlockBits(imgData);
        }
    }
}

/// <summary>
/// Custom read-only stream for byte buffer that can be used
/// with Tiff.ClientOpen method.
/// </summary>
public class TiffStreamForBytes : TiffStream
{
    private byte[] m_bytes;
    private int m_position;

    public TiffStreamForBytes(byte[] bytes)
    {
        m_bytes = bytes;
        m_position = 0;
    }

    public override int Read(object clientData, byte[] buffer, int offset, int count)
    {
        if ((m_position + count) > m_bytes.Length)
            return -1;

        Buffer.BlockCopy(m_bytes, m_position, buffer, offset, count);
        m_position += count;
        return count;
    }

    public override void Write(object clientData, byte[] buffer, int offset, int count)
    {
        throw new InvalidOperationException("This stream is read-only");
    }

    public override long Seek(object clientData, long offset, SeekOrigin origin)
    {
        switch (origin)
        {
            case SeekOrigin.Begin:
                if (offset > m_bytes.Length)
                    return -1;

                m_position = (int)offset;
                return m_position;

            case SeekOrigin.Current:
                if ((offset + m_position) > m_bytes.Length)
                    return -1;

                m_position += (int)offset;
                return m_position;

            case SeekOrigin.End:
                if ((m_bytes.Length - offset) < 0)
                    return -1;

                m_position = (int)(m_bytes.Length - offset);
                return m_position;
        }

        return -1;
    }

    public override void Close(object clientData)
    {
        // nothing to do
        return;
    }

    public override long Size(object clientData)
    {
        return m_bytes.Length;
    }
}

在PDF文件中,图像对象的行长度等于字节数。许多其他图像系统的数据双字或四字对齐。3300像素=413字节用于PDF,但416字节用于DWORD对齐位图。检查正在创建的位图中的间距值。您可以共享您的PDF文件吗?这里是指向文件BitBank的链接-在我的代码中,如上所示的图像步幅为416。与BitMiracle.Libtiff配合使用时,步幅为416。我想知道这是否与图像是G3还是G4以及数据中的换行符有关,如/EndOfLine true所示。@BitBank iText将步幅计算为412.5 413四舍五入。有没有办法计算或读取音高?我试过谷歌搜索,但什么也没找到。注意:EndOfLine参数不是用于换行:它是一个表示扫描线结束的特定位模式。因此,如果绘图位模式已经填充了整行,则不需要在那里,除非标志明确指出它应该在那里,但从技术上讲,应该可以在这之前发出一个行尾。扫描线的其余部分用零填充。感谢您的澄清。