1 图片处理
1.1 编辑图片的几个方法
第一种
先用UIImage对象加载一张图片
然后转化成CGImageRef放到CGContext中去编辑
第二种
用CGImageCreate函数创建CGImageRef
然后把CGImageRef放到CGContext中去编辑
第三种
用CGImageCreateCopy 或者CGImageCreateCopyWithColorSpace函数拷贝
CGImageRefCGImageCreate (
size_t width, //图片的宽度
size_t height, //图片的高度
size_t bitsPerComponent, //图片每个颜色的bits,比如rgb颜色空间,有可能是5 或者8 ==
size_t bitsPerPixel, //每一个像素占用的buts,15 位24位 32位等等
size_t bytesPerRow, //每一行占用多少bytes 注意是bytes不是bits 1byte =8bit
CGColorSpaceRef colorspace, //颜色空间,比如rgb
CGBitmapInfo bitmapInfo, //layout,像素中bit的布局, 是rgba还是 argb,==
CGDataProviderRef provider, //数据源提供者,url或者内存==
const CGFloat decode[], //一个解码数组
bool shouldInterpolate, //抗锯齿参数
CGColorRenderingIntent intent
//图片渲染相关参数
);
1.2 示例代码
CGImageRef CGImageCreate(size_t width, size_theight, size_tbitsPerComponent, size_t bitsPerPixel, size_tbytesPerRow, CGColorSpaceRef space, CGBitmapInfo bitmapInfo, CGDataProviderRefprovider, const CGFloat decode[], boolshouldInterpolate, CGColorRenderingIntent intent);
通过这个方法,我们可以创建出一个CGImageRef类型的对象,下面分别对参数进行解释:
sizt_t是定义的一个可移植性的单位,在64位机器中为8字节,32位位4字节。
width:图片宽度像素
height:图片高度像素
bitsPerComponent:每个颜色的比特数,例如在rgba-32模式下为8
bitsPerPixel:每个像素的总比特数
bytesPerRow:每一行占用的字节数,注意这里的单位是字节
space:颜色空间模式,例如const CFStringRef kCGColorSpaceGenericRGB 这个函数可以返回一个颜色空间对象。
bitmapInfo:位图像素布局,枚举如下:
typedef CF_OPTIONS(uint32_t, CGBitmapInfo) {
kCGBitmapAlphaInfoMask = 0x1F,
kCGBitmapFloatComponents = (1 << 8),
kCGBitmapByteOrderMask = 0x7000,
kCGBitmapByteOrderDefault = (0 << 12),
kCGBitmapByteOrder16Little = (1 << 12),
kCGBitmapByteOrder32Little = (2 << 12),
kCGBitmapByteOrder16Big = (3 << 12),
kCGBitmapByteOrder32Big = (4 << 12)
}
provider:数据源提供者
decode[]:解码渲染数组
shouldInterpolate:是否抗锯齿
intent:图片相关参数
CGImageRef CGImageMaskCreate(size_t width, size_theight, size_t bitsPerComponent, size_t bitsPerPixel, size_tbytesPerRow, CGDataProviderRef provider, const CGFloat decode[], boolshouldInterpolate)
这个方法用于创建mask图片图层,可以设置其显示部分与不显示部分达到特殊的效果,参数意义同上。
CGImageRef CGImageCreateCopy(CGImageRefimage)
这个方法可以复制一个CGImageRef对象
CGImageRef CGImageCreateWithJPEGDataProvider(CGDataProviderRef source, const CGFloat decode[], boolshouldInterpolate, CGColorRenderingIntent intent)
通过JPEG数据源获取图像
CGImageRef CGImageCreateWithPNGDataProvider(CGDataProviderRefsource, const CGFloat decode[], boolshouldInterpolate, CGColorRenderingIntent intent)
通过PNG数据源获取图像
CGImageRef CGImageCreateWithImageInRect(CGImageRefimage, CGRectrect)
截取图像的一个区域重绘图像
CGImageRef CGImageCreateWithMask(CGImageRef image, CGImageRefmask)
截取mask图像的某一区域重绘
CGImageRef CGImageCreateWithMaskingColors(CGImageRefimage, const CGFloatcomponents[])
通过颜色分量数组创建位图
CGImageRef CGImageCreateCopyWithColorSpace(CGImageRefimage, CGColorSpaceRef space)
通过颜色空间模式复制位图
CGImageRef CGImageRetain(CGImageRefimage)
引用+1
void CGImageRelease(CGImageRefimage)
引用-1
bool CGImageIsMask(CGImageRefimage)
返回是否为Mask图层
size_t CGImageGetWidth(CGImageRefimage)
获取宽度像素
size_t CGImageGetHeight(CGImageRefimage)
获取高度像素
下面这些方法分别获取相应属性
size_t CGImageGetBitsPerComponent(CGImageRefimage)
size_t CGImageGetBitsPerPixel(CGImageRefimage)
size_t CGImageGetBytesPerRow(CGImageRefimage)
CGColorSpaceRef CGImageGetColorSpace(CGImageRef image)CG_EXTERN CGImageAlphaInfo CGImageGetAlphaInfo(CGImageRefimage)
CGDataProviderRef CGImageGetDataProvider(CGImageRefimage)
const CGFloat *CGImageGetDecode(CGImageRefimage)
bool CGImageGetShouldInterpolate(CGImageRefimage)
CGColorRenderingIntent CGImageGetRenderingIntent(CGImageRefimage)
CGBitmapInfo CGImageGetBitmapInfo(CGImageRefimage)
1.3 PNG与JPEG优劣比较
存储速度:JPG更快
压缩比:JPG更大;
图片质量:JPG更好
JPG不支持透明效果;
UIImageJPEGRepresentation方法在耗时上比较少 而UIImagePNGRepresentation耗时操作时间比较长;
UIImageJPEGRepresentation函数需要两个参数:图片的引用和压缩系数.而UIImagePNGRepresentation只需要图片引用作为参数.通过在实际使用过程中,比较发现: UIImagePNGRepresentation(UIImage* image) 要比UIImageJPEGRepresentation(UIImage* image, 1.0) 返回的图片数据量大很多.譬如,同样是读取摄像头拍摄的同样景色的照片, UIImagePNGRepresentation()返回的数据量大小为199K ,而 UIImageJPEGRepresentation(UIImage* image, 1.0)返回的数据量大小只为140KB,比前者少了50多KB.如果对图片的清晰度要求不高,还可以通过设置 UIImageJPEGRepresentation函数的第二个参数,大幅度降低图片数据量.譬如,刚才拍摄的图片, 通过调用UIImageJPEGRepresentation(UIImage* image, 1.0)读取数据时,返回的数据大小为140KB,但更改压缩系数后,通过调用UIImageJPEGRepresentation(UIImage* image, 0.5)读取数据时,返回的数据大小只有11KB多,大大压缩了图片的数据量 ,而且从视角角度看,图片的质量并没有明显的降低.因此,在读取图片数据内容时,建议优先使用UIImageJPEGRepresentation,并可根据自己的实际使用场景,设置压缩系数,进一步降低图片数据量大小.
1.4 图片缩放
图片缩放的三个函数
http://www.cnblogs.com/pengyingh/articles/2355052.html
程序中一个界面用到了好多张大图,内存报警告了,所以做了一下图片缩放,在网上找了别人写的代码
//把图片做等比缩放,生成一个新图片
- (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize sourceImage:(UIImage*)sourceImage {
// UIGraphicsBeginImageContext(targetSize);
// [sourceImage drawInRect:CGRectMake(0,0, targetSize.width, targetSize.height)];
// UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
// UIGraphicsEndImageContext();
// return scaledImage;
UIImage*newImage = nil;
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);
UIGraphicsBeginImageContext(targetSize);// this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage =UIGraphicsGetImageFromCurrentImageContext();
if(newImage== nil)
NSLog(@"could not scale image");
//pop thecontext to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
//把图片按照新大小进行裁剪,生成一个新图片
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize image:(UIImage *)sourceImage
{
// UIImage*sourceImage = self;
UIImage*newImage = nil;
CGSizeimageSize = sourceImage.size;
CGFloat width= imageSize.width;
CGFloat height= imageSize.height;
CGFloattargetWidth = targetSize.width;
CGFloattargetHeight = 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;
// centerthe image
if (widthFactor > heightFactor)
{
thumbnailPoint.y = (targetHeight -scaledHeight) *0.5;
}
else
if(widthFactor < heightFactor)
{
thumbnailPoint.x =(targetWidth - scaledWidth) *0.5;
}
}
UIGraphicsBeginImageContext(targetSize);// this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage =UIGraphicsGetImageFromCurrentImageContext();
if (newImage== nil)
NSLog(@"could not scale image");
//pop thecontext to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)generatePhotoThumbnail:(UIImage *)image
{
// Create a thumbnail version of the image for the eventobject.
CGSize size =image.size;
CGSize croppedSize;
CGFloat ratio=64.0;//这个是设置转换后图片的尺寸大小
CGFloat offsetX =0.0;
CGFloat offsetY =0.0;
// check the size of the image, we want to make it
// a square with sides the size of the smallest dimension
if(size.width > size.height) {
offsetX = (size.height - size.width) /2;
croppedSize = CGSizeMake(size.height, size.height);
}else{
offsetY = (size.width - size.height) /2;
croppedSize = CGSizeMake(size.width, size.width);
}
// Crop the image before resize
CGRect clippedRect = CGRectMake(offsetX *-1, offsetY * -1, croppedSize.width, croppedSize.height);
//裁剪图片
CGImageRef imageRef = CGImageCreateWithImageInRect([image CGImage], clippedRect);
// Donecropping
// Resize the image
CGRect rect = CGRectMake(0.0,0.0,ratio, ratio);
UIGraphicsBeginImageContext(rect.size);
[[UIImage imageWithCGImage: imageRef] drawInRect: rect];
UIImage *thumbnail =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
// DoneResizing
return thumbnail;
}
实际应用简化
-(UIImage *)generatePhotoThumbnail:(UIImage *)image
{
CGRect rect=CGRectMake(0,0,60,78);
//裁剪图片
CGImageRefimageRef=CGImageCreateWithImageInRect([image CGImage], CGRectMake(0,0,140,182));
UIGraphicsBeginImageContext(rect.size);
[[UIImage imageWithCGImage:imageRef]drawInRect:rect];
//如果不裁剪图片可以直接画
//[image drawInRect:CGRectMake(0, 0,theSize.width, theSize.height)];
UIImage*thumbnail=UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
returnthumbnail;
}
附:
UIImage类并没有提供缩放图片需要用到的API,是不是觉得很吃惊?没关系,我们自己来添加一个。
定义缩放图片的Category
// UIImage+Scale.h
@interfaceUIImage (scale)
-(UIImage*)scaleToSize:(CGSize)size;
@end
实现这个Category的定义
// UIImage+Scale.m
#import"UIImage+Scale.h"
@implementation UIImage (scale)
-(UIImage*)scaleToSize:(CGSize)size
{
// 创建一个bitmap的context
// 并把它设置成为当前正在使用的context
UIGraphicsBeginImageContext(size);
// 绘制改变大小的图片
[self drawInRect: CGRectMake(0,0, size.width, size.height)];
// 从当前context中创建一个改变大小后的图片
UIImage* scaledImage =UIGraphicsGetImageFromCurrentImageContext();
// 使当前的context出堆栈
UIGraphicsEndImageContext();
// 返回新的改变大小后的图片
return scaledImage;
}
@end
如何使用
// 创建图片
UIImage*image =[UIImage imageNamed:@"myImage.png"];
// 更改图片大小
UIImage *scaledImage=[image scaleToSize:CGSizeMake(25.0f,35.0f)]
1.5 参考链接
IOS-图片操作集合
http://blog.csdn.net/ch_soft/article/details/7685753
UIImagePNGRepresentation存在缓慢问题
http://blog.sina.com.cn/s/blog_95a3991f010162ws.html
UIImage变为NSData并进行压缩
http://www.cnblogs.com/robinkey/archive/2013/01/21/2869930.html
UIImageJPEGRepresentation和UIImagePNGRepresentation
http://blog.csdn.net/mideveloper/article/details/11473627
png有透明通道,JPEG无
http://blog.163.com/chentong1115@126/blog/static/45314732200972323921819/
透明PNG圖片有黑邊的解決方法
用UIImage和UIButton画出的按钮,使用透明的png图片,为什么会出现白边
http://segmentfault.com/q/1010000000095447
JPG、PNG和GIF图片的基本原理及优化方法
http://www.mahaixiang.cn/Photoshop/400.html
JPEG原理详细
http://blog.chinaunix.net/uid-27002868-id-3220554.html
IOS开发中图片资源使用png还是jpg格式
http://www.cnblogs.com/wengzilin/p/3485298.html
(good)ios开发图片格式的选择:png和jpg
http://m.blog.csdn.net/blog/awaylin113/22712317
IOS开发之保存图片到Documents目录及PNG,JPEG格式相互转换
http://blog.csdn.net/sanpintian/article/details/7418755
iOS过滤png图片透明部分点击事件
http://www.cocoachina.com/industry/20121127/5192.html
JPEG压缩原理
http://blog.csdn.net/xfortius/article/details/8904012
png压缩原理
http://blog.csdn.net/zykun/article/details/1825086
iOS开发,图片使用png好还是jpg好?
http://www.cocoachina.com/bbs/read.php?tid=110115
2 绘制文本
2.1 NSMutableAttributedString绘制
CGRect textViewRect = CGRectMake(ICON_SPACE, _imageHeight + ICON_SPACE, _postContentTextView.frame.size.width, _labelSize);
NSMutableAttributedString *str = [[NSMutableAttributedString alloc] initWithString: vm.contentText];
[str addAttribute:NSForegroundColorAttributeName value: kContentTextColor range:NSMakeRange(0,[vm.contentText length])];
[str addAttribute: NSFontAttributeName value: kContentTextFont range:NSMakeRange(0,[vm.contentText length])];
[str addAttribute: NSBackgroundColorDocumentAttribute value: [UIColor whiteColor] range: NSMakeRange(0, [vm.contentText length])];
[str drawInRect: textViewRect];
2.2 参考资料
IOS开发(78)之绘制文本
http://www.2cto.com/kf/201305/212045.html
iOS界面上绘制不同字体 颜色 大小的字符串
http://blog.csdn.net/wsk_123_123/article/details/23277457
初探NSAttributedString和NSMutableAttributedString的使用-LiuWJ
http://www.tuicool.com/articles/Fvqia2
iOS字符属性NSAttributedString描述
http://my.oschina.net/lanrenbar/blog/395909
NSAttributedString详解
http://www.cnblogs.com/zhw511006/archive/2012/09/21/2696700.html
3 异步绘制
3.1 异步绘制示例
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
CGRect drawRect = _bgImageView.frame;
UIGraphicsBeginImageContextWithOptions(drawRect.size, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
if(!context) {
return;
}
[[UIColor whiteColor] set];
CGContextFillRect(context, drawRect);
CGRect imgRect = CGRectZero;
if ([vm.contentImgPath length] > 0) {
imgRect =CGRectMake(0, 0, BODY_HEIGTH, _imageHeight);
[vm.contentImage drawInRect: contentImageView.frame blendMode: kCGBlendModeNormal alpha:1];
}
CGRect textViewRect = CGRectZero;
if ([vm.contentText length] > 0) {
NSMutableAttributedString*str;
if (!isContentDisplayCompletly) {
if (vm.digestText) {
str = [[NSMutableAttributedString alloc] initWithString: vm.digestText attributes: contentTextView.typingAttributes];
}else
str = [[NSMutableAttributedString alloc] initWithString: vm.contentText attributes: contentTextView.typingAttributes];
}else
str = [[NSMutableAttributedString alloc] initWithString: vm.contentText attributes: contentTextView.typingAttributes];
[strdrawInRect: contentTextView.frame];
}
if (_subjectTitleHeight> 0) {
CGRect subjectIconFrame = CGRectMake(_subjectButton.frame.origin.x, _subjectButton.frame.origin.y, 16, 16);
UIImage*iconImg = [UIImage imageNamed:@"FlagIcon"];
subjectIconFrame.size = iconImg.size;
[iconImg drawInRect: subjectIconFrame blendMode: kCGBlendModeNormal alpha:1];
CGRect subjectTitleFrame = CGRectMake(subjectIconFrame.origin.x + subjectIconFrame.size.width, subjectIconFrame.origin.y, 100, _subjectTitleHeight);
[_subjectButton.titleLabel.attributedText drawInRect: subjectTitleFrame];
}
UIImage*temp = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
dispatch_async(dispatch_get_main_queue(),^{
_bgImageView.image = nil;
_bgImageView.image=temp;
[self setHidden:NO];
});
});
3.2 DrawRect之后注意用hitTest:withEvent:方法处理事件接收
//用户触摸时第一时间加载内容
- (UIView*)hitTest:(CGPoint)point withEvent:(UIEvent*)event{
UIView*result = [super hitTest: point withEvent: event];
CGPoint buttonPoint = [_subjectButton convertPoint: point fromView: self];
if ([_subjectButton pointInside:buttonPointwithEvent:event]){
return _subjectButton;
}
returnresult;
}
3.3 参考链接
[iOS Animation]-CALayer绘图效率-异步绘制
http://my.oschina.net/u/2438875/blog/507545?fromerr=R4LnEaJ5
CGDataProviderCreateWithData对内存数据的释放
http://www.taofengping.com/2012/11/04/cgdataprovidercreatewithdata_memory_release/#.VnJQ6jaitZF
IOS中使用像素位图(CGImageRef)对图片进行处理
http://my.oschina.net/u/2340880/blog/406437?p={{currentPage-1}}
4 Asyncdisplaykit
4.1 参考链接
Asyncdisplaykit指南(一)
http://www.th7.cn/Program/IOS/201410/302413.shtml
AsyncDisplayKit教程:达到60FPS的滚动帧率
http://www.cocoachina.com/swift/20141124/10298.html
http://asyncdisplaykit.org/guide/
AsyncDisplayKit入门指南
http://www.cocoachina.com/ios/20141020/9975.html
5 开发技巧
5.1 常见问题
5.1.1 CGBitmapContextCreateImage绘制后内存泄露导致内存告警
CGBitmapContextCreateImage绘制的图片会造成内存无法释放,应该换用CGDataProviderCreateWithCFData。
5.1.1.1 方案一:修改源代码,入缓存前压缩
http://my.oschina.net/u/1244672/blog/510379
SDWebImage有一个SDWebImageDownloaderOperation类来执行下载操作的。里面有个下载完成的方法:
- (void)connectionDidFinishLoading:(NSURLConnection*)aConnection {
SDWebImageDownloaderCompletedBlock completionBlock = self.completedBlock;
@synchronized(self) {
CFRunLoopStop(CFRunLoopGetCurrent());
self.thread = nil;
self.connection= nil;
[[NSNotificationCenter defaultCenter] postNotificationName: SDWebImageDownloadStopNotificati onobject: nil];
}
if (![[NSURLCache sharedURLCache] cachedResponseForRequest:_request]) {
responseFromCached= NO;
}
if(completionBlock)
{
if(self.options & SDWebImageDownloaderIgnoreCachedResponse &&responseFromCached) {
completionBlock(nil, nil, nil, YES);
}
else {
UIImage *image= [UIImage sd_imageWithData: self.imageData];
NSString *key= [[SDWebImageManager sharedManager] cacheKeyForURL: self.request.URL];
image = [self scaledImageForKey: key image: image];
// Do notforce decoding animated GIFs
if (!image.images) {
image = [UIImage decodedImageWithImage: image];
}
if (CGSizeEqualToSize(image.size, CGSizeZero)) {
completionBlock(nil, nil, [NSError errorWithDomain:@"SDWebImageErrorDomain" code:0userInfo:@{NSLocalizedDescriptionKey : @"Downloaded image has 0pixels"}], YES);
}
else {
completionBlock(image, self.imageData, nil, YES);
}
}
}
self.completionBlock= nil;
[self done];
}
其中,UIImage*image = [UIImage sd_imageWithData:self.imageData];就是将data转换成image。
再看看sd_imageWithData:这个方法:
+ (UIImage*)sd_imageWithData:(NSData *)data {
UIImage*image;
NSString*imageContentType = [NSData sd_contentTypeForImageData: data];
if ([imageContentType isEqualToString:@"image/gif"]) {
image =[UIImage sd_animatedGIFWithData: data];
}
#ifdefSD_WEBP
else if([imageContentType isEqualToString:@"image/webp"])
{
image =[UIImage sd_imageWithWebPData: data];
}
#endif
else {
image =[[UIImage alloc] initWithData: data];
UIImageOrientation orientation = [self sd_imageOrientationFromImageData: data];
if(orientation != UIImageOrientationUp) {
image =[UIImage imageWithCGImage: image.CGImage scale: image.scale orientation: orientation];
}
}
return image;
}
这个方法在UIImage+MultiFormat里面,是UIImage的一个类别处理。这句话很重要image =[[UIImage alloc] initWithData: data]; SDWebImage把下载下来的data直接转成image,然后没做等比缩放直接存起来使用。所以,我们只需要在这边做处理即可:
UIImage+MultiFormat添加一个方法:
+(UIImage*)compressImageWith:(UIImage *)image
{
float imageWidth = image.size.width;
float imageHeight = image.size.height;
float width =640;
float height =image.size.height/(image.size.width/width);
float widthScale = imageWidth /width;
float heightScale = imageHeight /height;
// 创建一个bitmap的context
// 并把它设置成为当前正在使用的context
UIGraphicsBeginImageContext(CGSizeMake(width, height));
if (widthScale> heightScale) {
[image drawInRect: CGRectMake(0, 0, imageWidth /heightScale , height)];
}
else {
[image drawInRect: CGRectMake(0, 0, width , imageHeight /widthScale)];
}
// 从当前context中创建一个改变大小后的图片
UIImage*newImage = UIGraphicsGetImageFromCurrentImageContext();
// 使当前的context出堆栈
UIGraphicsEndImageContext();
return newImage;
}
然后在:image =[[UIImage alloc] initWithData: data];下面调用以下:
if (data.length/1024 > 1024) {
image = [self compressImageWith: image];
}
当data大于1M的时候做压缩处理。革命尚未成功,还需要一步处理。在SDWebImageDownloaderOperation的connectionDidFinishLoading方法里面的:
UIImage *image= [UIImage sd_imageWithData: self.imageData];
//将等比压缩过的image在赋在转成data赋给self.imageData
NSData *data =UIImageJPEGRepresentation(image, 1);
self.imageData = [NSMutableData dataWithData: data];
5.1.1.2 方案二:设置全局缓存大小
http://www.myexception.cn/swift/2033029.html
1、首先在appdelegate方法didFinishLaunchingWithOptions
SDImageCache.sharedImageCache().maxCacheSize=1024*1024*8设置一下最大的缓存大小。
2、在appdelegate applicationDidReceiveMemoryWarning里加入
SDImageCache.sharedImageCache().clearMemory()
SDWebImageManager.sharedManager().cancelAll()
5.1.1.3 方案三:定时清理内存缓存
http://www.bubuko.com/infodetail-956863.html
经过尝试,发现了一个最简单的完美解决该问题的方法
在使用SDWebImage加载较多图片造成内存警告时,定期调用
[[SDImageCache sharedImageCache] setValue:nilforKey:@"memCache"];
5.1.1.4 方案四(不推荐):修复SD库代码,不做解压,直接返回压缩的原图
5.1.1.5 方案五(推荐):使用CGDataProviderRef进行图形解压重绘
iOS开发中界面展示大图片时UIImage的性能有关问题
http://www.myexception.cn/operating-system/578931.html
#import "SDWebImageDecoder.h"
@implementationUIImage (ForceDecode)
+ (UIImage*)decodedImageWithImage:(UIImage*)image {
if (image.images) {
// Do not decode animated images
return image;
}
UIImage *decompressedImage;
@autoreleasepool{
//核心代码,可以解决内存未释放问题
NSData *data = UIImageJPEGRepresentation(image, 1);
CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
CGImageRef imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, NO, kCGRenderingIntentDefault);
// CGImageRef imageRef = image.CGImage;
CGSize imageSize = CGSizeMake(CGImageGetWidth(imageRef), CGImageGetHeight(imageRef));
CGRect imageRect = (CGRect){.origin = CGPointZero, .size=imageSize};
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
int infoMask = (bitmapInfo & kCGBitmapAlphaInfoMask);
BOOL anyNonAlpha = (infoMask == kCGImageAlphaNone || infoMask == kCGImageAlphaNoneSkipFirst || infoMask ==kCGImageAlphaNoneSkipLast);
// CGBitmapContextCreate doesn't support kCGImageAlphaNone with RGB.
//https://developer.apple.com/library/mac/#qa/qa1037/_index.html
if (infoMask == kCGImageAlphaNone&& CGColorSpaceGetNumberOfComponents(colorSpace)
> 1) {
// Unset the old alpha info.
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
// Set noneSkipFirst.
bitmapInfo |= kCGImageAlphaNoneSkipFirst;
}
// Some PNGs tell us they have alpha but only 3 components. Odd.
else if (!anyNonAlpha && CGColorSpaceGetNumberOfComponents(colorSpace)
== 3) {
// Unset the old alpha info.
bitmapInfo &= ~kCGBitmapAlphaInfoMask;
bitmapInfo |=kCGImageAlphaPremultipliedFirst;
}
// It calculates the bytes-per-row based on the bitsPerComponent and width arguments.
CGContextRef context = CGBitmapContextCreate(NULL,
imageSize.width,
imageSize.height,
CGImageGetBitsPerComponent(imageRef), 0, colorSpace, bitmapInfo);
CGColorSpaceRelease(colorSpace);
// If failed, return undecompressed image
if (!context) return image;
CGContextDrawImage(context, imageRect, imageRef);
CGImageRef decompressedImageRef = CGBitmapContextCreateImage(context);
CGContextRelease(context);
decompressedImage = [UIImage imageWithCGImage: decompressedImageRef scale: image.scale orientation: image.imageOrientation];
CGImageRelease(decompressedImageRef);
}
// CVPixelBufferRef pixelBuffer;
// CreateCGImageFromCVPixelBuffer(pixelBuffer,&decompressedImageRef);
// CGImage *cgImage =CGBitmapContextCreateImage(context);
// CFDataRef dataRef =CGDataProviderCopyData(CGImageGetDataProvider(cgImage));
// CGImageRelease(cgImage);
// image->imageRef = dataRef;
// image->image = CFDataGetBytePtr(dataRef);
return decompressedImage;
}
5.1.2 UIImage自定义绘制的四种方法
///方法中会自动做缩放处理
+(void) getBitmapImage: (UIImage *)image Size: (CGSize)imageSize WithCompletionBlock:(HJCallbackBlock)block
{
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
UIGraphicsBeginImageContextWithOptions(imageSize, YES, 0);
CGContextRef context = UIGraphicsGetCurrentContext();
if(!context) {
dispatch_async(dispatch_get_main_queue(), ^{
block(image);
});
}
CGRect rect = CGRectMake(0, 0, imageSize.width, imageSize.height);
//坐标系统已经自动考虑了缩放因素,不需要额外处理
[image drawInRect: rect blendMode: kCGBlendModeNormal alpha:1];
UIImage *temp = UIGraphicsGetImageFromCurrentImageContext();
NSData *tempData = UIImageJPEGRepresentation(temp, 1);
UIGraphicsEndImageContext();
//设置SDWebImage库的缓存
NSString *device = [HJUtility getCurDeviceModel];
if ([device rangeOfString:@"iPhone 4"].length > 0) {
if (tempData.length > 500000) {
tempData =UIImageJPEGRepresentation(temp, 0.4);
}
temp = [UIImage imageWithData: tempData];
}
dispatch_async(dispatch_get_main_queue(), ^{
if(block) {
block(temp);
}
});
});
//方案二,内存有释放,挂机
// UIGraphicsBeginImageContextWithOptions(imageSize, NO, 0);
//
// CGContextRef context = UIGraphicsGetCurrentContext();
// CGRect rect = CGRectMake(0, 0, imageSize.width * [UIScreenmainScreen].scale, imageSize.height * [UIScreen mainScreen].scale);
// // draw alpha-mask
//// CGContextSetBlendMode(context, kCGBlendModeNormal);
// CGContextDrawImage(context, rect, image.CGImage);
// // draw tint color, preserving alpha values of original image
//// CGContextSetBlendMode(context, kCGBlendModeSourceIn);
//
// CGContextFillRect(context, rect);
//
// //Set the original greyscale template as the overlay of the new image
// UIImage *imgData = [self verticallyFlipImage:image];
// [imgData drawInRect:imageRect];
// UIImage *colouredImage = UIGraphicsGetImageFromCurrentImageContext();
// UIGraphicsEndImageContext();
// colouredImage = [self verticallyFlipImage:colouredImage];
// CGContextRelease(context);
// return colouredImage;
//方案三,CGBitmapContextCreate方案,内存没释放
// CGFloat targetWidth = imageSize.width * [UIScreen mainScreen].scale;
// CGFloat targetHeight = imageSize.height * [UIScreen mainScreen].scale;
// CGImageRef imageRef = [image CGImage];
// CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
// CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
// CGContextRef bitmapContext;
// bitmapContext = CGBitmapContextCreate(NULL, targetWidth,targetHeight,CGImageGetBitsPerComponent(imageRef),CGImageGetBytesPerRow(imageRef),colorSpaceInfo, bitmapInfo);
// CGContextDrawImage(bitmapContext, CGRectMake(0, 0, targetWidth,targetHeight), imageRef);
//
// CGImageRef imgref = CGBitmapContextCreateImage(bitmapContext);
// UIImage* newImage = [UIImage imageWithCGImage:imgref];
//
// CGColorSpaceRelease(colorSpaceInfo);
// CGContextRelease(bitmapContext);
// CGImageRelease(imgref);
//
// return newImage;
//方案四,CGBitmapContextCreate方案,但是采用CGDataProviderCreateWithCFData方案解决内存占用问题
// NSData *data = UIImageJPEGRepresentation(image, 1);
// CGDataProviderRef dataProvider =CGDataProviderCreateWithCFData((__bridge CFDataRef)data);
// CGImageRef imageRef = CGImageCreateWithJPEGDataProvider(dataProvider,
// NULL, NO,
// kCGRenderingIntentDefault);
//
// CGFloat targetWidth = imageSize.width * [UIScreen mainScreen].scale;
// CGFloat targetHeight = imageSize.height * [UIScreen mainScreen].scale;
// // CGImageRef imageRef = [image CGImage];
//
// CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef);
//
// CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef);
// CGContextRef bitmapContext;
// bitmapContext = CGBitmapContextCreate(NULL, targetWidth,targetHeight,CGImageGetBitsPerComponent(imageRef),0, colorSpaceInfo,bitmapInfo);
// CGContextDrawImage(bitmapContext, CGRectMake(0, 0, targetWidth,targetHeight), imageRef);
//
// // If failed, return undecompressed image
// if (!bitmapContext) return image;
//
// CGImageRef imgref = CGBitmapContextCreateImage(bitmapContext);
// UIImage* newImage = [UIImage imageWithCGImage:imgref];//[UIImageimageWithCGImage:decompressedImageRef scale:image.scaleorientation:image.imageOrientation];
//
// CGColorSpaceRelease(colorSpaceInfo);
// CGContextRelease(bitmapContext);
// CGImageRelease(imgref);
//
// return newImage;
}
5.1.3 绘制时单元格底部出现高度不定的细微黑线
问题原因:
将Text做宽高计算时,高度值容易得出小数数值,而页面绘制均是基于整数像素点绘制,对于小数点部分,系统会做舍去处理(即便有缩放),固留下高度不定的未绘制区域(为黑色)。
解决方案:
将计算出来的高度值做向下取整处理即可。
CGRect labelFrame = [content boundingRectWithSize: size options: NSStringDrawingTruncatesLastVisibleLine | NSStringDrawingUsesLineFragmentOrigin | NSStringDrawingUsesFontLeading attributes:_postContentTextView.typingAttributes context: nil];
labelSize = labelFrame.size;
labelSize.height = ceilf(labelSize.height);
6 参考链接
(GOOD)iOS开发中界面展示大图片时UIImage的性能有关问题
http://www.myexception.cn/operating-system/578931.html
(Good)iPhone - UIImage Leak, CGBitmapContextCreateImage Leak
http://stackoverflow.com/questions/1427478/iphone-uiimage-leak-cgbitmapcontextcreateimage-leak
Another iPhone - CGBitmapContextCreateImage Leak
http://stackoverflow.com/questions/1434714/another-iphone-cgbitmapcontextcreateimage-leak
UIGraphicsBeginImageContext vs CGBitmapContextCreate
http://stackoverflow.com/questions/4683448/uigraphicsbeginimagecontext-vs-cgbitmapcontextcreate
iPhone - CGBitmapContextCreateImage Leak, Anyone else withthis problem?
Build and Analyze false positive on leak detection?
http://stackoverflow.com/questions/8438249/build-and-analyze-false-positive-on-leak-detection
iPhone - Multiple CGBitmapContextCreateImage Calls -ObjectAlloc climbing
(Good)ios开发图片处理,内存泄露
http://www.oschina.net/question/736524_69802
主题:CGBitmapContextCreateImage(bitmap)内存泄露问题处理
http://www.cocoachina.com/bbs/read.php?tid=31835
iOS异步图片加载优化与常用开源库分析
http://luoyibu.com/2015/05/12/iOS异步图片加载优化与常用开源库分析/
主题:图片处理开源函数ImageProcessing CGDataProviderCreateWithData Bug修复
http://www.cocoachina.com/bbs/read.php?tid=116149
CGDataProviderCreateWithData对内存数据的释放
http://www.taofengping.com/2012/11/04/cgdataprovidercreatewithdata_memory_release/#.VmpqgoSitZE
IOS7.x下UIGraphicsGetImageFromCurrentImageContext引发内存暴涨,导致应用被结束掉
http://blog.163.com/l1_jun/blog/static/1438638820155593641529/
在iOS中与CGContextRef的内存泄漏
http://www.itstrike.cn/Question/55b86ce7-dfba-4548-a103-22dc5317420a.html
使用AFNetworking, SDWebimage和OHHTTPStubs
http://blog.shiqichan.com/using-afnetworking-sdwebimage-and-ohhttpstubs/
SDWebImage缓存图片的机制(转)
http://blog.csdn.net/zhun36/article/details/8900327
近来一个swift项目用uicollectionview 用sdwebimage 加载图片,发生内存猛增,直接闪退的情况,简单说一下解决方案
http://www.myexception.cn/swift/2033029.html
关于SDWebImage加载高清图片导致app崩溃的问题
http://www.bubuko.com/infodetail-956863.html
SDWebImage加载大图导致的内存警告问题
http://blog.csdn.net/richer1997/article/details/43481959
解决MWPhotoBrowser中的SDWebImage加载大图导致的内存警告问题
http://my.oschina.net/u/1244672/blog/510379
使用SDWebImage加载大量图片后造成内存泄露的解决办法
http://www.bubuko.com/infodetail-985746.html
UIGraphicsBeginImageContext系列知识
http://blog.sina.com.cn/s/blog_5fb39f9101017n1v.html
iOS绘图教程
http://blog.csdn.net/nogodoss/article/details/18660153
CGBitmapContextCreate函数
http://blog.csdn.net/thanklife/article/details/25790433
UIGraphicsBeginImageContext创建的映像停留在内存中永恒
多次在cell中加载网络图片后,内存增长,以前资源未释放
http://bbs.csdn.net/topics/390891681
请问下面的代码有潜在的内存泄漏?
[ios]UIGraphicsGetImageFromCurrentImageContext()-内存泄漏
http://www.itstrike.cn/Question/88ada9bd-911c-44a7-874b-e04c1a1c2bca.html
[转载]ios开发之View属性hidden, opaque, alpha的区别
http://blog.sina.com.cn/s/blog_7da2c9030101ev8n.html
利用预渲染加速iOS设备的图像显示
http://www.keakon.net/2011/07/26/利用预渲染加速iOS设备的图像显示
iOS使用CGContextRef绘制各种图形
http://www.devstore.cn/essay/essayInfo/116.html
iOS CGContextRef画图小结
http://blog.sina.com.cn/s/blog_9693f61a0101deko.html
IOS用CGContextRef画各种图形(文字、圆、直线、弧线、矩形、扇形、椭圆、三角形、圆角矩形、贝塞尔曲线、图片)
http://blog.csdn.net/rhljiayou/article/details/9919713
iOS画图 以及清空
http://blog.csdn.net/woshidaniu/article/details/46683409
7 Quartz 2D
7.1 参考链接
iOS通过Quartz画矩形、文字、线
http://blog.csdn.net/onlyou930/article/details/7726399
Quartz 2D参考-文本
http://blog.csdn.net/kmyhy/article/details/7258338
Quartz 2D (ProgrammingWithQuartz) note