我正在缩放并裁剪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];
});
});
我尝试使用CGDataProviderRef获取NSData,但是当我最终获得NSData时,将它放入UIImage中的UIImageView中显示任何内容。
所以底线问题是。我可以使用GCD在块中的另一个线程中执行[UIImage imageWithData:]
和UIImageJPEGRepresentation
吗?
答案 0 :(得分:8)
您可以在后台使用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
很难找到示例代码,这是一种使用ImageIO保存PNG图像的方法(基于“使用Quartz编程:Mac OS X中的2D和PDF图形”中的代码):
// 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 );
}
答案 1 :(得分:2)
Apple的官方立场是UIKit的任何部分都不是线程安全的。但是,您的其余代码似乎是基于Quartz的,当您使用它时, 是线程安全的。
你可以在后台线程上做所有事情,然后回到主要的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);
答案 2 :(得分:0)
我认为它是线程安全的,因为我做类似的事情来调整UIImage的大小,或者将图像数据存储到后台线程中的数据库。并且,主线程有时被命名为UI线程。有关更新屏幕的任何内容都应在UI线程上执行。但是,UIImage是存储图像数据的对象。它不是UIView的子类。所以,它是线程安全的。