原文转载自「刘悦的技术博客」https://v3u.cn/a_id_190

我们知道,在前端界有一个共识:速度就是生命,带宽就是金钱。怎样将页面加载速度有效提升是无数前端工程师无时不刻在思考的课题,目前的网络环境中,除了视频,图片仍旧是占用流量较大的一部分,对于app端尤其如此,因此,如何在保证图片视觉不失真的前提下缩小图片体积,对于节省带宽和电池电量都十分重要,因此Google在十年前提出了一种新的图片压缩格式 :WebP,给图片的优化提供了新的方向。

WebP的优势在于它具有更优的图像数据压缩算法,在拥有肉眼几乎无法识别差异的图像质量前提下,带来更小的图片体积,同时具备了无损和有损的压缩模式、Alpha 透明以及动画的特性,从JPEG 和 PNG 上的转化效果都非常突出、稳定和统一,全球著名视频网站YouTube的视频缩略图采用WebP后,网页加载速度提升了10%,提升效果可见一斑:

本次我们以本站为例子,使用Python3对站内图片进行无损压缩和转换,同时利用Nginx针对Webp图片判断请求头来对老版本浏览器做向下兼容,实现Webp图片的无缝切换。

首先,将网站的图片转换为Webp格式,这里我们使用PIL库,该库广泛用于Python中的图像处理,并且PIL图像库中最重要的类是Image类,该类在模块中以相同的名称定义。

安装PIL:

python3 -m pip install --upgrade pip
python3 -m pip install --upgrade Pillow

可以通过open方法加载图像文件并且展示它:

from PIL import Image
img = Image.open('sample.jpg')
img.show()

Image.convert()方法可以返回该图像的转换后的副本。此方法可通过调色板转换像素。当前版本支持“ L”,“ RGB”和“ CMYK”之间的所有格式转换。save(fp,format)使用两个输入参数,第一个是保存转换后的文件的文件路径(fp),第二个是要转换成的文件格式。

转换JPG到PNG:

from PIL import Image
img = Image.open('sample.jpg').convert('RGB')
img.save('sample.jpg.png', 'png')

转换PNG到JPG:

from PIL import Image
img = Image.open('sample.png').convert('RGB')
img.save('sample.png.jpeg', 'jpeg')

转换PNG到WEBP:

from PIL import Image
img = Image.open('sample.png').convert('RGB')
img.save('sample.png.webp', 'webp')

转换JPG到WEBP:

from PIL import Image
img = Image.open('sample.jpg').convert('RGB')
img.save('sample.jpg.webp', 'webp')

看起来相当简单,有的时候,我们可能需要把某个目录下的图片进行批量转换,首先读取所有需要转换的图片:

import os  files = os.listdir('/opt/img')  images = [file for file in files if file.endswith(('jpg','png','jpeg'))]  print(images)liuyue:mytornado liuyue$ python3 "/Users/liuyue/wodfan/work/mytornado/test_webp.py"
['qrcode.png', 'touxiang_1.png', 'code.jpeg', 'test.png', 'touxiang1.jpg', 'logo_dark.png', 'logo.png', 'touxiang.png', 'code1.jpeg']
liuyue:mytornado liuyue$

随后建立转换方法:

def convert_image(image_path, image_type):  im = Image.open(image_path)  print(image_path)  im = im.convert('RGB')  image_name = image_path.split('.')[0]  print(f"This is the image name: {image_name}")  if not os.path.exists(f"{image_path}.webp"):  if image_type == 'jpg' or image_type == 'png' or image_type == 'jpeg':  im.save(f"{image_name}.{image_type}.webp", 'webp')  else:  raise Error

这里我们将转换后的副本统一加上后缀.webp

之后进行转换操作:

for image in images:  if image.endswith('jpg'):  convert_image(image, image_type='jpg')  elif image.endswith('jpeg'):  convert_image(image, image_type='jpg')  elif image.endswith('png'):  convert_image(image, image_type='png')  else:  raise Error

这里需要注意的是,是在原图文件名基础上加入后缀.webp,而不是覆盖原图后缀,这样后面替换图片内容时会更加方便。

