背景:

时隔近半年,拖延癌晚期快犯了。然并卵,依然没有完全想好如何来编写这一章节,从哪一个维度来介绍。“合抱之木,九层之塔”,都是日积月累而成,思来想去还是先把之前积累下的资料整理写出来,后期的构想继续交给拖延癌吧。

题记:像素Pixel:

像素(Pixel)这个概念在不同的场景中会有不同的含义。如上一章所述,我们理清了数字图像中的像素Pixel与显示设备、打印机与相机领域的像素边界,后续没有特殊说明《DICOM世界观》系列中专指这个概念。然而,随着一步步接近概念的核心,会发现数字图像的像素Pixel也还有各种各样的描述和定义。我们日常生活中使用终端设备种类繁多,电脑、平板、智能手机(还可以细分为Android、iOS、Windows Phone等)等等,都需要可视化的展示,都有约定俗成的规则。

信息时代,有一张巨型的网,即WWW,World Wide Web(中文译作万维网,我觉得中文译者的意译外沿更广,万维,万意指无穷,维意指一切事和物,万维即万事万物;网即连接,互联互通),背后有一个强大的国际中立机构,W3C(World Wide Web Consortium),即万维网联盟。百度百科的介绍(其实还是想推荐Wiki百科[1]):

万维网联盟创建于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],是一种给网页内容添加样式的机制。网页中的每个可视化元素都会有一个尺寸,在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=196inch1 px = \frac{1}{96}inch,可以推算出激光打印与显示器两种设备的物理像素尺寸,即:
-

1pxlaserprint=116px=196∗4∗4inch1pxlaserprint=116px=196∗4∗4inch

1px_{laserprint}=\frac{1}{16}px=\frac{1}{96*4*4}inch
-

1pxmonitor=1px=196inch1pxmonitor=1px=196inch

1px_{monitor}=1px=\frac{1}{96}inch

也就是说激光打印机的分辨率远高于显示器,倍数是16倍,显示器中一个物理像素点的空间在激光打印机中是4∗4=164∗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×1DevicePixel1_{CSS Pixel}=n×1_{Device Pixel}呢,其实先辈们已经给出了答案——参数devicePixelRatio[4],官方描述是:

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]):


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],也有中文翻译版,翻译还原度较高Rem VS Px [7]

【备注2】:注意,devicePixelRatio这个参数改变的时候并不会触发某个事件或者发出消息,因此需要每次使用之前主动获取。
【备注3】:关于如何使用CSS Pixel与DevicePixel,以及media query中引入的新特性,详细可参照经典博文A pixel is not a pixel is not a pixel[8]

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画板Size_{画布}===Size_{画板},即画布大小永远等于画板大小。但是如果同时开启了CSS的style设置,那么此刻画板与画布尺寸就会分离,CSS只改变画板大小( 但却会触发画布的缩放变化,具体详见下一节)。即:

通过canvas自带的属性height和width可以同时修改canvas元素在html中的大小(画板大小)以及canvas内部可绘制区域的大小(画布大小),而通过CSS属性只能改变canvas元素在html中的大小(即画板大小),却不会改变canvas内部可绘制区域的大小(即画布大小)

其实,通过canvas.height与canvas.width可以获得一个height×width×4height×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\frac{200}{300}的压缩,高度进行 200150200150\frac{200}{150}的拉伸
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×4300×150×4个字节,其实这恰恰是backingStoreRatio=1backingStoreRatio=1backingStoreRatio=1的特殊情况罢了。通常为了处理方便,浏览器会在内存中存储300×150×4×backingStoreRatio300×150×4×backingStoreRatio300×150×4×backingStoreRatio个字节,这里我们可以简单的认为是为了提高精度吧,具体细节会在下一篇博文中详细介绍,有兴趣的同学可以先浏览一下博文High DPI Canvas[10]。

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来对图像进行缩放的截图,具体的实现方式和使用的算法,就放到下一篇博文进行详细阐述,敬请期待!

作者:zssure@163.com
时间:2018-07-21

【参考资料】:
1. WWW维基百科:https://en.wikipedia.org/wiki/World_Wide_Web
2. CSS官方说明:https://www.w3.org/Style/CSS/#specs
3. CSS中length介绍: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
5. Physical Size of CSS Units On Smartphones, Tablets & Co: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/
7. Rem VS Px: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
9. Canvas Element维基百科:https://en.wikipedia.org/wiki/Canvas_element
10. Canvas像素操作High DPI Canvas:https://www.html5rocks.com/en/tutorials/canvas/hidpi/
11. webgl&canvas&css pixel size:https://jameshfisher.com/2017/10/08/webgl-sizes.html
12. https://developer.mozilla.org/en-US/docs/Web/CSS/image-rendering
13. https://drafts.csswg.org/css-images-3/#propdef-image-rendering
14. http://phrogz.net/tmp/canvas_image_zoom.html
15. http://vaughnroyko.com/state-of-nearest-neighbor-interpolation-in-canvas/
16. 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
18. http://alistapart.com/article/a-pixel-identity-crisis
19. http://phrogz.net/tmp/canvas_image_zoom.html
20. https://css-tricks.com/fun-times-css-pixel-art/
21. http://www.siolon.com/blog/understanding-hardware-and-css-pixels/
22. http://xahlee.info/js/web_design_screen_density.html
23. http://xahlee.info/js/css_units.html
24. http://xahlee.info/js/css_pixel_ruler.html
25. 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
27. http://www.datagenetics.com/blog/december32013/index.html

