如何将ICC添加到现有PDF文档

时间:2015-12-07 16:17:10

标签: java pdf pdfbox

我有一个使用CMYK颜色的现有PDF文档。它是使用我获得的特定ICC配置文件创建的。如果我在配置文件处于活动状态而非打开的情况下打开文档,颜色明显不同。据我所知,使用各种工具,文档中没有嵌入ICC配置文件。我想要做的是在PDF中嵌入ICC配置文件,以便第三方可以使用正确的颜色打开和查看它。我的理解是这可能与PDF格式有关,但我尝试过的任何东西似乎都没有用。

我在查看一些示例的基础上使用PDFBox编写了一个小程序,但似乎没有任何效果。我觉得我在某个地方错过了一步。

package com.mapsherpa.tools.addicc;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.InputStream;

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

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

public class AddICC {

public AddICC() {
    // TODO Auto-generated constructor stub
}

public static void main(String[] args) {
    AddICC app = new AddICC();
    try {
        if( args.length != 3) {
            app.usage();
        } else {
            app.doIt(args[0], args[1], args[2]);
        }
    }
    catch (Exception e) {
        e.printStackTrace();
    }
}

private void doIt(String input, String output, String icc) throws IOException {
    // TODO Auto-generated method stub

    System.out.printf("Adding %s to %s and saving as %s\n", icc, input, output);

    PDDocument doc = null;
    try
    {
        File file = new File(input);
        doc = PDDocument.load(file);
        PDDocumentCatalog cat = doc.getDocumentCatalog();
        PDMetadata metadata = new PDMetadata(doc);
        cat.setMetadata(metadata);
        InputStream colorProfile = new FileInputStream(icc);
        PDOutputIntent oi = new PDOutputIntent(doc, colorProfile);
        oi.setInfo("SWOP (Coated), 20%, GCR, None");
        oi.setOutputCondition("SWOP (Coated), 20%, GCR, None");
        oi.setOutputConditionIdentifier("SWOP (Coated), 20%, GCR, None");
        oi.setRegistryName("http://www.color.org");
        cat.addOutputIntent(oi);
        doc.save(output);
        System.out.println("Finished adding color profile");
    } 
    catch (Exception e)
    {
        System.out.println("Exception processing color profile");
        e.printStackTrace();
    }
    finally
    {
        if (doc != null) {
            doc.close();
        }
    }

}

private void usage() {
    // TODO Auto-generated method stub
    System.err.println("Usage: " + this.getClass().getName() + " <input-file> <output-file> <icc-file>");
}

}

我不是Java专家,但我确实设法让它运行,它似乎做了一些事情,但我仍然没有看到正确的颜色,并且没有迹象表明使用imagemagick或pdfinfo它有颜色配置文件。

我觉得我应该以某种方式指出文档颜色空间是ICCBased但我看不到使用PDFBox API做任何明显的方法。

任何帮助都会受到赞赏(甚至被告知它不起作用!)

编辑:

我认为这是按照写入的方式工作,因为它将所需的输出意图添加到文档中。但是,我也发现这不是我需要的 - 我现在相信我需要它来添加一个/ ICCBased流到PDF - 叹息。下面更新的代码基于this stackoverflow question's更新的createColorSpace函数。

private static PDColorSpace createColorSpace( PDDocument doc, ColorSpace cs ) throws IOException
{
    PDColorSpace retval = null;
    if( cs.isCS_sRGB() )
    {
        retval = PDDeviceRGB.INSTANCE;
    }
    else if( cs instanceof ICC_ColorSpace )
    {
        ICC_ColorSpace ics = (ICC_ColorSpace)cs;

        // CREATING MANUALLY THE COS ARR  ****************************
        COSArray cosArray = new COSArray();  
        cosArray.add(COSName.ICCBASED);
        PDStream pdStream = new PDStream(doc);
        cosArray.add(pdStream.getStream());

        // USING DIFFERENT CONSTRUTOR  *******************************
        PDICCBased pdCS = new PDICCBased( cosArray );
        retval = pdCS;
        COSArray ranges = new COSArray();
        for( int i=0; i<cs.getNumComponents(); i++ )
        {
            ranges.add( new COSFloat( ics.getMinValue( i ) ) );
            ranges.add( new COSFloat( ics.getMaxValue( i ) ) );
        }
        PDStream iccData = pdCS.getPDStream();
        OutputStream output = null;
        try
        {
            output = ((COSStream)iccData.getCOSObject()).createFilteredStream();
            output.write( ics.getProfile().getData() );
        }
        finally
        {
            if( output != null )
            {
                output.close();
            }
        }
        pdCS.setNumberOfComponents( cs.getNumComponents() );
    }
    else
    {
        throw new IOException( "Not yet implemented:" + cs );
    }
    return retval;
}

private void doIt(String input, String output, String icc) throws IOException {
    // TODO Auto-generated method stub

    System.out.printf("Adding %s to %s and saving as %s\n", icc, input, output);

    PDDocument doc = null;
    try
    {
        File file = new File(input);
        doc = PDDocument.load(file);

        ICC_ColorSpace iccColorSpace = new ICC_ColorSpace(ICC_Profile.getInstance(icc));

        PDColorSpace colorSpace = createColorSpace(doc, iccColorSpace);

        doc.save(output);
        System.out.println("Finished adding color profile");
    } 
    catch (Exception e)
    {
        System.out.println("Exception processing color profile");
        e.printStackTrace();
    }
    finally
    {
        if (doc != null) {
            doc.close();
        }
    }

}

此代码现在有一个例外:

java.io.IOException: Unknown color space number of components:-1
at org.apache.pdfbox.pdmodel.graphics.color.PDICCBased.getAlternateColorSpace(PDICCBased.java:269)
at org.apache.pdfbox.pdmodel.graphics.color.PDICCBased.loadICCProfile(PDICCBased.java:151)
at org.apache.pdfbox.pdmodel.graphics.color.PDICCBased.<init>(PDICCBased.java:89)
at com.mapsherpa.tools.addicc.AddICC.createColorSpace(AddICC.java:65)
at com.mapsherpa.tools.addicc.AddICC.doIt(AddICC.java:109)
at com.mapsherpa.tools.addicc.AddICC.main(AddICC.java:39)

在这行代码中:

cosArray.add(pdStream.getStream());

我在这段代码和另一个答案之间可以看到的唯一区别是我正在加载现有的PDF文档,而不是创建一个新的空文档。

为了进行测试,我使用的是Adobe的US Web(Coated)SWOP v2 icc配置文件,但我测试的任何配置文件都是相同的例外。根据我对阅读PDFBox源码的理解,它不是配置文件的问题,而是从文档中读取流(没有/ ICCBased流,这个问题的全部要点:))

编辑2:如果与PDFBox 1.8.10一起使用,上面的代码实际上没有异常运行 - 显然我已经在2.0.0 RC2中链接而没有意识到它(总Java新手)。

0 个答案:

没有答案