/ 博客 / 1123浏览

利用 Aliyun OSS 显示图片 Exif 信息

首先要感谢 @fooleap 发给我的极为给力的 jQuery 实现显示图片 Exif 代码,解决了我十年来 😥 的一个夙愿:显示博客图片 Exif(什么是 Exif?)信息——以后再也不需要在图片的 title 属性里人肉输入用了什么设备了!

虽然从来没学过 jQuery,但好歹有十多年前可怜的一点 js 基础,加上百度,一晚上摸索着居然也搞出来了。

注意:以下代码实现的基础是图片托管于 Aliyun OSS 或 Qiniu 等。

1、将根据自己需求修订后的 jQuery 代码 yourjscode.js 上传至主题下 js 文件夹:

/* -------------------------------------------------
 * Description: New exif.js file. Just make it neat.
 * Edition:   v1.4
 * Time:    2018/11/18 23:46
 * Author:   blog.fooleap.org & synyan.cn
 * ------------------------------------------------*/
window.$ = jQuery;
$(document).ready(function(){
$('.post-content img[src*="synyan.cn"]').each(function(){
  var _ = this; 
  var $el = $(this); 
  var displayinfo;
  if( _.src.toLowerCase().lastIndexOf('.jpg') )
    var index = _.src.toLowerCase().lastIndexOf('.jpg');
    else if( _.src.toLowerCase().lastIndexOf('.jpeg') )
    var index = _.src.toLowerCase().lastIndexOf('.jpeg');
  else
    return;
  var titleString = _.title;
  var titleCamera = false;
  if (titleString.indexOf("Camera") >= 0) titleCamera = true;
  if( index > -1 ){
    var exifUrl = _.src.slice(0, index)+'.jpg?x-oss-process=image/info';
    $.ajax({
      url: exifUrl,
      success: function (res) {
        var exif = res;
        var parse = function(attr, label){
        return !attr ? '' : ( label ? label + ' ' : '') + attr.value + ' ';
   }
   /* 情况 1 */
   if (!!parse(exif.Make) && !!parse(exif.Model) && !!parse(exif.DateTimeOriginal)){
    /* 情况 1.1 */
    var imgCameraOne = parse(exif.Model).replace("Canon","");
    var imgCameraOne = parse(exif.Model).replace("HTC","");
    var focalLengthInNumber = Math.round((eval(parse(exif.FocalLength,'')))*100)/100;
    var focalLengthIn35mmFilmOutput;
    var focalLengthIn35mmFilmNumber = eval(parse(exif.FocalLengthIn35mmFilm,''));
    var focalLenghtOutput;
   if (!focalLengthInNumber) {
    focalLenghtOutput = "";
    if (!focalLengthIn35mmFilmNumber)
      focalLengthIn35mmFilmOutput = "";
    else
      focalLengthIn35mmFilmOutput = " eqv " + focalLengthIn35mmFilmNumber + "mm";
   }
   else {
      focalLenghtOutput = "·" + " f=" + focalLengthInNumber + "mm";
      if (focalLengthIn35mmFilmNumber)
       focalLengthIn35mmFilmOutput = " eqv " + focalLengthIn35mmFilmNumber + "mm";
      else {
       focalLengthIn35mmFilmOutput = "";
      }
      if (focalLengthInNumber == focalLengthIn35mmFilmNumber) {
       focalLenghtOutput = "";
       focalLengthIn35mmFilmOutput = "·" + " f=" + focalLengthInNumber + "mm";
      }
      else;
    }
    var content = '<div class="exif-caption" exif-data="'
          + parse(exif.Make, '')
          + imgCameraOne
          + parse(exif.LensModel,'·')
          + parse(exif.DateTimeOriginal, '·')
          + focalLenghtOutput
          + focalLengthIn35mmFilmOutput
          + '"></div>';
    }
    /* 情况 2 */
    else if (!parse(exif.Make) || !parse(exif.Model) || !parse(exif.DateTimeOriginal)) {
       if (titleString && titleCamera) {
        var imgTitle = titleString;
        imgTitle = imgTitle.replace(/(Camera:/i, '');
        imgTitle = imgTitle.replace(/)/i, '');
        if (imgTitle.indexOf("+") >= 0) {
          var imgTitleString = imgTitle.split("+");
          var imgCamera = imgTitleString[0];
          var imgLens = imgTitleString[1];
          var imgFilm = imgTitleString[2];
          var imgScanner = imgTitleString[3];
        if (!imgLens){
          imgTitle = "" + imgCamera;
        }
        else if (!imgFilm) {
          imgTitle = "" + imgCamera +"·" + imgLens;
        }
        else if (!imgScanner) {
          imgTitle = "" + imgCamera +"·" + imgLens + "·" + imgFilm;
        }
        else {
          imgTitle = "" + imgCamera +"·" + imgLens + "·" + imgFilm + "·" + imgScanner;
        }
     }
     else if(imgTitle.indexOf("+") < 0 && titleString.indexOf("Camera:") >=0){
        imgTitle = "" + imgTitle;
     }
     if (exif.DateTimeOriginal) {
        var content = '<div class="exif-caption" exif-data="'
              + imgTitle
              + parse(exif.DateTimeOriginal, '·')
              + '"></div>';
     }
     /* 情况 2.1 */
      if (!(exif.DateTimeOriginal)) {
         /* 情况 2.1.1 */
         if ((exif.DateTime && !exif.DateTimeDigitized)) {
           var content = '<div class="exif-caption" exif-data="'
                 + imgTitle 
                 + parse(exif.DateTime, '·')
                 + '"></div>';
       }
       else if ((exif.DateTimeDigitized)) {
         var content = '<div class="exif-caption" exif-data="'
               + imgTitle
               + parse(exif.DateTimeDigitized, '·')
               + '"></div>';
       }
       else {
         var content = '<div class="exif-caption" exif-data="'
               + imgTitle
               + '"></div>';
       }
      }
    }
    /* 情况 3 */
    else {
       var content = '<div class="exif-caption" exif-data="'
             + ' 无 Exif 信息 '
             + '"></div>';
    }
   }
   else;
   $(".post-content img").attr({title:""});
   $el.after(content);
   }
   })
   }
  })
})

