欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS中大尺寸圖片的旋轉(zhuǎn)與縮放實(shí)例詳解

 更新時(shí)間:2018年09月05日 09:42:51   作者:BourbonZ  
圖片縮小旋轉(zhuǎn)是我們?cè)陂_(kāi)發(fā)中經(jīng)常會(huì)遇到的一個(gè)功能,下面這篇文章主要給大家介紹了關(guān)于iOS中大尺寸圖片的旋轉(zhuǎn)與縮放的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),需要的朋友可以參考借鑒,下面來(lái)一起看看吧

前言

由于iPhone的硬件性能限制,直到iPhone 6s開(kāi)始,才將最大內(nèi)存拓展到2G。

可即使是如此,也不代表一個(gè)應(yīng)用可使用的空間是2G。

一張10000 x 10000的圖片,如果通過(guò)UIImageJPEGRepresentation方法將圖片轉(zhuǎn)成內(nèi)存數(shù)據(jù),會(huì)有一個(gè)峰值波動(dòng)。

這里的峰值其實(shí)是圖片在解壓時(shí)產(chǎn)生的位圖數(shù)據(jù)所占空間,然后才轉(zhuǎn)換成我們可以操作的NSData。

其計(jì)算公式是 W x H x 4 / 1024 / 1024 也就是 10000 x 10000 x4 /1024 / 1024 = 381.4(M)。

這里會(huì)產(chǎn)生381M的消耗,及時(shí)會(huì)被回收,但是想一下,如果圖片尺寸很大,數(shù)量很多的時(shí)候,很容易就會(huì)發(fā)生異常了。

本文將給大家詳細(xì)介紹關(guān)于iOS大尺寸圖片旋轉(zhuǎn)與縮放的相關(guān)內(nèi)容,分享出來(lái)供大家參考學(xué)習(xí),話不多說(shuō)了,接下來(lái)說(shuō)下具體的操作

旋轉(zhuǎn)

我們知道如果對(duì)一個(gè)UIImage對(duì)象進(jìn)行旋轉(zhuǎn)操作,相信做項(xiàng)目時(shí)肯定會(huì)有用到 UIImage 這個(gè)類,可以有如下的方式

通過(guò) CGContextDrawImage 進(jìn)行圖片繪制

+ (UIImage *)image:(UIImage *)image rotation:(UIImageOrientation)orientation {

 long double rotate = 0.0;
 CGRect rect;
 float translateX = 0;
 float translateY = 0;
 float scaleX = 1.0;
 float scaleY = 1.0;

 switch (orientation) {
 case UIImageOrientationLeft:
 rotate = M_PI_2;
 rect = CGRectMake(0, 0, image.size.height, image.size.width);
 translateX = 0;
 translateY = -rect.size.width;
 scaleY = rect.size.width/rect.size.height;
 scaleX = rect.size.height/rect.size.width;
 break;
 default:
 rotate = 0.0;
 rect = CGRectMake(0, 0, image.size.width, image.size.height);
 translateX = 0;
 translateY = 0;
 break;
 }

 UIGraphicsBeginImageContext(rect.size);
 CGContextRef context = UIGraphicsGetCurrentContext();
 //做CTM變換
 CGContextTranslateCTM(context, 0.0, rect.size.height);
 CGContextScaleCTM(context, 1.0, -1.0);
 CGContextRotateCTM(context, rotate);
 CGContextTranslateCTM(context, translateX, translateY);

 CGContextScaleCTM(context, scaleX, scaleY);
 //繪制圖片
 CGContextDrawImage(context, CGRectMake(0, 0, rect.size.width, rect.size.height), image.CGImage);
 UIImage *newPic = UIGraphicsGetImageFromCurrentImageContext();
 return newPic;
} 

這里有一個(gè)問(wèn)題是,這里會(huì)創(chuàng)建一個(gè)新的圖片大小空間的,然后進(jìn)行重新繪制??赡軙?huì)存在一個(gè)隱患,就是當(dāng)圖片尺寸過(guò)大的時(shí)候,就會(huì)出現(xiàn)內(nèi)存占用過(guò)高的情況

