news 2026/9/25 3:05:38

react-native-skia 图像偏移过滤器 Offset 完全指南:属性、示例与底层实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
react-native-skia 图像偏移过滤器 Offset 完全指南:属性、示例与底层实现
  • 图形学
  • 移动开发
  • 跨平台
  • UI组件

【免费下载链接】react-native-skia

High-performance React Native Graphics using Skia

项目地址:https://gitcode.com/gh_mirrors/re/react-native-skia
点击查看免费下载

本文围绕 react-native-skia 提供的Offset图像过滤器展开,讲解如何沿 X/Y 轴平移被过滤的图像,涵盖组件属性、声明式用法、与Skia.ImageFilter.MakeOffset底层 API 的对应关系,以及如何将其与Blur等过滤器组合使用。读完本文,你将掌握在 apps/docs/docs/image-filters/offset.md 场景下实现像素级平移、组合滤镜与 Web 端兼容性处理的具体方案。

Offset 是什么

Offset是 react-native-skia 提供的图像过滤器(Image Filter)组件。图像过滤器是一类作用于图像所有像素颜色位上的效果(见 图像过滤器总览),而Offset的作用非常直观:将输入图像沿 X 轴与 Y 轴平移指定的像素距离,其余像素保持原样。

该过滤器与 SVG 的feOffset滤镜(即 Web 标准中的<feOffset>元素)行为一致,因此熟悉 SVG 滤镜的开发者可以无缝迁移到 react-native-skia。

组件属性

Offset组件接受以下属性:

名称类型说明
xnumber沿 X 轴的偏移量(单位:像素)。
ynumber沿 Y 轴的偏移量(单位:像素)。
children?ImageFilter可选的图像过滤器,会先被应用,再执行本偏移。

从源码看,Offset的组件实现位于 packages/skia/src/renderer/components/imageFilters/Offset.tsx,其类型定义OffsetImageFilterProps位于 packages/skia/src/dom/types/ImageFilters.ts:

export interface OffsetImageFilterProps extends ChildrenProps { x: number; y: number; }

组件默认值为x = 0、y = 0,即不传属性时过滤器不产生任何平移效果。x、y均可为负值(向相反方向平移)。

基础示例:平移一张图片

下面是最简单的用法——在Canvas中绘制一张图片,并应用Offset将其向右下角各平移 64 像素:

import { Canvas, Image, Offset, useImage, Fill } from "@shopify/react-native-skia"; const Filter = () => { const image = useImage(require("./assets/oslo.jpg")); if (!image) { return null; } return ( <Canvas style={{ width: 256, height: 256 }}> <Fill color="lightblue" /> <Image image={image} x={0} y={0} width={256} height={256} fit="cover" > <Offset x={64} y={64} /> </Image> </Canvas> ); };

要点说明:

  • useImage返回的图片加载完成前为null,因此需要先做空值判断(如上例中的if (!image)提前返回);
  • Offset作为<Image>的子组件(children)使用,形成"先渲染图片、再对结果施加偏移"的滤镜管线;
  • 背景先填充了lightblue,这样偏移后露出的画布区域可见,能直观看到平移产生的"空边"效果;
  • fit="cover"会让图片按覆盖方式填充到 256×256 的区域。

运行效果如下图所示(完整示例源自 offset.md 示例代码):

组合滤镜:Offset 作为子过滤器管道的一环

Offset的children属性允许传入另一个图像过滤器,使其先于偏移执行。这在构建复合效果时非常实用,例如"先模糊、再平移":

import { Canvas, Image, Offset, Blur, useImage } from "@shopify/react-native-skia"; const Composed = () => { const image = useImage(require("./assets/oslo.jpg")); if (!image) { return null; } return ( <Canvas style={{ width: 256, height: 256 }}> <Image image={image} x={0} y={0} width={256} height={256} fit="cover"> <Offset x={40} y={40}> <Blur blur={6} mode="clamp" /> </Offset> </Image> </Canvas> ); };

