跳转到内容
菜单
自动
简体中文
v1 处于长期维护状态,将继续接收兼容性、安全和严重错误修复。查看 v2 当前版本

视觉示例集

这些图片来自仓库中的示例用例。先用它们确认你需要的功能,再按照相应指南使用当前代码。

瀑布照片底部附近放置了一层文字水印
带有颜色、样式和锚点定位的文字图层
彩色背景上放置了一层图片水印
缩放后定位于背景之上的图片图层
多个样式各自独立的文字水印
多个拥有独立样式的文字图层
背景上放置了一层旋转后的图片水印
旋转后的图片图层
山间湖泊上错行平铺了带描边的 CONFIDENTIAL 文字
带旋转、描边和错行排列的文字平铺
await Marker.markText({
backgroundImage: { src: photo },
watermarkTexts: [
{
text: '© Acme Studio',
position: { position: Position.bottomRight, X: 20, Y: 20 },
style: { color: '#FFFFFFB3', fontSizeRatio: 0.022 },
},
],
saveFormat: ImageFormat.jpg,
quality: 92,
});
await Marker.markImage({
backgroundImage: { src: photo },
watermarkImages: [
{
src: qrCode,
position: { position: Position.bottomLeft, X: 24, Y: 24 },
scale: 0.5,
trimTransparentPadding: true,
},
],
saveFormat: ImageFormat.png,
});

结合半透明填充、对比色描边、旋转和错行排列,可以让水印保持清晰,同时尽量保留照片内容。

await Marker.markText({
backgroundImage: { src: photo },
watermarkTexts: [
{
text: 'CONFIDENTIAL',
layout: {
type: 'tile',
gapX: '8%',
gapY: '7%',
offsetX: '-2%',
stagger: true,
},
style: {
color: '#FFFFFF88',
fontSizeRatio: 0.024,
rotate: -24,
strokeStyle: { color: '#0F172A88', width: 2 },
},
},
],
saveFormat: ImageFormat.jpg,
quality: 92,
});

同一份 layout 也可以用于 watermarkImages 中的图片,或传给 Marker.mark 的图片图层。

使用 Marker.mark 时,后面的图层会绘制在前面的图层之上。

await Marker.mark({
backgroundImage: { src: photo },
watermarks: [
{
type: 'image',
src: logo,
position: { position: Position.center },
alpha: 0.8,
},
{
type: 'text',
text: 'APPROVED',
position: { position: Position.center },
style: { color: '#FFFFFF', fontSize: 32, bold: true },
},
],
saveFormat: ImageFormat.png,
});

multiply 会保留 Logo 的深色细节并透出底图,screen 适合浅色文字;两者仍会与图层的 alpha 一起生效。

await Marker.mark({
backgroundImage: { src: photo },
watermarks: [
{
type: 'image',
src: logo,
blendMode: 'multiply',
position: { position: Position.center },
scale: 0.7,
alpha: 0.85,
},
{
type: 'text',
text: 'SCREEN LIGHT',
blendMode: 'screen',
position: { position: Position.bottomCenter, Y: 32 },
style: { color: '#FFE9B8', fontSize: 36, bold: true },
},
],
saveFormat: ImageFormat.png,
});

createRecipe 会保存有序图层和导出设置。文字模板可以读取每张图片的变量,以及内置的 indexfilenamevisibleWhen 只在条件匹配时保留对应图层。即使 Web 任务完成顺序不同,批量结果也始终与输入顺序一致。

const recipe = Marker.createRecipe({
schemaVersion: 1,
watermarks: [
{
type: 'text',
text: '© {{studio}} · {{filename}} · #{{index}}',
position: { position: Position.bottomRight, X: 24, Y: 24 },
style: { color: '#FFFFFF', fontSize: 28, bold: true },
},
{
type: 'image',
src: logo,
visibleWhen: { variable: 'showLogo', equals: true },
position: { position: Position.topRight, X: 24, Y: 24 },
scale: 0.25,
},
],
saveFormat: ImageFormat.jpg,
quality: 90,
});
const controller = new AbortController();
const results = await recipe.applyMany(
photos.map((src, index) => ({
backgroundImage: { src },
filename: `photo-${index + 1}`,
variables: { studio: 'Acme Studio', showLogo: index % 2 === 0 },
})),
{
concurrency: 2,
signal: controller.signal,
onProgress({ settled, total, failed }) {
console.log(`${settled}/${total}${failed} 个失败`);
},
}
);
const savedRecipe = JSON.stringify(recipe.toJSON());

缺少模板变量或变量值不合法时,只会拒绝对应输入。调用 controller.abort() 后不会再派发新任务;已经开始渲染的图片仍会正常结束。单张图片失败会记录为 rejected,不会中断其他任务。

浏览器批量处理本地文件时,可以显式返回二进制结果:

const webRecipe = Marker.createRecipe(recipeOptions, { resultType: 'blob' });
const blob = await webRecipe.apply({ backgroundImage: { src: file } });

SDK 不会自动创建 Object URL。只有在界面需要预览时,才由调用方创建并及时释放。

如需免安装体验 Web SDK,请打开在线体验。如需使用原生交互控件和查看架构状态面板,请运行 React Native 示例Expo 示例