接下來(lái)介紹一種另辟蹊徑的解決方法--通過(guò)給圖片添加濾鏡的方式。

既然操作的對(duì)象是圖片,那么它就會(huì)各種濾鏡展示。系統(tǒng)給我們提供了多大一百多種濾鏡,這里的濾鏡不單只顏色等狀態(tài)發(fā)生變化。

這其中就有我們需要的濾鏡Key inputTransform。

+ (UIImage *)getRotationImage:(UIImage *)image rotation:(CGFloat)rotation {

 CIImage *ciImage = [[CIImage alloc] initWithImage:image];
 CIFilter *filter = [CIFilter filterWithName:@"CIAffineTransform" keysAndValues:kCIInputImageKey, ciImage, nil];

 [filter setDefaults];
 CGAffineTransform transform = CATransform3DGetAffineTransform([self rotateTransform:CATransform3DIdentity clockwise:NO angle:rotation]);
 [filter setValue:[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)] forKey:@"inputTransform"];

 //根據(jù)濾鏡設(shè)置圖片
 CIContext *context = [CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer : @(NO)}];
 CIImage *outputImage = [filter outputImage];
 CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];

 UIImage *result = [UIImage imageWithCGImage:cgImage];

 CGImageRelease(cgImage);

 return result;
}
+ (CATransform3D)rotateTransform:(CATransform3D)initialTransform clockwise:(BOOL)clockwise angle:(CGFloat)angle {

 CGFloat arg = angle*M_PI / 180.0f;
 if(!clockwise){
 arg *= -1;
 }
 //進(jìn)行形變
 CATransform3D transform = initialTransform;
 transform = CATransform3DRotate(transform, arg, 0, 0, 1);
 CGFloat _flipState1 = 0;
 CGFloat _flipState2 = 0;
 transform = CATransform3DRotate(transform, _flipState1*M_PI, 0, 1, 0);
 transform = CATransform3DRotate(transform, _flipState2*M_PI, 1, 0, 0);

 return transform;
} 

通過(guò)這種操作,可以利用GPU來(lái)進(jìn)行圖片操作,可以一定程度的降低消耗,節(jié)約資源。

縮放

既然圖片很大,那么我們可以通過(guò)縮放的方式,來(lái)減小圖片的尺寸,減少內(nèi)存消耗,進(jìn)而降低異常風(fēng)險(xiǎn)。

我們通常采用UIImage提供的系統(tǒng)方法drawInRect 及其一系列的方法,來(lái)進(jìn)行圖片縮放。

可是這種操作的缺陷和最開(kāi)始介紹的旋轉(zhuǎn)一樣,其實(shí)質(zhì)都是進(jìn)行圖片的重新繪制。

通過(guò)繪制圖片的方式進(jìn)行圖片縮放

+ (UIImage *)image:(UIImage *)image transformtoSize:(CGSize)Newsize {
 // 創(chuàng)建一個(gè)bitmap的context
 UIGraphicsBeginImageContext(Newsize);
 // 繪制改變大小的圖片
 [image drawInRect:CGRectMake(0, 0, Newsize.width, Newsize.height)];
 // 從當(dāng)前context中創(chuàng)建一個(gè)改變大小后的圖片
 UIImage *TransformedImg=UIGraphicsGetImageFromCurrentImageContext();
 // 使當(dāng)前的context出堆棧
 UIGraphicsEndImageContext();
 // 返回新的改變大小后的圖片
 return TransformedImg;
}

這里是內(nèi)存消耗。通過(guò)看圖可以發(fā)現(xiàn),針對(duì)大圖,在進(jìn)行縮放的時(shí)候,內(nèi)存消耗的峰值能達(dá)到426M,耗時(shí)在1.5s左右
由于我們使用的手機(jī)是iPhone X,在更低端的設(shè)備上,這是多么大的損耗,很容易發(fā)生異常

既然上面的方法損耗很大,我們來(lái)看下另外的一種方式。

先看下內(nèi)存消耗

通過(guò)圖上可以看出,在進(jìn)行圖片縮放的時(shí)候,內(nèi)存有小幅增加,產(chǎn)生的消耗在18M,耗時(shí)也在1.5s左右。

