Ω
OmniCrop v1.0.0
🎮 在线演练场

OmniCrop 技术文档

OmniCrop 是基于 react-easy-crop 优秀设计思想深度重构的跨端图片裁剪套件,专为微信小程序原生、Taro、uni-app、React Native 和 Web 多端生态打造。彻底打破了传统小程序组件卡顿、掉帧与内存泄漏的痛点。

⚡ 60 FPS 零跨桥

WXS / SJS 视图层脚本直接驱动变换,杜绝频繁 setData 通信延迟。

📐 自由几何变换

支持 1:1、4:3、16:9 与自由拉伸,支持双指缩放、旋转与水平/垂直镜像。

🛡️ Canvas 2D 导出

内置 EXIF 自动纠偏与动态高倍 DPR 抗锯齿,智能降采样防止 iOS 闪退。

📦 包矩阵与安装 (非 @ 作用域平铺命名)

根据用户要求,所有包名去除了 @ 命名空间,可直接通过 npm / pnpm / yarn 安装:

平台 / 场景 Subpath 导出导入路径 核心底层机制
微信原生小程序 omni-crop/weixin WXML + WXSS + WXS 视图层脚本
Taro 3 (React/Vue) omni-crop/taro 跨端同构组件 + Canvas 驱动
uni-app (Vue 3) omni-crop/uni-app Vue 3 SFC + useOmniCrop 状态钩子
React Native omni-crop/react-native Reanimated 3 Worklet + GestureHandler
Web React omni-crop/react (或 omni-crop) HTML5 Canvas + Pointer Events
核心数学几何计算 omni-crop/core 纯 TS 无依赖 Headless 状态机引擎
跨端 Canvas 导出器 omni-crop/exporter EXIF 纠偏流水线 + Canvas 2D Driver
# 统一安装单个 npm 工具包即可 (零多包分发繁琐)
npm install omni-crop
# 或
pnpm add omni-crop

🎮 在线交互演练场 (Live Studio)

在当前页面直接操控 OmniCrop 核心状态机与真实 Canvas 2D 导出引擎。

可直接交互体验
● 60 FPS 实时运算 缩放: 1.00x · 旋转: 0°
Cropper
测试图片
裁剪比例
几何操作
导出预览 - × - px
导出结果

⚡ 60FPS 零跨桥手势引擎工作原理

微信小程序采用双线程模型(逻辑层 JS 与 视图层 WebView 物理隔离)。如果像传统组件那样在 touchmove 中触发 setData,每次事件都需要经历 JSON 序列化、跨进程通信以及反序列化,导致无法跟手。

💡 WXS 零通信架构:

1. 在 index.wxs 视图脚本中直接绑定 onTouchStart / onTouchMove / onTouchEnd。
2. 手势移动期间,实时根据双指距离计算缩放比例,并通过 ownerInstance.selectComponent().setStyle({ transform: ... }) 直接操作渲染节点。
3. 只有手指完全脱离屏幕时,才调用 ownerInstance.callMethod('onWxsGestureEnd') 向逻辑线程派发最终坐标。

📚 组件 Props 属性参考

属性名 类型 默认值 说明
image string 必填 图片 URL 地址、本地临时路径或 Base64
aspect number | 'free' 4 / 3 裁剪比例(如 1、4/3、16/9),传入 'free' 为自由比例
cropShape 'rect' | 'round' 'rect' 裁剪框形状('rect' 矩形,'round' 圆形头像遮罩)
showGrid boolean true 是否展示九宫格辅助网格线
restrictPosition boolean true 防露白限制:开启后图片边缘不可移入裁剪框内部

🛠️ 组件 Ref 实例方法 (Imperative API)

方法名 参数 返回值 说明
rotate(stepAngle) number = 90 void 顺时针旋转指定角度
zoomIn(step) number = 0.25 void 步进放大
zoomOut(step) number = 0.25 void 步进缩小
setZoom(zoom) number void 精准设置缩放倍率(与滑块拖动无缝绑定)
flipHorizontal() - void 水平翻转切换
flipVertical() - void 垂直翻转切换
reset() - void 重置所有变换至初始值
exportCroppedImage(opts) ExportOptions Promise<CropResult> 通过 Canvas 2D 离屏导出裁切图片路径

📱 微信原生小程序完整集成示例

// page.json
{
  "usingComponents": {
    "omni-crop": "omni-crop/weixin"
  }
}

<!-- page.wxml -->
<omni-crop
  id="cropper"
  image="{{imageUrl}}"
  aspect="{{1}}"
  cropShape="round"
  bindcropcomplete="onCropComplete"
/>

<view class="zoom-slider-bar">
  <text bindtap="onZoomOut">–</text>
  <slider min="1" max="4" step="0.01" value="{{zoom}}" bindchanging="onZoomSlider" />
  <text bindtap="onZoomIn">+</text>
  <text bindtap="onReset">⟳ 重置</text>
</view>

<button bindtap="doExport">导出头像</button>

// page.js
Page({
  data: { imageUrl: 'https://cdn.example.com/demo.jpg', zoom: 1 },
  onZoomSlider(e) {
    this.selectComponent('#cropper').setZoom(e.detail.value);
  },
  async doExport() {
    const res = await this.selectComponent('#cropper').exportCroppedImage({
      format: 'png',
      quality: 0.95,
      dpr: 2
    });
    console.log('裁剪文件本地路径:', res.uri);
  }
});

💡 常见问题与解决方案 (FAQ)

Q: 为什么裁剪远程 CDN 图片时偶尔黑屏或提示跨域?

解答:微信小程序 Canvas 2D 规范要求外链图片必须具备有效下载凭证。omni-crop/exporter 内置了 wx.downloadFile 自动拦截预加载,确保图片先落盘到本地临时文件再写入 Canvas,同时请在微信开放平台将您的 CDN 域名添加到合法 downloadFile 白名单中。

Q: 如何防止低端 iPhone 导出 4K/2000万像素照片时闪退?

解答:omni-crop/exporter 默认限制了 maxResolution: 4096。若用户原图高达 8000 像素,导出器会自动执行保比例下采样(Downsampling),彻底避免 iOS WebView 显存崩溃(OOM)。

OmniCrop Project · Released under the MIT License.
面向小程序与跨端现代技术栈构建