惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
Google DeepMind News
Google DeepMind News
S
SegmentFault 最新的问题
Project Zero
Project Zero
D
DataBreaches.Net
I
InfoQ
L
Lohrmann on Cybersecurity
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
酷 壳 – CoolShell
酷 壳 – CoolShell
Stack Overflow Blog
Stack Overflow Blog
The Register - Security
The Register - Security
Recorded Future
Recorded Future
Vercel News
Vercel News
博客园 - 司徒正美
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
I
Intezer
The Hacker News
The Hacker News
F
Fortinet All Blogs
Microsoft Azure Blog
Microsoft Azure Blog
P
Proofpoint News Feed
Help Net Security
Help Net Security
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Scott Helme
Scott Helme
T
Threatpost
爱范儿
爱范儿
N
Netflix TechBlog - Medium
D
Docker
云风的 BLOG
云风的 BLOG
C
Cisco Blogs
K
Kaspersky official blog
H
Help Net Security
S
Secure Thoughts
T
Threat Research - Cisco Blogs
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
S
Security @ Cisco Blogs
Cyberwarzone
Cyberwarzone
N
News and Events Feed by Topic
G
Google Developers Blog
Forbes - Security
Forbes - Security
博客园 - 三生石上(FineUI控件)
博客园 - 叶小钗
B
Blog
Google DeepMind News
Google DeepMind News
Recent Announcements
Recent Announcements
Simon Willison's Weblog
Simon Willison's Weblog
S
Securelist
P
Privacy International News Feed
Spread Privacy
Spread Privacy
The Last Watchdog
The Last Watchdog

Hsu Yeung 的博客

三圣花市 | Hsu Yeung 的博客 梦 | Hsu Yeung 的博客 周末午餐 | Hsu Yeung 的博客 张家界 | Hsu Yeung 的博客 话剧《寻她芳踪·张爱玲》 | Hsu Yeung 的博客 博客自动生成文章目录 | Hsu Yeung 的博客 灭螂行动! | Hsu Yeung 的博客 张靓颖成都演唱会 | Hsu Yeung 的博客 最近对博客做的一些微调总结 | Hsu Yeung 的博客 Windows 上安装 Lua | Hsu Yeung 的博客 网站支持展示 B 站 iframe 视频 SpringBoot 中使用 RedisTemplate 存取整数值的坑 | Hsu Yeung 的博客 SQL JOIN 中 ON 与 WHERE 的区别 值得记录的一些工作近况 | Hsu Yeung 的博客 周传雄成都演唱会 | Hsu Yeung 的博客 并行操作导致获取数据库连接超时 | Hsu Yeung 的博客 风信子 | Hsu Yeung 的博客 Linux 安装并配置 Nginx | Hsu Yeung 的博客 使用 logrotate 切割 nginx 日志 郁金香土培结果 | Hsu Yeung 的博客 MySQL LEFT JOIN 右表有多条数据但只取最新的一条 | Hsu Yeung 的博客 获取数据库锁等待超时问题 | Hsu Yeung 的博客 从零开始挑选相机 | Hsu Yeung 的博客 郁金香 | Hsu Yeung 的博客 我的第一束花 | Hsu Yeung 的博客 快乐的一周 | Hsu Yeung 的博客 重庆,来了 | Hsu Yeung 的博客 散步 | Hsu Yeung 的博客 Git 工作区、暂存区、版本库之间的关系 | Hsu Yeung 的博客 Collectors.toMap() 操作 value 为 null 的情况 AOP 记录请求参数时序列化异常问题 | Hsu Yeung 的博客 第一次参加演唱会 | Hsu Yeung 的博客 MySQL FIND_IN_SET 函数的使用 | Hsu Yeung 的博客 自动拆箱机制导致编译失败 | Hsu Yeung 的博客 最近 | Hsu Yeung 的博客 夜爬龙泉山 | Hsu Yeung 的博客 在 Windows 上安装多个版本 JDK 并切换使用的版本 安装 Windows Terminal 和 gsudo 记录 意外的奖励 | Hsu Yeung 的博客 记第一次修热水器 | Hsu Yeung 的博客 在 Windows 电脑上调试 iPhone Safari 浏览器的网页 给网站加上 RSS | Hsu Yeung 的博客 打雷了 | Hsu Yeung 的博客 豉汁蒸排骨 | Hsu Yeung 的博客 我的 2022 年 | Hsu Yeung 的博客 如何使用 Git 给代码打 tag | Hsu Yeung 的博客 记一次有趣的上班经历 | Hsu Yeung 的博客 我记得 | Hsu Yeung 的博客 Spring 新增或修改请求 header 参数 | Hsu Yeung 的博客 Spring 事务传播机制 | Hsu Yeung 的博客 在家自制“周黑鸭” | Hsu Yeung 的博客 晚餐 | Hsu Yeung 的博客 如何解决逻辑删除与数据库唯一约束冲突 | Hsu Yeung 的博客 [转]漫画赏析:Linux 内核到底长啥样 | Hsu Yeung 的博客 数据库逻辑设计之三大范式通俗理解 | Hsu Yeung 的博客 计算机中的大小端是指什么 | Hsu Yeung 的博客 MySQL 学习笔记 | Hsu Yeung 的博客 [转]《玉子市场》的人物魅力 | Hsu Yeung 的博客 Linux 安装 Redis | Hsu Yeung 的博客 Linux 安装 MySQL | Hsu Yeung 的博客 Linux 安装 JDK | Hsu Yeung 的博客 [转]Thymeleaf 表达式工具类 | Hsu Yeung 的博客 Shell 基础入门介绍 | Hsu Yeung 的博客 Linux 中的软链接和硬链接 | Hsu Yeung 的博客 MySQL 将某些字段的值排在最前或最后 | Hsu Yeung 的博客 数据结构与算法学习笔记 | Hsu Yeung 的博客 Visual Studio Code 如何编写运行 C 程序?
网站支持 Live Photo 图片展示 | Hsu Yeung 的博客
2026-03-17 · via Hsu Yeung 的博客

