<Img> 元件
使用 <Img> 元件在 Remotion 中顯示圖片,確保圖片在渲染時完整載入,避免渲染閃爍問題。
什麼是 <Img>?
<Img> 標籤的用法與普通的 <img> HTML 標籤相同,但有一個關鍵優勢:若使用 <Img>,Remotion 會確保圖片在渲染該幀之前完整載入。 這樣可以避免圖片在渲染時尚未載入完成所造成的閃爍(flickering)問題。
API
src
將圖片放入 public/ 資料夾,並使用 staticFile() 來參照它。
使用本地靜態檔案:
import { AbsoluteFill, Img, staticFile } from "remotion";
export const MyComp: React.FC = () => {
return (
<AbsoluteFill>
<Img src={staticFile("hi.png")} />
</AbsoluteFill>
);
};使用遠端圖片:
import { AbsoluteFill, Img } from "remotion";
export const MyComp: React.FC = () => {
return (
<AbsoluteFill>
<Img src={"https://picsum.photos/200/300"} />
</AbsoluteFill>
);
};onError
為了以更健壯的方式使用 <Img> 標籤,你應該處理圖片無法載入時發生的錯誤:
import { AbsoluteFill, Img, staticFile } from "remotion";
export const MyComp: React.FC = () => {
return (
<AbsoluteFill>
<Img
src={staticFile("hi.png")}
onError={(event) => {
// 在此處理圖片載入錯誤
console.error("圖片載入失敗", event);
}}
/>
</AbsoluteFill>
);
};重要:若發生錯誤,必須卸載該元件或替換
src,否則渲染將會逾時。從 v3.3.82 起,圖片載入失敗後會先重試,重試失敗後才觸發onError。
maxRetries v3.3.82
若圖片載入失敗,從 v3.3.82 起會自動重試。預設值為 2。
重試使用指數退避策略:
- 第一次與第二次嘗試之間延遲 1000ms
- 然後是 2000ms
- 然後是 4000ms
- 以此類推
pauseWhenLoading? v4.0.111
若設為 true,在圖片載入時暫停 Player。請參閱:緩衝狀態。
delayRenderTimeoutInMilliseconds? v4.0.140
自訂此元件進行的 delayRender() 呼叫的逾時時間(毫秒)。
delayRenderRetries? v4.0.140
自訂此元件進行的 delayRender() 呼叫的重試次數。建議優先使用 maxRetries prop,而非此 prop。
其他 Props
<Img> 繼承了普通 <img> 標籤的所有 props,例如 style、className、alt 等。
錯誤行為
- 從 v4.0.0 起:若圖片載入失敗且沒有剩餘重試次數,則會呼叫
cancelRender拋出錯誤,除非你使用onError()處理錯誤。 - 從 v3.3.82 起:若圖片載入失敗,會最多重試兩次。
- 更早的版本:載入圖片失敗會導致 console 中出現錯誤訊息,並最終逾時。
GIF 動畫
不要使用 <Img> 標籤來顯示 GIF。請改用 @remotion/gif 套件:
import { Gif } from "@remotion/gif";
import { staticFile } from "remotion";
export const MyComp: React.FC = () => {
return (
<Gif
src={staticFile("animation.gif")}
width={400}
height={300}
fit="fill"
/>
);
};限制
Chrome 可顯示的最大解析度為 2^29 像素(5.39 億像素)。Remotion 繼承了此限制。
進階應用範例
帶動畫效果的圖片
搭配 interpolate 和 useCurrentFrame 製作圖片動畫:
import { AbsoluteFill, Img, staticFile, interpolate, useCurrentFrame } from "remotion";
export const AnimatedImage: React.FC = () => {
const frame = useCurrentFrame();
const opacity = interpolate(frame, [0, 30], [0, 1], {
extrapolateRight: "clamp",
});
const scale = interpolate(frame, [0, 30], [0.8, 1], {
extrapolateRight: "clamp",
});
return (
<AbsoluteFill
style={{ justifyContent: "center", alignItems: "center" }}
>
<Img
src={staticFile("logo.png")}
style={{
opacity,
transform: `scale(${scale})`,
width: 400,
height: 400,
objectFit: "contain",
}}
/>
</AbsoluteFill>
);
};多張圖片的輪播效果
import { AbsoluteFill, Img, staticFile, Sequence } from "remotion";
const images = ["slide1.png", "slide2.png", "slide3.png"];
const SLIDE_DURATION = 60; // 每張幻燈片顯示 2 秒(30fps)
export const Slideshow: React.FC = () => {
return (
<AbsoluteFill>
{images.map((image, index) => (
<Sequence
key={image}
from={index * SLIDE_DURATION}
durationInFrames={SLIDE_DURATION}
>
<AbsoluteFill>
<Img
src={staticFile(image)}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
onError={() => console.error(`Failed to load ${image}`)}
/>
</AbsoluteFill>
</Sequence>
))}
</AbsoluteFill>
);
};帶有錯誤處理的容錯圖片元件
import { AbsoluteFill, Img, staticFile } from "remotion";
import { useState } from "react";
interface ResilientImageProps {
src: string;
fallbackSrc?: string;
}
export const ResilientImage: React.FC<ResilientImageProps> = ({
src,
fallbackSrc,
}) => {
const [currentSrc, setCurrentSrc] = useState(src);
const [failed, setFailed] = useState(false);
if (failed) {
return (
<div
style={{
width: "100%",
height: "100%",
backgroundColor: "#333",
display: "flex",
alignItems: "center",
justifyContent: "center",
color: "white",
}}
>
圖片載入失敗
</div>
);
}
return (
<Img
src={currentSrc}
onError={() => {
if (fallbackSrc && currentSrc !== fallbackSrc) {
setCurrentSrc(fallbackSrc);
} else {
setFailed(true);
}
}}
style={{ width: "100%", height: "100%", objectFit: "cover" }}
/>
);
};相容性
| 環境 | 支援 |
|---|---|
| Chrome | 是 |
| Firefox | 是 |
| Safari | 是 |
| 客戶端渲染 | 是 |
| 伺服器端渲染 | 是 |
| Player | 是 |
| Studio | 是 |