圖片的加載方式 iOS 目前有2種:
成都創(chuàng)新互聯(lián)為客戶提供專業(yè)的網(wǎng)站制作、成都網(wǎng)站制作、程序、域名、空間一條龍服務(wù),提供基于WEB的系統(tǒng)開發(fā). 服務(wù)項(xiàng)目涵蓋了網(wǎng)頁設(shè)計(jì)、網(wǎng)站程序開發(fā)、WEB系統(tǒng)開發(fā)、微信二次開發(fā)、手機(jī)網(wǎng)站開發(fā)等網(wǎng)站方面業(yè)務(wù)。
1.Resource 它是指inageWithContentsFile:創(chuàng)建圖片的圖片管理方式;
2.ImageAssets 它是指使用imageNamed:創(chuàng)建圖片的圖片的管理方式;
UIImage內(nèi)存處理:
真是的App開發(fā)中,常用的無非是1和2兩種方式
1的優(yōu)缺點(diǎn):
1的使用方式:NSString *path =[[NSBundle mainBundle]pathForResource:@"image@2x" type:@"png"];
UIImage *image = [UIImage imageWithContentsOfFile:path];
1的內(nèi)部實(shí)現(xiàn)方式:+ (instancetype)imageWithContentsOfFile:(NSString *)fileName {
NSUInteger scale = 0;
{
scale = 2;//這一部分是提取fileName中@號后面的那個(gè)數(shù)字,如果存在則為1
}
return [[self alloc] initWithData:[NSData dataWithContentsOfFile:fileName scale:scale]];
}
這種方式使用的時(shí)候會有個(gè)局限性,這個(gè)圖片必須是在.ipa的根目錄或者沙盒中。根目錄就是把圖片文件拖到工程中,沙盒中的圖片是寫入進(jìn)去或者存進(jìn)去的;
1的特性:在1的圖片管理方式中,所有的圖片創(chuàng)建都是通過讀取文件數(shù)據(jù)得到的,讀取一次文件數(shù)據(jù)就會產(chǎn)生一次NSData以及產(chǎn)生一個(gè)UIImage,當(dāng)圖片創(chuàng)建好后會銷毀對應(yīng)的NSData,當(dāng)UIImage的引用計(jì)數(shù)變?yōu)?的時(shí)候自動(dòng)銷毀UIImage,這樣的話就可以保證圖片不會長期存在內(nèi)存中。
1的使用場景:由于這種方法的特性,所以1得方法一般用在圖片數(shù)據(jù)很大,圖片一般不需要多次使用的情況,比如引導(dǎo)頁面的背景(圖片全屏),有時(shí)候運(yùn)行APP才顯示,有時(shí)候根本就用不到。
1的優(yōu)點(diǎn):圖片的生命周期可以得到管理,當(dāng)需要圖片的時(shí)候就創(chuàng)建一個(gè),當(dāng)不需要圖片的時(shí)候就讓他銷毀,圖片不會長期的保存在內(nèi)存中,因此不會有內(nèi)存浪費(fèi),在減少大圖的內(nèi)存占用中,1方式優(yōu)先。
2的方式:2的設(shè)計(jì)初衷主要是為了解決自動(dòng)適配Retian屏和非Retian屏,也就是說為了解決iPhone4和iPhone3GS以及以前的機(jī)型的屏幕適配,雖然沒有3GS了,但是plus出來了,需要3x
2的使用方式:UIImage *image = [UIImage imageName:@"image"];
2的特性:與1相似,2也是從圖片文件中讀取圖片數(shù)據(jù)轉(zhuǎn)化成UIImage,只不過這些圖片都打包在2中,最大的區(qū)別就是圖片有緩存。相當(dāng)于與一個(gè)字典,key是圖片名,value是圖片對象。調(diào)用imageNamed:方法的時(shí)候先從這個(gè)字典中去取,如果取到就直接返回,如果娶不到再去文件中創(chuàng)建,然后保存在這個(gè)字典中。由于字典的key和value都是強(qiáng)引用,所以一旦創(chuàng)建后的圖片永不銷毀。
2的內(nèi)部實(shí)現(xiàn)方式:+(instancetype)imageName:(NSString*)imageName {
if(!imageName)
return nil;
}
UIImage *image = self.imageBuff[imageName];
if(image){
return image;
}
NSString *path = @"image Path";
image = [UIImage imageNamed: ?];
if(image){
self.imageBuff[imageName] = image;
}
return image;
}
+ (NSMutableDictionary*)imageBuff {
static NSMutableDictionary *_imageBuff;
static dispatch_once_t onceToken;
dispatch_once(onceToken,^{
_imageBuff = [[NSMutableDictionary alloc]init];
});
return _imageBuff;
}
2的使用場景:最主要的使用場景就是icon類的圖片,一般的icon類的圖片大小在3kb到20kb不等,都是一些小文件
2的優(yōu)點(diǎn):當(dāng)一個(gè)icon在多個(gè)地方需要被顯示的時(shí)候,其對應(yīng)的UIImage對象只會被創(chuàng)建1次,而且多個(gè)地方的icon都將會共用一個(gè)UIImage對象,減少沙盒的讀取操作。
在項(xiàng)目中經(jīng)常遇到要上傳圖片,如果直接上傳,那么會上傳比較大的圖片,導(dǎo)致費(fèi)流量,刷新時(shí)加載圖片時(shí)間過長,手機(jī)內(nèi)存占用率高等問題。
一、先來介紹下概念:
圖片的壓縮其實(shí)是倆概念,
1、是 “壓” 文件體積變小,但是像素?cái)?shù)不變,長寬尺寸不變,那么質(zhì)量可能下降,
2、是 “縮” 文件的尺寸變小,也就是像素?cái)?shù)減少。長寬尺寸變小,文件體積同樣會減小。
二、解決方法(以上傳頭像為例),先縮再壓:
2.1 矯正圖片方向(照片是有方向的,避免出現(xiàn)“倒立”的情況)
- (UIImage*)fixOrientation:(UIImage*)aImage {
// No-op if the orientation is already correct
if(aImage.imageOrientation==UIImageOrientationUp)
returnaImage;
// We need to calculate the proper transformation to make the image upright.
// We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirrored.
CGAffineTransformtransform =CGAffineTransformIdentity;
switch(aImage.imageOrientation) {
caseUIImageOrientationDown:
caseUIImageOrientationDownMirrored:
transform =CGAffineTransformTranslate(transform, aImage.size.width, aImage.size.height);
transform =CGAffineTransformRotate(transform,M_PI);
break;
caseUIImageOrientationLeft:
caseUIImageOrientationLeftMirrored:
transform =CGAffineTransformTranslate(transform, aImage.size.width,0);
transform =CGAffineTransformRotate(transform,M_PI_2);
break;
caseUIImageOrientationRight:
caseUIImageOrientationRightMirrored:
transform =CGAffineTransformTranslate(transform,0, aImage.size.height);
transform =CGAffineTransformRotate(transform, -M_PI_2);
break;
default:
break;
}
switch(aImage.imageOrientation) {
caseUIImageOrientationUpMirrored:
caseUIImageOrientationDownMirrored:
transform =CGAffineTransformTranslate(transform, aImage.size.width,0);
transform =CGAffineTransformScale(transform, -1,1);
break;
caseUIImageOrientationLeftMirrored:
caseUIImageOrientationRightMirrored:
transform =CGAffineTransformTranslate(transform, aImage.size.height,0);
transform =CGAffineTransformScale(transform, -1,1);
break;
default:
break;
}
// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRefctx =CGBitmapContextCreate(NULL, aImage.size.width, aImage.size.height,
CGImageGetBitsPerComponent(aImage.CGImage),0,
CGImageGetColorSpace(aImage.CGImage),
CGImageGetBitmapInfo(aImage.CGImage));
CGContextConcatCTM(ctx, transform);
switch(aImage.imageOrientation) {
caseUIImageOrientationLeft:
caseUIImageOrientationLeftMirrored:
caseUIImageOrientationRight:
caseUIImageOrientationRightMirrored:
CGContextDrawImage(ctx,CGRectMake(0,0,aImage.size.height,aImage.size.width), aImage.CGImage);
break;
default:
CGContextDrawImage(ctx,CGRectMake(0,0,aImage.size.width,aImage.size.height), aImage.CGImage);
break;
}
CGImageRef cgimg =CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImageimageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;
}
2.2 拿到上面矯正過的圖片,縮小圖片尺寸,調(diào)用下面方法傳入newSize,如(200,200):
+ (UIImage*)imageWithImageSimple:(UIImage*)image scaledToSize:(CGSize)newSize
{
UIGraphicsBeginImageContext(newSize);
[imagedrawInRect:CGRectMake(0,0,newSize.width,newSize.height)];
UIImage* newImage =UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
2.3 將2.2的圖片再壓,這個(gè)方法可以重復(fù)壓
//調(diào)整大小
NSData *imageData =UIImageJPEGRepresentation(newImage,rate);
NSUIntegersizeOrigin = [image Datalength];//多少KB
NSUIntegersizeOriginKB = sizeOrigin /1024;//多少KB
2.4 上傳頭像
調(diào)用后臺接口,把imageData二進(jìn)制數(shù)據(jù)上傳即可
總結(jié):對圖片壓縮處理時(shí),在保證圖片清晰度變化不大時(shí),減小圖片文件大小。方法2.2中的newSize 和 2.3中的rate要以實(shí)際效果來設(shè)置,我在自己項(xiàng)目中上傳的頭像最終尺寸是200*200像素,大小為4KB左右。
對于iOS開發(fā)者而言,想要打造一款美圖App,最佳首選的開源框架莫過于GPUImage。它內(nèi)嵌了上百種圖像濾鏡,能夠滿足市面上的一切美顏開發(fā)方案。同時(shí)也具備了實(shí)時(shí)美顏的功能。通過這樣強(qiáng)大的開源框架,我們可以在其上層開發(fā)屬于我們自己的美圖應(yīng)用。SnapseedImitation 是以Snapseed為原型,利用GPUImage框架開發(fā)的圖像處理軟件。
SnapseedImitation
Github地址:
主要依賴GPUImage Github:
1.安裝Cocoapods
2.pod 'GPUImage'
3. improt 導(dǎo)入GPUImage.h后編譯即可。
通過GPUImagePicture獲取待編輯圖像,再經(jīng)過GPUImageFilter渲染后產(chǎn)出一幀frame,經(jīng)由消息管道通知后,便可在GPUImageView顯示編輯后的圖片,或者我們可以通過GPUImageFilter直接導(dǎo)出渲染后的UIImage。
GPUImageInputGPUImageFilterGPUImageOutput
以拉升變形濾鏡為例:
//@拉升變形鏡濾鏡
//創(chuàng)造輸入源
GPUImagePicture* gpupicture = [[GPUImagePicturealloc]initWithImage:[UIImageimageNamed:@"Duck.jpg"]];
//創(chuàng)建濾鏡
PUImageStretchDistortionFilter* stretchDistortionFilter = [GPUImageStretchDistortionFilternew];
//為濾鏡賦值
stretchDistortionFilter.center=CGPointMake(0.2,0.2);
//將輸入源和濾鏡綁定
[gpupicture addTarget:stretchDistortionFilter];
//為原圖附上濾鏡效果[gpupicture processImage];
//濾鏡收到原圖產(chǎn)生的一個(gè)frame,并將它作為自己的當(dāng)前圖像緩存
[stretchDistortionFilter useNextFrameForImageCapture];
//通過濾鏡,獲取當(dāng)前的圖像。
UIImage*image = [stretchDistortionFilter imageFromCurrentFramebuffer];
圖像拉升變形前后對比 :
開發(fā)過程中,必然會有多種濾鏡復(fù)合的需求,例如一個(gè)可以變化亮度、對比度、曝光的圖像調(diào)節(jié)程序。但是依照上一個(gè)示例,我們每添加一種濾鏡,便會代替之前的濾鏡效果。如果每次處理的都是上一次的filter導(dǎo)出的UIImage圖片的話,又會導(dǎo)致無法恢復(fù)到原圖樣子,導(dǎo)致失真。(可參考在繪畫板中,把圖片縮小到最小,再放大,圖片變成為了一個(gè)像素塊。)
這時(shí)候,我們需要一個(gè)很好用的類:GPUImageFilterPipeline
GPUImageFilterPipeline可以將多個(gè)濾鏡進(jìn)行復(fù)合,并且在多次處理后,仍然能夠恢復(fù)成為原圖不失真。
仍然以拉升變形和卡通描邊效果為例 :
//獲取原圖
GPUImagePicture* gpupicture = [[GPUImagePicturealloc]initWithImage:[UIImageimageNamed:@"Duck.jpg"]];
//輸出圖像的
ViewGPUImageView* gpuimageView = [[GPUImageViewalloc]initWithFrame:CGRectMake(0,60,320,320)];[self.viewaddSubview:gpuimageView];
//卡通描邊濾鏡
GPUImageToonFilter* toonFilter = [GPUImageToonFilternew];toonFilter.threshold=0.1;
//拉升變形濾鏡
GPUImageStretchDistortionFilter* stretchDistortionFilter = [GPUImageStretchDistortionFilternew];
stretchDistortionFilter.center=CGPointMake(0.5,0.5);
//將濾鏡組成數(shù)組
NSArray* filters = @[toonFilter,stretchDistortionFilter];
//通過pipline,將輸入源,輸出,濾鏡,三方綁定
GPUImageFilterPipeline* pipLine = [[GPUImageFilterPipelinealloc]initWithOrderedFilters:filters input:self.gpupictureoutput:self.gpuimageView];
//繪制產(chǎn)出最終帶有復(fù)合濾鏡的圖像。
[self.gpupictureprocessImage];
//獲取產(chǎn)出的UIImage圖像
//此時(shí)調(diào)用useNextFrameForImageCapture的可以是任一在數(shù)組中的Filter。
[stretchDistortionFilter useNextFrameForImageCapture];
UIImage* image = [self.pipLinecurrentFilteredFrame];
基于GPUImage框架,我為其添加了一套了Snapseed的UI,通過手勢識別方案對圖像濾鏡進(jìn)行調(diào)節(jié)拖控。
更多內(nèi)容:
GPUImage 進(jìn)階學(xué)習(xí),實(shí)時(shí)視頻錄制,人臉檢測
UIImageView *imageView = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"bgImage"]];?
創(chuàng)建并設(shè)置默認(rèn)圖, 也可以
UIImageView*imageView = [[UIImageView alloc] init];
imageView.image= [UIImageimageNamed:@"bgImage"];
還可以這樣先設(shè)置imageview的大, 在設(shè)置圖片
UIImageView*imageView = [[UIImageView alloc] initWithFrame:(CGRectMake(0,144,SCREEN_Width,50))];
imageView.image= [UIImageimageNamed:@"bgImage"];
由此可看imageview的frame可以這樣設(shè)置
imageView.frame=CGRectMake(0,144,SCREEN_Width,50);
通常我們使用的的imageview都會添加圓角邊框
imageView.layer.masksToBounds = YES;
imageView.layer.cornerRadius=25;
imageView.layer.borderColor = [UIColor blueColor].CGColor;
imageView.layer.borderWidth=1;
這個(gè)圓角和邊框像view和label以及button的設(shè)置方式都是一樣的 當(dāng)然imageview也一樣
imageView.backgroundColor= [UIColorclearColor]; 圖片設(shè)置背景顏色, 我通常使用clearColor ?透明
?imageView.userInteractionEnabled = YES; 圖片設(shè)置成可交互, 設(shè)置為NO則不能交互
[self.viewaddSubview: imageView]; 添加視圖也可叫做顯示視圖
設(shè)置圖片內(nèi)容的布局方式 imageView.contentMode
這個(gè)屬性是用來設(shè)置圖片的顯示方式,如居中、居右,是否縮放等
imageView.contentMode = UIViewContentModeScaleAspectFit;
UIViewContentMode contentMode枚舉類型
? ? (1)? UIViewContentModeScaleToFill; ? ??默認(rèn),對圖片進(jìn)行拉伸處理(不是按比例),是充滿bouns
? (2)? UIViewContentModeScaleAspectFit; ? ??按原圖比例進(jìn)行拉伸,是圖片完全展示在bouns中
? ? (3)? UIViewContentModeScaleAspectFill; ? ??按原圖比例填充,使圖片展示在bouns中,可能只顯示部分
? ? (4)? UIViewContentModeRedraw; ? ??重劃邊界變化(重設(shè) - setNeedsDisplay)
? ? (5)? UIViewContentModeCenter; ? ??圖片顯示在imageview的正中間,原圖大小
? ? (6)? UIViewContentModeTop; ? ??圖片顯示在imageview的上部,原圖大小
? ? (7)? UIViewContentModeBottom; ? ??圖片顯示在imageview的下部,原圖大小
? ? (8)? UIViewContentModeLeft; ? ??圖片顯示在imageview的左部,原圖大小
? ? (9)? UIViewContentModeRight; ? ??圖片顯示在imageview的右部,原圖大小
? ? (10)? UIViewContentModeTopLeft; ? ??圖片顯示在imageview的左上部,原圖大小
? ? (11)? UIViewContentModeTopRight; ? ??圖片顯示在imageview的右上部,原圖大小
? ? (12)? UIViewContentModeBottomLeft; ? ??圖片顯示在imageview的左下部,原圖大小
? ? (13)? UIViewContentModeBottomRight; ? ??圖片顯示在imageview的右下部,原圖大小
imageView.alpha = 1.0; ? ?設(shè)置圖片透明度
???NSString *path1 = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"jpg"];
???NSString *path2 = [[NSBundle mainBundle] pathForResource:@"2" ofType:@"jpg"];
???NSString *path3 = [[NSBundle mainBundle] pathForResource:@"3" ofType:@"jpg"];
???imageView.animationImages = @[[UIImage imageWithContentsOfFile:path1],[UIImage imageWithContentsOfFile:path2],[UIImage imageWithContentsOfFile:path3]];
???imageView.animationDuration = 5.0f; ? ?設(shè)置循環(huán)一次的時(shí)間
???imageView.animationRepeatCount = 0;? ? // 設(shè)置循環(huán)次數(shù)(0為無線循環(huán))
???[imageView startAnimating];? ? ? ? ? ? // 開始動(dòng)畫
???[imageView stopAnimating];? ? ? ? ? ? ? // 停止動(dòng)畫
NSData *imageData = [NSData dataWithContentsOfFile:path];
UIImage *image4 = [UIImage imageWithData:imageData];
NSString *path = [[NSBundle mainBundle] pathForResource:@"1" ofType:@"jpg"];
UIImage *image2 = [UIImage imageWithContentsOfFile:path];
ImageView.hidden?=?NO;????隱藏或者顯示圖片?YES為隱藏
[ImageView?sizeToFit];????將圖片尺寸調(diào)整為與內(nèi)容圖片相同
UITapGestureRecognizer?*singleTap = [[UITapGestureRecognizer?alloc]?initWithTarget:self?action:@selector(tapImageView:)];?//?設(shè)置手勢
[ImageView?addGestureRecognizer:singleTap];?//?給圖片添加手勢