Skip to content

图片(Image)实现技术 ​

重要通知

类目简介

基本概况 ​

​

不同终端设备加载 ​

  • ⚠️ 需要准备不同分辨率的图片数据源,否则同一张图片依旧是相同图片体积。
<picture>
  <!-- 超大桌面屏:≥1680px -->
  <source 
    srcset="{{ section.settings.image_1680 | img_url: '1680x' }}" 
    media="(min-width: 1680px)"
  >
  <!-- 笔记本/中端桌面屏:≥1366px -->
  <source 
    srcset="{{ section.settings.image_1366 | img_url: '1366x' }}" 
    media="(min-width: 1366px)"
  >
  <!-- 平板横屏/小桌面:≥1025px(原代码断点) -->
  <source 
    srcset="{{ section.settings.image | img_url: '1025x' }}" 
    media="(min-width: 1025px)"
  >
  <!-- 平板竖屏/大屏手机横屏:≥750px -->
  <source 
    srcset="{{ section.settings.image_750 | img_url: '750x' }}" 
    media="(min-width: 750px)"
  >

  <!-- 兜底:手机竖屏(<750px),所有不匹配以上断点的设备 -->
  <img 
    src="{{ section.settings.image_wap | img_url: '750x' }}" 
    width="100%" 
    height="auto" 
    alt="图片描述"
    loading="lazy"
  >
</picture>





<picture>
	<source srcset="http://test.ysunlight.com/server/static/images/goods/001.jpg" media="(min-width: 1024px)" />
	<img src="http://test.ysunlight.com/server/static/images/goods/002.jpg" />
</picture>



<picture>
  <source srcset="landscape.png" media="(min-width: 1024px)" />
  <img src="fallback.png" />
</picture>



<picture>
  <source srcset="landscape.png" media="(min-width: 1000px)" width="1000" height="400" />
  <source srcset="square.png" media="(min-width: 800px)" width="800" height="800" />
  <source srcset="portrait.png" media="(min-width: 600px)" width="600" height="800" />
  <img src="fallback.png" alt="当浏览器不支持来源时使用的图片" width="500" height="400" />
</picture>

下载图片 ​

export function downloadIamge(imgsrc, name) {
	//下载图片地址和图片名
	var image = new Image()
	// 解决跨域 Canvas 污染问题
	image.src = imgsrc
	// image.src = imgsrc + '?timestamp=' + new Date().getTime()
	// console.log(image)
	image.setAttribute('crossorigin', 'anonymous')
	image.onload = function () {
		var canvas = document.createElement('canvas')
		canvas.width = image.width
		canvas.height = image.height
		var context = canvas.getContext('2d')
		context.drawImage(image, 0, 0, image.width, image.height)
		var url = canvas.toDataURL('image/png') //得到图片的base64编码数据
		var a = document.createElement('a') // 生成一个a元素
		var event = new MouseEvent('click') // 创建一个单击事件
		a.download = name || 'photo' // 设置图片名称
		a.href = url // 将生成的URL设置为a.href属性
		a.dispatchEvent(event) // 触发a的单击事件
	}
	image.onerror = (err) => {
		console.log(err)
		window.open(imgsrc)
		// var img = document.getElementById('girlImg') // 获取要下载的图片
		// var url = imgsrc // 获取图片地址
		// var a = document.createElement('a') // 创建一个a节点插入的document
		// var event = new MouseEvent('click') // 模拟鼠标click点击事件
		// a.download = name // 设置a节点的download属性值
		// a.href = url // 将图片的src赋值给a节点的href
		// a.target = '_blank'
		// a.dispatchEvent(event) // 触发鼠标点击事件
	}
}

图像<img>标签 ​

定义 HTML 页面中的图像。

<!--draggable 设置拖动权限-->
<img src="" draggable="false" crossorigin="anonymous" alt="" title="" />
<!--crossorigin属性 | Access-Control-Allow-Credentials
  anonymous:如果使用这个值的话就会在请求中的header中的带上Origin属性,但请求不会带上cookie和其他的一些认证信息。
  use-credentials:这个就同时会在跨域请求中带上cookie和其他的一些认证信息。

  例如阿里云OSS上的图片路径,设置crossorigin后需要加上时间戳,'jsdhfkhdjf?t=' + Date.now()
    这里顺带提下img加载相关 属性
    onload:表示加载好,换言之,没有加载好不会执行;
    onAbort:图片加载的时候,用户通过点击停止加载时出发
    onerror:如果图片不存在(网络很不通畅,也可能触发 onerror事件)
    complete:图片显示出来以后为true,
