Search code examples
pdfcore-graphicsquartz-graphicscolor-space

Modify pdf metadata color space using CoreGraphics


I m trying to change color space for image objects of a pdf file, but first problem is that I cannot find ICC color profile inside pdf metadata.

All I have in Metadata is one array with 2 components:

ColorSpace :
    Name value: ICCBased
    Stream value (null) 

And when I get the Stream parsed into a dictionary:

Color Space Name ICCBased
  Filter :
    Name value: FlateDecode
  Length :
   integer value: 389757 
  N :
   integer value: 4 
  Range :
   ARRAY with value:
    integer value: 0 
    integer value: 1 
    integer value: 0 
    integer value: 1 
    integer value: 0 
    integer value: 1 
    integer value: 0 
    integer value: 1 

But I am unable to find in metadata the ICC profile data used on the color space of the image, the one you can see with acrobat:

enter image description here

By the way, if you are interested on how to get metadata form pdf file with coreGraphics here I put some code:

...

CGPDFDocumentRef pdfDocument = CGPDFDocumentCreateWithURL(pdfURL);

CGPDFPageRef page = CGPDFDocumentGetPage(pdfDocument, pageNumber);

CGPDFContentStreamRef contentStream =

CGPDFContentStreamCreateWithPage(page); CGPDFOperatorTableRef

operatorTable = CGPDFOperatorTableCreate();

CGPDFOperatorTableSetCallback(operatorTable, "Do", &op_Do);

CGPDFScannerRef contentStreamScanner =

CGPDFScannerCreate(contentStream, operatorTable, NULL);

CGPDFScannerScan(contentStreamScanner);

....

And then on the callback:

static void op_Do(CGPDFScannerRef s, void *info) {

CGPDFObjectRef imageObject = CGPDFContentStreamGetResource(cs, "XObject", imageLabel);

CGPDFStreamRef xObjectStream;

if (CGPDFObjectGetValue(imageObject, kCGPDFObjectTypeStream, &xObjectStream)) {

    CGPDFDictionaryRef xObjectDictionary = CGPDFStreamGetDictionary(xObjectStream);

    const char *subtype;

    CGPDFDictionaryGetName(xObjectDictionary, "Subtype", &subtype);

    if (strcmp(subtype, "Image") == 0) {

        NSString *imageID = [NSString stringWithCString: imageLabel encoding: NSASCIIStringEncoding];

        CGPDFDictionaryApplyFunction(xObjectDictionary, ListDictionaryObjects, NULL);

if (CGPDFDictionaryGetName(xObjectDictionary, "ColorSpace", &colorSpaceName)){

            fprintf(stdout,"Color Space Name %s\n", colorSpaceName);

}else{

            //Getting Color space array
            CGPDFArrayRef objectArray;

            CGPDFDictionaryGetArray(xObjectDictionary, "ColorSpace", &objectArray);
            //getting each array position             
            CGPDFStreamRef colorsSpaceStream;

            CGPDFArrayGetName(objectArray, 0, &colorSpaceName);

            fprintf(stdout,"Color Space Name %s\n", colorSpaceName);

            CGPDFArrayGetStream(objectArray, 1, &colorsSpaceStream);

            CGPDFDictionaryRef dictionary = CGPDFStreamGetDictionary(colorsSpaceStream);

            CGPDFDictionaryApplyFunction(dictionary, ListDictionaryObjectsLow, NULL);

}

...

And finally in ListDictionaryObjects functions I go through dictionary objects:

void ListDictionaryObjects (const char *key, CGPDFObjectRef object, void *info) { fprintf(stdout, "%s :\n", key);

CGPDFObjectType type = CGPDFObjectGetType(object);
switch (type) {
    case kCGPDFObjectTypeDictionary: {
        CGPDFDictionaryRef objectDictionary;
        if (CGPDFObjectGetValue(object, kCGPDFObjectTypeDictionary, &objectDictionary)) {
            fprintf(stdout," Dictionary value with: %zd elements\n", CGPDFDictionaryGetCount(objectDictionary));
            CGPDFDictionaryApplyFunction(objectDictionary, ListDictionaryObjectsLow, NULL);
        }
    }
        break;
    case kCGPDFObjectTypeInteger: {
        CGPDFInteger objectInteger;
        if (CGPDFObjectGetValue(object, kCGPDFObjectTypeInteger, &objectInteger)) {
           fprintf(stdout," integer value: %ld \n", (long int)objectInteger);
        }

    }
    break;
    case kCGPDFObjectTypeReal:{
        CGPDFReal objectReal;
        if (CGPDFObjectGetValue(object, kCGPDFObjectTypeReal, &objectReal)){
            fprintf(stdout," real value: %5.2f\n", objectReal);
        }
    } ...

Solution

  • Assigning a new color profile (i.e. without altering values in the object) to all objects of a certain color space can be done by creating a Quartz Filter with ColorSync Utility.

    A technical note from the Mac Developer Library from 2005 about "ColorSync on Mac OS X" stated:

    Quartz filters are currently available only through the various Mac OS X system-built utilities and applications. However, a new set of API's will be forthcoming.

    But I could not find any other mention to Quartz Filters in Apple's documentation for developers.

    I know this is not terribly helpful, but maybe it gives you a hint of were to look.

    Edit: See this answer to "Apply a Quartz filter while saving PDF under Mac OS X 10.6.3"