Это UIImageJPEGRepresentation() ориентирован на многопотоковое исполнение?

Я масштабирую и обрезаю UIImage и я хочу иметь возможность сделать это в блоке, который является потокобезопасным. Я не мог найти в документах ли UIImageJPEGRepresentation является потокобезопасным.

в следующем коде я обрезаю и масштабирую a CGImage, затем я создаю UIImage от этого и получить UIImageJPEGRepresentation. Конечная цель этого блока-получить NSData* из масштабированной / обрезанной версии.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
    CGImageRef imageRef = photo.CGImage;
    CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
    CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);

    CGContextRef bitmap;

    if (photo.imageOrientation == UIImageOrientationUp || photo.imageOrientation == UIImageOrientationDown) {
        bitmap = CGBitmapContextCreate(NULL, kFINAL_WIDTH, kFINAL_HEIGHT, CGImageGetBitsPerComponent(imageRef), 0, colorSpaceInfo, bitmapInfo);
    } else {
        bitmap = CGBitmapContextCreate(NULL, kFINAL_HEIGHT, kFINAL_WIDTH, CGImageGetBitsPerComponent(imageRef), 0, colorSpaceInfo, bitmapInfo);
    }

    CGContextSetInterpolationQuality(bitmap, kCGInterpolationHigh);
    CGContextDrawImage(bitmap, drawRect, imageRef);
    CGImageRef ref = CGBitmapContextCreateImage(bitmap);

    NSData *finalData = UIImageJPEGRepresentation([UIImage imageWithCGImage:ref], 1.0);

    CGContextRelease(bitmap);
    CGImageRelease(ref);

    dispatch_async(dispatch_get_main_queue(), ^{
        [self.delegate sendNSDataBack:finalData];
    });
});

Я попытался получить NSData с помощью CGDataProviderRef, но когда я наконец получил NSData, помещая его в UIImage в UIImageView, ничего не отображал.

Итак, Нижний вопрос. Могу ли я сделать [UIImage imageWithData:] и UIImageJPEGRepresentation в другом потоке в блоке с использованием GCD?

3 ответов


вы можете использовать UIImageJPEGRepresentation() в фоновом режиме (я использую его таким образом в текущем проекте).

однако то, что вы не можете сделать, это создать UIImage так, как вы делаете в фоновом режиме,[UIImage imagewithCGImage] вызов должен выполняться в основном потоке (как правило, все вызовы UIKit должны выполняться в основном потоке).

Это похоже на случай, когда вам может понадобиться вложенные блоки.

Edit: мой собственный код, который я нашел, вызывает [UIImage imagewithCGImage] а в фоновый поток, но я все еще подозрителен, что может вызвать проблемы в некоторых случаях. Но мой код работает.

Edit2: я только что заметил, что вы изменяете размер изображения, UIImage+Resize. В этом посте есть очень хороший класс, связанный с этим, который был построен для этого надежным способом:

http://vocaro.com/trevor/blog/2009/10/12/resize-a-uiimage-the-right-way/

вы действительно должны прочитать всю страницу, чтобы понять нюансы изменения размера изображения. Как я уже сказал, я использую это из фонового потока, хотя часть того, что он делает внутри, - это то, что вы делали.

Edit3: если вы работаете на iOS4 или более поздней версии, вы можете изучить использование imageio framework для вывода изображений, что, скорее всего, будет потокобезопасным:

http://developer.apple.com/graphicsimaging/workingwithimageio.html

пример кода для этого трудно найти, вот метод, который сохраняет PNG-изображение с помощью ImageIO (на основе кода в " Программирование с кварцем: 2D и PDF графики в Mac OS X):

// You'll need both ImageIO and MobileCoreServices frameworks to have this compile
#import <ImageIO/ImageIO.h>
#import <MobileCoreServices/MobileCoreServices.h>

void exportCGImageToPNGFileWithDestination( CGImageRef image, CFURLRef url)
{
    float resolution = 144;
    CFTypeRef keys[2];
    CFTypeRef values[2];
    CFDictionaryRef options = NULL;

    // Create image destination to go into URL, using PNG
    CGImageDestinationRef imageDestination = CGImageDestinationCreateWithURL( url, kUTTypePNG, 1, NULL);

    if ( imageDestination == NULL )
    {
        fprintf( stderr, "Error creating image destination\n");
        return;
    }

    // Set the keys to be the X and Y resolution of the image
    keys[0] = kCGImagePropertyDPIWidth;
    keys[1] = kCGImagePropertyDPIHeight;

    // Create a number for the DPI value for the image
    values[0] = CFNumberCreate( NULL, kCFNumberFloatType, &resolution );
    values[1] = values[0];

    // Options dictionary for output
    options = CFDictionaryCreate(NULL,
                                 (const void **)keys,
                                 (const void **)values,
                                 2,
                                 &kCFTypeDictionaryKeyCallBacks,
                                 &kCFTypeDictionaryValueCallBacks);

    CFRelease(values[0]);

    // Adding the image to the destination
    CGImageDestinationAddImage( imageDestination, image, options );
    CFRelease( options );

    // Finalizing writes out the image to the destination
    CGImageDestinationFinalize( imageDestination );
    CFRelease( imageDestination );
}

is thread-safe при использовании в том, как вы его используете.

Вы можете делать все в фоновом потоке, а затем выполнить вызов UIImageJPEGRepresentation() вернуться на main:

// ...
CGImageRef ref = CGBitmapContextCreateImage(bitmap);

dispatch_async(dispatch_get_main_queue(), ^ {
    NSData *finalData = UIImageJPEGRepresentation([UIImage imageWithCGImage:ref], 1.0);
    [self.delegate sendNSDataBack:finalData];
});

CGContextRelease(bitmap);
CGImageRelease(ref);

Я думаю, что это потокобезопасно, потому что я делаю подобные вещи, чтобы изменить размер UIImage или сохранить данные изображения в базе данных в фоновом потоке. И, основной поток иногда называется UI thread. Все, что касается обновления экрана, должно выполняться в потоке пользовательского интерфейса. Но UIImage является объектом для хранения данных изображения. Он не является подклассом из UIView. Таким образом, это потокобезопасно.