-->

srcset属性 ​

是以逗号分隔的图像文件名及其宽度或密度描述符的列表。

  • ⚠️ 需要准备不同分辨率的图片数据源,否则同一张图片依旧是相同图片体积。
<img
  src="image-800.jpg"
  srcset="
    image-400.jpg   400w,
    image-600.jpg   600w,
    image-800.jpg   800w,
    image-1000.jpg 1000w
  "
  sizes="(min-width: 1000px) 900px, calc(100vw - 2rem)"
  alt="Product"
/>



<img 
	src="flower-large.jpg" 
	srcset="flower-small.jpg 480w, flower-large.jpg 1080w" 
  srcset="header640.png 640w, header960.png 960w, header1024.png 1024w"
	sizes="50vw"
/>


<img
  loading="lazy"
  width="200"
  height="200"
  sizes="auto, (max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)"
  srcset="
    swing-200.jpg   200w,
    swing-400.jpg   400w,
    swing-800.jpg   800w,
    swing-1600.jpg 1600w
  "
  src="swing-400.jpg"
  alt="壶铃摆动" />

sizes 告诉浏览器:这张图在页面上占多宽
vw:视口单位,`100vw = 屏幕宽度


<!--模式 1:宽度描述符 w(最常用,配合 sizes)-->
语法:图片地址 宽度w, 图片地址 宽度w
w = 图片原生像素宽度,不是屏幕宽度
浏览器逻辑:
根据 sizes 算出图片实际显示宽度
自动对比 srcset 里图片宽度,选择满足分辨率最合适的图
src 作为降级兜底(不支持 srcset 的浏览器使用)


<!--模式 2:像素密度描述符 x(倍图,无需 sizes)-->
语法:图片地址 倍率x, 图片地址 倍率x
x = 设备像素比(1x 普通屏、2x 视网膜屏、3x 高清手机屏)
适合:图片固定尺寸展示(图标、固定 banner)

<!--
⚠️ # 和 x 描述符区分(不要搞混)
- `srcset 400w 800w + sizes`:**窗口宽度变化,切换不同体积图片(我们要的效果)**
- `srcset 1x 2x`:**只看设备屏幕 DPR,不看窗口大小,小窗口高 DPR 依旧加载大图**,不适合响应式窗口切换图片。
-->

案例 1:w 宽度模式(响应式大图,配合 sizes,主流方案) ​

语法说明
srcset="url1 宽度w, url2 宽度w, url3 宽度w"
sizes="媒体条件 图片显示宽度, 默认宽度"
sizes 告诉浏览器:这张图在页面上占多宽
vw:视口单位,`100vw = 屏幕宽度
示例:窗口不同宽度,图片展示宽度不一样


<img
  src="img-1080.jpg"
  <!-- 多张图原生宽度 -->
  srcset="img-480.jpg 480w, img-720.jpg 720w, img-1080.jpg 1080w, img-1440.jpg 1440w"
  <!-- 
  规则:
  视口≥1200px → 图片显示宽度600px
  视口≥768px → 图片显示宽度80vw
  其余情况 → 图片显示宽度100vw
  -->
  sizes="(min-width: 1200px) 600px, (min-width:768px) 80vw, 100vw"
  alt="花卉图片"
>
⚠️ 重要规则:使用 w 单位强烈建议搭配 sizes;不写 sizes,浏览器默认sizes=100vw,容易选错图片。

案例 2:固定 50vw ​

图片始终占视口 50% 宽度

浏览器计算演示: 屏幕宽度 1000px → 图片显示宽度 = 500px 浏览器优先选择 ≥500px 宽度的图片 → 加载 flower-large.jpg(1080w)

<img
  src="flower-large.jpg"
  srcset="flower-small.jpg 480w, flower-large.jpg 1080w"
  sizes="50vw"
  alt="花朵"
/>

案例 3:x 倍图模式(图标、固定尺寸图片,不需要 sizes) ​

