前言

时光匆匆,转眼清明已过。但是杭州还是有一丝丝寒冷,风力没有春天的味道。年前积压的一些需求已经全部完成上线,这星期学了点东西,同通过文章的形式记录一下,防止以后自己忘记。

正文开始

事情是这样的,产品经理来问我,为什么图片上传之后,变成横向的了。如下图所示:

image.png

根据情景分析,这张图片是由手机拍摄的,并且上传到网站上的时候,默认就是逆时针旋转了 90 度。现在需要解决的问题是将其顺时针旋转 90 度,变成正常显示。

主角登场

本篇文章的主角便是——EXIF。简单的说,它是读取图片元数据的一个工具包,Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。

使用方法

1、通过 npm 安装。 2、通过静态资源 CDN 的形式,标签引入。

下面介绍的例子就是通过标签引入的方式:

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4. <meta charset="UTF-8">
  5. <meta name="viewport" content="width=device-width, initial-scale=1.0">
  6. <link rel="stylesheet/less" type="text/css" href="./styles.less" />
  7. <title>EXIF</title>
  8. </head>
  9. <body>
  10. <div class="box">
  11. <img width="200px" id="img" src="" alt="图片" />
  12. <input id="input" type="file" onchange="upLoad()" />
  13. </div>
  14. <script>
  15. function upLoad() {
  16. var fileInput = document.getElementById('input')
  17. var file = fileInput.files[0] // 获取上传图片的信息
  18. console.log('file', file)
  19. EXIF.getData(file, function() {
  20. let exifTags = EXIF.getAllTags(this); // 获取上传图片的元数据
  21. console.log('exifTags', exifTags)
  22. let reader = new FileReader();
  23. reader.readAsDataURL(file);
  24. reader.onload = e => {
  25. let imgData = e.target.result;
  26. // 8 表示 顺时针转了90; 3 表示 转了 180; 6 表示 逆时针转了90
  27. if (
  28. exifTags.Orientation == 8 ||
  29. exifTags.Orientation == 3 ||
  30. exifTags.Orientation == 6
  31. ) {
  32. const img = new Image();
  33. img.src = imgData;
  34. img.onload = function () {
  35. let cvs = document.createElement('canvas');
  36. let ctx = cvs.getContext('2d');
  37. //如果旋转90
  38. if (
  39. exifTags.Orientation == 8 ||
  40. exifTags.Orientation == 6
  41. ) {
  42. cvs.width = img.height;
  43. cvs.height = img.width;
  44. } else {
  45. cvs.width = img.width;
  46. cvs.height = img.height;
  47. }
  48. if (exifTags.Orientation == 6) {
  49. //原图逆时针转了90, 所以要顺时针旋转90
  50. ctx.rotate(Math.PI / 180 * 90);
  51. ctx.drawImage(
  52. img,
  53. 0,
  54. 0,
  55. img.width,
  56. img.height,
  57. 0,
  58. -img.height,
  59. img.width,
  60. img.height
  61. );
  62. }
  63. if (exifTags.Orientation == 3) {
  64. //原图逆时针转了180, 所以顺时针旋转180
  65. ctx.rotate(Math.PI / 180 * 180);
  66. ctx.drawImage(
  67. img,
  68. 0,
  69. 0,
  70. img.width,
  71. img.height,
  72. -img.width,
  73. -img.height,
  74. img.width,
  75. img.height
  76. );
  77. }
  78. if (exifTags.Orientation == 8) {
  79. //原图顺时针旋转了90, 所以要你时针旋转90
  80. ctx.rotate(Math.PI / 180 * -90);
  81. ctx.drawImage(
  82. img,
  83. 0,
  84. 0,
  85. img.width,
  86. img.height,
  87. -img.width,
  88. 0,
  89. img.width,
  90. img.height
  91. );
  92. }
  93. const url = cvs.toDataURL('image/png')
  94. let imgNode = document.getElementById('img')
  95. imgNode.setAttribute('src', url)
  96. }
  97. } else {
  98. let imgNode = document.getElementById('img')
  99. imgNode.setAttribute('src', imgData)
  100. }
  101. }
  102. })
  103. }
  104. </script>
  105. <script src="https://cdn.bootcss.com/exif-js/2.3.0/exif.min.js"></script>
  106. </body>
  107. </html>

上述代码获取到图片的数据之后,关键是 Orientation 参数,它表示拍摄方向。通过返回的数字判断这张图片旋转的方向,然后通过 canvas 画布再重新绘制一张图片,最后输出到 DOM 节点。

image.png

总结

exif 还有很多值得研究的地方,本篇文章只是需要针对旋转方向去做重绘,顾之研究了片面,需要对图像做深度研究的同学,可以深究。