iOS中如何实现大尺寸图片旋转与缩放功能(ios,移动开发)

时间:2024-04-29 23:07:18 作者 : 石家庄SEO 分类 : 移动开发
  • TAG :

前言

由于iPhone的硬件性能限制,直到iPhone 6s开始,才将最大内存拓展到2G。

可即使是如此,也不代表一个应用可使用的空间是2G。

一张10000 x 10000的图片,如果通过UIImageJPEGRepresentation方法将图片转成内存数据,会有一个峰值波动。

这里的峰值其实是图片在解压时产生的位图数据所占空间,然后才转换成我们可以操作的NSData。

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

这里会产生381M的消耗,及时会被回收,但是想一下,如果图片尺寸很大,数量很多的时候,很容易就会发生异常了。

本文将给大家详细介绍关于iOS大尺寸图片旋转与缩放的相关内容,分享出来供大家参考学习,话不多说了,接下来说下具体的操作

旋转

我们知道如果对一个UIImage对象进行旋转操作,相信做项目时肯定会有用到 UIImage 这个类,可以有如下的方式

通过 CGContextDrawImage 进行图片绘制

+(UIImage*)image:(UIImage*)imagerotation:(UIImageOrientation)orientation{longdoublerotate=0.0;CGRectrect;floattranslateX=0;floattranslateY=0;floatscaleX=1.0;floatscaleY=1.0;switch(orientation){caseUIImageOrientationLeft: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);CGContextRefcontext=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();returnnewPic;}

这里有一个问题是,这里会创建一个新的图片大小空间的,然后进行重新绘制。可能会存在一个隐患,就是当图片尺寸过大的时候,就会出现内存占用过高的情况

接下来介绍一种另辟蹊径的解决方法--通过给图片添加滤镜的方式。

既然操作的对象是图片,那么它就会各种滤镜展示。系统给我们提供了多大一百多种滤镜,这里的滤镜不单只颜色等状态发生变化。

这其中就有我们需要的滤镜Key inputTransform。