接下来的课题就是怎样判断客户端的浏览器是否支持Webp格式的图片,目前ios和新版的Safari浏览器已经对webp进行了适配,但是对于老版本的系统和浏览器怎么向下兼容是一个令人头疼的问题。

可以在前端通过js脚本来进行判断:

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='; //一像素图片
})();  console.log(window.isSupportWebp);
true

原理就是加载一像素的webp判断是否显示成功,如果window.isSupportWebp为true我们就可以将webp后缀加载否则就加载原后缀的图片,但是基于前端的解决方案需要修改大量的代码,同时如果判断业务逻辑放在页面里无形中也增加了页面负担,有没有方法在不变动代码逻辑的前提下,可以自动切换图片后缀呢?答案就在后端的Nginx。

我们知道浏览器的每个请求头中都带有"Accept"字段,例如:

Accept:image/webp,image/apng,image/*,*/*;q=0.8

此时通过nginx对Accept进行判断,如果带有webp,说明该浏览器支持webp,我们就由后端加载webp,如果头部没有webp字样,说明浏览器不支持,此时nginx继续加载原后缀文件,这也就是为什么之前在图片转换过程中要保留原始图片文件的原因。

首先打开nginx的mime.types文件,查看nginx是否配置webp,如果没有需要手动加上:

vim /etc/nginx/mime.types

可以看到全部文件类型:

types {  text/html                                        html htm shtml;  text/css                                         css;  text/xml                                         xml;  image/gif                                        gif;  image/jpeg                                       jpeg jpg;  application/javascript                           js;  application/atom+xml                             atom;  application/rss+xml                              rss;  text/mathml                                      mml;  text/plain                                       txt;  text/vnd.sun.j2me.app-descriptor                 jad;  text/vnd.wap.wml                                 wml;  text/x-component                                 htc;  image/png                                        png;  image/svg+xml                                    svg svgz;  image/tiff                                       tif tiff;  image/vnd.wap.wbmp                               wbmp;  image/webp                                       webp;  image/x-icon                                     ico;  image/x-jng                                      jng;
"/etc/nginx/mime.types" 97L, 5231C                            22,5         顶端  application/octet-stream                         deb;  application/octet-stream                         dmg;  application/octet-stream                         iso img;  application/octet-stream                         msi msp msm;  audio/midi                                       mid midi kar;  audio/mpeg                                       mp3;  audio/ogg                                        ogg;  audio/x-m4a                                      m4a;  audio/x-realaudio                                ra;  video/3gpp                                       3gpp 3gp;  video/mp2t                                       ts;  video/mp4                                        mp4;  video/mpeg                                       mpeg mpg;  video/quicktime                                  mov;  video/webm                                       webm;  video/x-flv                                      flv;  video/x-m4v                                      m4v;  video/x-mng                                      mng;  video/x-ms-asf                                   asx asf;  video/x-ms-wmv                                   wmv;  video/x-msvideo                                  avi;
}

主要查看有没有webp,如果没有进行添加:

image/webp                                       webp;

随后修改主配置文件:

vim /etc/nginx/nginx.conf

在http配置中加上webp文件的判断逻辑:

map $http_accept $webp_suffix {  default   "";  "~*webp"  ".webp";
}

同时在server中配置逻辑,如果支持就将头部信息替换为webp后缀文件:

location ~* ^/v3u/Public/images/.+\.(png|jpe?g)$ {  add_header Vary Accept;  try_files $uri$webp_suffix $uri =404;
}

完整配置如下:

