Технические вопросы и ответы QA1509

Получение пиксельных данных от объекта CGImage

Q: Как делают я получаю доступ к пиксельным данным a CGImage объект?

A: Как делают я получаю доступ к пиксельным данным a CGImage объект?

На Mac OS X 10.5 или позже, новый вызов был добавлен, который позволяет Вам получать данные фактического пикселя из a CGImage объект. Этот вызов, CGDataProviderCopyData, возвращает объект CFData, содержащий пиксельные данные от рассматриваемого изображения. Пример использования этого вызова для получения пиксельных данных из a CGImage показан в Перечислении 1. Как только у Вас есть объект CFData с Вашей информацией о пикселе, можно вызвать CFDataGetBytePtr получить указатель на пиксельные данные, или CFDataGetBytes скопировать поддиапазон пиксельных данных.

Перечисление 1  , Получающее данные необработанного пикселя от a CGImage.

CFDataRef CopyImagePixels(CGImageRef inImage) {     return CGDataProviderCopyData(CGImageGetDataProvider(inImage)); }

До Mac OS X 10.5 пиксели изображения не так легко доступны. Единственный способ гарантировать доступ к эквивалентным битам состоит в том, чтобы создать растровый контекст с буфером памяти, который Вы указываете и затем рисуете CGImage к использованию контекста CGContextDrawImage. После рисования CGImage к контексту у Вас будет копия данных в буфере, который Вы указали (к которому можно также легко получить доступ с помощью CGBitmapContexGetData функция). Код в Перечислении 2 демонстрирует, как сделать это.

Для получения дополнительной информации о создании растровых контекстов для других форматов пикселя, посмотрите Кварц 2D Руководство по программированию.

Перечисление 2  , Получающее доступ к пиксельным данным a CGImage.

void ManipulateImagePixelData(CGImageRef inImage)
{
    // Create the bitmap context
    CGContextRef cgctx = CreateARGBBitmapContext(inImage);
    if (cgctx == NULL) 
    { 
        // error creating context
        return;
    }

     // Get image width, height. We'll use the entire image.
    size_t w = CGImageGetWidth(inImage);
    size_t h = CGImageGetHeight(inImage);
    CGRect rect = {{0,0},{w,h}}; 

    // Draw the image to the bitmap context. Once we draw, the memory 
    // allocated for the context for rendering will then contain the 
    // raw image data in the specified color space.
    CGContextDrawImage(cgctx, rect, inImage); 

    // Now we can get a pointer to the image data associated with the bitmap
    // context.
    void *data = CGBitmapContextGetData (cgctx);
    if (data != NULL)
    {

        // **** You have a pointer to the image data ****

        // **** Do stuff with the data here ****

    }

    // When finished, release the context
    CGContextRelease(cgctx); 
    // Free image data memory for the context
    if (data)
    {
        free(data);
    }

}

CGContextRef CreateARGBBitmapContext (CGImageRef inImage)
{
    CGContextRef    context = NULL;
    CGColorSpaceRef colorSpace;
    void *          bitmapData;
    int             bitmapByteCount;
    int             bitmapBytesPerRow;

     // Get image width, height. We'll use the entire image.
    size_t pixelsWide = CGImageGetWidth(inImage);
    size_t pixelsHigh = CGImageGetHeight(inImage);

    // Declare the number of bytes per row. Each pixel in the bitmap in this
    // example is represented by 4 bytes; 8 bits each of red, green, blue, and
    // alpha.
    bitmapBytesPerRow   = (pixelsWide * 4);
    bitmapByteCount     = (bitmapBytesPerRow * pixelsHigh);

    // Use the generic RGB color space.
    colorSpace = CGColorSpaceCreateWithName(kCGColorSpaceGenericRGB);
    if (colorSpace == NULL)
    {
        fprintf(stderr, "Error allocating color space\n");
        return NULL;
    }

    // Allocate memory for image data. This is the destination in memory
    // where any drawing to the bitmap context will be rendered.
    bitmapData = malloc( bitmapByteCount );
    if (bitmapData == NULL) 
    {
        fprintf (stderr, "Memory not allocated!");
        CGColorSpaceRelease( colorSpace );
        return NULL;
    }

    // Create the bitmap context. We want pre-multiplied ARGB, 8-bits 
    // per component. Regardless of what the source image format is 
    // (CMYK, Grayscale, and so on) it will be converted over to the format
    // specified here by CGBitmapContextCreate.
    context = CGBitmapContextCreate (bitmapData,
                                    pixelsWide,
                                    pixelsHigh,
                                    8,      // bits per component
                                    bitmapBytesPerRow,
                                    colorSpace,
                                    kCGImageAlphaPremultipliedFirst);
    if (context == NULL)
    {
        free (bitmapData);
        fprintf (stderr, "Context not created!");
    }

    // Make sure and release colorspace before returning
    CGColorSpaceRelease( colorSpace );

    return context;
}

Ссылки



История версии документа


ДатаПримечания
27.08.2008

Обновленный для обращения к CGDataProviderCopyData (), доступный с Mac OS X 10.5.

05.03.2007

Новый документ, описывающий, как получить доступ к пиксельным данным объекта CGImage