Это 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. Таким образом, это потокобезопасно.