2、在 Single.php 头部插入:

<script src="<?phpecho get_stylesheet_directory_uri() ?>/js/yourjscode.js"></script>

3、添加 css 代码(从 @fooleap 的博客扒下来的,同样也是修订了一番,最终符合 WordPress 的贴图规范,再次感谢 @fooleap):

/* exif css */
.post-content .wp-caption .exif-caption:before{
  max-width: 100%;
  text-align: center;
  margin: 0 auto;
  content: attr(exif-data);
  display: block;
  position: absolute !important;
  top: 20px;
  left: 25px;
  right: 25px;
  background-color: black;
  color: white;
  font-size: 12px;
  line-height: 25px;
  height: 25px;
  overflow: hidden;
  opacity: 0;
  transition: opacity .5s;
  -webkit-transition: opacity .5s;
}
.wp-caption:hover .exif-caption[exif-data]:before {
  opacity: .7;
}

4、Aliyun 开通“跨域访问”。

大功告成! 😉

鼠标移到图片上显示Exif信息
鼠标移到图片上显示 Exif 信息

2018 年 11 月 3 日

昨晚做得匆忙,开会抽空之余继续优化了一下代码:

  • 删掉了无用的几行代码。
  • 以前人肉输入的 title 属性也没浪费,加入判断语句,如果 Exif 为空或不全,则取出 title 标签中的部分文字,嵌入显示完整信息。
无Exif的胶片引入title信息
无 Exif 的胶片引入 title 信息

2018 年 11 月 4 日

发现存量图片显示 Exif 存在各种 bug,原代码越改越多越糊涂,改到后来已经不知道到底在写什么了。

于是静下心来列了一张代码结构表:

情况 1:
正常 Exif(标准是 Make/Model/DateTimeOriginal/FNumber 同时存在)。
	情况 1.1:
	若 Make 为 Canon/HTC,Model 中去除一个重复的 Canon/HTC 字样。

情况 2:
有 Exif 但 Exif 不全(标准是 Make/Model/DateTimeOriginal/FNumber 有一个不存在),或无 Exif,以人工输入的 title="(Camera:Make & Model + [LensModel] + [Film] + [Scanner])"通过分割+号代替 Make/Model/LensModel 并添上其它属性。
	情况 2.1:
	若 DateTimeOriginal 不存在,则以 DateTime 显示修改时间。
		情况 2.1.1:
		若 DateTime 不存在,则不显示修改时间。
		情况 2.1.2:
		若 DateTimeDigitalized 存在,则以 DateTimeDigitalized 显示图片时间。