+(UIImage*)getRotationImage:(UIImage*)imagerotation:(CGFloat)rotation{CIImage*ciImage=[[CIImagealloc]initWithImage:image];CIFilter*filter=[CIFilterfilterWithName:@"CIAffineTransform"keysAndValues:kCIInputImageKey,ciImage,nil];[filtersetDefaults];CGAffineTransformtransform=CATransform3DGetAffineTransform([selfrotateTransform:CATransform3DIdentityclockwise:NOangle:rotation]);[filtersetValue:[NSValuevalueWithBytes:&transformobjCType:@encode(CGAffineTransform)]forKey:@"inputTransform"];//根据滤镜设置图片CIContext*context=[CIContextcontextWithOptions:@{kCIContextUseSoftwareRenderer:@(NO)}];CIImage*outputImage=[filteroutputImage];CGImageRefcgImage=[contextcreateCGImage:outputImagefromRect:[outputImageextent]];UIImage*result=[UIImageimageWithCGImage:cgImage];CGImageRelease(cgImage);returnresult;}+(CATransform3D)rotateTransform:(CATransform3D)initialTransformclockwise:(BOOL)clockwiseangle:(CGFloat)angle{CGFloatarg=angle*M_PI/180.0f;if(!clockwise){arg*=-1;}//进行形变CATransform3Dtransform=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);returntransform;}

通过这种操作,可以利用GPU来进行图片操作,可以一定程度的降低消耗,节约资源。

缩放

既然图片很大,那么我们可以通过缩放的方式,来减小图片的尺寸,减少内存消耗,进而降低异常风险。

我们通常采用UIImage提供的系统方法drawInRect 及其一系列的方法,来进行图片缩放。

可是这种操作的缺陷和最开始介绍的旋转一样,其实质都是进行图片的重新绘制。

通过绘制图片的方式进行图片缩放

+(UIImage*)image:(UIImage*)imagetransformtoSize:(CGSize)Newsize{//创建一个bitmap的contextUIGraphicsBeginImageContext(Newsize);//绘制改变大小的图片[imagedrawInRect:CGRectMake(0,0,Newsize.width,Newsize.height)];//从当前context中创建一个改变大小后的图片UIImage*TransformedImg=UIGraphicsGetImageFromCurrentImageContext();//使当前的context出堆栈UIGraphicsEndImageContext();//返回新的改变大小后的图片returnTransformedImg;}

这里是内存消耗。通过看图可以发现,针对大图,在进行缩放的时候,内存消耗的峰值能达到426M,耗时在1.5s左右
由于我们使用的手机是iPhone X,在更低端的设备上,这是多么大的损耗,很容易发生异常

iOS中如何实现大尺寸图片旋转与缩放功能

既然上面的方法损耗很大,我们来看下另外的一种方式。

先看下内存消耗

iOS中如何实现大尺寸图片旋转与缩放功能

通过图上可以看出,在进行图片缩放的时候,内存有小幅增加,产生的消耗在18M,耗时也在1.5s左右。

这样的效果是非常显著的。下面来看代码

+(UIImage*)resizeImage:(UIImage*)imagetoSize:(CGSize)size{CIImage*ciImage=[[CIImagealloc]initWithImage:image];//创建一个inputimage类型的滤镜CIFilter*filter=[CIFilterfilterWithName:@"CIAffineTransform"keysAndValues:kCIInputImageKey,ciImage,nil];//设置默认的滤镜效果[filtersetDefaults];//设置缩放比例CGFloatscale=1;if(size.width!=CGFLOAT_MAX){scale=(CGFloat)size.width/image.size.width;}elseif(size.height!=CGFLOAT_MAX){scale=(CGFloat)size.height/image.size.height;}//进行赋值CGAffineTransformtransform=CGAffineTransformMakeScale(scale,scale);[filtersetValue:[NSValuevalueWithBytes:&transformobjCType:@encode(CGAffineTransform)]forKey:@"inputTransform"];//通过GPU的方式来进行处理CIContext*context=[CIContextcontextWithOptions:@{kCIContextUseSoftwareRenderer:@(NO)}];//根据滤镜输出图片CIImage*outputImage=[filteroutputImage];CGImageRefcgImage=[contextcreateCGImage:outputImagefromRect:[outputImageextent]];//创建UIImage对象,并释放资源UIImage*result=[UIImageimageWithCGImage:cgImage];CGImageRelease(cgImage);returnresult;}

可以发现我们这里使用的和旋转是同样的方式。通过给图片添加滤镜能够很安全的实现我们的需求。

总结

1.针对巨幅图片操作,可以采用这种思路:先生成一个尺寸小的缩略图,然后在进行各种操作,可以降低资源消耗;

2.通过CoreImage.framework来进行图片处理。

3.之前一直对CoreImage.framework的理解,只是其能够对图片和视频添加那种可见的滤镜,未曾想过这种滤镜也支持缩放和旋转。

? 为什么CoreImage.framework的方式能够很安全呢?

该框架从iOS 5开始投入使用,通过对CoreGraphics.framework、CoreVideo.framework、Image I/O.framework进行数据处理,

可以自由在CPU和GPU之间切换运算方式,

可以最大限度的利用GPU来进行计算,降低内存消耗,

甚至可以对视频进行实时滤镜处理。

针对不能通过原生对UIView进行transform操作的时候,CoreImage.framework会是你的朋友。

最直接的来自文档

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.

它已经帮你把所有东西都处理好了

 </div> <div class="zixun-tj-product adv-bottom"></div> </div> </div> <div class="prve-next-news">
本文:iOS中如何实现大尺寸图片旋转与缩放功能的详细内容,希望对您有所帮助,信息来源于网络。
上一篇:怎么在iOS中判断是否越狱设备下一篇:

7 人围观 / 0 条评论 ↓快速评论↓

(必须)

(必须,保密)

阿狸1 阿狸2 阿狸3 阿狸4 阿狸5 阿狸6 阿狸7 阿狸8 阿狸9 阿狸10 阿狸11 阿狸12 阿狸13 阿狸14 阿狸15 阿狸16 阿狸17 阿狸18