从CGPDFPageRef中提取缩略图

时间:2010-08-31 11:57:09

标签: iphone image thumbnails quartz-graphics cgpdfdocument

我正在尝试为CGPDFDocument创建缩略图 在Quartz Programming Guide的PDF Document Parsing部分中,有以下代码:

CGPDFDictionaryRef d;
CGPDFStreamRef stream; // represents a sequence of bytes
d = CGPDFPageGetDictionary(page);
// check for thumbnail data
if (CGPDFDictionaryGetStream (d, “Thumb”, &stream)){
    // get the data if it exists
    data = CGPDFStreamCopyData (stream, &format);

下一步是使用data来创建图像 Sugar回答了从PDF中提取图像的类似问题: Extracting images from a PDF

我正在尝试使用其答案中列出的decodeValuesFromImageDictionary()getImageRef()函数创建一个UIImage来表示我的缩略图。

我的问题是我获得的图像有错误的颜色和错误的尺寸,除非我将CGImageCreate()函数的CGColorSpaceRef参数设置为CGColorSpaceCreateDeviceGray(),在这种情况下我得到(正确的)灰度缩略图的表示当然不是我想要的。
通过检查缩略图流字典,我知道图像格式是CGPDFDataFormatRaw,而ColorSpace是DeviceRGB。我也知道有两个滤镜(ASCII85Decode和FlateDecode)应用于图像,即使我不确定这是否有意义。

非常感谢任何关于为什么会发生这种情况的建议或见解以及如何解决这个问题!

1 个答案:

答案 0 :(得分:0)

您指定的链接提供的代码中的mona m包含注释行:

//      cgColorSpace = colorSpaceFromPDFArray(colorSpaceArray);

不是分析colorSpaceArray并获得准确的色彩空间,而是将CGColorSpaceCreateDeviceRGB分配给错误的cgColorSpace变量。

这是一种缺失方法的实现,我在互联网上找到了它。

CGColorSpaceRef colorSpaceFromPDFArray(CGPDFArrayRef colorSpaceArray){
CGColorSpaceRef       cgColorSpace = NULL, alternateColorSpace = NULL;
CGPDFStreamRef        stream;
const char            *colorSpaceName = NULL, *alternateColorSpaceName = NULL;
CGPDFInteger        numberOfComponents;
CGPDFDictionaryRef    dict;
bool                retrieved;
CGFloat                *range;
CGPDFArrayRef        rangeArray;

if (CGPDFArrayGetName(colorSpaceArray, 0, &colorSpaceName)) {
    if (strcmp(colorSpaceName, "ICCBased") == 0) {
        if (CGPDFArrayGetStream(colorSpaceArray, 1, &stream)) {
            dict = CGPDFStreamGetDictionary(stream);

            // First obtain the alternate color space if present
            if (CGPDFDictionaryGetName(dict, "Alternate",  &alternateColorSpaceName)) {
                if (strcmp(alternateColorSpaceName, "DeviceRGB") == 0) {
                    alternateColorSpace = CGColorSpaceCreateDeviceRGB();
                } else if (strcmp(alternateColorSpaceName, "DeviceGray") == 
                           0) {
                    alternateColorSpace = CGColorSpaceCreateDeviceGray();
                } else if (strcmp(alternateColorSpaceName, "DeviceCMYK") == 
                           0) {
                    alternateColorSpace = CGColorSpaceCreateDeviceCMYK();
                }
            }

            // Obtain the preferential color space
            CGPDFDataFormat        dataFormat;
            CFDataRef            colorSpaceDataPtr = 
            CGPDFStreamCopyData(stream, &dataFormat);

            if (dataFormat == CGPDFDataFormatRaw) {
                CGDataProviderRef    profile = 
                CGDataProviderCreateWithCFData(colorSpaceDataPtr);

                retrieved = CGPDFDictionaryGetInteger(dict, "N", 
                                                      &numberOfComponents);

                // Deduce an alternate color space if we don't have one 
                //already
                if (alternateColorSpace == NULL) {
                    switch (numberOfComponents) {
                        case 1:
                            alternateColorSpace = CGColorSpaceCreateDeviceGray();
                            break;
                        case 3:
                            alternateColorSpace = CGColorSpaceCreateDeviceRGB();
                            break;
                        case 4:
                            alternateColorSpace = CGColorSpaceCreateDeviceCMYK();
                            break;
                        default:
                            break;
                    }
                }

                range = malloc(numberOfComponents * 2 * sizeof(CGFloat));
                if (!CGPDFDictionaryGetArray(dict, "Range", &rangeArray)) {
                    for (int i = 0; i < numberOfComponents * 2; i += 2) {
                        range[i] = (i % 2 == 0) ? 0.0 : 1.0;
                    }
                } else {
                    size_t count = CGPDFArrayGetCount(rangeArray);
                    for (int i = 0; i < count; i++) {
                        (void)CGPDFArrayGetNumber(rangeArray, i, &range[i]);
                    }

                }


                cgColorSpace = CGColorSpaceCreateICCBased(numberOfComponents, range, profile, 
                                           alternateColorSpace);
                CGDataProviderRelease(profile);
                free(range);
                if (cgColorSpace) {
                    // Since we have a preferential color space, we no 
                    //longer need the hang on to the alternate color space
                    CGColorSpaceRelease(alternateColorSpace);
                } else {
                    cgColorSpace = alternateColorSpace;
                }

            } else if (dataFormat == CGPDFDataFormatJPEGEncoded) {
                //
            } else if (dataFormat == CGPDFDataFormatJPEG2000) {
                //
            }
        }
    } else if (strcmp(colorSpaceName, "Indexed") == 0) {
        CGColorSpaceRef baseSpace;
        CGPDFArrayRef    base = NULL;
        CGPDFInteger    highValue = 0;
        CGPDFStreamRef    stream = NULL;
        CGPDFStringRef    string;
        const unsigned char *chars;
        const char        *namedColorSpaceName;

        if (CGPDFArrayGetArray(colorSpaceArray, 1, &base)) {
            baseSpace = colorSpaceFromPDFArray(base);
        } else if (CGPDFArrayGetName(colorSpaceArray, 1, 
                                     &namedColorSpaceName)) {
            if (strcmp(namedColorSpaceName, "DeviceRGB") == 0) {
                baseSpace = CGColorSpaceCreateDeviceRGB();
            } else if (strcmp(namedColorSpaceName, "DeviceGray") == 0) {
                baseSpace = CGColorSpaceCreateDeviceGray();
            } else if (strcmp(namedColorSpaceName, "DeviceCMYK") == 0) {
                baseSpace = CGColorSpaceCreateDeviceCMYK();
            }
        }

        retrieved = CGPDFArrayGetInteger(colorSpaceArray, 2, &highValue);

        if (CGPDFArrayGetStream(colorSpaceArray, 3, &stream)) {
            chars = CFDataGetBytePtr(CGPDFStreamCopyData(stream, NULL));
        } else if (CGPDFArrayGetString(colorSpaceArray, 3, &string)) {
            chars = CGPDFStringGetBytePtr(string);
        } else {

            // TODO: Raise some error state?
        }

        cgColorSpace = CGColorSpaceCreateIndexed(baseSpace, highValue, 
                                                 chars);
    }
}

return (CGColorSpaceRef)CFMakeCollectable(cgColorSpace);

}

但不幸的是,我最终在图像上得到了一些灰点。