DICOM世界观·第二章:[2]像素操作相关推荐

  1. DICOM世界观·第二章:[1]像素 Pixel (Picture Element)

    背景: 原本该小节想直接套用上世纪一片著名论文<A Pixel Is Not A Little Square>作为标题,怎奈英文原文信息量较大,内部蕴含了很多关于采样定理的信息论知识,虽然 ...

  2. linux 设计一个程序,要求打开文件 pass 所有者,第二章 Linux 文件操作

    文档均来自网络,如有侵权请联系我删除文档 第二章 Linux 文件操作(4学时) 实验一文件属性和无缓冲I/O 实验目的 1.熟悉Linux文件系统属性控制 2.掌握不带缓存的文件I/O程序设计方法 ...

  3. 第二章Linux 基本命令操作

    第二章Linux 基本命令操作 本节所讲内容: 2.1 Linux 终端介绍.Shell 提示符.Bash Shell基本语法: 2.2 基本命令操作: 2.3 系统时间管理: 2.4 帮助命令使用: ...

  4. WCF 第二章 契约 单向操作

    当一个客户端需要向一个服务端发送消息但是不接受返回消息时,但不消息交换模式很有用.使用这个模式,客户端只需要消息成功传递的确认:它不需要服 务端返回一个精确的消息.有时单步模式被错误的称作" ...

  5. JavaScript基础——第二章,JavaScript操作BOM对象

    一,BOM模型(Borwser Object Model) BOM提供了独立内容的,可以与浏览器窗口进行互动的对象结构 BOM可实现功能: 弹出新的浏览器窗口 移动,关闭浏览器窗口以及调整窗口的大小 ...

  6. 点阵图像与矢量图像的计算机记录原理,第二章像素地概念,分辨率地概念,点阵及矢量图象地特点。第四节:图像格式地选择.docx...

    实用标准文案 实用标准文案 精彩文档 精彩文档 第二章 像素的概念,分辨率的概念,点阵及矢量图象的特点.第四节:图像格 式的选择 图像格式,矢量,图片,格式,jpg 从上面点阵与矢量两者的对比中,似乎 ...

  7. 计算机的指令合成为,第二章计算机操作基础知识doc

    第二章计算机操作基础知识doc (29页) 本资源提供全文预览,点击全文预览即可全文预览,如果喜欢文档就下载吧,查找使用更方便哦! 23.9 积分 第二章  计算机操作基础知识第一节  计算机基础知识 ...

  8. 《canvas》之第8章 像素操作

    <canvas>之第8章 像素操作 第8章 像素操作 8.1 像素操作简介 8.1.1 getImageData()方法 8.1.2 putImageData()方法 8.1.3 getI ...

  9. 第二章 3ds Max物体的操作及选择

    系列文章 3DSMAX学习 第一章 3ds Max基础界面和操作​​​​​​​ 第二章 3ds Max物体的操作及选择 文章目录 目录 系列文章 3DSMAX学习 文章目录 一.3ds Max物体操作 ...

  10. 简学Python第二章__巧学数据结构文件操作

    Python第二章__巧学数据结构文件操作 欢迎加入Linux_Python学习群  群号:478616847 目录: 列表 元祖 索引 字典 序列 文件操作 编码与文件方法 本站开始将引入一个新的概 ...

最新文章

  1. ckeditor finder php,CKEDITOR CKFINDER的图片上传配置(C#/asp.net/php)
  2. python用merge匹配和左连接_左手用R右手Python系列——数据合并与追加
  3. 天气数据获取接口和网址汇总
  4. 到天宫做客(洛谷P1178题题解,Java语言描述)
  5. 【比赛经验】陈成龙博士Kaggle计算机编程竞赛数据挖掘经验分享
  6. postgre查询表最后更新日期_Power BI 10月份功能更新浅译
  7. Ural 1001 Reverse Root 解题报告
  8. VISIO各种图标超全(IT行业专用网络及硬件)_几招教你如何轻松解决视频行业痛点...
  9. Electron 使用Widevine CDM插件
  10. Photoshop插件-删除中间调通道蒙板-脚本开发-PS插件
  11. FPGA数字IC的Verilog刷题解析基础版02——T触发器(异步复位和同步复位)
  12. 586A 586B线序
  13. eclipse项目名前出现红色感叹号,小红叉解决(转)
  14. html视频设置自动播放下一个,在html5中,如何使用video标签让两个不同的视频文件按顺序自动播放?...
  15. 第1章 开篇-为什么要做CI/CD?
  16. 如何用tensorflow使用自定义数据来训练,做物体检测
  17. (JAVA) 相反数
  18. html国庆节代码,小程序10行代码实现微信头像挂红旗,国庆节个性化头像
  19. 机器学习概述----机器学习并没有那么深奥,它很有趣(2)
  20. quartus的操作和仿真

热门文章

  1. phpstudy 运行PHP项目
  2. BC20+MQTT+OneNet 订阅主题总是error
  3. 高龄脑卒中患者的运动处方
  4. cocos 微信小游戏 加载云端资源
  5. 再爆hzhost6.5虚拟主机管理系统的SQL注入漏洞3
  6. 纵向时间线html,51个css时间轴
  7. 零基础个人网站搭建教程(一个完全的新人如何搭建自己的个人网站)
  8. 服务器租用多少钱一年呢?
  9. Unreal Engine 4学习资料整理
  10. linux下内存如何释放,如何释放linux的内存