适合固定大小图片,不用写 sizes

普通屏幕:加载 1x iphone / 安卓高清屏:自动加载 2x/3x 高清图

<img
  src="icon-1x.png"
  srcset="icon-1x.png 1x, icon-2x.png 2x, icon-3x.png 3x"
  alt="图标"
  width="48" height="48"
/>

案例 4:混合禁用!❌ 禁止 w 和 x 混用 ​

<!-- 错误!不能同时有w 和 x -->
<img srcset="a.jpg 480w, b.jpg 2x">

案例 5:picture + srcset 艺术响应式(换图,不只是换尺寸) ​

srcset 只是同构图不同尺寸;想要不同屏幕展示完全不一样裁切图,搭配 <picture>

<picture>
  <source media="(min-width:1000px)" srcset="banner-pc.jpg">
  <source media="(min-width:600px)" srcset="banner-tablet.jpg">
  <img src="banner-mobile.jpg" alt="轮播图">
</picture>

案例 6:极简移动端自适应(只两张图) ​

<img
  src="720.jpg"
  srcset="480.jpg 480w, 720.jpg 720w"
  sizes="100vw"
  alt="海报"
/>

sizes属性 ​

表示资源大小的、以逗号隔开的一个或多个字符串。在支持 srcset 的用户代理中,当使用 w 描述符时,src 属性会被忽略。当匹配了媒体条件 (max-width: 600px) 时,将加载 200 像素宽的图像(最匹配的图像),否则将加载另一幅图像。

<img
  src="clock-demo-200px.png"
  alt="Clock"
  srcset="clock-demo-200px.png 200w, clock-demo-400px.png 400w"
  sizes="(max-width: 600px) 200px, 50vw" />


<img
  loading="lazy"
  width="200"
  height="200"
  sizes="auto, (max-width: 30em) 100vw, (max-width: 50em) 50vw, calc(33vw - 100px)"
  srcset="
    swing-200.jpg   200w,
    swing-400.jpg   400w,
    swing-800.jpg   800w,
    swing-1600.jpg 1600w
  "
  src="swing-400.jpg"
  alt="壶铃摆动" />


<!--窗口不同宽度,图片展示宽度不一样-->
<img
  src="img-1080.jpg"
  <!-- 多张图原生宽度 -->
  srcset="img-480.jpg 480w, img-720.jpg 720w, img-1080.jpg 1080w, img-1440.jpg 1440w"
  <!-- 
  规则:
  视口≥1200px → 图片显示宽度600px
  视口≥768px → 图片显示宽度80vw
  其余情况 → 图片显示宽度100vw
  -->
  sizes="(min-width: 1200px) 600px, (min-width:768px) 80vw, 100vw"
  alt="花卉图片"
>

loading 属性 ​

loading 属性指定浏览器是应立即加载图像还是延迟加载图像。

----------------------------------------------------------------------------------
  值	描述
----------------------------------------------------------------------------------
  eager	默认,图像立即加载。
  lazy	图像延迟加载,只有鼠标滚动到该图片所在位置才会显示。
----------------------------------------------------------------------------------
  • 代码示例
<!--loading属性支持的值
  auto: 浏览器默认的延迟加载行为,与不包含属性相同。
  lazy:推迟资源的加载,直到它到达与视口的计算距离。
  eager:立即加载资源,无论它位于页面上的哪个位置。
-->
<img src="image.png" loading="lazy" alt="…" width="200" height="200">
<!-- 设置延迟加载的图片 -->
<img decoding="async" src="/images/paris.jpeg" alt="Paris" style="width:100%" loading="lazy">

decoding ​

用于告诉浏览器如何解析图像数据。具体来说,在渲染其他的内容更新前,是否应该等待图像解码完成。



表示解码方式的字符串。可选的值有:

"sync"
同步解码图像,与其他内容一起原子化渲染。

"async"
异步解码图像,允许在解码完成前渲染其他内容。

"auto"
对解码模式没有偏好;让浏览器决定最适合用户的模式。这是默认值,但不同的浏览器拥有不同的默认行为:

Chromium 默认为 "sync"。
Firefox 默认为 "async"。
Safari 除少数情况外默认为 "sync"。

fetchpriority ​