1. 什么是 Live Photos

iPhone6s 和 6s Plus 中增加了一个全新特性—— Live Photos,这新特性的作用是在照片拍摄前后录制一段 1.5 秒的动态视频,当用户在照片上深按一下,照片就会自动播放动态效果。用户还可以将 Live Photos 设置为锁屏墙纸,随时重现动态瞬间。(来自百度百科)

2. 使用方式

在评论时使用如下语法即可:

![图片说明](图片链接)(视频链接)

最终会被渲染成如下 HTML 代码:

<figure>
    <div class='livePhotoContainer'
        data-live-photo
        data-effect-type='live'
        data-playback-style='full'
        data-proactively-loads-video='true'
        data-photo-src='图片链接'
        data-video-src='视频链接'></div>
    <figcaption>图片说明</figcaption>
</figure>

3. 文章中的效果展示

电脑端请将鼠标光标放在图片左上角的 LIVE 字样上开始播放,光标移出停止。

手机端长按图片开始播放,松开停止。

桂花

4. 评论区的使用示例

以下示范步骤均在 Windows 电脑上操作,如果是 Mac 电脑有不同的地方需要大家自己搜索一下解决方案

步骤较多,请耐心观看

  1. 参照苹果官方文档中不同设备的导出方式将 Live Photo 照片以及对应的视频导出
  2. 检查导出后图片的编码格式,是否是 JPG 格式,不是的话需要自己搜索一下如何导出为 JPG 格式
  3. 以宽高比为 3:4 为例(下同),修改图片大小不超过 1008 x 1344
  4. 检查导出后视频的编码格式,如果是 HEVCH.265,需要使用例如 ffmpeg 之类的工具将其转为 H.264 编码格式
  5. 修改视频大小不超过 720 x 960
  6. 将你的图片以及视频上传至一个互联网可访问的地方并提供一个访问链接。且视频的提供方需要支持 206 状态码的 分段传输 功能(这个主要是为了兼容 Safari 浏览器)
  7. 在评论区中按照前文中提到的语法输入你的图片以及视频的访问链接即可

4.1. 如何压缩图片