这里<Blur>作为Offset的子节点先执行模糊,模糊结果再被整体平移 40 像素。这种"子过滤器先应用、父过滤器后应用"的嵌套语义,与 图像过滤器总览 中介绍的组合方式(如ColorMatrix嵌套在Blur内)一脉相承,也呼应了 SVG 滤镜 DAG(有向无环图)中的输入-输出串联模型。

底层实现:从组件到 Skia.ImageFilter.MakeOffset

声明式组件如何被翻译为底层 API

Offset组件本身是一个轻量封装(Offset.tsx),它把x、y转发给 DOM 节点skOffsetImageFilter。在渲染记录(Recorder)层,declareOffsetImageFilter负责把属性翻译成 Skia 工厂调用(packages/skia/src/sksg/Recorder/commands/ImageFilters.ts):

const declareOffsetImageFilter = ( ctx: DrawingContext, props: OffsetImageFilterProps ) => { "worklet"; const { x, y } = props; const imgf = ctx.Skia.ImageFilter.MakeOffset(x, y, null); ctx.imageFilters.push(imgf); };

注意这里传给MakeOffset的第三个参数是null,表示使用"动态源图像"(即当前正在绘制的输入内容)作为过滤输入。这解释了声明式用法中为何Offset无需显式指定输入——它天然作用于其宿主元素(如<Image>)的渲染结果。

命令式 API:Skia.ImageFilter.MakeOffset

如果你更偏好命令式写法,可以直接使用Skia.ImageFilter.MakeOffset工厂方法(类型签名见 packages/skia/src/skia/types/ImageFilter/ImageFilterFactory.ts):

