Извлечение уменьшенного изображения из CGPDFPageRef - PullRequest
2 голосов
/ 31 августа 2010

Я пытаюсь создать миниатюры изображений для CGPDFDocument.
В разделе «Анализ документа 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 для представления моего эскиза.

Моя проблема в том, что полученное мной изображение имеет неправильные цвета и неправильные размеры, кроме случаев, когда я устанавливаю аргумент CGColorSpaceRef функции CGImageCreate() равным CGColorSpaceCreateDeviceGray(), и в этом случае я получаю (правильное) представление в оттенках серогоминиатюры, что, конечно, не то, что я хочу.
Из проверки словаря потока миниатюр я знаю, что формат изображения - CGPDFDataFormatRaw, а ColorSpace - DeviceRGB.Я также знаю, что к изображению применяются два фильтра (ASCII85Decode и FlateDecode), хотя я не уверен, имеет ли это какое-либо значение.

Будем очень благодарны за любые предложения или понимание того, почему это происходит и что делать, чтобы это исправить!

1 Ответ

0 голосов
/ 09 сентября 2010

мона в коде, указанном по указанной вами ссылке, содержит закомментированную строку:

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

}

Но, к сожалению, в конце я получаю серые точки на изображении.

...