這樣的效果是非常顯著的。下面來(lái)看代碼

+(UIImage *)resizeImage:(UIImage *)image toSize:(CGSize)size {

 CIImage *ciImage = [[CIImage alloc] initWithImage:image];
 //創(chuàng)建一個(gè)input image類型的濾鏡
 CIFilter *filter = [CIFilter filterWithName:@"CIAffineTransform" keysAndValues:kCIInputImageKey, ciImage, nil];
 //設(shè)置默認(rèn)的濾鏡效果
 [filter setDefaults];

 //設(shè)置縮放比例
 CGFloat scale = 1;
 if (size.width != CGFLOAT_MAX) {
 scale = (CGFloat) size.width / image.size.width;
 } else if (size.height != CGFLOAT_MAX) {
 scale = (CGFloat) size.height / image.size.height;
 }

 //進(jìn)行賦值
 CGAffineTransform transform = CGAffineTransformMakeScale(scale, scale);
 [filter setValue:[NSValue valueWithBytes:&transform objCType:@encode(CGAffineTransform)] forKey:@"inputTransform"];

 //通過(guò)GPU的方式來(lái)進(jìn)行處理
 CIContext *context = [CIContext contextWithOptions:@{kCIContextUseSoftwareRenderer : @(NO)}];
 //根據(jù)濾鏡輸出圖片
 CIImage *outputImage = [filter outputImage];
 CGImageRef cgImage = [context createCGImage:outputImage fromRect:[outputImage extent]];
 //創(chuàng)建UIImage 對(duì)象,并釋放資源
 UIImage *result = [UIImage imageWithCGImage:cgImage];

 CGImageRelease(cgImage);

 return result;
}

可以發(fā)現(xiàn)我們這里使用的和旋轉(zhuǎn)是同樣的方式。通過(guò)給圖片添加濾鏡能夠很安全的實(shí)現(xiàn)我們的需求。

總結(jié)

1.針對(duì)巨幅圖片操作,可以采用這種思路:先生成一個(gè)尺寸小的縮略圖,然后在進(jìn)行各種操作,可以降低資源消耗;

2.通過(guò)CoreImage.framework來(lái)進(jìn)行圖片處理。

3.之前一直對(duì)CoreImage.framework的理解,只是其能夠?qū)D片和視頻添加那種可見(jiàn)的濾鏡,未曾想過(guò)這種濾鏡也支持縮放和旋轉(zhuǎn)。

? 為什么CoreImage.framework的方式能夠很安全呢?

該框架從iOS 5開(kāi)始投入使用,通過(guò)對(duì)CoreGraphics.framework、CoreVideo.framework、Image I/O.framework進(jìn)行數(shù)據(jù)處理,

可以自由在CPU和GPU之間切換運(yùn)算方式,

可以最大限度的利用GPU來(lái)進(jìn)行計(jì)算,降低內(nèi)存消耗,

甚至可以對(duì)視頻進(jìn)行實(shí)時(shí)濾鏡處理。

針對(duì)不能通過(guò)原生對(duì)UIView進(jìn)行transform操作的時(shí)候,CoreImage.framework會(huì)是你的朋友。

最直接的來(lái)自文檔

Core Image is an image processing and analysis technology designed to provide near real-time processing for still and video images. It operates on image data types from the Core Graphics, Core Video, and Image I/O frameworks, using either a GPU or CPU rendering path. Core Image hides the details of low-level graphics processing by providing an easy-to-use application programming interface (API). You don't need to know the details of OpenGL, OpenGL ES, or Metal to leverage the power of the GPU, nor do you need to know anything about Grand Central Dispatch (GCD) to get the benefit of multicore processing. Core Image handles the details for you.

它已經(jīng)幫你把所有東西都處理好了,大膽的用吧

代碼地址 (本地下載

總結(jié)

以上就是這篇文章的全部?jī)?nèi)容了,希望本文的內(nèi)容對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,如果有疑問(wèn)大家可以留言交流,謝謝大家對(duì)腳本之家的支持。