MakeOffset( dx: number, dy: number, input?: SkImageFilter | null, // 为 null 时使用动态源图像 cropRect?: SkRect | null // 可选:裁剪输入与输出 ): SkImageFilter;

参数说明:

  • dx/dy:沿 X / Y 轴的偏移量;
  • input:输入过滤器;为null时使用动态源图像(例如保存的图层或当前绘制内容);
  • cropRect:可选的裁剪矩形,同时裁剪输入与输出。

该命令式过滤器同样可以作为<ImageFilter filter={...} />的filter属性传入声明式组件。仓库的 e2e 测试(packages/skia/src/renderer/tests/e2e/ImageFilter.spec.tsx)展示了这一用法:

const offsetFilter = Skia.ImageFilter.MakeOffset(20, 20, null); const img = await surface.draw( <Group> <ImageFilter filter={offsetFilter} /> <Circle cx={50} cy={50} r={30} color="blue" /> </Group> ); checkImage(img, docPath("image-filter/offset-filter.png"));

同一个测试文件还验证了"偏移 + 模糊"的复合过滤器写法(Skia.ImageFilter.MakeOffset(10, 10, blurFilter)),与声明式children嵌套在语义上完全等价。

组合与合成顺序

在渲染记录器中,多个过滤器通过Skia.ImageFilter.MakeCompose(outer, inner)依次合成(composeImageFilters):后弹出的过滤器作为外层的outer,先弹出的作为内层的inner。因此嵌套顺序决定了效果的执行顺序——越内层的子过滤器越先作用于源图像,这一点在组合Blur与Offset时需特别留意。

平台差异:React Native Web 上的注意点

react-native-skia 同时支持原生(Android/iOS)与 Web 平台。在 Web 端,MakeOffset由 CanvasKit 实现(packages/skia/src/skia/web/JsiSkImageFilterFactory.ts):

MakeOffset(dx, dy, input?, cropRect?) { const inputFilter = input === null || input === undefined ? null : JsiSkImageFilter.fromValue(input); if (cropRect) { console.warn("cropRect is not supported on React Native Web for MakeOffset"); } const filter = this.CanvasKit.ImageFilter.MakeOffset(dx, dy, inputFilter); return new JsiSkImageFilter(this.CanvasKit, filter); }

两点平台差异值得记住:

  1. cropRect在 Web 端不被支持:传入时会打印一条警告"cropRect is not supported on React Native Web for MakeOffset"并被忽略,因此在跨平台项目中应避免依赖cropRect参数;
  2. input为null或undefined时,Web 端同样会回退为使用动态源图像,行为与原生端一致。

典型应用场景

Offset虽然简单,却是很多复杂效果的基础构件,常见用途包括:

  • 投影/描边效果:DropShadow过滤器内部正是通过"偏移 + 模糊 + 混合"实现的。事实上,MakeInnerShadow的源码(ImageFilters.ts)就调用了MakeOffset(dx, dy, f1)来定位阴影:先生成轮廓,再偏移出阴影位置,最后模糊。
  • 像素级平移:将贴图、文字或图形整体移动若干像素,制造"错位"或"重影"效果;
  • 复合滤镜的中间步骤:作为过滤器 DAG 中的一环,例如先偏移再混合(MakeCompose/MakeBlend),实现更精细的合成控制;
  • 动画偏移:由于Offset的属性可以被 react-native-skia 的动画系统驱动(x、y支持传入动画值),可以轻松实现图片缓慢滑动、视差滚动等动效。

小结

  • Offset是 react-native-skia 中最基础的图像过滤器之一,等价于 SVG 的feOffset,作用是把输入图像沿 X/Y 轴平移;
  • 属性极简:x、y两个必选数字,children可嵌套其他过滤器实现"先过滤、再偏移";
  • 底层由Skia.ImageFilter.MakeOffset(dx, dy, input, cropRect)实现,声明式组件与命令式 API 完全互通;
  • Web 端基于 CanvasKit 实现,但cropRect不被支持,跨平台开发时需规避。

如需查看更多过滤器,可继续阅读 图像过滤器总览、模糊滤镜 Blur、位移映射 DisplacementMap 与 阴影 Shadows。

  • 图形学
  • 移动开发
  • 跨平台
  • UI组件

【免费下载链接】react-native-skia

High-performance React Native Graphics using Skia

项目地址:https://gitcode.com/gh_mirrors/re/react-native-skia
点击查看免费下载

相关推荐

上一篇:SQLModel 删除数据教程:用 session.delete() 与 commit 完成数据库 DELETE 操作
下一篇:HoppscotchAPI测试认证:提升职业竞争力的途径

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/25 3:04:23

BullMQ 去除子任务失败依赖:removeDependencyOnFailure 选项深入解析

后端消息队列任务调度 【免费下载链接】bullmq BullMQ - Message Queue and Batch processing for NodeJS, Python, .NET, Elixir, Rust and PHP based on Redis or PostgreSQL 项目地址&#xff1a; https://gitcode.com/gh_mirrors/bu/bullmq 点击查看 免费下载 导读 在基于…

作者头像 李华
网站建设 2026/9/25 3:04:18

dsh-market 测试体系拆解:四层测试如何守护真实 pnpm 安装链

dsh-market 测试体系拆解&#xff1a;四层测试如何守护真实 pnpm 安装链 【免费下载链接】dsh-market The plugin market inside DeepSeek Harness — browse, search, one-click install DSH 可视化插件市场 项目地址: https://gitcode.com/gh_mirrors/ds/dsh-market …

作者头像 李华
网站建设 2026/9/25 3:02:37

.NET + Semantic Kernel 搭建 MCP 能力层实战解析

MCP&#xff08;Model Context Protocol&#xff09;是2025年AI工程圈最绕不开的热词。如果你最近在做Agent相关项目&#xff0c;大概率已经发现&#xff0c;MCP把“工具怎么暴露给AI”这件事彻底标准化了。而.NET这一端&#xff0c;最有组合价值的就是Semantic Kernel&#xf…

作者头像 李华
网站建设 2026/9/25 2:58:23

Python线程并发编程实战与性能优化

1. 为什么需要线程并发在Python中处理I/O密集型任务时&#xff0c;传统的同步编程方式会遇到明显的性能瓶颈。比如一个网络爬虫程序&#xff0c;如果采用顺序执行的方式下载100个网页&#xff0c;大部分时间都会浪费在等待网络响应上。这时候线程并发就能显著提升效率。我去年优…

作者头像 李华