- 浏览: 199568 次
- 性别:
- 来自: 广州
文章分类
最新评论
-
feihumingyue:
nice 很好啊
JSF中如何使用FacesContext类 -
wgcniler:
请问如果传到存储过程的参数是一个嵌套表的话该怎么写?自定义的o ...
spring中调用存储过程 -
wgcniler:
请问如果传到存储过程的参数是ARRAY,但ARRAY的元素不是 ...
spring中调用存储过程 -
bengan:
谢谢楼上的提示
关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案 -
gypgyp:
用xcode的菜单:product/profile,弹出窗口中 ...
关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案
转载自 http://stackoverflow.com/questions/1282830/uiimagepickercontroller-uiimage-memory-and-more
I've noticed that there are many questions about how to handle UIImage objects, especially in conjunction with UIImagePickerController and then displaying it in a view (usually a UIImageView). Here is a collection of common questions and their answers. Feel free to edit and add your own.
I obviously learnt all this information from somewhere too. Various forum posts, StackOverflow answers and my own experimenting brought me to all these solutions. Credit goes to those who posted some sample code that I've since used and modified. I don't remember who you all are - but hats off to you!
How Do I Select An Image From the User's Images or From the Camera?
You use UIImagePickerController. The documentation for the class gives a decent overview of how one would use it, and can be found here.
Basically, you create an instance of the class, which is a modal view controller, display it, and set yourself (or some class) to be the delegate. Then you'll get notified when a user selects some form of media (movie or image in 3.0 on the 3GS), and you can do whatever you want.
My Delegate Was Called - How Do I Get The Media?
The delegate method signature is the following:
-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info;
You should put a breakpoint in the debugger to see what's in the dictionary, but you use that to extract the media. For example:
UIImage* image =[info objectForKey:UIImagePickerControllerOriginalImage];
There are other keys that work as well, all in the documentation.
OK, I Got The Image, But It Doesn't Have Any Geolocation Data. What gives?
Unfortunately, Apple decided that we're not worthy of this information. When they load the data into the UIImage, they strip it of all the EXIF/Geolocation data. But, see the answer to the next question for a way to get at the original image data (on iOS 4+)
Can I Get To The Original File Representing This Image on the Disk?
As of iOS 4, you can, but it's very annoying. Use the following code to get an AssetsLibrary URL for the image, and then pass the URL to assetForURL:resultBlock:failureBlock:
NSURL *referenceURL =[info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary*library =[[ALAssetsLibrary alloc] init];
[library assetForURL:referenceURL resultBlock:^(ALAsset*asset){
// code to handle the asset here
} failureBlock:^(NSError*error){
// error handling
}];
[library release];
It's annoying because the user is asked if your application can access your current location, which is rather confusing since you are actually trying to access the user's photo library. Unless you're actually trying to get at the EXIF location data, the user is going to be a bit confused.
Make sure to include the AssetsLibrary framework to make this work.
How Can I Look At The Underlying Pixels of the UIImage?
Since the UIImage is immutable, you can't look at the direct pixels. However, you can make a copy. The code to this looks something like this:
UIImage* image =...;// An image
NSData* pixelData =(NSData*)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsignedchar* pixelBytes =(unsignedchar*)[pixelData bytes];
// Take away the red pixel, assuming 32-bit RGBA
for(int i =0; i <[pixelData length]; i +=4){
pixelBytes[i]=0;// red
pixelBytes[i+1]= pixelBytes[i+1];// green
pixelBytes[i+2]= pixelBytes[i+2];// blue
pixelBytes[i+3]= pixelBytes[i+3];// alpha
}
However, note that CGDataProviderCopyData provides you with an "immutable" reference to the data - meaning you can't change it (and you may get a BAD_ACCESS error if you do). Look at the next question if you want to see how you can modify the pixels.
How Do I Modify The Pixels of the UIImage?
The UIImage is immutable, meaning you can't change it. Apple posted a great article on how to get a copy of the pixels and modify them, and rather than copy and paste it here, you should just go read the article.
Once you have the bitmap context as they mention in the article, you can do something similar to this to get a new UIImage with the modified pixels:
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
Do remember to release your references though, otherwise you're going to be leaking quite a bit of memory.
After I Select 3 Images From The Camera, I Run Out Of Memory. Help!
You have to remember that even though on disk these images take up only a few hundred kilobytes at most, that's because they're compressed as a PNG or JPG. When they are loaded into the UIImage, they become uncompressed. A quick over-the-envelope calculation would be:
width x height x 4= bytes in memory
That's assuming 32-bit pixels. If you have 16-bit pixels (some JPGs are stored as RGBA-5551), then you'd replace the 4 with a 2.
Now, images taken with the camera are 1600 x 1200 pixels, so let's do the math:
1600 x 1200 x 4=7,680,000 bytes =~8 MB
8 MB is a lot, especially when you have a limit of around 24 MB for your application. That's why you run out of memory.
OK, I Understand Why I Have No Memory. What Do I Do?
There is never any reason to display images at their full resolution. The iPhone has a screen of 480 x 320 pixels, so you're just wasting space. If you find yourself in this situation, ask yourself the following question: Do I need the full resolution image?
If the answer is yes, then you should save it to disk for later use.
If the answer is no, then read the next part.
Once you've decided what to do with the full-resolution image, then you need to create a smaller image to use for displaying. Many times you might even want several sizes for your image: a thumbnail, a full-size one for displaying, and the original full-resolution image.
OK, I'm Hooked. How Do I Resize the Image?
Unfortunately, there is no defined way how to resize an image. Also, it's important to note that when you resize it, you'll get a new image - you're not modifying the old one.
There are a couple of methods to do the resizing. I'll present them both here, and explain the pros and cons of each.
Method 1: Using UIKit
+(UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;
{
// Create a graphics image context
UIGraphicsBeginImageContext(newSize);
// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
// Get the new image from the context
UIImage* newImage =UIGraphicsGetImageFromCurrentImageContext();
// End the context
UIGraphicsEndImageContext();
// Return the new image.
return newImage;
}
This method is very simple, and works great. It will also deal with the UIImageOrientation for you, meaning that you don't have to care whether the camera was sideways when the picture was taken. However, this method is not thread safe, and since thumbnailing is a relatively expensive operation (approximately ~2.5s on a 3G for a 1600 x 1200 pixel image), this is very much an operation you may want to do in the background, on a separate thread.
Method 2: Using CoreGraphics
+(UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize;
{
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGImageRef imageRef =[sourceImage CGImage];
CGBitmapInfo bitmapInfo =CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);
if(bitmapInfo == kCGImageAlphaNone){
bitmapInfo = kCGImageAlphaNoneSkipLast;
}
CGContextRef bitmap;
if(sourceImage.imageOrientation ==UIImageOrientationUp|| sourceImage.imageOrientation ==UIImageOrientationDown){
bitmap =CGBitmapContextCreate(NULL, targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}else{
bitmap =CGBitmapContextCreate(NULL, targetHeight, targetWidth,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}
if(sourceImage.imageOrientation ==UIImageOrientationLeft){
CGContextRotateCTM(bitmap, radians(90));
CGContextTranslateCTM(bitmap,0,-targetHeight);
}elseif(sourceImage.imageOrientation ==UIImageOrientationRight){
CGContextRotateCTM(bitmap, radians(-90));
CGContextTranslateCTM(bitmap,-targetWidth,0);
}elseif(sourceImage.imageOrientation ==UIImageOrientationUp){
// NOTHING
}elseif(sourceImage.imageOrientation ==UIImageOrientationDown){
CGContextTranslateCTM(bitmap, targetWidth, targetHeight);
CGContextRotateCTM(bitmap, radians(-180.));
}
CGContextDrawImage(bitmap,CGRectMake(0,0, targetWidth, targetHeight), imageRef);
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return newImage;
}
The benefit of this method is that it is thread-safe, plus it takes care of all the small things (using correct color space and bitmap info, dealing with image orientation) that the UIKit version does.
How Do I Resize and Maintain Aspect Ratio (like the AspectFill option)?
It is very similar to the method above, and it looks like this:
+(UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSizeWithSameAspectRatio:(CGSize)targetSize;
{
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor =0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint =CGPointMake(0.0,0.0);
if(CGSizeEqualToSize(imageSize, targetSize)== NO){
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if(widthFactor > heightFactor){
scaleFactor = widthFactor;// scale to fit height
}
else{
scaleFactor = heightFactor;// scale to fit width
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if(widthFactor > heightFactor){
thumbnailPoint.y =(targetHeight - scaledHeight)*0.5;
}
elseif(widthFactor < heightFactor){
thumbnailPoint.x =(targetWidth - scaledWidth)*0.5;
}
}
CGImageRef imageRef =[sourceImage CGImage];
CGBitmapInfo bitmapInfo =CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);
if(bitmapInfo == kCGImageAlphaNone){
bitmapInfo = kCGImageAlphaNoneSkipLast;
}
CGContextRef bitmap;
if(sourceImage.imageOrientation ==UIImageOrientationUp|| sourceImage.imageOrientation ==UIImageOrientationDown){
bitmap =CGBitmapContextCreate(NULL, targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}else{
bitmap =CGBitmapContextCreate(NULL, targetHeight, targetWidth,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}
// In the right or left cases, we need to switch scaledWidth and scaledHeight,
// and also the thumbnail point
if(sourceImage.imageOrientation ==UIImageOrientationLeft){
thumbnailPoint =CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
CGFloat oldScaledWidth = scaledWidth;
scaledWidth = scaledHeight;
scaledHeight = oldScaledWidth;
CGContextRotateCTM(bitmap, radians(90));
CGContextTranslateCTM(bitmap,0,-targetHeight);
}elseif(sourceImage.imageOrientation ==UIImageOrientationRight){
thumbnailPoint =CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
CGFloat oldScaledWidth = scaledWidth;
scaledWidth = scaledHeight;
scaledHeight = oldScaledWidth;
CGContextRotateCTM(bitmap, radians(-90));
CGContextTranslateCTM(bitmap,-targetWidth,0);
}elseif(sourceImage.imageOrientation ==UIImageOrientationUp){
// NOTHING
}elseif(sourceImage.imageOrientation ==UIImageOrientationDown){
CGContextTranslateCTM(bitmap, targetWidth, targetHeight);
CGContextRotateCTM(bitmap, radians(-180.));
}
CGContextDrawImage(bitmap,CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), imageRef);
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return newImage;
}
The method we employ here is to create a bitmap with the desired size, but draw an image that is actually larger, thus maintaining the aspect ratio.
So We've Got Our Scaled Images - How Do I Save Them To Disk?
This is pretty simple. Remember that we want to save a compressed version to disk, and not the uncompressed pixels. Apple provides two functions that help us with this (documentation is here):
NSData*UIImagePNGRepresentation(UIImage*image);
NSData*UIImageJPEGRepresentation(UIImage*image,CGFloat compressionQuality);
And if you want to use them, you'd do something like:
UIImage* myThumbnail =...;// Get some image
NSData* imageData =UIImagePNGRepresentation(myThumbnail);
Now we're ready to save it to disk, which is the final step (say into the documents directory):
// Give a name to the file
NSString* imageName =@"MyImage.png";
// Now, we have to find the documents directory so we can save it
// Note that you might want to save it elsewhere, like the cache directory,
// or something similar.
NSArray* paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString* documentsDirectory =[paths objectAtIndex:0];
// Now we get the full path to the file
NSString* fullPathToFile =[documentsDirectory stringByAppendingPathComponent:imageName];
// and then we write it out
[imageData writeToFile:fullPathToFile atomically:NO];
You would repeat this for every version of the image you have.
How Do I Load These Images Back Into Memory?
Just look at the various UIImage initialization methods, such as +imageWithContentsOfFile: in the Apple documentation.
I've noticed that there are many questions about how to handle UIImage objects, especially in conjunction with UIImagePickerController and then displaying it in a view (usually a UIImageView). Here is a collection of common questions and their answers. Feel free to edit and add your own.
I obviously learnt all this information from somewhere too. Various forum posts, StackOverflow answers and my own experimenting brought me to all these solutions. Credit goes to those who posted some sample code that I've since used and modified. I don't remember who you all are - but hats off to you!
How Do I Select An Image From the User's Images or From the Camera?
You use UIImagePickerController. The documentation for the class gives a decent overview of how one would use it, and can be found here.
Basically, you create an instance of the class, which is a modal view controller, display it, and set yourself (or some class) to be the delegate. Then you'll get notified when a user selects some form of media (movie or image in 3.0 on the 3GS), and you can do whatever you want.
My Delegate Was Called - How Do I Get The Media?
The delegate method signature is the following:
-(void)imagePickerController:(UIImagePickerController*)picker
didFinishPickingMediaWithInfo:(NSDictionary*)info;
You should put a breakpoint in the debugger to see what's in the dictionary, but you use that to extract the media. For example:
UIImage* image =[info objectForKey:UIImagePickerControllerOriginalImage];
There are other keys that work as well, all in the documentation.
OK, I Got The Image, But It Doesn't Have Any Geolocation Data. What gives?
Unfortunately, Apple decided that we're not worthy of this information. When they load the data into the UIImage, they strip it of all the EXIF/Geolocation data. But, see the answer to the next question for a way to get at the original image data (on iOS 4+)
Can I Get To The Original File Representing This Image on the Disk?
As of iOS 4, you can, but it's very annoying. Use the following code to get an AssetsLibrary URL for the image, and then pass the URL to assetForURL:resultBlock:failureBlock:
NSURL *referenceURL =[info objectForKey:UIImagePickerControllerReferenceURL];
ALAssetsLibrary*library =[[ALAssetsLibrary alloc] init];
[library assetForURL:referenceURL resultBlock:^(ALAsset*asset){
// code to handle the asset here
} failureBlock:^(NSError*error){
// error handling
}];
[library release];
It's annoying because the user is asked if your application can access your current location, which is rather confusing since you are actually trying to access the user's photo library. Unless you're actually trying to get at the EXIF location data, the user is going to be a bit confused.
Make sure to include the AssetsLibrary framework to make this work.
How Can I Look At The Underlying Pixels of the UIImage?
Since the UIImage is immutable, you can't look at the direct pixels. However, you can make a copy. The code to this looks something like this:
UIImage* image =...;// An image
NSData* pixelData =(NSData*)CGDataProviderCopyData(CGImageGetDataProvider(image.CGImage));
unsignedchar* pixelBytes =(unsignedchar*)[pixelData bytes];
// Take away the red pixel, assuming 32-bit RGBA
for(int i =0; i <[pixelData length]; i +=4){
pixelBytes[i]=0;// red
pixelBytes[i+1]= pixelBytes[i+1];// green
pixelBytes[i+2]= pixelBytes[i+2];// blue
pixelBytes[i+3]= pixelBytes[i+3];// alpha
}
However, note that CGDataProviderCopyData provides you with an "immutable" reference to the data - meaning you can't change it (and you may get a BAD_ACCESS error if you do). Look at the next question if you want to see how you can modify the pixels.
How Do I Modify The Pixels of the UIImage?
The UIImage is immutable, meaning you can't change it. Apple posted a great article on how to get a copy of the pixels and modify them, and rather than copy and paste it here, you should just go read the article.
Once you have the bitmap context as they mention in the article, you can do something similar to this to get a new UIImage with the modified pixels:
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
Do remember to release your references though, otherwise you're going to be leaking quite a bit of memory.
After I Select 3 Images From The Camera, I Run Out Of Memory. Help!
You have to remember that even though on disk these images take up only a few hundred kilobytes at most, that's because they're compressed as a PNG or JPG. When they are loaded into the UIImage, they become uncompressed. A quick over-the-envelope calculation would be:
width x height x 4= bytes in memory
That's assuming 32-bit pixels. If you have 16-bit pixels (some JPGs are stored as RGBA-5551), then you'd replace the 4 with a 2.
Now, images taken with the camera are 1600 x 1200 pixels, so let's do the math:
1600 x 1200 x 4=7,680,000 bytes =~8 MB
8 MB is a lot, especially when you have a limit of around 24 MB for your application. That's why you run out of memory.
OK, I Understand Why I Have No Memory. What Do I Do?
There is never any reason to display images at their full resolution. The iPhone has a screen of 480 x 320 pixels, so you're just wasting space. If you find yourself in this situation, ask yourself the following question: Do I need the full resolution image?
If the answer is yes, then you should save it to disk for later use.
If the answer is no, then read the next part.
Once you've decided what to do with the full-resolution image, then you need to create a smaller image to use for displaying. Many times you might even want several sizes for your image: a thumbnail, a full-size one for displaying, and the original full-resolution image.
OK, I'm Hooked. How Do I Resize the Image?
Unfortunately, there is no defined way how to resize an image. Also, it's important to note that when you resize it, you'll get a new image - you're not modifying the old one.
There are a couple of methods to do the resizing. I'll present them both here, and explain the pros and cons of each.
Method 1: Using UIKit
+(UIImage*)imageWithImage:(UIImage*)image scaledToSize:(CGSize)newSize;
{
// Create a graphics image context
UIGraphicsBeginImageContext(newSize);
// Tell the old image to draw in this new context, with the desired
// new size
[image drawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
// Get the new image from the context
UIImage* newImage =UIGraphicsGetImageFromCurrentImageContext();
// End the context
UIGraphicsEndImageContext();
// Return the new image.
return newImage;
}
This method is very simple, and works great. It will also deal with the UIImageOrientation for you, meaning that you don't have to care whether the camera was sideways when the picture was taken. However, this method is not thread safe, and since thumbnailing is a relatively expensive operation (approximately ~2.5s on a 3G for a 1600 x 1200 pixel image), this is very much an operation you may want to do in the background, on a separate thread.
Method 2: Using CoreGraphics
+(UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSize:(CGSize)newSize;
{
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGImageRef imageRef =[sourceImage CGImage];
CGBitmapInfo bitmapInfo =CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);
if(bitmapInfo == kCGImageAlphaNone){
bitmapInfo = kCGImageAlphaNoneSkipLast;
}
CGContextRef bitmap;
if(sourceImage.imageOrientation ==UIImageOrientationUp|| sourceImage.imageOrientation ==UIImageOrientationDown){
bitmap =CGBitmapContextCreate(NULL, targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}else{
bitmap =CGBitmapContextCreate(NULL, targetHeight, targetWidth,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}
if(sourceImage.imageOrientation ==UIImageOrientationLeft){
CGContextRotateCTM(bitmap, radians(90));
CGContextTranslateCTM(bitmap,0,-targetHeight);
}elseif(sourceImage.imageOrientation ==UIImageOrientationRight){
CGContextRotateCTM(bitmap, radians(-90));
CGContextTranslateCTM(bitmap,-targetWidth,0);
}elseif(sourceImage.imageOrientation ==UIImageOrientationUp){
// NOTHING
}elseif(sourceImage.imageOrientation ==UIImageOrientationDown){
CGContextTranslateCTM(bitmap, targetWidth, targetHeight);
CGContextRotateCTM(bitmap, radians(-180.));
}
CGContextDrawImage(bitmap,CGRectMake(0,0, targetWidth, targetHeight), imageRef);
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return newImage;
}
The benefit of this method is that it is thread-safe, plus it takes care of all the small things (using correct color space and bitmap info, dealing with image orientation) that the UIKit version does.
How Do I Resize and Maintain Aspect Ratio (like the AspectFill option)?
It is very similar to the method above, and it looks like this:
+(UIImage*)imageWithImage:(UIImage*)sourceImage scaledToSizeWithSameAspectRatio:(CGSize)targetSize;
{
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor =0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint =CGPointMake(0.0,0.0);
if(CGSizeEqualToSize(imageSize, targetSize)== NO){
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if(widthFactor > heightFactor){
scaleFactor = widthFactor;// scale to fit height
}
else{
scaleFactor = heightFactor;// scale to fit width
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if(widthFactor > heightFactor){
thumbnailPoint.y =(targetHeight - scaledHeight)*0.5;
}
elseif(widthFactor < heightFactor){
thumbnailPoint.x =(targetWidth - scaledWidth)*0.5;
}
}
CGImageRef imageRef =[sourceImage CGImage];
CGBitmapInfo bitmapInfo =CGImageGetBitmapInfo(imageRef);
CGColorSpaceRef colorSpaceInfo =CGImageGetColorSpace(imageRef);
if(bitmapInfo == kCGImageAlphaNone){
bitmapInfo = kCGImageAlphaNoneSkipLast;
}
CGContextRef bitmap;
if(sourceImage.imageOrientation ==UIImageOrientationUp|| sourceImage.imageOrientation ==UIImageOrientationDown){
bitmap =CGBitmapContextCreate(NULL, targetWidth, targetHeight,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}else{
bitmap =CGBitmapContextCreate(NULL, targetHeight, targetWidth,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo);
}
// In the right or left cases, we need to switch scaledWidth and scaledHeight,
// and also the thumbnail point
if(sourceImage.imageOrientation ==UIImageOrientationLeft){
thumbnailPoint =CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
CGFloat oldScaledWidth = scaledWidth;
scaledWidth = scaledHeight;
scaledHeight = oldScaledWidth;
CGContextRotateCTM(bitmap, radians(90));
CGContextTranslateCTM(bitmap,0,-targetHeight);
}elseif(sourceImage.imageOrientation ==UIImageOrientationRight){
thumbnailPoint =CGPointMake(thumbnailPoint.y, thumbnailPoint.x);
CGFloat oldScaledWidth = scaledWidth;
scaledWidth = scaledHeight;
scaledHeight = oldScaledWidth;
CGContextRotateCTM(bitmap, radians(-90));
CGContextTranslateCTM(bitmap,-targetWidth,0);
}elseif(sourceImage.imageOrientation ==UIImageOrientationUp){
// NOTHING
}elseif(sourceImage.imageOrientation ==UIImageOrientationDown){
CGContextTranslateCTM(bitmap, targetWidth, targetHeight);
CGContextRotateCTM(bitmap, radians(-180.));
}
CGContextDrawImage(bitmap,CGRectMake(thumbnailPoint.x, thumbnailPoint.y, scaledWidth, scaledHeight), imageRef);
CGImageRefref=CGBitmapContextCreateImage(bitmap);
UIImage* newImage =[UIImage imageWithCGImage:ref];
CGContextRelease(bitmap);
CGImageRelease(ref);
return newImage;
}
The method we employ here is to create a bitmap with the desired size, but draw an image that is actually larger, thus maintaining the aspect ratio.
So We've Got Our Scaled Images - How Do I Save Them To Disk?
This is pretty simple. Remember that we want to save a compressed version to disk, and not the uncompressed pixels. Apple provides two functions that help us with this (documentation is here):
NSData*UIImagePNGRepresentation(UIImage*image);
NSData*UIImageJPEGRepresentation(UIImage*image,CGFloat compressionQuality);
And if you want to use them, you'd do something like:
UIImage* myThumbnail =...;// Get some image
NSData* imageData =UIImagePNGRepresentation(myThumbnail);
Now we're ready to save it to disk, which is the final step (say into the documents directory):
// Give a name to the file
NSString* imageName =@"MyImage.png";
// Now, we have to find the documents directory so we can save it
// Note that you might want to save it elsewhere, like the cache directory,
// or something similar.
NSArray* paths =NSSearchPathForDirectoriesInDomains(NSDocumentDirectory,NSUserDomainMask, YES);
NSString* documentsDirectory =[paths objectAtIndex:0];
// Now we get the full path to the file
NSString* fullPathToFile =[documentsDirectory stringByAppendingPathComponent:imageName];
// and then we write it out
[imageData writeToFile:fullPathToFile atomically:NO];
You would repeat this for every version of the image you have.
How Do I Load These Images Back Into Memory?
Just look at the various UIImage initialization methods, such as +imageWithContentsOfFile: in the Apple documentation.
发表评论
-
iOS 监听音量调节 事件
2013-08-14 12:18 1070iOS 监听音量调节 事件 做项目需要音量调节的事件来控制其 ... -
viewDidUnload viewDidLoad UIViewController内存管理相关的几个方法
2012-08-23 01:52 1271viewDidUnload viewDidLoad UIVie ... -
Objective-C的Properties
2012-08-21 18:20 1666Objective-C是苹果为Cocoa框架下设计的面向对象语 ... -
objective-c properties 概念
2012-08-21 17:50 792学了一段时间 objective-c properties 概 ... -
UIVideoEditorController 使用
2012-07-18 15:15 1670概述 不能定制界面,不可派生子类。 使用步骤: 检查制定源是否 ... -
iphone app 四种崩溃类型
2012-07-17 22:42 1130一.四种崩溃类型 程序崩溃: 可能是最常见的,经常发生于内存 ... -
首先查看crash log中的崩溃线程
2012-07-15 15:47 1860首先查看crash log中的崩溃线程,假如是这样的: Th ... -
iOS【EXC_BAD_ACCESS 】crash报告分析
2012-07-15 15:40 7925做iOS的开发者,经常都会遇到这个问题,我在这里做一下简单的分 ... -
objective-c aes加密
2012-05-11 11:21 3608在cocoa看到的加密代码,介绍一下。 aes加密的,1M的数 ... -
NSObject类所支持的一些基本方法
2012-04-10 14:33 1350NSObject类所支持的一些基本方法 对象是否class- ... -
关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的解决方案
2012-03-31 11:52 2206关于出现僵尸信号SIGBAT或者EXC_BAD_ACCESS的 ... -
Xcode4.2新特性之storyboards (故事板)
2012-03-31 11:43 4337Xcode4.2新特性之storyboards ... -
iPhone OS体系结构
2012-03-29 07:43 1657iPhone OS体系结构 iPhone OS有着绚丽优雅的外 ... -
iPhone的软件栈分成好几层
2012-03-29 07:01 1210iPhone的软件栈分成好几层。应用程序位于最高的抽象层,而系 ... -
UIImagePickerController使用
2012-03-17 22:47 4273UIImagePickerController使用 引用UI ... -
wait_fences: failed to receive reply: 10004003奇怪的错误
2012-03-17 11:09 2737今日遇到wait_fences: failed to rece ... -
iphone app 本地化程序名称
2012-03-17 01:38 910本地化程序名称 1、 建立InfoPlist.strings ... -
iphone app 为图片添加边框
2012-03-17 01:30 2513头文件中#import <QuartzCore/Quar ... -
objective-c 内存管理的文章摘录2
2012-03-15 01:09 864Cocoa内存管理规则 1)当 ... -
objective-c 内存管理的文章摘录1
2012-03-15 01:02 911今天有空想学习一下objective-c的内存管理的知识就上网 ...
相关推荐
Cocoa 第五版 高清 带图片 Cocoa Programming for OS X
对于刚刚加入这个阵营的开发者来说, Cocoa像是一个巨大而未知的新世界。Cocoa开发环 境的各种特性、工具、概念、术语、编程接口、甚至是编程语言对他们来说可能都比较生 疏。 Cocoa基本原理指南提供了领略Cocoa...
对于刚刚加入这个阵营的开发者来说,Cocoa 像是一个巨大而未知的新世界。Cocoa 开发环境的各种特性、工具、概念、术语、编程接口、甚至是编程语言对他们来说可能都比较生疏。Cocoa 基本原理指南提供了领略Cocoa 技术...
Cocoa Fundamentals Guide 的中文版
Mantle 是 Cocoa 和 Cocoa Touch 的模型框架,你可以通过它为你的 Cocoa 和 Cocoa Touch 写简单的模型层。示例代码:@interface XYUser : MTLModel @property (readonly, nonatomic, copy) NSString *name;...
从官网复制的iOS开发参考文献:Cocoa基础指南介绍
Cocoa Programming Developer’s Handbook 书籍以及配套源码 对应的中文译本名《Cocoa编程开发者手册》,这里提供的是其原本,技术人员建议还是读原本。 《Cocoa编程开发者手册》是关于MacOSX上CocoaAPI的指南,...
·用Cocoa的文本处理能力操作文本数据 ·用Cocoa来绘图 ·本地化您的应用程序以支持多语言 ·完善您的应用程序,添加用于Dock上的图标、提供帮助和打包发布。 在每章的结尾您将看到一些练习,挑战您改进刚创建的...
Cocoa Design Patterns.pdf Cocoa Design Patterns.pdf
这本书手把手教你使用xcode开发cocoa程序,菜鸟必备
cocoa 2d 游戏开发 iphone iOS cocoa2d 游戏 ipad
cocoa开发者手册是本经典的cocoa开发教程,主要帮助读者理清开发中常用的API,不适合初学cocoa开发的人员
[奥莱理] Cocoa Objective-C 开发学习手册 第4版 (英文版) [奥莱理] Learning Cocoa with Objective-C 4th Edition (E-Book) ☆ 图书概要:☆ You’ll learn how to work with the Xcode IDE, Objective-C’s ...
Cocoa编程经典的入门书籍,图文讲解,易于学习
iOS 和 macOS 性能优化书。iOS and macOS Performance Tuning Cocoa, Cocoa Touch, Objective-C, and Swift
The key to creating a modern Mac application is Cocoa. According to Apple, Cocoa is a set of object-oriented frameworks that provide a runtime environment for Mac OS X applications. As you make your ...
cocoa 设计模式 英文版,本书介绍了 cocoa 的基本设计模式,以 MVC 为基础,有助于更好地理解 cocoa 框架
适用于初学者,了解苹果公司的cocoa框架,为深入编程打下坚实的基础
讲述Cocoa的一些基本原理,方便深入了解开发的背后原理,拒绝搬砖,要坚决改变世界!
Cocoa下NSTableView的简单使用