背景:
时隔近半年,拖延癌晚期快犯了。然并卵,依然没有完全想好如何来编写这一章节,从哪一个维度来介绍。“合抱之木,九层之塔”,都是日积月累而成,思来想去还是先把之前积累下的资料整理写出来,后期的构想继续交给拖延癌吧。
题记:像素Pixel:
像素(Pixel)这个概念在不同的场景中会有不同的含义。如上一章所述,我们理清了数字图像中的像素Pixel与显示设备、打印机与相机领域的像素边界,后续没有特殊说明《DICOM世界观》系列中专指这个概念。然而,随着一步步接近概念的核心,会发现数字图像的像素Pixel也还有各种各样的描述和定义。我们日常生活中使用终端设备种类繁多,电脑、平板、智能手机(还可以细分为Android、iOS、Windows
Phone等)等等,都需要可视化的展示,都有约定俗成的规则。
信息时代,有一张巨型的网,即WWW,World Wide Web(
中文译作万维网,我觉得中文译者的意译外沿更广,万维,万意指无穷,维意指一切事和物,万维即万事万物;网即连接,互联互通
),背后有一个强大的国际中立机构,W3C(World Wide Web Consortium),即万维网联盟。百度百科的介绍(其实还是想推荐Wiki百科[1]
<https://en.wikipedia.org/wiki/World_Wide_Web>):
万维网联盟创建于1994年,是Web技术领域最具权威和影响力的国际中立性技术标准机构。到目前为止,W3C已发布了200多项影响深远的Web技术标准及实施指南,如广为业界采用的超文本标记语言(标准通用标记语言下的一个应用)、可扩展标记语言(标准通用标记语言下的一个子集)以及帮助残障人士有效获得Web内容的信息无障碍指南(WCAG)等,有效促进了Web技术的互相兼容,对互联网技术的发展和应用起到了基础性和根本性的支撑作用。万维网联盟标准不是某一个标准,而是一系列标准的集合。网页主要由三部分组成:结构(Structure)、表现(Presentation)和行为(Behavior)。
对应的标准也分三方面:结构化标准语言主要包括XHTML和XML,表现标准语言主要包括CSS,行为标准主要包括对象模型(如W3C DOM)、
ECMAScript等。这些标准大部分由W3C起草和发布,也有一些是其他标准组织制订的标准,比如ECMA(European Computer
Manufacturers Association)的ECMAScript标准。
随着基础网络建设的快速发展,5G、6G……的逐步出现,再加上现如今火热的前端程序员市场,仿佛预示着万维互联时代的彻底来临,接下来让我们从日常触手可及的互联网入手,来介绍其中相关的各种像素概念。
1. CSS中的像素(Pixel in CSS)
CSS, Cascading Style Sheets[2] <https://www.w3.org/Style/CSS/#specs>
,是一种给网页内容添加样式的机制。网页中的每个可视化元素都会有一个尺寸,在CSS标准中定义尺寸有两种方式:relative与absolute。顾名思义,相对尺寸是相较于某一个已知尺寸的相对尺寸,可以认为单位是作为参照的元素的“真实尺寸”。绝对尺寸是固定不变的,与现实世界中的某个物理量相关联(例如现实世界中的长度度量单位有米、厘米、毫米、英寸等),当可视化输出的终端设备明确以后,根据终端物理参数,就可以具体计算出可视化每个元素的真实物理世界尺寸。
在CSS标准定义的绝对尺寸中有一个我们需要着重介绍的,那就是像素px(pixel)。这个度量单位基于一种假设,即reference
pixel假设([3]),标准中描述reference pixel的原文如下:
The reference pixel is the visual angle of one pixel on a device with a pixel
density of 96dpi and a distance from the reader of an arm’s length. For a
nominal arm’s length of 28 inches, the visual angle is therefore about 0.0213
degrees. For reading at arm’s length, 1px thus corresponds to about 0.26 mm
(1/96 inch).
标准中已经假设物理设备的分辨率是96dpi,再结合一定的视距来描述参考像素reference pixel。倘若物理设备分辨率发生变化,
同样的视距,一个CSS中的reference pixel可能会对应多个物理像素device pixel,如下图所示:
如上图所示,已知:1px=196inch1px=196inch,可以推算出激光打印与显示器两种设备的物理像素尺寸,即:
- 1pxlaserprint=116px=196∗4∗4inch1pxlaserprint=116px=196∗4∗4inch
- 1pxmonitor=1px=196inch1pxmonitor=1px=196inch
也就是说激光打印机的分辨率远高于显示器,倍数是16倍,显示器中一个物理像素点的空间在激光打印机中是4∗4=164∗4=16个像素点。由此可以看出,
CSS的reference pixel是一种逻辑像素,是对device pixel的一种抽象,是device与web
developer之间的一个中间层,将设备的物理参数对开发者透明。
正如计算机领域一句名言所述:“Any problem in computer science can be solved by anther layer
of indirection.”,计算机科学领域没有哪一个问题是不能通过添加抽象中间层来解决的,如果有,那就抽象两层^_^。
那么具体的1CSSPixel=n×1DevicePixel1CSSPixel=n×1DevicePixel呢,其实先辈们已经给出了答案——参数
devicePixelRatio[4]
<https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio>
,官方描述是:
The Window property devicePixelRatio returns the ratio of the resolution in
physical pixels to the resolution in CSS pixels for the current display device.
This value could also be interpreted as the ratio of pixel sizes: the size of
one CSS pixel to the size of one physical pixel. In simpler terms, this tells
the browser how many of the screen’s actual pixels should be used to draw a
single CSS pixel.
如下几张图所示,用我自己本机的Chrome浏览器测试的结果(常见的智能手机参数值,请参考博文Physical Size of CSS Units On
Smartphones, Tablets & Co[5]
<http://christopheraue.net/design/physical-size-of-css-units-on-smartphones-tablets>
):
Chrome浏览器(版本 67.0.3396.99(64 位))页面缩小至最小25%时候的数值
Chrome浏览器(版本 67.0.3396.99(64 位))页面100%正常比例时候的数值
Chrome浏览器(版本 67.0.3396.99(64 位))页面放大至500%最大比例时候的数值
【备注1】
:在前端开发过程中,常常会有人告诉你用相对长度em和rem来代替像素,因为它们会使你的设计更容易,似乎在行业中也变成了一个约定俗成的标准。其实随着物理设备分辨率的发展,W3C标准以及浏览器的进步,依赖于像素才是王道,我们生活在一个DPI独立的世界,虚拟像素和逻辑屏幕分辨率将会成为我们需要关心的一切。具体为什么要使用像素,以及使用像素带来的计算便利,可以参见博文
Rem Viva CSS Reference Pixel[6]
<https://mindtheshift.wordpress.com/2015/04/02/r-i-p-rem-viva-css-reference-pixel/>
,也有中文翻译版,翻译还原度较高Rem VS Px [7]
<https://www.w3cplus.com/css/r-i-p-rem-viva-css-reference-pixel.html>
【备注2】:注意,devicePixelRatio这个参数改变的时候并不会触发某个事件或者发出消息,因此需要每次使用之前主动获取。
【备注3】:关于如何使用CSS Pixel与DevicePixel,以及media query中引入的新特性,详细可参照经典博文A pixel is not
a pixel is not a pixel[8]
<https://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html>
2. Canvas中的像素(Pixel in Canvas)
在前端开发过程中,最熟悉的三剑客就是HTML、CSS与JavaScript(说实话当年js真的是被诟病的不行不行滴,想如今倒好,前端严重供不应求啊!!!
)。上一节中已经介绍了CSS中的像素,其实最应该开始介绍的是Canvas中的像素Pixel,因为HTML是网页的载体,包含各种元素;而CSS仅仅是HTML的装饰,
网页可以只有HTML元素,却不能只有CSS。但是之所以选择先介绍CSS Pixel因为在介绍canvas时会用到上文提到的CSS
Pixel,所以就倒着介绍了一下,详情往下看。
Canvas元素
([9])是HTML5标准中的一部分,最早由苹果公司引进。既然是HTML5一部分,自然就可以用height和width属性来描述canvas元素的大小,即element
size,默认尺寸是width=300px,height=150px
(如果style未设置的话,px即指上一节中的CSSPixel)。因为canvas发明的用处是希望能够让用户在HTML中有一个自由操作进行自由绘制的区域,所以其实canvas有两个大小。一个是画板的大小,一个是画布的大小:
使用canvas的属性height与width,如果没有通过CSS的style.height与style.width设置时候,Size画布===Size画板
Size画布===Size画板,即画布大小永远等于画板大小。但是如果同时开启了CSS的style设置,那么此刻画板与画布尺寸就会分离,CSS只改变画板大小(
但却会触发画布的缩放变化,具体详见下一节)。即:
通过canvas自带的属性height和width可以同时修改canvas元素在html中的大小(画板大小)以及canvas内部可绘制区域的大小(画布大小),而通过CSS属性只能改变canvas元素在html中的大小(即画板大小),却不会改变canvas内部可绘制区域的大小(即画布大小)
。
其实,通过canvas.height与canvas.width可以获得一个height×width×4height×width×4
的数组(因为canvas默认支持RGBA四通道),这里的一个RGBA值对应一个颜色值,也可以说是对应一个Canvas Pixel,由此可以看出Canvas
Pixel又是一个抽象概念,就是一幅图像中的一个像素点。——这可能跟我们直观的像素理解最最接近。
让我们看一个例子体会一下:
<!DOCTYPE html> <html> <head> <title>Demo</title> <meta http-equiv=
"Content-Type" content="text/html; charset=utf-8"/> <script type=
"text/javascript"> function drawDiagonal(){ var canvas=document.getElementById(
"a"); var context=canvas.getContext("2d"); context.beginPath(); context.moveTo(0
,0); context.lineTo(200,200); context.stroke(); } window.onload=drawDiagonal; </
script> </head> <body> <canvas id="a" style="border:1px
solid;width:200px;height:200px;"></canvas> </body> </html>
代码中期望绘制一个对角线,即点(0,0)与点(200,200)相连,但最终显示的效果却是下图中最右侧的黄色区域(没有那根细细的红线)。
图中已经很清楚的表明了为何出来的结果不是对角线,具体的执行流程如下:
1. canvas自身默认属性为height=150px,width=300px(这里的px指的是canvas pixel,即一个RGBA值)
2.
context.moveto、context.lineto都是在(1)中的canvas坐标系进行绘制,即绘制出来的结果是上图最左侧的部分,如果此时不设置style,使得style.width=canvas.widh,style.height=canvas.height的话,那么最终结果应该是左图的绿色填充部分,没有那根红色的细线,其余部分因为canvas元素在HTML中的可视范围所限被隐藏了。
3. 然而此时设置了style.height=200px;style.width=200px(这里的px就是上一章节提到的CSS
Pixel),那么此刻会将上图左侧绿色填充部分进行整体缩放,宽度进行200300200300的压缩,高度进行200150200150的拉伸
4. 最后就得到了上图右侧黄色部分的结果图(再说一次,没有图中的细细的红线)
【备注】:之所以有人认为应该画出对角线来,是因为错误的将Canvas Pixel等同于CSS
Pixel了,误认为lineto与moveto操作中对应的canvas pixel坐标与style中CSS
Pixel的坐标相同。其实lineto、moveto操作永远都是canvas pixel的索引坐标系,CSS pixel坐标系是对整个canvas进行控制的。
如果依然沿用上一小节提到的“中间层”理论,可以将canvas
pixel看作是真实图像与图像显示之间的一种抽象,或者再通俗一点来讲就是图像概念与计算机内存中存储的0和1的一层抽象。而如果还要深入进去的话,你会发现先辈们对这一层“中间层”使用的是——参数
backingStoreRatio
。比如我添加一个默认的canvas对象到HTML中,默认属性canvas.height=150,canvas.width=300,即存储中应该占有300×150
×4300×150×4个字节,其实这恰恰是backingStoreRatio=1backingStoreRatio=1
的特殊情况罢了。通常为了处理方便,浏览器会在内存中存储300×150×4×backingStoreRatio300×150×4×backingStoreRati
o个字节,这里我们可以简单的认为是为了提高精度吧,具体细节会在下一篇博文中详细介绍,有兴趣的同学可以先浏览一下博文High DPI Canvas[10]
<https://www.html5rocks.com/en/tutorials/canvas/hidpi/>。
3. CSS与Canvas中的缩放(Scale in CSS & Canvas)
这里简单提一下Scale in CSS & Canvas,即CSS与Canvas两个体系中的缩放问题,具体理论细节会放到下一篇博文
DICOM世界观·[3]像素操作中的算法中进行详细展开,届时会第一次介绍部分入门级的图像处理算法,敬请期待!
其实通过上文的几个例子,可以深刻体会到:我们看到的不一定是我们想象中的,我们想象中的也不一定会是我们想看到的。在了解了CSS Pixel与Canvas
Pixel概念后,也仅仅是对互联网时代下的显示机制刚开始入门,当面对缩放问题的时候,会进入到一个“黑洞”中。在本篇博文最后我们先简单提一下两种情况下对缩放的约定。
3.1. CSS中的缩放(Scale in CSS)
在W3C标准中,有规定CSS是如何对图像进行缩放操作的,即通过image-rendering属性。
如图所示,每一种取值代表一种特殊的处理方式,具体如下:
1. auto:缩放算法由具体的标准实现方(即主流的浏览器开发商,诸如Chrome/Chrome for
Android/Edge/Firefox/Safari/iOS Safari等等)自己提供。
2. smooth:算法必须要尽可能的提高图像显示质量,诸如双线性插值等等。
3. high-quality:等同于smooth,但是更注重效率,尤其是当硬件受限的时候。
4. crisp-edges:算法必须能够保留高对比度和边缘,不能进行光滑处理。
5. pixelated:使用最邻近插值算法或者类似的,进行像素级的操作。
官网具体效果示意图如下(仔细看还是能够看出来区别的):
Mozilla开发者社区介绍image-rendering时也有一些示例图:
3.2. Canvas中的缩放(Scale in Canvas)
上文提到过canvas其实是图像与计算机内部存储数组之间的一个抽象层,其实背后对应一个RGBA的Canvas
Pixel像素数组,即backingStoreArray,由此自然可以想到:
所谓的缩放无非就是采样率的变化,即upsampling或者downsampling。换言之就是根据显示的需要通过upsampling或者downsampling的方式改变backingStoreArray的大小。这个也就是canvas内部提供的scale做的事情,
官方的描述:
The CanvasRenderingContext2D.scale() method of the Canvas 2D API adds a
scaling transformation to the canvas units by x horizontally and by y
vertically.
By default, one unit on the canvas is exactly one pixel. If we apply, for
instance, a scaling factor of 0.5, the resulting unit would become 0.5 pixels
and so shapes would be drawn at half size. In a similar way setting the scaling
factor to 2.0 would increase the unit size and one unit now becomes two pixels.
This results in shapes being drawn twice as large.
看了上述的描述,估计有一些同学也已经猜出来了,前文也提到过标准只制定规范却并不约束具体的实现,也就是说对于不同的实现方很可能canvas.scale对应的方法是不同的,这一点需要切记。这里摘取几个通过canvas来对图像进行缩放的截图,具体的实现方式和使用的算法,就放到下一篇博文进行详细阐述,敬请期待!
作者:[email protected]
时间:2018-07-21
【参考资料】:
1. WWW维基百科:https://en.wikipedia.org/wiki/World_Wide_Web
<https://en.wikipedia.org/wiki/World_Wide_Web>
2. CSS官方说明:https://www.w3.org/Style/CSS/#specs
<https://www.w3.org/Style/CSS/#specs>
3. CSS中length介绍:https://www.w3.org/TR/2016/CR-css-values-3-20160929/#lengths
<https://www.w3.org/TR/2016/CR-css-values-3-20160929/#lengths>
4. devicePixelRatio:
https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio
<https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio>
5. Physical Size of CSS Units On Smartphones, Tablets & Co:
http://christopheraue.net/design/physical-size-of-css-units-on-smartphones-tablets
<http://christopheraue.net/design/physical-size-of-css-units-on-smartphones-tablets>
6. Rem Viva CSS Reference Pixel英文原文:
https://mindtheshift.wordpress.com/2015/04/02/r-i-p-rem-viva-css-reference-pixel/
<https://mindtheshift.wordpress.com/2015/04/02/r-i-p-rem-viva-css-reference-pixel/>
7. Rem VS Px:
https://www.w3cplus.com/css/r-i-p-rem-viva-css-reference-pixel.html
<https://www.w3cplus.com/css/r-i-p-rem-viva-css-reference-pixel.html>
8. 经典博文A pixel is not a pixel is not a pixel:
https://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html
<https://www.quirksmode.org/blog/archives/2010/04/a_pixel_is_not.html>
9. Canvas Element维基百科:https://en.wikipedia.org/wiki/Canvas_element
<https://en.wikipedia.org/wiki/Canvas_element>
10. Canvas像素操作High DPI Canvas:
https://www.html5rocks.com/en/tutorials/canvas/hidpi/
<https://www.html5rocks.com/en/tutorials/canvas/hidpi/>
11. webgl&canvas&css pixel size:
https://jameshfisher.com/2017/10/08/webgl-sizes.html
<https://jameshfisher.com/2017/10/08/webgl-sizes.html>
12. https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering
<https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering>
13. https://drafts.csswg.org/css-images-3/#propdef-image-rendering
<https://drafts.csswg.org/css-images-3/#propdef-image-rendering>
14. http://phrogz.net/tmp/canvas_image_zoom.html
<http://phrogz.net/tmp/canvas_image_zoom.html>
15. http://vaughnroyko.com/state-of-nearest-neighbor-interpolation-in-canvas/
<http://vaughnroyko.com/state-of-nearest-neighbor-interpolation-in-canvas/>
16. https://phoboslab.org/log/2012/09/drawing-pixels-is-hard
<https://phoboslab.org/log/2012/09/drawing-pixels-is-hard>
17.
https://stackoverflow.com/questions/18761404/how-to-scale-images-on-a-html5-canvas-with-better-interpolation
<https://stackoverflow.com/questions/18761404/how-to-scale-images-on-a-html5-canvas-with-better-interpolation>
18. http://alistapart.com/article/a-pixel-identity-crisis
<http://alistapart.com/article/a-pixel-identity-crisis>
19. http://phrogz.net/tmp/canvas_image_zoom.html
<http://phrogz.net/tmp/canvas_image_zoom.html>
20. https://css-tricks.com/fun-times-css-pixel-art/
<https://css-tricks.com/fun-times-css-pixel-art/>
21. http://www.siolon.com/blog/understanding-hardware-and-css-pixels/
<http://www.siolon.com/blog/understanding-hardware-and-css-pixels/>
22. http://xahlee.info/js/web_design_screen_density.html
<http://xahlee.info/js/web_design_screen_density.html>
23. http://xahlee.info/js/css_units.html
<http://xahlee.info/js/css_units.html>
24. http://xahlee.info/js/css_pixel_ruler.html
<http://xahlee.info/js/css_pixel_ruler.html>
25.
https://stackoverflow.com/questions/12735997/css-pixels-vs-device-pixels-on-iphone
<https://stackoverflow.com/questions/12735997/css-pixels-vs-device-pixels-on-iphone>
26.
https://stackoverflow.com/questions/27382331/how-a-css-pixel-size-is-calculated
<https://stackoverflow.com/questions/27382331/how-a-css-pixel-size-is-calculated>
27. http://www.datagenetics.com/blog/december32013/index.html
<http://www.datagenetics.com/blog/december32013/index.html>
热门工具 换一换