跳转到内容

Image Toolkit

@easyx/image-toolkit 把图片处理全部放在浏览器:服务端零图片库、零原生依赖。内置引擎基于 @imagemagick/magick-wasm(ImageMagick 编译为 WebAssembly),运行在自建 Worker 中,不阻塞主线程。

入口内容依赖
@easyx/image-toolkit同构纯逻辑:魔数嗅探、格式判定、操作归一化、缩放换算零重量依赖(服务端可安全引用)
@easyx/image-toolkit/ui浏览器侧:引擎客户端、hooks、图片编辑内容区React + wasm 引擎(惰性加载)

纯客户端

处理全在浏览器,服务端零图片库,能力随浏览器能力走。

不阻塞主线程

wasm 实例化与处理都在 Worker 中,主线程只负责带进度的下载。

预览即所得

拖动对比原图与结果,同区域对齐;参数变化后防抖自动预览。

自研裁切台

裁切框可拖动、可拖边与角改尺寸,比例可选锁定或自由,支持键盘操作。

无损优先

PNG / WebP / TIFF 逐像素无损;界面按格式实时提示可用策略。

UI 自研

除 React 外不依赖任何 UI 库,表单控件基于原生元素。

Terminal window
pnpm add @easyx/image-toolkit

react / react-dom 为 peer 依赖,需宿主自行安装(仅 ./ui 入口需要)。样式编译后内联进 JS,宿主无需单独引入。

import { IMAGE_LIMITS, isProcessableFormat, sniffImage } from '@easyx/image-toolkit';
const meta = sniffImage(bytes); // 魔数嗅探:非图片返回 null

sniffImage 以魔数判定类型与尺寸,不信任客户端声明的 MIME,是阻止存储型 XSS 的第一道闸门。

包内只提供编辑内容区 <ImageEditor>,容器与保存动作都由宿主负责:

import { ImageEditor, type ImageEditorResult } from '@easyx/image-toolkit/ui';
import { useState } from 'react';
function CoverEditor() {
const [preview, setPreview] = useState<ImageEditorResult | null>(null);
return (
<>
<ImageEditor src={sourceUrl} onResultChange={setPreview} />
{/* 保存 / 下载由宿主自行实现 */}
<button
disabled={!preview?.result || preview.pending}
onClick={() => preview?.result && download(preview.result)}
>
保存
</button>
</>
);
}

内容区内部已含 ImageEngineGate:引擎加载进度、错误与重试都在内部处理。onResultChange 返回 { result, pending, noop, unsupported, error },result 为 null 表示当前设置未产生变更或尚不可保存。

样式走包内 SCSS + CSS 变量(--easyx-image-toolkit-*),覆盖变量即可定制外观。暗色按三级判定,命中即生效:

  1. 令牌作用域根上的 easyx-image-toolkit-dark class
  2. 宿主祖先的 data-theme 以 dark 结尾(如 dark / admin-dark)
  3. 宿主未声明主题时跟随 prefers-color-scheme

若宿主用类名等 CSS 覆盖不到的方式表达主题,用 <ImageEditor theme="dark" /> 显式指定。

  • 引擎与打包:能力矩阵、无损收益、wasm 资源与宿主打包器配置、已知取舍
  • API 参考:两个入口的导出清单、引擎 API 与类型