聊聊图片那些事

图片的底层原理

计算机中的颜色表示

计算机在表示颜色的时候,有两种形式,一种称作索引颜色(Index Color),一种称作直接颜色(Direct Color)

  • 索引色

用一个数字来代表(索引)一种颜色,在存储图片的时候,存储一个数字的组合,同时存储数字到图片颜色的映射。这种方式只能存储有限种颜色,比如某计算机系统中,使用一个字节的数字来索引一种颜色,一个字节 2^8 表示一个颜色,也就是最多支持 256 种颜色。

  • 直接色

使用四个数字来代表一种颜色,这四个数字分别代表这个颜色中红色、绿色、蓝色以及透明度

图片构成方式

  • 位图(Bitmap)

又叫栅格图、点阵图,使用像素阵列来表示图像。位图就是由象素阵列的排列来实现其显示效果的,每个象素有自己的颜色信息,在对位图图像进行编辑操作的时候,可操作的对象是每个象素,我们可以改变图像的色相、饱和度、明度,从而改变图像的显示效果。位图根据位深度,有 1、4、8、16、24、32 位图像等。位图放大会失真变模糊。

  • 矢量图

计算机图形学中用点、直线或者多边形等基于数学方程的几何图元表示图像。相比较位图,矢量图保存最少的信息,体积更小,缩放不会失真。

为什么SVG格式的图片放大不会失真模糊呢?

SVG(可缩放矢量图形)是一种基于XML的图形格式,与传统的位图图形(如JPEG、PNG)不同,SVG使用矢量图形描述图像。它描述图像的方式是基于数学公式和几何路径,SVG图像使用路径来定义图形,路径包含了一系列的命令和坐标点,用于绘制线条、曲线、形状等,当你放大SVG图像时,浏览器或图形软件会重新计算路径的坐标,并按比例进行缩放,而不会引入额外的像素或失真,SVG图像也可以包含文本信息,而这些文本信息同样是基于矢量的,因此也可以无损缩放。

图片格式

不同的图片格式在不同的应用场景下有各自的优缺点。以下是常见的图片格式(JPEG、PNG、GIF、WebP)的对比:

图片格式 优点 缺点 使用场景
JPEG - 高压缩率 - 有损压缩 - 照片、复杂图像
- 广泛支持 - 可能出现压缩失真
PNG - 无损压缩 - 文件大小相对较大 - 透明背景、图标、简单图像
- 支持透明度 - 不适用于照片
GIF - 支持动画 - 有限色彩 - 简单动画、图标
- 支持透明度 - 不适用于照片
WebP - 高压缩率 - 浏览器支持相对有限 - 现代浏览器、要求高压缩率和透明度
- 支持透明度 - 部分浏览器不支持

选择合适的图片格式取决于具体的应用场景和需求。JPEG适用于照片,PNG适用于需要保持图像质量和透明背景的场景,GIF适用于简单动画和图标,而WebP则是一种现代的、通常具有较高压缩率的格式,但需考虑浏览器兼容性。

图片跨域问题

图片(以及其他资源,如脚本、样式表等)存在跨域问题是由浏览器的同源策略(Same-Origin Policy)引起的。同源策略是一种安全机制,限制了来自不同源(域名、协议、端口)的页面对资源的访问,目的是防止恶意网站通过一些手段获取用户的敏感信息。

同源策略对于JavaScript访问其他域的资源有着严格的限制。解决图片跨域主要有以下方式:

  1. CORS(跨域资源共享) 在提供图片的服务器上配置CORS头,允许特定域(你的网站域)的访问。

  2. JSONP(仅适用于GET请求) 使用Script标签 JSONP利用了Script标签不受同源策略限制的特性,通过动态创建Script标签来加载跨域资源。

  3. 代理服务器:在你的域内设置一个代理服务器,该代理服务器可以访问其他域上的资源。前端通过访问代理服务器来获取资源,绕过了同源策略。

图片相关优化操作

  • 图片懒加载。使用intersectionObserve或者使用 getBoundingClientRect结合视窗的高度来判断是否在可视区域内,如果在即将预设的data-src属性赋值到img标签src属性即可

  • 图片预加载。动态创建img标签,提前加载图片,后续可从缓存中读取。

  • 图片手动压缩。 使用压缩工具进行手动压缩

  • 图片CDN加速。 静态资源放在CDN上,可以加速用户访问速度

  • 图片加载失败处理

