使用 PDFBox、iText 和 Ghostscrip 将 ICC 配置文件嵌入 PDF 时遇到困难

问题描述 投票:0回答:1

我一直致力于将 ICC 配置文件 (AdobeRGB1998.icc) 嵌入到 PDF 文件中。尽管多次尝试使用各种工具,但我无法让 ICC 配置文件显示在元数据中。 我想要实现的是在元数据中显示 ICC 配置文件标签,如以下屏幕截图所示: ExtractedInfoUsingExifTool.exe

我花了无数的时间并尝试了以下方法: PDF盒 Java代码

import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.common.PDStream;
import org.apache.pdfbox.pdmodel.graphics.color.PDOutputIntent;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;

public class EmbedICCWithPDFBox {
    public static void main(String[] args) {
        if (args.length != 3) {
            System.err.println("Usage: java EmbedICCWithPDFBox <pdfPath> <outputPdfPath> <iccPath>");
            return;
        }

        String pdfPath = args[0];
        String outputPdfPath = args[1];
        String iccPath = args[2];

        try {
            embedICCProfile(pdfPath, outputPdfPath, iccPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void embedICCProfile(String pdfPath, String outputPdfPath, String iccPath) throws IOException {
        PDDocument document = PDDocument.load(new File(pdfPath));

        try (FileInputStream iccStream = new FileInputStream(iccPath)) {
            PDStream iccPDStream = new PDStream(document, iccStream);
            iccPDStream.addCompression();

            PDOutputIntent outputIntent = new PDOutputIntent(document, iccPDStream);
            outputIntent.setInfo("sRGB IEC61966-2.1");
            outputIntent.setOutputCondition("sRGB IEC61966-2.1");
            outputIntent.setOutputConditionIdentifier("sRGB IEC61966-2.1");
            outputIntent.setRegistryName("http://www.color.org");

            document.getDocumentCatalog().addOutputIntent(outputIntent);

            System.out.println("ICC profile embedded successfully.");
        }

        document.save(outputPdfPath);
        document.close();
    }
}

iText Java代码

import com.itextpdf.kernel.pdf.*;
import java.io.FileInputStream;
import java.io.IOException;

public class EmbedICCWithIText {
    public static void embedICCProfile(String pdfPath, String outputPdfPath, String iccPath) throws IOException {
        PdfDocument pdfDoc = new PdfDocument(new PdfReader(pdfPath), new PdfWriter(outputPdfPath));

        try (FileInputStream iccStream = new FileInputStream(iccPath)) {
            byte[] iccProfileBytes = iccStream.readAllBytes();
            PdfStream iccPdfStream = new PdfStream(iccProfileBytes);
            iccPdfStream.put(PdfName.N, new PdfNumber(3));
            iccPdfStream.put(PdfName.Length, new PdfNumber(iccProfileBytes.length));
            iccPdfStream.put(PdfName.Filter, PdfName.FlateDecode);

            PdfDictionary outputIntentDict = new PdfDictionary();
            outputIntentDict.put(PdfName.Type, PdfName.OutputIntent);
            outputIntentDict.put(PdfName.S, PdfName.GTS_PDFA1);
            outputIntentDict.put(PdfName.OutputConditionIdentifier, new PdfString("AdobeRGB (1998)"));
            outputIntentDict.put(PdfName.OutputCondition, new PdfString("Adobe RGB (1998)"));
            outputIntentDict.put(PdfName.Info, new PdfString("Adobe RGB (1998)"));
            outputIntentDict.put(PdfName.DestOutputProfile, iccPdfStream);

            PdfArray outputIntents = new PdfArray();
            outputIntents.add(outputIntentDict);
            pdfDoc.getCatalog().put(PdfName.OutputIntents, outputIntents);

            System.out.println("ICC profile embedded successfully.");
        }
        pdfDoc.close();
    }

    public static void main(String[] args) {
        if (args.length != 3) {
            System.err.println("Usage: java EmbedICCWithIText <pdfPath> <outputPdfPath> <iccPath>");
            return;
        }

        String pdfPath = args[0];
        String outputPdfPath = args[1];
        String iccPath = args[2];

        try {
            embedICCProfile(pdfPath, outputPdfPath, iccPath);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

GhostScript 命令

gswin64c.exe -o C:/ghost/output_done_Ghostscript.pdf -sDEVICE=pdfwrite -dPDFSETTINGS=/prepress -sProcessColorModel=DeviceRGB -sOutputICCProfile=C:/ghost/AdobeRGB1998.icc -dEmbedAllFonts=true -dSubsetFonts=true -dMaxSubsetPct=100 -dPDFX=true -dCompatibilityLevel=1.4 C:/ghost/test1_no_xref.pdf

问题: 尽管报告嵌入成功,但 ExifTool 未检测到 ICC 配置文件:

exiftool.exe -G1 "C:/PDFWorkFlow/output_done_PDFBox.pdf"

什么可能导致 ICC 配置文件无法正确嵌入 PDF 中?是否有任何其他步骤或替代方法可以尝试确保 ICC 配置文件已嵌入且可检测? 任何见解或建议将不胜感激。谢谢!

java windows itext pdfbox ghostscript
1个回答
0
投票

我在您的文件中找到了 ICC 配置文件:

Root/Pages/Kids/[0]/Resources/ColorSpace/DefaultRGB/[1]
。这是 icc 配置文件可以出现的许多地方之一。在这个文件中,作者重新定义了默认的 RGB 色彩空间。

PDFBox 2.0 / jdk11 的此代码将 icc 配置文件添加为每个页面的默认 RGB:

public static void addDefaultRGB(String pdfPath, String outputPdfPath, String iccPath) throws IOException
{
    byte[] iccProfileData;
    try (InputStream is = new FileInputStream(iccPath))
    {
        iccProfileData = is.readAllBytes();
    }
    try (PDDocument document = PDDocument.load(new File(pdfPath)))
    {
        PDICCBased iccColorSpace = new PDICCBased(document);
        PDStream pdStream = iccColorSpace.getPDStream();
        try (OutputStream outputStream = pdStream.createOutputStream(COSName.FLATE_DECODE))
        {
            outputStream.write(iccProfileData);
        }
        pdStream.getCOSObject().setInt(COSName.N, 3);
        pdStream.getCOSObject().setItem(COSName.ALTERNATE, COSName.DEVICERGB);
        for (PDPage page : document.getPages())
        {
            PDResources resources = page.getResources();
            if (resources == null)
            {
                resources = new PDResources();
                page.setResources(resources);
            }
            resources.put(COSName.DEFAULT_RGB, iccColorSpace);
        }
        document.save(outputPdfPath);
    }
}
© www.soinside.com 2019 - 2024. All rights reserved.