iOS关于@2x,@3x的区别及图片的绘制

为什么会有2倍,3倍图

网络上会有很多的解释,这些解释都是对的。

通俗点说,出现这种区别是因为,屏幕尺寸没有屏幕分辨率增长的快(所以更高清了)。所以,对于iPhone6来说,1pt(代码中的尺寸值单位,也可理解为屏幕物理尺寸的换算单位)代表2px。对于iPhone6P来说,1pt代表3px。

所以对于iPhone6P和iPhone6来说,我们如果都想在屏幕上显示一个100ptx100pt的图片。

iPhone6就需要加载一个尺寸 200px x 200px 的图片。

iPhone6P需要加载一个尺寸 300px x 300px 的图片。

因为如果iPhone6加载一个100px x 100px的图片,它实际上要填充的是200px x 200px像素的空间。所以会被放大,看起来就模糊了。

分2倍3倍图,是为了让不同设备显示图片能够更加清晰。

但是我们开发的时候,设计师通常会将3种大小的图都输出出来,我们也通常选择将3种规格的图片都拖到工程中(现在1x的设备快绝迹了,所以也可以只添加2x和3x)。

如果仅仅是为了显示更清晰,我们为什么不只用3倍图呢?

只用3倍图,不同手机加载之后也只会去缩小,可以避免因放大而导致的模糊。还会因为引入更少的图片,减少包的大小。

看起来挺好的,也没什么问题。

但是如果只用3倍图,可能会引入如下问题(按照上面例子):

iPhone6加载3倍图时,首先会将3倍图数据加载到内存中,造成了一定的内存损耗,因为大多数情况下,2倍图会比3倍图尺寸小一些。

iPhone6加载300px x 300px 的图片后,图片尺寸会变成 150pt x 150pt,如果显示要求 100pt x 100pt,需要给ImageView设定具体尺寸。而且缩放会增加一些计算量。

iPhone6在将要显示图片的时候,会将图片发送到GPU,GPU会为图片分配计算空间。如果图片大了一些,会消耗过多的GPU计算量。

有一些GPU只允许传入长宽都是2的N次幂尺寸的图片,所以传入GPU前,需要将图片变大为长宽均为2的N次幂。如果图片大了一些,会增加很多计算量,也会急剧增加内存消耗。

如果同时引入3种尺寸的图片,能够避免上述问题。根据经验,多引入的2种尺寸图片,对ipa包体的大小影响极小。

获取当前屏幕px和pt的关系

可以使用 UIScreen.main.scale (OC: [UIScreen mainScreen].scale)来获取 1pt = ?px 的值。

iPhone6中 这个值为2。

iPhone6p中 这个值为3。

比如,我们想要绘制一条高度为1px的线。我们就可以这样写:

//这个 1.0 / UIScreen.main.scale 得到的就是1px对应的pt数值let lineView =UIView(frame:CGRect(x:0, y:100, width:UIScreen.main.bounds.width, height:1.0/UIScreen.main.scale));superView.addSubview(lineView);

绘制图片

如果我们有如下需求,可能就需要自己绘制图片了。

需要对已存在的图片进行修改,比如尺寸修改,添加水印等。

需要根据不同的需求生成图片,比如将富文本变成图片。

需要将当前的某个View输出成图片。

绘制的基本代码如下:

func test(){    let size =CGSize(width:100, height:100)    var img =nil;//开启绘制环境//第一个参数 size 表示将要绘制的图片尺寸(单位是pt)。//第二个参数 固定传false,如果置为true,则不会绘制透明区域,透明区域会变成黑色。//第三个参数 表示输出的图片是几倍图。一般设为 UIScreen.main.scale,如果你设置的数值小于 UIScreen.main.scale,绘制出的图片可能会比较模糊(图片的物理尺寸小于size),如果大于UIScreen.main.scale,图片可能会被缩放(图片物理尺寸大于size)。这里物理尺寸指将生成的图片,输出成文件后的图片文件尺寸。//另一个重载函数:UIGraphicsBeginImageContext(CGSize) scale值总是1。UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.main.scale);        ...具体绘制工作//从环境中将绘制的图片输出到img中img =UIGraphicsGetImageFromCurrentImageContext();//结束绘制,释放资源UIGraphicsEndImageContext();// img 就是绘制后的图片iflet i = img {        let imgData =UIImagePNGRepresentation(i);//若UIGraphicsBeginImageContextWithOptions第三个参数为scale,输出的sava.png的尺寸将为 (size.width x scale, size.height x scale),单位是px。imgData?.write(to: URL.init(fileURLWithPath:"save.png"));    }}

细节请看上面注释,另外有2点需要注意。

整个过程所有计算尺寸都是pt。

scale只与输出图片的大小有关,不参与任何尺寸计算。

内容就这么多,下面介绍几个常用的绘制图片的例子:

publicclassTest {//缩放publicstaticfunc resize(srcImg:UIImage, toSize:CGSize) ->UIImage? {UIGraphicsBeginImageContextWithOptions(toSize,false,UIScreen.main.scale);                srcImg.draw(in:CGRect(x:0, y:0, width: toSize.width, height: toSize.height));                let img =UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();returnimg;    }//截图publicstaticfunc screenShot() ->UIImage? {iflet windowLayer =UIApplication.shared.keyWindow?.layer {UIGraphicsBeginImageContextWithOptions(UIScreen.main.bounds.size,false,UIScreen.main.scale);iflet ctx =UIGraphicsGetCurrentContext() {                windowLayer.render(in: ctx);            }            let img =UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();returnimg;        }returnnil;    }//根据传入颜色生成图片publicstaticfunc createImage(color:UIColor, size:CGSize) ->UIImage? {UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.main.scale);iflet ctx =UIGraphicsGetCurrentContext() {            let layer =CALayer.init();            layer.backgroundColor = color.cgColor;            layer.bounds =CGRect(x:0, y:0, width: size.width, height: size.height);            layer.render(in: ctx);        }        let img =UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();returnimg;    }//根据富文本生成图片publicstaticfunc createImage(attributedString:NSAttributedString, size:CGSize) ->UIImage? {UIGraphicsBeginImageContextWithOptions(size,false,UIScreen.main.scale);                attributedString.draw(in:CGRect(x:0, y:0, width: size.width, height: size.height));                let img =UIGraphicsGetImageFromCurrentImageContext();UIGraphicsEndImageContext();returnimg;    }}

作者:hard_man

链接:https://www.jianshu.com/p/cd72ad707bf3

來源:简书

简书著作权归作者所有,任何形式的转载都请联系作者获得授权并注明出处。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,014评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,796评论 3 386
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,484评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,830评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,946评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,114评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,182评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,927评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,369评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,678评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,832评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,533评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,166评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,885评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,128评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,659评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,738评论 2 351

推荐阅读更多精彩内容