情况 3:
无 Exif,无 title,提示无 Exif 信息。

按照代码结构表重写一遍,清爽整洁多了。精简后的代码已更新至代码 1。


2020 年 4 月 14 日

针对 2018 年 11 月写的关于不具有 Exif 的图片(如:胶片扫描件)添加 title 属性并获取数据的方法,经过一年半来的实践,认为并不好……

以前人肉输入的 title 属性也没浪费,加入判断语句,如果 Exif 为空或不全,则取出 title 标签中的部分文字,嵌入显示完整信息。

尤其是 WordPress 将后台编辑器更新为古腾堡后,如果更新区块则会导致原有 title 全部遗失。另外今后也许第三方会出新的 Exif 解析工具,人肉添加 title 并后期调用的原始方法在实现了自己的历史价值后,应该丢入垃圾堆。推荐直接利用批量改图工具,为不具有原始 Exif 属性的图片添加 Exif 以达到一劳永逸的目的。相关改图工具包括(推荐度以数字排序):

Mac:

  1. ImageExifEditor
  2. Exif Editor for Mac

Windows:

  1. Photos Exif Editor
  2. ExifTool
  3. PowerExif
  4. ExifDateEdit

Ubuntu:

  1. jhead 库
  2. libexif 库

(为啥没有封装好的软件包?都用 Linux 了还要啥 interface……)


2022 年 7 月 17 日

因佳能、部分索尼相机所拍照片 exif 不带 exif.FocalLengthIn35mmFilm(等效 35mm 焦距)标签,故自己测算传感器大小转换为 35mm 胶片 factor 后人工计算等效焦距,并代码如下:

/* 如果相机无等效 35mm 但可计算等效 */
/* 开始 */
var specialCameras = [
	"Canon EOS M200 1.6",
	"Canon PowerShot G7 X Mark III 2.7272",
	"Canon PowerShot G5 X Mark II 2.7272",
	"Canon PowerShot Pro1 3.94",
	"Canon PowerShot A70 6.4815",
	"SONY DSC-T9 6.0"
];
var exifModel = parse(exif.Model).toString();
function factor(n) {
	for (var i in specialCameras) {
		if (specialCameras[i].search(n) != -1) {
			var str = specialCameras[i];
			var spstr = str.split(" ");
			var c = spstr[spstr.length-1];
			return c;
			};
	}
}
focalLengthIn35mmFilmNumber = Math.round(eval(focalLengthInNumber * factor(exifModel)));
focalLengthIn35mmFilmOutput = " eqv " + focalLengthIn35mmFilmNumber + "mm";
if(!focalLengthIn35mmFilmNumber)
	focalLengthIn35mmFilmOutput = '';
/* 结束 */