js 复制代码
const imgOnError = (e) => {
  e.currentTarget.onerror = null
  e.currentTarget.src = '默认占位图片地址'
  e.currentTarget.className = 'error'
}

// react
<img src={oss_url} onError={imgOnError}/>
  • img标签在移动端如果src上没有一个有效的值,会产生一个白色的边框。有时候我们为了兜底隐藏该边框需要做一个处理。
css 复制代码
img[src=""],
img:not([src]) {
    opacity: 0;
}
  • 图片裁剪。 图片裁剪大致流程如下:

详细流程推荐阅读👉:从零开始做一个图片裁剪组件

  • 图片添加水印

推荐阅读👉:# 前端水印实现方案

图片资源优化

前端根据不同的设备的分辨率自动调整图片大小

1.使用srcsetsizes属性

srcset 属性用于指定一组备选的图片资源,以逗号分隔每个图片资源并指定对应的分辨率宽度,浏览器会根据当前设备的像素密度(DPR)和 CSS 像素比例(devicePixelRatio)来选择最佳匹配的图片资源进行加载;而 sizes 属性则用于设置媒体查询条件或者视口尺寸条件,用于判断图片显示在页面中的大小。

以下是一个示例代码:

js 复制代码
<img src="small.jpg"
     srcset="small.jpg 640w, medium.jpg 960w, large.jpg 1200w"
     sizes="(max-width: 480px) 100vw, (max-width: 1024px) 50vw, 33.3vw">

在上述示例中,srcset 属性列出了三种不同大小的备选图片资源,并指定了相应的分辨率宽度。如果当前设备的窗口宽度为 800px,浏览器将会选择 medium.jpg 这个备选图片资源进行加载。而 sizes 属性则设置了两个条件,当窗口宽度小于等于 480px 时,图片将会占满整个窗口宽度;当窗口宽度大于 480px 且小于等于 1024px 时,图片将会占据窗口宽度的一半;当窗口宽度大于 1024px 时,图片将会占据窗口宽度的三分之一。

需要注意的是,srcset 和 sizes 属性并不兼容所有浏览器,使用前建议进行兼容性检查。

2.模拟scrsetsizes属性 首先,将 img 元素的 src 属性设置为最小分辨率的图片,然后在 JavaScript 中获取该元素并动态地更新其 src 属性,以便在设备像素密度变化时加载最合适的图片资源。

html 复制代码
<img id="my-image" src="small.jpg">
js 复制代码
function getBestImageSrcset() {
  var windowWidth = window.innerWidth;
  var images = [
    {srcset: "small.jpg", width: 640},
    {srcset: "medium.jpg", width: 960},
    {srcset: "large.jpg", width: 1200}
  ];
  var bestImage = images[0];
  for (var i = 1; i < images.length; i++) {
    if (windowWidth >= images[i].width && images[i].width > bestImage.width) {
      bestImage = images[i];
    }
  }
  return bestImage.srcset;
}

var myImage = document.getElementById("my-image");
myImage.src = getBestImageSrcset();

在上述示例中,getBestImageSrcset() 函数会根据当前设备分辨率的宽度和一组备选的图片资源(包括 srcset 和宽度)计算出最佳图片资源,并返回其相对路径。接下来,通过 JavaScript 获取 img 元素并动态更新其 src 属性为最佳图片资源的相对路径。这样可以确保在不同设备的分辨率下都可以加载最合适的图片资源。

实际开发中需要根据具体情况进行优化和调整。这种方式也可能存在一定的兼容问题。

3.使用成熟的第三方库

  • Picturefill
  • next/image

4.使用CSS媒体查询:可以通过CSS的媒体查询来根据设备的屏幕尺寸和像素密度,为不同的设备设置不同的背景图片。

css 复制代码
.my-element {
  background-image: url('low-res.jpg');
}

@media only screen and (min-width: 768px) {
  .my-element {
    background-image: url('medium-res.jpg');
  }
}