相關(guān)文章

  • iOS實(shí)現(xiàn)列表與網(wǎng)格兩種視圖的相互切換

    iOS實(shí)現(xiàn)列表與網(wǎng)格兩種視圖的相互切換

    相信大家應(yīng)該也都發(fā)現(xiàn)了,在現(xiàn)在很多的電商app中,都會(huì)有列表視圖和網(wǎng)格兩種視圖的相互切換。例如京東和淘寶。這樣更利于提高用戶的體驗(yàn)度,所以這篇文章小編就是大家分享下利用iOS實(shí)現(xiàn)列表與網(wǎng)格兩種視圖相互切換的方法,文中介紹的很詳細(xì),感興趣的下面來(lái)一起看看吧。
    2016-10-10
  • ios開(kāi)發(fā)中的容錯(cuò)處理示例詳解

    ios開(kāi)發(fā)中的容錯(cuò)處理示例詳解

    最近發(fā)現(xiàn)還是有很多朋友在問(wèn)類似解析時(shí)容錯(cuò)問(wèn)題怎么解決,所以下面這篇文章主要給大家介紹了關(guān)于ios開(kāi)發(fā)中的容錯(cuò)處理的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們一起來(lái)看看吧
    2018-05-05
  • iOS表視圖之下拉刷新控件功能的實(shí)現(xiàn)方法

    iOS表視圖之下拉刷新控件功能的實(shí)現(xiàn)方法

    下拉刷新是重新刷新表視圖或列表,以便重新加載數(shù)據(jù),這種模式廣泛用于移動(dòng)平臺(tái),相信大家對(duì)于此也是非常熟悉的,那么iOS是如何做到的下拉刷新呢?下面小編給大家分享iOS表視圖之下拉刷新控件的實(shí)現(xiàn)方法,一起看看吧
    2017-01-01
  • IOS 基本文件操作實(shí)例詳解

    IOS 基本文件操作實(shí)例詳解

    這篇文章主要介紹了IOS 基本文件操作實(shí)例詳解 的相關(guān)資料,需要的朋友可以參考下
    2017-06-06
  • 兩種iOS隱藏導(dǎo)航欄的正確方法

    兩種iOS隱藏導(dǎo)航欄的正確方法

    這篇文章主要為大家詳細(xì)介紹了iOS導(dǎo)航欄的正確隱藏方式,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-03-03
  • iOS tableView多輸入框如何獲取數(shù)據(jù)

    iOS tableView多輸入框如何獲取數(shù)據(jù)

    這篇文章主要給大家介紹了關(guān)于iOS tableView多輸入框如何獲取數(shù)據(jù)的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-04-04
  • IOS實(shí)現(xiàn)郵箱模糊匹配的功能

    IOS實(shí)現(xiàn)郵箱模糊匹配的功能

    在一些App的訂單填寫頁(yè),輸入用戶郵箱有個(gè)提示郵箱后綴的功能,很好用!還可以根據(jù)各個(gè)郵箱類型用戶量來(lái)做一個(gè)優(yōu)先級(jí)的匹配哦。這個(gè)功能該如何實(shí)現(xiàn)呢,下面來(lái)一起看看。
    2016-08-08
  • iOS實(shí)現(xiàn)導(dǎo)航欄透明示例代碼

    iOS實(shí)現(xiàn)導(dǎo)航欄透明示例代碼

    本篇文章主要介紹了iOS實(shí)現(xiàn)導(dǎo)航欄透明示例代碼,小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-03-03
  • iOS中關(guān)于Taptic-Engine震動(dòng)反饋的深入解析

    iOS中關(guān)于Taptic-Engine震動(dòng)反饋的深入解析

    這篇文章主要給大家介紹了關(guān)于iOS中關(guān)于Taptic-Engine震動(dòng)反饋的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧。
    2017-11-11
  • IOS開(kāi)發(fā)中使用UIFont設(shè)置字體及批量創(chuàng)建控件

    IOS開(kāi)發(fā)中使用UIFont設(shè)置字體及批量創(chuàng)建控件

    這篇文章主要介紹了IOS開(kāi)發(fā)中使用UIFont設(shè)置字體及批量創(chuàng)建控件的方法,內(nèi)容很實(shí)用,感興趣的小伙伴們可以參考一下
    2016-03-03

最新評(píng)論