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圖片有黑邊的解決方法

http://www.minroad.com/?p=9

用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?

http://stackoverflow.com/questions/1431566/iphone-cgbitmapcontextcreateimage-leak-anyone-else-with-this-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

http://stackoverflow.com/questions/1436465/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创建的映像停留在内存中永恒

http://codego.net/589714/

多次在cell中加载网络图片后,内存增长,以前资源未释放

http://bbs.csdn.net/topics/390891681

请问下面的代码有潜在的内存泄漏?

http://codego.net/459077/

[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

http://renxiangzyq.iteye.com/blog/1188025

【IOS开发高级系列】异步绘制专题相关推荐

  1. 【IOS开发进阶系列】动画专题

    1 CALayer IOS SDK详解之CALayer(一) http://doc.okbase.net/Hello_Hwc/archive/123447.html 1.1 基本概念 1.1.1 CA ...

  2. iOS开发UINavigation系列四——导航控制器UINavigationController

    iOS开发UINavigation系列四--导航控制器UINavigationController 一.引言 在前面的博客中,我么你介绍了UINavigationBar,UINavigationIte ...

  3. IOS开发基础之异步下载网络图片第1部分

    IOS开发基础之异步下载网络图片第1部分 加入ATS // LJAppInfo.h // 37-异步下载网络图片 // Created by 鲁军 on 2021/3/10. #import < ...

  4. IOS开发高级之点餐系统的实现-01

    IOS开发高级之点餐系统的实现-01 // // ViewController.m // 01-点餐系统 // // Created by 鲁军 on 2021/2/11. //#import &qu ...

  5. iOS开发——高级篇——线程同步、线程依赖、线程组

    前言 对于iOS开发中的网络请求模块,AFNet的使用应该是最熟悉不过了,但你是否把握了网络请求正确的完成时机?本篇文章涉及线程同步.线程依赖.线程组等专用名词的含义,若对上述名词认识模糊,可先进行查 ...

  6. iOS开发 高级绘图

    概述 在iOS中可以很容易的开发出绚丽的界面效果,一方面得益于成功系统的设计,另一方面得益于它强大的开发框架.今天我们将围绕iOS中两大图形.图像绘图框架进行介绍:Quartz 2D绘制2D图形和Co ...

  7. iOS开发——高级篇——iOS开发之网络安全密码学

    一.非对称加密 - RSA : + 公钥加密,私钥解密: + 私钥加密,公钥解密: + 只能通过因式分解来破解 二.对称加密 - DES - 3DES - AES (高级密码标准,美国国家安全局使用, ...

  8. iOS开发-聊天气泡的绘制和聊天消息列表

    iOS开发中什么最重要?流媒体?即时通讯?还是其他什么技术?其实都不是,最重要的东西诚然只是iOS的基础,比如画一个按钮,封装一个控件,扩展一个类等等.这些东西看似简单,实则很难,所有的技术都基于这些 ...

  9. iOS开发学习系列(1)———Swift语言入门

    缘起 对于成为全栈开发者的目标而言,很好奇自己几年前怎么就没想过iOS开发的事情.iOS好歹也是移动操作系统两巨头之一.反思了下,有可能是因为之前对Object-C太无感导致的.现在趁着Swift,借 ...

最新文章

  1. 基于深度学习的NLP 32页最新进展综述,190篇参考文献
  2. axure8 事件改变样式_15. 教你零基础搭建小程序:小程序事件绑定(2)
  3. 一、flask的基本使用-flask
  4. 震惊整个世界的新发现,科学界的大骗局
  5. (cljs/run-at (JSVM. :all) 细说函数)
  6. linux 虚拟机大量udp请求失败_利用PXE远程装机服务批量部署Linux
  7. 【java】System.arraycopy为什么快
  8. Python的__init__和self是做什么的?
  9. 向园子里的朋友探讨一个问题:如果判定一个对象已被处置
  10. c#中ToString(yyyyMMdd) 与ToString(yyyymmdd)区别
  11. 发明与实用新型专利了解
  12. PHP实现敏感词过滤
  13. [置顶] 礼物:《红孩儿引擎内功心法修练与Cocos2d-x》之结点系统(场景,层,精灵)...
  14. 针对传感网的数据管理系统结构有_2010年自考管理信息系统模拟试题及答案(三)...
  15. composer 镜像
  16. StringTokenizer类详解
  17. 深度学习在音频信号处理领域中的进展(截止至2019年5月)
  18. 【渝粤题库】陕西师范大学164107 电子商务信息安全 作业(高起专)
  19. opentp1如何连接oracle,Oracle用户安全管理
  20. TextView中设置行间距的方法

热门文章

  1. SQL优化中索引列使用函数之灵异事件
  2. 【RMF】ros机器人中间件框架学习系列二:运行demos
  3. mysql exists 效率_Mysql之exists和inner join效率问题(1)
  4. sklearn之逻辑回归LR
  5. Android面试,给正在找工作的安卓攻城师们 ... ...
  6. 外贸公司怎么群发邮件?群发邮件邮箱怎么发更高效?
  7. Base64编解码工具
  8. 域服务器用户一直被锁,Windows Server 2019 域用户账户锁定策略
  9. System.IO.FileNotFoundException: Could not load file or assembly ‘xx.dll‘ or one of its dependencies
  10. 从 RGB 到 HSV 的转换详细介绍