拆解iOS实况照片📷 - 附React web实现

前言

我认为苹果的实况照片(live photo)是一个伟大的发明,可以让你的回忆变得鲜活起来。前几天想在我的web项目中还原苹果系统里实况照片的效果,发现网络上相关的教程很少,于是我在调研实现之后,想和大家分享一下。

技术实现

文件格式

实况照片其实并不是一个什么神奇的魔法图片格式,它仅仅是一个"图片+视频的组合包 "。你在iPhone上拍摄一个实况照片,它会存储一个HEIC或者JPG图片、再存储一个3秒左右的MOV视频。iOS相册中查看图片,静态显示图片,长按播放视频,就是所谓的实况照片了。

iOS相关设置

  • 选择实况照片"图片部分"的格式:在iphone设置 -> 相机 -> 格式 -> 相机拍摄

    • 选择"高效"(默认):图片存储为HEIF格式,保证画质无损情况下可以压缩更多空间。但是浏览器默认不支持显示HEIF格式的图片(见PS部分)
    • 选择"兼容性最佳":图片存储为更传统的JPEG格式
  • 分享完整实况照片:iOS相册 -> 选择一个实况照片 -> 分享 -> 选项 -> 启用"所有照片数据"

    • 这样分享给你的电脑,你会发现电脑里是一个文件夹,里面包含了一张图片和一段MOV视频

web实现

想在web中实现实况照片效果,苹果官方提供了一个工具库(LivePhotosKit JS)

这个库提供了一个Player,你可以使用react的useRef,将对应div的Ref传入这个Player,让你的组件受player的控制。你可以通过player设置图片部分资源、视频部分资源、控制播放与暂停。

React代码

  • LivePhotoPlayer.tsx 实现了实况照片的展示,支持长按播放、松开回弹
tsx 复制代码
import React, { useEffect, useRef, useCallback } from 'react'
import * as LivePhotosKitNS from 'livephotoskit'

const LivePhotosKit: typeof LivePhotosKitNS =
  (LivePhotosKitNS as any).default ?? LivePhotosKitNS

type LivePhotoPlayerProps = {
  photoUrl: string
  videoUrl: string
  style?: React.CSSProperties
}

export const LivePhotoPlayer = ({
  photoUrl,
  videoUrl,
  style,
}: LivePhotoPlayerProps) => {
  const containerRef = useRef<HTMLDivElement>(null)
  const playerRef = useRef<any>(null)
  const timerRef = useRef<ReturnType<typeof setTimeout> | null>(null)

  useEffect(() => {       //初始化player
    if (!containerRef.current) return
    const player = LivePhotosKit.Player(containerRef.current)
    player.photoSrc = photoUrl
    player.videoSrc = videoUrl
    player.showsNativeControls = true //显示一个icon控件
    player.playbackStyle = LivePhotosKit.PlaybackStyle.FULL
    playerRef.current = player
  }, [])

  const handlePointerDown = useCallback(() => {   //长按播放
    timerRef.current = setTimeout(() => {
      playerRef.current?.play()
    }, 200)
  }, [])

  const handlePointerUp = useCallback(() => {      //松开暂停
    if (timerRef.current) clearTimeout(timerRef.current)
    playerRef.current?.stop()
  }, [])

  return (
    <div
      ref={containerRef}
      style={style}
      className="cursor-pointer"
      onPointerDown={handlePointerDown}
      onPointerUp={handlePointerUp}
      onPointerLeave={handlePointerUp}
    />
  )
}

PS

为什么浏览器不支持HEIF?

  1. 专利费: HEIF 核心的 HEVC 编码涉及昂贵的专利授权费用。

  2. 算力要求: 解码 HEIF 比解码 JPEG 更消耗 CPU/GPU 资源。

  3. 竞争对手: Google 等巨头正在推广 WebPAVIF ,后者同样高效且完全开源免费

    苹果之所以选择 HEIC,是因为自 A10 芯片起,iPhone 硬件层面就集成了 HEVC 编解码器,拍照和查看时几乎不耗电,且能省下一半的手机空间。

  • 如果想在web上支持HEIF格式,需要使用一些库来转换,如libheifheic2any ,本文不作介绍了。
相关推荐
前端老兵AI2 小时前
Electron 桌面应用开发入门:前端工程师的跨平台利器
前端·electron
胖子不胖2 小时前
浅析cubic-bezier
前端
reasonsummer2 小时前
【办公类-133-02】20260319_学区化展示PPT_02_python(图片合并文件夹、提取同名图片归类文件夹、图片编号、图片GIF)
前端·数据库·powerpoint
胡耀超2 小时前
Web Crawling 网络爬虫全景:技术体系、反爬对抗与全链路成本分析
前端·爬虫·python·网络爬虫·数据采集·逆向工程·反爬虫
阿明的小蝴蝶2 小时前
记一次Gradle环境的编译问题与解决
android·前端·gradle
Ruihong2 小时前
【VuReact】轻松实现 Vue 到 React 路由适配
前端·react.js
山_雨2 小时前
startViewTransition
前端
写代码的【黑咖啡】2 小时前
Python Web 开发新宠:FastAPI 全面指南
前端·python·fastapi
凉_橙2 小时前
gitlab CICD
前端