Создание PDF-файла вручную с нуля и вставка изображений - PullRequest
1 голос
/ 29 января 2020

Я пытаюсь сгенерировать файл PDF программно.

Весь случай таков: я получаю многостраничный PDFS. Каждая страница представляет собой изображение с содержанием, которое я хочу. Я не хочу использовать внешние библиотеки, потому что я ищу производительность \ оптимизацию (в долгосрочной перспективе это будет иметь значение для меня). Раньше у меня было что-то уже работающее (я создал систему, такую ​​как header \ file content (image) \ footer), и это всегда работало. Однако что-то изменилось, и оно перестало работать.

В любом случае, чтобы исправить это и построить с нуля, вот шаги, которые я выполнил:

  1. Извлечена часть FlateDecode, связанная с файл изображения (один из многих)
  2. Создан из него чистый JPEG (без заголовков фотошопа и т. д. c, простой файл JPEG)
  3. Отправил файл в какой-либо онлайн-сервис для конвертации PDF ; создал файл из этого JPEG.
  4. Определил, как был создан файл PDF и часть изображения. Кодировал все вручную, включал ссылки в таблицу внешних ссылок
  5. Все, что я получил, это то, что "Файл поврежден". Я сравнил оба файла (исходный и созданный мной), и они кажутся почти одинаковыми (разница в размере из-за части изображения).

Я не знаю, что еще делай так как все вроде бы почти точно. Я также декодировал некоторую строковую часть FlateDecode внутри PDF-файла, но не смог найти ничего, связанного с позиционированием объекта внутри файла.

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

using (var b = new BinaryWriter(File.Open(@"C:\test\Rio\Reboot\fullmanual01.pdf", FileMode.Create)))
{
    var imgBytes = File.ReadAllBytes(@"C:\test\Rio\Reboot\decompressedimg.raw");
    var firstFlate = File.ReadAllBytes(@"C:\test\Rio\Reboot\flateStr01.raw");
    var FlateDecompressed = Encoding.ASCII.GetString(FlateDecompress(firstFlate));
    string crlf = Environment.NewLine;

    var pdfHeader = Encoding.ASCII.GetBytes($"%PDF-1.4{crlf}");
    b.Write(pdfHeader);
    pdfHeader = StringToByteArray("25E2E3CFD30D0A");
    b.Write(pdfHeader);
    var pdfObj = new PDFStrObject(1, $"/Type /Page{crlf}/MediaBox [ 0 0 595 769 ]{crlf}/Resources << /XObject << /X0 3 0 R >> >>{crlf}/Contents 4 0{crlf}/Parent 2 0 R{crlf}/Rotate 360{crlf}>>{crlf}endobj{crlf}").byteFromStrObj;
    b.Write(pdfObj);
    var secondObjPos = b.BaseStream.Position.ToString("0000000000");
    pdfObj = new PDFStrObject(3, $"/Type /XObject{crlf}/Subtype /Image{crlf}/Width 1016{crlf}/Height 1328{crlf}/BitsPerComponent 8{crlf}/ColorSpace /DeviceGray{crlf}/Filter /FlateDecode{crlf}/Length {imgBytes.Length}{crlf}>>{crlf}stream{crlf}").byteFromStrObj;
    b.Write(pdfObj);
    b.Write(imgBytes);
    b.Write(Encoding.ASCII.GetBytes($"{crlf}endstream{crlf}endobj{crlf}"));
    var thirdObjPos = b.BaseStream.Position.ToString("0000000000");
    pdfObj = new PDFStrObject(4, $"/Filter /FlateDecode{crlf}/Length 45{crlf}>>{crlf}stream{crlf}").byteFromStrObj;
    b.Write(pdfObj);
    b.Write(firstFlate);
    b.Write(Encoding.ASCII.GetBytes($"{crlf}endstream{crlf}endobj{crlf}"));
    var secondPos = b.BaseStream.Position;
    pdfObj = new PDFStrObject(2, $"/Type /Pages{crlf}/Kids [ 1 0 R ]{crlf}/Count 1{crlf}>>{crlf}endobj{crlf}").byteFromStrObj;
    b.Write(pdfObj);
    var firstObjPos = b.BaseStream.Position.ToString("0000000000"); //2 0 obj
    pdfObj = new PDFStrObject(5, $"/Type /Catalog{crlf}/Pages 2 0{crlf}>>{crlf}endobj{crlf}").byteFromStrObj;
    b.Write(pdfObj);
    var fourthObhPos = b.BaseStream.Position.ToString("0000000000");
    b.Write(Encoding.ASCII.GetBytes($"xref{crlf}0 6{crlf}"));
    b.Write(Encoding.ASCII.GetBytes($"0000000000 65535 f{crlf}0000000017 00000 n{crlf}"));

    b.Write(Encoding.ASCII.GetBytes($"{firstObjPos} 00000 n{crlf}"));

    b.Write(Encoding.ASCII.GetBytes($"{secondObjPos} 00000 n{crlf}"));

    b.Write(Encoding.ASCII.GetBytes($"{thirdObjPos} 00000 n{crlf}"));
    b.Write(Encoding.ASCII.GetBytes($"{fourthObhPos} 00000 n{crlf}"));
    b.Write(Encoding.ASCII.GetBytes($"trailer{crlf}<<{crlf}/Size 6{crlf}/Root 5 0{crlf}/ID [<05bebfaf5c6382cfbc44cd1b3389e097><05bebfaf5c6382cfbc44cd1b3389e097>]{crlf}>>{crlf}startxref{crlf}{b.BaseStream.Position+7}{crlf}%%EOF{crlf}"));
}

и класс для создания объектов:

class PDFStrObject
{
    public string strObj { get; private set; }
    public byte[] byteFromStrObj { get; private set; }
    public PDFStrObject(int objNum, string content)
    {
        string crlf = Environment.NewLine;

        strObj =  $"{objNum} 0 obj{crlf}<<{crlf}{content}";
        byteFromStrObj = Encoding.ASCII.GetBytes(strObj);
    }
}

Файлы, которые я использовал, находятся здесь: https://drive.google.com/drive/folders/11HN9cB9Cs7uqBQdpZkNyNKt29sl_xJrL?usp=sharing

Описание:

decompressedimg-convertido.pdf -> Файл, который я преобразовал онлайн.

decompressedimg.raw -> Изображение часть, которую я извлек из многостраничного PDF. Размеры: W: 1016, H: 1328

fullmanual01.pdf -> Файл, сгенерированный с использованием моего кода.

PDfRjMultiplePages -> Файл PDF с несколькими страницами, которые я хочу программно извлечь страницы от.

Любой вклад приветствуется. Я также ответил на вопрос: Ошибка записи файла PDF с нуля , но не удалось найти подсказку для того, что я пытаюсь сделать (к сожалению)

Танки

1 Ответ

3 голосов
/ 30 января 2020

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

enter image description here

Он указывает на красный, но должен укажите на синее пятно.

Другая очевидная проблема заключается в том, что у вас есть более ранняя таблица внешних ссылок в середине файла. Таким образом, вы пытались (возможно, случайно) создать линеаризованный или инкрементальный PDF-файл. На основании вашего описания нет смысла делать что-либо из этого. Вы должны просто придерживаться базового c PDF, одной таблицы внешних ссылок в конце файла.

Вам следует присмотреться к тому посту , на который вы ссылались , он кажется хорошим отправная точка.

PDF 1.7 spe c также предоставляет очень простую, привет-работу, примеры.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...