user root;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;  # Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;  events {  worker_connections 1024;
}  http {  log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '  '$status $body_bytes_sent "$http_referer" '  '"$http_user_agent" "$http_x_forwarded_for"';  access_log  /var/log/nginx/access.log  main;  map $http_accept $webp_suffix {  default   "";  "~*webp"  ".webp";
}  sendfile            on;  tcp_nopush          on;  tcp_nodelay         on;  keepalive_timeout   65;  types_hash_max_size 2048;  include             /etc/nginx/mime.types;  default_type        application/octet-stream;  gzip on;  gzip_min_length  1k;  gzip_buffers     4 16k;  gzip_http_version 1.0;  gzip_comp_level 2;  gzip_types       text/plain application/x-javascript text/css application/xml text/javascript application/x-httpd-php image/jpeg image/gif image/png;  gzip_vary on;  gzip_disable msie6;  open_file_cache max=1000 inactive=20s;  open_file_cache_valid 30s;  open_file_cache_min_uses 5;  open_file_cache_errors off;  # Load modular configuration files from the /etc/nginx/conf.d directory.  # See http://nginx.org/en/docs/ngx_core_module.html#include  # for more information.  include /etc/nginx/conf.d/*.conf;  server {  location ~* ^/v3u/Public/images/.+\.(png|jpe?g)$ {  add_header Vary Accept;  try_files $uri$webp_suffix $uri =404;
}  include /etc/nginx/default.d/*.conf;  location / {  }  error_page 404 /404.html;  location = /40x.html {  }  error_page 500 502 503 504 /50x.html;  location = /50x.html {  }  }  #include vhost/*.conf;
}

修改好配置文件之后,先不要着急重启服务器,检测一下配置文件语法:

[root@iz2ze0ndt5s9wq2s6ff8g6z nginx]# nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
[root@iz2ze0ndt5s9wq2s6ff8g6z nginx]#

如果没有问题,重启服务:

systemctl restart nginx.service

现在让我们来测试一下,以本站的logo图片为例子,如果是不支持webp格式的浏览器,比如低版本的Safari(13.0.3):

可以看到加载图片的类型保持了原图片后缀:png

现在换一个浏览器,使用支持webp的chrome(88.0.4324):

可以看到已经自动切换为webp格式了,让我们再次通过google的页面性能打分工具PageSpeedInsights对本站进行评测:

https://developers.google.com/speed/pagespeed/insights/

一望而知,页面加载速度都得到了提升,并且在Google的页面优化建议中,已经达成了采用新一代格式提供图片的要求。

结语:当然了,其实Nginx是可以对图片进行实时压缩的,但是那样需要单独安装模块以及其他服务的介入,这对于低版本服务器无疑是要耗费成本的,所以本方案就是通过python3脚本提前将图片转换好,再用nginx判断一下即可,仅仅一个脚本+两行配置文件即可完成系统升级,看起来此方案是最佳选择,既没有前端代码侵入,也不需要各种复杂的配置和服务搭建。相信在不远的将来,基于google开源的VP8视频编码格式的 WebM 视频也将会大面积的替代传统的mp4格式,前端架构的性能优化,始终是业界亘古不变的课题之一。

原文转载自「刘悦的技术博客」 https://v3u.cn/a_id_190

石火电光追风逐日|前端优化之次时代图片压缩格式WebP的项目级躬身实践(Python3 PIL+Nginx)相关推荐

  1. 三个前端浏览器图片制作-风格迁移,图片压缩,照片动漫化

    原文链接:https://dsx2016.com/?p=1821 公众号:大师兄2016 风格迁移 https://github.com/reiinakano/arbitrary-image-styl ...

  2. 前端开发:浅谈图片优化的方法

    在网站优化中,如果图片优化得好,不但可以提高页面的加载速度,提升网站的用户体验,而且还可以通过图片优化来节省网站的带宽.那么作为页面构建工程师应该采用什么方法来优化图片,既能保证UI的还原度,又使图片 ...

  3. 【Android 内存优化】Android 原生 API 图片压缩原理 ( Bitmap_compress 方法解析 | Skia 二维图形库 | libjpeg 函数库 | libpng 函数库 )

    文章目录 一. 图片质量压缩方法 二. Skia 二维图形库 三. libjpeg.libpng 函数库引入 在博客 [Android 内存优化]图片文件压缩 ( Android 原生 API 提供的 ...

  4. 【Android 内存优化】Android 原生 API 图片压缩代码示例 ( PNG 格式压缩 | JPEG 格式压缩 | WEBP 格式压缩 | 动态权限申请 | Android10 存储策略 )

    文章目录 一. 图片质量压缩 二. 图片尺寸压缩 三. Android 10 文件访问 四. 完整源码示例 上一篇博客 [Android 内存优化]图片文件压缩 ( Android 原生 API 提供 ...

  5. 改善前端优化的有用技巧

    改善前端优化的有用技巧 1.缓存JavaScript和CSS样式 尽可能少地向服务器发出请求.记得10年前,一个页面上要加载5-6个JS,但理想情况下,你应该有一个JS文件和一个CSS文件,这就足够了 ...

  6. 前端优化方案-JavaScript 优化方案 收藏 此文于2010-06-04被推荐到CSDN首页

    前端优化方案-JavaScript 优化方案 收藏 此文于2010-06-04被推荐到CSDN首页 如何被推荐? Author: 李丽媛 Date: 2010/6/2 Email: lly219#gm ...

  7. 实践中的电商前端优化

    前端优化已经是一个被写烂的题材了. 虽千万人吾往矣,这里我仅分享我的一些实践经验. 欢迎一起交流 欢迎关注我的个人公众号,不定期更新自己的工作心得. 正文如下 前端性能 1. 模块化 严格来说,代码模 ...

  8. 网页中加载obj模型比较慢_Web前端优化技巧分享,让你的网页显示的更流畅

    如果我们在打开一个网站时速度很慢,势必会影响体验,甚至会造成用户流失.浏览量下降的情况.想要解决这个问题自然就需要Web前端开发人员对前端页面进行优化,众所周知,前端的页面主要包括HTML.CSS.J ...

  9. Serverless——前端的3.0时代

    导语:<信息简史>中说"进化本身是生物体与环境之间持续不断的信息交换的具体表现",前端技术的进化也是如此.浩瀚的前端宇宙中,又出现过哪些耀眼的星辰呢?指引前端未来的&q ...

  10. 乾坤 微前端_拥抱云时代的前端开发架构——微前端

    微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员.团队的增加,从一个普通应用演变成一个巨石应用(Frontend Monolith),随之而来的应用不可维护的问题.这类问题在企业级 ...

最新文章

  1. 盖茨在毕业礼上给毕业生的11个人生建议
  2. JsTree中提示:Cannot read property 'core' of underfined
  3. Oracle中exists与in的效率探讨
  4. SQL 2000 中如何 纵表变横表
  5. HTMLTESTRunner自动化测试报告增加截图功能
  6. 请问诸位大神,Android怎么实现图片转动
  7. php mysql 创建数据表_PHP MySQL 创建数据表
  8. 今天参加广州.NET俱乐部活动,运气超好
  9. centos7部署gitlab遇到的坑
  10. 计算机辅助建筑制图规范,房屋建筑制图统一标准 [附条文说明] GB/T50001-2017
  11. 数据库 蚂蚁_蚂蚁金服自研数据库OceanBase性能超过甲骨文引热议
  12. 计算机小知识140,140个电脑小知识,电脑知识-
  13. matlab 矩阵白化,主成分分析中如何对矩阵进行白化处理
  14. 数据结构(计算机存储、组织数据方式)
  15. 基于爬取百合网的数据,用matplotlib生成图表
  16. java comp env_Java:comp/env/讲解与JNDI(转)
  17. HTML背景样式简单介绍
  18. 不是广告!!迎来1w粉丝,本号送书啦!|原创
  19. 几款好用的Tooltips 提示框插件
  20. YV12toI420 yuv420、NV12、YV12相互转换

热门文章

  1. 有什么适合做移动端的报表工具
  2. JAVA微信小程序医院预约挂号小程序系统毕业设计 开题报告
  3. 我的十年 Oracle DBA 奋斗路 - 回首向来萧瑟处,也无风雨也无晴
  4. 仿节奏大师java_HelloCpp 仿节奏大师Android游戏版本,只实现了击键功能,可以给大家启发. 238万源代码下载- www.pudn.com...
  5. 用 Python 总结分析男篮世界杯
  6. 校园二手市场需求分析
  7. Python学习心得体会
  8. 注解之注解的基本概念
  9. HTML+CSS网页设计期末课程大作业:个人网站设计——个人介绍(7页) web前端开发技术 web课程设计 网页规划与设计
  10. 如何用WinRAR给压缩包设置和取消密码