从 CGPDFPageRef 中提取缩略图

发布于 2024-09-17 17:51:11 字数 998 浏览 9 评论 0原文

我正在尝试为 CGPDFDocument 创建缩略图。
在 Quartz 编程指南的 PDF 文档解析部分,有以下代码:

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中提取图像的类似问题: 从 PDF 中提取图像

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

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

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

I am attempting to create thumbnail images for a CGPDFDocument.
In the PDF Document Parsing section of the Quartz Programming Guide, there is the following code:

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);

The next step would be to use data to create the image.
Sugar answers the similar question of extracting images from PDF here:
Extracting images from a PDF

I am attempting to use the decodeValuesFromImageDictionary() and getImageRef() functions listed in his answer to create a UIImage to represent my thumbnail.

My problem is that the image I obtain has wrong colors and wrong dimensions, except when I set the CGColorSpaceRef argument of the CGImageCreate() function to CGColorSpaceCreateDeviceGray(), in which case I get the (correct) greyscale representation of the thumbnail which of course is not what I want.
I know from inspecting the thumbnail stream dictionary that the image format is CGPDFDataFormatRaw and the ColorSpace is DeviceRGB. I also know that two filters (ASCII85Decode and FlateDecode) are applied to the image, even though I am not sure if this is of any significance.

Any suggestions or insight as to why this happens and what to do to fix it is greatly appreciated!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小巷里的女流氓 2024-09-24 17:51:11

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

//      cgColorSpace = colorSpaceFromPDFArray(colorSpaceArray);

CGColorSpaceCreateDeviceRGB 不是分析 colorSpaceArray 并获取准确的颜色空间,而是分配给 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);

不幸的是我最后在图像上出现了一些灰点。

mona m in code provided by link you specified contains commented line:

//      cgColorSpace = colorSpaceFromPDFArray(colorSpaceArray);

Instead of analyzing colorSpaceArray and getting accurate Color Space a CGColorSpaceCreateDeviceRGB is assigned to cgColorSpace variable which is wrong.

Here is an implementation of missing method, I found it in the internet.

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);

}

But unfortunately I am getting some grey dots on image at the end.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文