При декодировании изображения в PDF как FlateDecode
через iTextSharp изображение искажается, и я не могу понять, почему.
Распознанный bpp - Format1bppIndexed
. Если я изменю значение PixelFormat
на Format4bppIndexed
, изображение будет в некоторой степени узнаваемо (уменьшено, цвета отключены, но читаемы) и будет дублировано 4 раза по горизонтали. Если я настраиваю формат пикселя на Format8bppIndexed
, он также в некоторой степени распознается и дублируется 8 раз по горизонтали.
Изображение ниже соответствует формату Format1bppIndexed
пикселей. К сожалению, я не могу показать остальные из-за ограничений безопасности.
Код, приведенный ниже, по сути, является единственным решением, с которым я столкнулся, замусоренным вокруг SO и сети.
int xrefIdx = ((PRIndirectReference)obj).Number;
PdfObject pdfObj = doc.GetPdfObject(xrefIdx);
PdfStream str = (PdfStream)(pdfObj);
byte[] bytes = PdfReader.GetStreamBytesRaw((PRStream)str);
string filter = ((PdfArray)tg.Get(PdfName.FILTER))[0].ToString();
string width = tg.Get(PdfName.WIDTH).ToString();
string height = tg.Get(PdfName.HEIGHT).ToString();
string bpp = tg.Get(PdfName.BITSPERCOMPONENT).ToString();
if (filter == "/FlateDecode")
{
bytes = PdfReader.FlateDecode(bytes, true);
System.Drawing.Imaging.PixelFormat pixelFormat;
switch (int.Parse(bpp))
{
case 1:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format1bppIndexed;
break;
case 8:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format8bppIndexed;
break;
case 24:
pixelFormat = System.Drawing.Imaging.PixelFormat.Format24bppRgb;
break;
default:
throw new Exception("Unknown pixel format " + bpp);
}
var bmp = new System.Drawing.Bitmap(Int32.Parse(width), Int32.Parse(height), pixelFormat);
System.Drawing.Imaging.BitmapData bmd = 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);
bmp.Save(@"C:\temp\my_flate_picture-" + DateTime.Now.Ticks.ToString() + ".png", ImageFormat.Png);
}
Что мне нужно сделать, чтобы мое извлечение изображений работало как нужно при работе с FlateDecode
?
ПРИМЕЧАНИЕ : я не хочу использовать другую библиотеку для извлечения изображений. Я ищу решение, использующее ТОЛЬКО iTextSharp и .NET FW. Если решение существует через Java (iText) и легко переносится на биты .NET FW, этого также будет достаточно.
ОБНОВЛЕНИЕ : для свойства ImageMask
установлено значение true, что подразумевает отсутствие цветового пространства и, следовательно, неявно черно-белое. При значении bpp, равном 1, значение PixelFormat
должно составлять Format1bppIndexed
, что, как упоминалось ранее, создает внедренное изображение, показанное выше.
ОБНОВЛЕНИЕ : Чтобы получить размер изображения, я извлек его с помощью Acrobat X Pro, а размер изображения для этого конкретного примера был указан как 2403x3005. При извлечении через iTextSharp размер был указан как 2544x3300. Я изменил размер изображения в отладчике на зеркальное отображение 2403x3005, однако при вызове Marshal.Copy(bytes, 0, bmd.Scan0, bytes.Length);
я получаю исключение.
Попытка чтения или записи в защищенную память. Это часто
признак того, что другая память повреждена.
Я предполагаю, что это связано с изменением размера и, следовательно, больше не соответствует используемым байтовым данным.
ОБНОВЛЕНИЕ : согласно рекомендации Джимми, я подтвердил, что вызов PdfReader.GetStreamBytes
возвращает длину в байтах [], равную ширине height / 8, так как GetStreamBytes
должен вызывать FlateDecode
. В результате ручного вызова FlateDecode
и вызова PdfReader.GetStreamBytes
длина байта [] составила 1049401, а ширина высота / 8 равна 2544 * 3300/8 или 1049400, поэтому разница равна 1. Не уверен, что это будет коренной причиной или нет, выключено одним; однако я не уверен, как решить, если это действительно так.
ОБНОВЛЕНИЕ : При попытке использовать подход, упомянутый kuujinbo, меня встречает IndexOutOfRangeException
, когда я пытаюсь вызвать renderInfo.GetImage();
в приемнике RenderImage
. Тот факт, что ширина * высота / 8, как указано выше, отключена на 1 по сравнению с длиной байта [] при вызове FlateDecode
, заставляет меня думать, что все они едины; однако решение все еще ускользает от меня.
at System.util.zlib.Adler32.adler32(Int64 adler, Byte[] buf, Int32 index, Int32 len)
at System.util.zlib.ZStream.read_buf(Byte[] buf, Int32 start, Int32 size)
at System.util.zlib.Deflate.fill_window()
at System.util.zlib.Deflate.deflate_slow(Int32 flush)
at System.util.zlib.Deflate.deflate(ZStream strm, Int32 flush)
at System.util.zlib.ZStream.deflate(Int32 flush)
at System.util.zlib.ZDeflaterOutputStream.Write(Byte[] b, Int32 off, Int32 len)
at iTextSharp.text.pdf.codec.PngWriter.WriteData(Byte[] data, Int32 stride)
at iTextSharp.text.pdf.parser.PdfImageObject.DecodeImageBytes()
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PdfDictionary dictionary, Byte[] samples)
at iTextSharp.text.pdf.parser.PdfImageObject..ctor(PRStream stream)
at iTextSharp.text.pdf.parser.ImageRenderInfo.PrepareImageObject()
at iTextSharp.text.pdf.parser.ImageRenderInfo.GetImage()
at cyos.infrastructure.Core.MyImageRenderListener.RenderImage(ImageRenderInfo renderInfo)
ОБНОВЛЕНИЕ : Попытка варьировать различные методы, перечисленные здесь в моем исходном решении, а также решение, предложенное kuujinbo с другой страницей в PDF, создает образы; однако проблемы всегда возникают, когда тип фильтра равен /FlateDecode
, и изображение для этого конкретного экземпляра не создается.