UIImageJPEGRepresentation () поток безопасен? - PullRequest
9 голосов
/ 27 апреля 2011

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

В следующем коде я обрезаю и масштабирую 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 ]

8 голосов
/ 27 апреля 2011

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

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

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

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

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

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

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

Edit3: Если вы работаете на iOS4 или более поздней версии, вы можете захотеть использоватькаркас ImageIO для вывода изображений, который с большей вероятностью является поточно-ориентированным:

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 );
}
2 голосов
/ 28 апреля 2011

Официальная позиция Apple заключается в том, что ни одна часть UIKit не является поточно-ориентированной.Тем не менее, остальная часть вашего кода, по-видимому, основана на кварце, который является поточно-ориентированным при использовании так, как вы его используете.

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

// ...
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);
0 голосов
/ 28 апреля 2011

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

...