提供获取图像时要使用的相对的优先级提示。

<img 
  src="image.png"
  fetchpriority="high" 表示其获取优先级相对其他图像要高。
  fetchpriority="low" 表示其获取优先级相对其他图像要低。
  fetchpriority="auto" 默认值:表示自动确定其相对其他图像的获取优先级。
/>

相关操作方法 ​

// 获取图片路径
let URL = window.URL || window.webkitURL;
let img_src = URL.createObjectURL(url);

// 释放内存
URL.revokeObjectURL(img_src);


const image = new Image();
image.onload = function(e) {
  let width = image.naturalWidth;
  let height = image.naturalHeight;
  if (width > height) {
    setw = window.FONT['size']/100*225;
    seth = window.FONT['size']/100*169;
  } else {
    setw = window.FONT['size']/100*169;
    seth = window.FONT['size']/100*225;
  }

  document.body.append(image);
}
image.onerror = function() {
  //
}

image.crossOrigin = 'anonymous';
image.src = thumbnail;


const initImageSize = (imageUrl: string) => {
	const image = new Image()

	return new Promise((resolve) => {
		image.onload = function (e) {
			const width = image.naturalWidth
			const height = image.naturalHeight

			resolve({ width, height })
		}

		image.onerror = function () {
			resolve({})
		}

		image.crossOrigin = 'anonymous'
		image.src = imageUrl
	})
}

上传图片 ​

const fileEl: HTMLInputElement = document.createElement("input");
if (!fileEl) return;

fileEl.setAttribute("type", "file");
fileEl.setAttribute("accept", "image/gif,image/jpeg,image/png");
fileEl.click();

const getFileData = (fileTarget: HTMLInputElement) => {
  return new Promise((resolve) => {
    fileTarget.onchange = async function (e) {
      // @ts-ignore # 忽视本行代码的小错误
      resolve(e.target.files[0]);
    };
  });
};

const fileData = await getFileData(fileEl);
const formData = new FormData();
// @ts-ignore # 忽视本行代码的小错误
formData.append("file", fileData);

new Image对象 ​

上传图片本地预览 ​

const fileEl: HTMLInputElement = document.createElement("input");
if (!fileEl) return;

fileEl.setAttribute("type", "file");
fileEl.setAttribute("accept", "image/gif,image/jpeg,image/png");
fileEl.click();

const getFileData = (fileTarget: HTMLInputElement) => {
  return new Promise((resolve) => {
    fileTarget.onchange = async function (e) {
      // @ts-ignore # 忽视本行代码的小错误
      resolve(e.target.files[0]);
    };
  });
};

const fileData = await getFileData(fileEl);

const reader = new FileReader();

// 异步
const getData = () => {
  const reader = new FileReader();
  return new Promise((resolve) => {
    reader.onload = function(e) {
			console.info(e.atrget.result);
      resolve(reader.result);
    }
  });
}

const imagePath = await getData();

​

图片实现原理 ​

​

​

图像(Image) ​

图像是位图(Bitmap)

图像增强 ​

前端图像处理图图像增强

改善图像质量、分析图像、图像转换、图像处理

AlloyImage 图像处理库:https://tool.oschina.net/alloyphoto#http://alloyteam.github.io/AlloyPhoto/ 1.图层功能,提供图层的添加,删除,交换图层顺序等功能,且包含与PS相对应的17种图层混合模式 2.图像的基本调节功能,包括亮度、对比度,色相、饱和度、明度调节 3.多种滤镜功能,去色、反相、高斯模糊、锐化、浮雕效果、查找边缘、马赛克、腐蚀等 4.处理后文件的保存,处理完成之后,可以将文件输出为base64形式间接使用和保存 5.高级组合效果,如素描,lomo,复古,素描等复合效果 如一个素描效果的实现

图像滤镜艺术:专业介绍图像处理中各种滤镜的算法实现。 ​