29

  1. fooleap

    取得数据的第一个判断写错了,我本意是想判断没有 exif 信息,不是 !!exif.Mark 而是 !exif.Make。

    Google Chrome 70 · Mac OS X 10.14
    1. S̆̈

      @fooleap 我其实也很疑惑,因为我后来也试了一下发现!!exif.Mark 无效,不过太晚了再加上能用就不管了……

      Wordpress App 11 · iPhone iOS 12.1
      1. fooleap

        @S̆̈看起来好折腾,不过习惯很好啊,想当年每张相片都插相机信息累坏了。

        Google Chrome 70 · Mac OS X 10.14
        1. S̆̈

          @fooleap 是啊,不过也没浪费,我改了代码了,以前留的信息都用上了,特别是胶片。其实当年如果不偷懒在修图时直接手工把 Exif 全都嵌进去就更完美了。现在是不高兴弄了……

          Google Chrome 70 · Mac OS X 10.14
          1. fooleap

            @S̆̈看你折腾了好多,其实 parse 直接提出来到外面更好。

            Google Chrome 70 · Mac OS X 10.14
            1. S̆̈

              @fooleap 这不是不会弄嘛。瞎折腾。

              Wordpress App 11 · iPhone iOS 12.1
  2. 老何

    阿里云的 oss 没搞懂,我也是借 @fooleap 之力用七牛云实现这一功能。

    Google Chrome 70 · Windows 10
    1. S̆̈

      @老何七牛云现在不能用测试域名了,所以我只能放弃。OSS 跟七牛云大差不差。@fooleap 是中国好博友,给戴大红花。

      Google Chrome 70 · Mac OS X 10.14
      1. fooleap

        @S̆̈夸得我不好意思了,绵薄之力。

        Google Chrome 70 · Mac OS X 10.14
        1. S̆̈

          @fooleap 别不好意思,以后有好代码要继续共享哦~ 😆

          Google Chrome 70 · Mac OS X 10.14
          1. 老何

            @S̆̈这扫描仪型号都出来了。

            Google Chrome 70 · Windows 10
            1. S̆̈

              @老何是的,不过胶片和扫描仪是从前人肉输的 title 属性,如今用函数方式取出来罢了。

              Google Chrome 70 · Mac OS X 10.14
  3. 大致

    没有跟 php 的交互为什么要用 ajax?

    Firefox 63 · Windows 7
    1. S̆̈

      @大致代码主干部分是 fooleap 友情赞助的,并不清楚为何用 ajax。看来回头是要自学一下了。

      Wordpress App 11 · iPhone iOS 12.1
    2. fooleap

      @大致可是和阿里云 OSS 交互了。
      我觉得使用 JS Ajax 应该是成本最低的一种实现方式。
      https://www.alibabacloud.com/help/zh/doc-detail/31928.html

      Google Chrome 69 · Windows 7
      1. 大致

        @fooleap 了解,阿里云。
        我一直觉得他们管的事太多了。

        Firefox 63 · Windows 7
  4. 木瓜园

    CORS,我现在就遇到了这个问题,一直解决不了

    Safari 12 · iPhone iOS 12.1
    1. S̆̈

      @木瓜园我看了一下,你应该也是用的比如七牛什么的 api 吧?图片都加了-1200x900.jpg 后缀。
      我一般是自己线下处理好了尺寸再上传的,减少开销。
      既然能加尺寸,exif 应该也能取得,CORS 在云存储的设置里应该有。

      Google Chrome 70 · Mac OS X 10.14
  5. JiaYin

    这功能我也喜欢,可惜我不会弄啊~~_(¦3」∠)_。。。。

    Google Chrome 70 · Windows 8.1
    1. S̆̈

      @JiaYin 学啊,不会我可以代劳,只要你把阿里云 OSS 开通就行。

      Google Chrome 70 · Mac OS X 10.14
      1. 牧羊人

        @S̆̈不用 oss 可以不呢?我记得之前自己另外个主题搞过,现在忘了

        Google Chrome 114 · Windows 10
  6. typecho模板

    膜拜大佬,看到这个就想起来 QQ 空间可以读取图片信息感觉很牛掰

    Google Chrome 68 · Windows 7
    1. S̆̈

      @typecho 模板我也是站在巨人的肩膀上。 😳

      Google Chrome 71 · Mac OS X 10.14
  7. 枫叶

    多谢老虎最后的代码结构表,给了我一个思路。哈哈~多谢多谢。 😐 😐 😐

    Google Chrome 72 · Windows 10
    1. S̆̈

      @枫叶不客气,好代码共享。

      Google Chrome 73 · Mac OS X 10.14
  8. 天才书剑

    本地测试了一下 一切都是按照教程所说,JS 也加载了,但是已经不能弹出来 EXIF 层了。

    另外我的图片后缀是这样的,好像不太一样
    .jpg?x-oss-process=image%2Fformat,webp

    Google Chrome 97 · Windows 10
    1. S̆̈

      @天才书剑 js 里的相关代码要根据自己的模板相应调一下的。可能涉及的点也比较多,我看你网站挂了,也没法帮你查原因。

      Safari 15 · Mac OS X 10.15
  9. Justin

    不明觉厉…… 我找到了一个比较傻瓜的方法,对小白用户或许会更友好些:只需要安装一个名为 Meow Lightbox 的 WordPress 插件,就可以实现在灯箱界面显示照片 EXIF 信息;唯一的不足需要手动点击图片进入灯箱模式才能看到。

    示例:https://zblogs.top/fujifilm-x-s10-first-photo-experience-test-sample/

    Google Chrome 110 · Mac OS X 10.15
    1. S̆̈

      @Justin 插件当然可以,也比较直观,就是自定义不容易。

      Microsoft Edge 110 · Windows 10

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注