CGPDF - Сохранение изображений с фильтром FlateDecode
Я пишу парсер PDF для работы, и мы используем Core Graphics для чтения всех данных с помощью обратных вызовов, а затем выписываем их с помощью Lib Haru, потому что нашему клиенту нужно выписать "настоящие" аннотации, а CG не может сделай это.
Ну, я дошел до того, что я получаю изображения (и сохраняю их в файл, чтобы убедиться, что я делаю это правильно, прежде чем я начну их рисовать), и я столкнулся с проблемой. Я получаю все объекты Image XObject из словаря ресурсов, а затем пытаюсь сохранить их с помощью этого кода
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDir = [paths objectAtIndex:0];
NSData *imageFileData = (NSData *)CGPDFStreamCopyData(objectStream, CGPDFDataFormatRaw);
NSString *fileName = [NSString stringWithFormat:@"%@/%s.png", documentsDir, name];
[imageFileData writeToFile:fileName atomically:YES];
где objectStream использует CGPDFDictionaryGetStream для извлечения XObject. Хорошо, он отлично работает, когда для фильтра задано значение "DCTDecode", но всякий раз, когда для фильтра задано значение "FlateDecode", сохраненное изображение повреждено и не открывается.
В этом посте я читал, что CGPDFStreamCopyData может декодировать текст с помощью FlateDecode (вплоть до нижней части поста в комментариях), но в CGPDFDataFormats есть только 3 формата данных, и ни один из них не работает.
Я считаю, что у меня также есть проблемы с текстом, который закодирован с помощью FlatDecode. Кто-нибудь есть какие-либо предложения о том, как идти о расшифровке этого? Конечно, CGPDF имеет что-то, что обрабатывает это, так как он появляется почти в каждом файле PDF, который я пытался открыть (хотя я не смог его найти).
Редактировать: я читал в нескольких местах, что я мог распаковать его с помощью zlib, поэтому я попробовал этот код, который я смог найти о том, как это сделать:
NSData* uncompressedImageData;
if ([imageFileData length] == 0)
uncompressedImageData = imageFileData;
else
{
z_stream strm;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.total_out = 0;
strm.next_in=(Bytef*)[imageFileData bytes];
strm.avail_in = [imageFileData length];
// Compresssion Levels: // Z_NO_COMPRESSION // Z_BEST_SPEED // Z_BEST_COMPRESSION // Z_DEFAULT_COMPRESSION
if (deflateInit(&strm, Z_DEFAULT_COMPRESSION) != Z_OK)
uncompressedImageData = nil;
NSMutableData *compressed = [NSMutableData dataWithLength:16384]; // 16K chuncks for expansion
do
{
if (strm.total_out >= [compressed length])
[compressed increaseLengthBy: 16384];
strm.next_out = [compressed mutableBytes] + strm.total_out; strm.avail_out = [compressed length] - strm.total_out;
deflate(&strm, Z_FINISH);
}
while (strm.avail_out == 0);
deflateEnd(&strm);
[compressed setLength: strm.total_out];
uncompressedImageData = [NSData dataWithData: compressed];
}
if(uncompressedImageData != nil)
[uncompressedImageData writeToFile:fileName atomically:YES];
Код не выдавал никаких исключений, когда я его запускал, но полученные изображения все еще не читались.
1 ответ
Ваше использование CGPDFStreamCopyData
Похоже, у вас возникло недопонимание: вы не устанавливаете нужный формат, функция устанавливает его в тот формат, который встречается в потоке. Типичное использование будет:
CGPDFDataFormat format;
CGPDFStreamCopyData(objectStream, &format);
if (format == CGPDFDataFormatRaw) {
//handle raw data...
} else if (format == CGPDFDataFormatJPEGEncoded) {
//handle jpeg data...
} else if (format == CGPDFDataFormatJPEG2000) {
//handle jpeg 2000 data
}
Изображения в формате PNG вообще не поддерживаются стандартом PDF, поэтому вы никогда не получите действительный файл PNG из потока данных изображения. Варианты: JPEG, JPEG2K и необработанные изображения (подробности см. В спецификации).
Кварц прозрачно обрабатывает zlib-сжатие, поэтому вы никогда не получите zlib-сжатые данные самостоятельно.