@media only screen and (min-width: 1200px) {
  .my-element {
    background-image: url('high-res.jpg');
  }
}
  1. 使用JavaScript动态加载:通过JavaScript可以根据设备的特性和屏幕信息动态选择加载不同分辨率的图片。可以通过window.devicePixelRatio获取设备的像素密度,并根据需要动态创建<img>标签并设置对应的图片路径。
js 复制代码
var image = new Image();
var pixelRatio = window.devicePixelRatio;

if (pixelRatio >= 2) {
  image.src = 'high-res.jpg';
} else if (pixelRatio >= 1.5) {
  image.src = 'medium-res.jpg';
} else {
  image.src = 'low-res.jpg';
}

document.body.appendChild(image);

通过上述方式,可以根据不同设备的屏幕尺寸和像素密度,提供适合的图片分辨率,以优化用户在不同设备上的图片显示效果和加载性能。

webp格式图片

webp格式图片为什么高效

1.图片压缩算法:WebP采用了一种基于预测的压缩算法,可以识别和删除图片中的冗余信息,从而实现更好的压缩效果。这种算法比传统的JPEG和PNG压缩算法更高效。

2.支持有损和无损压缩:WebP可以同时支持有损和无损压缩,这意味着它可以在保持高质量的同时实现更小的文件大小。

3.支持alpha通道压缩:WebP支持alpha通道压缩,这意味着它可以在压缩过程中保留图像的透明度信息,并产生更小的文件大小。

4.支持动态图像:WebP还支持动态图像,这种格式可以在一个文件中包含多个帧,从而可以创建动画效果。

如何解决webp格式在浏览器中不兼容的问题

WebP 是一种高效的图片格式,它可以帮助减少图片文件的大小,从而提高网页的加载速度。然而,由于某些浏览器不支持 WebP 格式,使用 WebP 格式可能会导致一些兼容性问题。以下是几种解决 WebP 格式在浏览器中不兼容的方法:

1.使用图片格式检测:在服务器端检测浏览器是否支持 WebP 格式,如果支持,则使用 WebP 格式的图片,否则使用其他格式的图片。这可以通过服务器端的代码来实现。

2.使用 polyfill:Polyfill 是一种 JavaScript 库,可以让浏览器支持某些不支持的功能。有一些 polyfill 可以帮助浏览器在不支持 WebP 格式的情况下,使用 WebP 格式的图片。这些 polyfill 可以通过第三方库或者 CDN 来获取。

3.使用picture标签

html 复制代码
<!-- WebP 格式图片 -->
<picture>
    <source srcset="example.webp" type="image/webp">
    <img src="example.jpg" alt="WebP Image">
</picture>

<picture> 标签用于提供WebP格式的备用,只有在浏览器支持WebP时才会加载

服务器端如何检测浏览器是否支持 WebP 格式

服务器端可以通过检测浏览器的 User-Agent 字符串来判断浏览器是否支持 WebP 格式。具体方法如下:

1.检查 User-Agent 是否包含关键字"Chrome"、"Opera"、"Edge"等支持 WebP 格式的浏览器名称和版本号。

2.如果浏览器名称和版本号匹配支持 WebP 格式的浏览器,则向客户端返回 WebP 格式的图片。

3.如果浏览器名称和版本号不匹配支持 WebP 格式的浏览器,则向客户端返回其他格式的图片。

相关推荐
Y.O.U..20 分钟前
美团AI面试总结
网络·面试·职场和发展
勘察加熊人1 小时前
angular九宫格ui
javascript·ui·angular.js
姑苏洛言2 小时前
30天搭建消防安全培训小程序
前端
左钦杨3 小时前
Nuxt2 vue 给特定的页面 body 设置 background 不影响其他页面
前端·javascript·vue.js
yechaoa3 小时前
【揭秘大厂】技术专项落地全流程
android·前端·后端
MurphyChen3 小时前
🤯 一行代码,优雅的终结 React Context 嵌套地狱!
前端·react.js
逛逛GitHub3 小时前
推荐 10 个受欢迎的 OCR 开源项目
前端·后端·github
ylfhpy3 小时前
Java面试黄金宝典1
java·开发语言·算法·面试·职场和发展
_xaboy4 小时前
开源 FormCreate 表单设计器配置组件的多语言
前端·vue.js·低代码·开源·可视化表单设计器
uglyduckling04124 小时前
小程序构建NPM失败
前端·小程序·npm