用 windows 自带的图片查看器打开图片,然后鼠标右键选择调整图像大小

调整图像大小
调整图像大小

然后选择定义自定义尺寸

自定义尺寸
自定义尺寸

勾选保持纵横比并输入图像的尺寸:

调整尺寸
调整尺寸

4.2. 如何查看视频的编码方式以及转换编码

ffmpeg 工具为例,控制台输入以下命令查看视频的编码信息:

ffprobe 视频路径 -show_streams -select_streams v -print_format json

如果不是 H.264 使用如下命令将其转为 H.264 编码:

ffmpeg -i 转换前的视频 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k 转换后的视频

4.3. 如何压缩视频到指定大小

依旧以 ffmpeg 为例,将视频压缩到 720 x 960,使用如下命令:

ffmpeg -i 转换前的视频 -vf scale=720:960 转换后的视频 -hide_banner

4.4. 评论区中的展示效果

输入评论内容
输入评论内容
点击预览
点击预览
评论出来的效果
评论出来的效果

5. 注意事项

  • 图片说明不是必填项,即使不填的话那一对中括号也不能少
  • 图片链接是你的 Live Photo 导出后的后缀为 .JPG 的图片的访问链接,如果是 HEIC 格式的话需要自己处理一下导出为 JPG 格式才行
  • 视频链接是你的 Live Photo 导出后的后缀为 .MOV 的视频的访问链接
  • 重点 1:宽高比为 3:4 比例的图片大小请勿超过 1088 x 1344,其他宽高比暂时没测试过,但越小越好,因为官方的实现原理原因,太大了会导致 safari 浏览器体验效果极差
  • 重点 2:视频格式必须是 .MOV 格式(不区分大小写),且返回的数据的响应头必须为 video/quicktime,且宽高比为 3:4 的视频的大小请勿超过 720 x 960,理由同上
  • 重点 3:视频编码方式需要是 H.264,如果导出来的是 HEVC 编码的,很多浏览器都不兼容这个编码的视频播放,需要自己转换一下
  • 重点 4:存在一定概率连续播放几次后就没法播放了,这个没法解决,只有刷新页面解决
  • 重点 5:这个功能的兼容性不是很好,Google、Safari 这些是没有问题的(版本过低也不行),其他浏览器以及一些应用内置的浏览器可能无法查看,所以如果你无法查看请切换浏览器试试

6. 实现原理

扩展代码:

const caret = /(^|[^\[])\^/g
const _label = /(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/
const _href = /<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/

function edit(regex, opt) {
  regex = typeof regex === 'string' ? regex : regex.source
  opt = opt || ''
  const obj = {
    replace: (name, val) => {
      val = val.source || val
      val = val.replace(caret, '$1')
      regex = regex.replace(name, val)
      return obj
    },
    getRegex: () => {
      return new RegExp(regex, opt)
    }
  }
  return obj
}

const livePhoto = {
  name: 'livePhoto',
  level: 'block',
  start(src) {
    return src.match(/![^!\n]/)?.index
  },
  tokenizer(src, tokens) {
    let rule = /^!?\[(label)\]\(\s*(photoSrc)?\s*\)\(\s*(videoSrc)?\s*\)/
    rule = edit(rule)
            .replace('label', _label)
            .replace('photoSrc', _href)
            .replace('videoSrc', _href)
            .getRegex()
    const match = rule.exec(src)
    if (match) {
      const token = {
        type: 'livePhoto',
        raw: match[0],
        text: match[0].trim(),
        label: match[1],
        photoSrc: match[2],
        videoSrc: match[3],
        tokens: []
      }
      this.lexer.inline(token.text, token.tokens)
      return token
    }
  },
  renderer(token) {
    return `
        <figure>
          <div class='livePhotoContainer'
              data-live-photo
              data-effect-type='live'
              data-playback-style='full'
              data-proactively-loads-video='true'
              data-photo-src='${token.photoSrc}'
              data-video-src='${token.videoSrc}'></div>
          <figcaption>${token.label}</figcaption>
        </figure>
      `
  }
}

marked.use({extensions: [livePhoto]})