itext PdfACopy теряет OutputIntent

Я хочу объединить файлы PDF/A 1b.

Я использую itext PdfACopy.getImportedPage, и ошибки нет. Проверки соответствия Itext в порядке.

Я получаю файл PDF/A 1b, который выглядит нормально.

Когда я проверяю соответствие PDF/A с помощью pdfbox, я получаю много ошибок :

2.4.3 : Invalid Color space, DestOutputProfile is missing
2.4.3 : Invalid Color space, The operator "g" can't be used without Color Profile
2.4.3 : Invalid Color space, The operator "f" can't be used without Color Profile
2.4.1 : Invalid Color space, The operator "rg" can't be used with CMYK Profile
2.4.3 : Invalid Color space, DestOutputProfile is missing

NB: все входные PDF-файлы действительны в формате PDF/A 1b.

Вот пример кода, который я использовал для получения PDF/A, который не соответствует PDF/A 1b.

Document document = new Document();
PdfACopy copy = new PdfACopy(document, new FileOutputStream(outFile), pdfAConformanceLevel);

document.open();

PdfReader reader;
int n;
for (int i = 0; i < args.length - 1; i++)
{
  reader = new PdfReader(args[i]);
  n = reader.getNumberOfPages();
  for (int page = 0; page < n;)
  {
    copy.addPage(copy.getImportedPage(reader, ++page));
  }

}

copy.createXmpMetadata();

document.close();

Так что я разозлился и решил разобраться.

Используя этот пример выгрузить профиль ICC из PDF Я вижу, что действительно ни один профиль ICC не был включен в мой сгенерированный PDF/A.

Посмотрев этот учебник, я, наконец, использовал код в PdfWriter.setOutputIntents(final PdfReader reader, final boolean checkExistence), чтобы получить намерения вывода. во входном PDF/A и вернуть его в выходной PDF/A.

И это работает...

Сначала я создал публичный метод

public static void copyOutputIntents(PdfReader reader, PdfACopy copy) throws IOException {


    PdfDictionary catalog = reader.getCatalog();

    PdfArray outs = catalog.getAsArray(PdfName.OUTPUTINTENTS);
    if (outs == null)
    {
        Logger.err("Reggie Watts gonna get you !!!");
    }
    else
    {
        if (outs.isEmpty())
        {
            Logger.err("Reggie Watts gonna get you !!!");
        }
        PdfDictionary out = outs.getAsDict(0);

        PRStream stream = (PRStream) PdfReader.getPdfObject(out.get(PdfName.DESTOUTPUTPROFILE));
        byte destProfile[] = null;
        if (stream != null)
        {
            destProfile = PdfReader.getStreamBytes(stream);
        }
        copy.setOutputIntents(getNameString(out, PdfName.OUTPUTCONDITIONIDENTIFIER), getNameString(out, PdfName.OUTPUTCONDITION), getNameString(out, PdfName.REGISTRYNAME), getNameString(out, PdfName.INFO), destProfile);

    }
}

пришлось также добавить метод getNameString, который я просто скопировал.

Итак, теперь мой код создает действительный PDF/A:

Document document = new Document();
PdfACopy copy = new PdfACopy(document, new FileOutputStream(outFile), pdfAConformanceLevel);

document.open();

PdfReader reader;
int n;
for (int i = 0; i < args.length - 1; i++)
{
  reader = new PdfReader(args[i]);
  n = reader.getNumberOfPages();
  for (int page = 0; page < n;)
  {
    copy.addPage(copy.getImportedPage(reader, ++page));
  }
  // get last PDF's intent and put it into the output one
  Stamper.copyOutputIntents(reader, copy);
}

copy.createXmpMetadata();

document.close();

Разве PdfACopy.addPage не следует сохранять намерение вывода добавленной страницы или каким-либо образом обрабатывать его?

Я не вижу смысла в классе высокого уровня, который не может создать действительный файл PDF/A.

Я что-то упускаю ? Я сошел с ума?

Простите за длинный пост.


person EricMas    schedule 24.04.2015    source источник
comment
Намерения вывода устанавливаются на уровне документа, а не на уровне страницы. См., например, PdfA1A: writer.setOutputIntents("Custom", "", "http://www.color.org", "sRGB IEC61966-2.1", icc); С помощью PdfACopy вы создаете новый writer (PdfACopy расширяет PdfWriter). Вам нужно добавить эти намерения в свой код, потому что PdfACopy не может решить, что использовать.   -  person Bruno Lowagie    schedule 24.04.2015
comment
Спасибо за ваш ответ и отличную работу. Поскольку описание PdfACopy в javadoc равно "Extension of PdfCopy that will attempt to keep a file in conformance with the PDF/A standard." , я думал, что он получит необходимые объекты из скопированной страницы, но вы правы, мне нужно работать на уровне документа, например, для метаданных XMP.   -  person EricMas    schedule 28.04.2015