https://www.kancloud.cn/trent/hotoimagefilter/102786 图像滤镜实现万能方法研究:https://trent.blog.csdn.net/article/details/42212459?spm=1001.2101.3001.6650.17&utm_medium=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-18.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~BlogCommendFromBaidu~default-18.no_search_link 图像处理的滤镜算法:https://blog.csdn.net/tomy2426214836/article/details/88889298 数字图像处理课题研究:https://blog.csdn.net/trent1985/category_9263763.html 数字图像处理研究:https://blog.csdn.net/trent1985/category_1850555.html 图片滤镜算法原理简单讲解:https://blog.csdn.net/weixin_34152820/article/details/85461116?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2~default~CTRLIST~default-1.no_search_link 图像处理的滤镜算法:https://blog.csdn.net/tomy2426214836/article/details/88889298 图像特效及滤镜算法汇总 https://blog.csdn.net/matrix_space/article/details/42743613?utm_medium=distribute.pc_relevant.none-task-blog-2~default~baidujs_title~default-1.essearch_pc_relevant&spm=1001.2101.3001.4242.2

MIME-type ​

​

​

image/gif	                                   gif
image/jpeg	                                 jpe
image/jpeg	                                 jpeg
image/jpeg	                                 jpg
image/png                                    png
image/bmp	                                   bmp

image/cis-cod	cod
image/ief	ief

image/pipeg	jfif
image/svg+xml	svg
image/tiff	tif
image/tiff	tiff
image/x-cmu-raster	ras
image/x-cmx	cmx
image/x-icon	ico
image/x-portable-anymap	pnm
image/x-portable-bitmap	pbm
image/x-portable-graymap	pgm
image/x-portable-pixmap	ppm
image/x-rgb	rgb
image/x-xbitmap	xbm
image/x-xpixmap	xpm
image/x-xwindowdump	xwd

常见不同图片格式 ​

  • APNG(动态可移植网络图形)——无损动画序列的不错选择(GIF 性能较差)。
  • AVIF(AV1 图像文件格式)——静态图像或动画的不错选择,其性能较好。
  • GIF(图像互换格式)——简单图像和动画的不错选择。
  • JPEG(联合图像专家组)——有损压缩静态图像的不错选择(目前最流行的格式)。
  • PNG(便携式网络图形)——对于无损压缩静态图像而言是不错的选择(质量略好于 JPEG)。
  • SVG(可缩放矢量图形)——矢量图像格式。用于必须以不同尺寸准确描绘的图像。
  • WebP(网络图片格式)——图像和动画的绝佳选择。

APNG ​

(动态可移植网络图形)——无损动画序列的不错选择(GIF 性能较差)。

AVIF ​

(AV1 图像文件格式)——静态图像或动画的不错选择,其性能较好。

GIF ​

(图像互换格式)——简单图像和动画的不错选择。

JPEG ​

(联合图像专家组)——有损压缩静态图像的不错选择(目前最流行的格式)。

PNG ​

(便携式网络图形)——对于无损压缩静态图像而言是不错的选择(质量略好于 JPEG)。

SVG ​

(可缩放矢量图形)——矢量图像格式。用于必须以不同尺寸准确描绘的图像。

WebP ​

(网络图片格式)——图像和动画的绝佳选择。

WebP ​

  • 检测浏览器是否支持WebP格式图片
window.isSupportWebp = false;  // 是否支持
(function() {
	var img = new Image(); 
	function getResult(event) {
			// 如果进入加载且图片宽度为1(通过图片宽度值判断图片是否可以显示)
			window.isSupportWebp = event && event.type === 'load' ? img.width == 1 : false;
	}
	img.onerror = getResult;
	img.onload = getResult;
	img.src = 'data:image/webp;base64,UklGRiQAAABXRUJQVlA4IBgAAAAwAQCdASoBAAEAAwA0JaQAA3AA/vuUAAA=';  // 一像素图片
})();

Gif ​

https://github.com/jnordberg/gif.js

常见算法列表 ​

FXAA 抗锯齿算法 ​

FXAA 抗锯齿算法的实现:https://jelly.jd.com/article/5efd42154b54be014cf4e646

​

​

​

​

​

​

​

​

​

​

插件体系 ​

cropperjs插件 ​

官网:https://github.com/fengyuanchen/cropperjs vue-cropperjs:https://github.com/Agontuk/vue-cropperjs

vue-cropperjs裁剪的尺寸变化事件导致滚动失效

​

​

图片工具 ​

CanvasKeyFrames ​

图片序列帧播放工具,用canvas操作图片动画,封装了常用方法。

​

Released under the MIT License.