Compare commits

..

No commits in common. "main" and "v1.5.0" have entirely different histories.
main ... v1.5.0

4 changed files with 24 additions and 42 deletions

View File

@ -1,10 +1,5 @@
# CHANGELOG - apigo.cc/go/vision # CHANGELOG - apigo.cc/go/vision
## v1.5.1 (2026-06-08)
- **JS 对齐 & 智能文档**:
- 将所有注册到 `jsmod` 的方法名统一为 PascalCase。
- **可选参数优化**: 将 `New``bg``Save``quality` 等改用指针类型包装。配合最新的 `go/js` 引擎,生成的 `.d.ts` 定义将正确标识为可选参数 `?`,大幅提升 AI 开发效率。
## v1.0.9 (2026-05-17) ## v1.0.9 (2026-05-17)
- **新特性**: 内置全能命令行工具 `vision` (`cmd/vision`)。 - **新特性**: 内置全能命令行工具 `vision` (`cmd/vision`)。
- **功能增强**: `vision.Load` 增加多级环境探测sips, heif-convert, magick, ffmpeg完美支持 HEIC 及其网格重构解码。 - **功能增强**: `vision.Load` 增加多级环境探测sips, heif-convert, magick, ffmpeg完美支持 HEIC 及其网格重构解码。

4
go.mod
View File

@ -21,8 +21,8 @@ require (
apigo.cc/go/safe v1.5.0 // indirect apigo.cc/go/safe v1.5.0 // indirect
github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 // indirect
github.com/kr/text v0.2.0 // indirect github.com/kr/text v0.2.0 // indirect
golang.org/x/crypto v0.52.0 // indirect golang.org/x/crypto v0.51.0 // indirect
golang.org/x/sys v0.45.0 // indirect golang.org/x/sys v0.44.0 // indirect
golang.org/x/text v0.37.0 // indirect golang.org/x/text v0.37.0 // indirect
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect

6
go.sum
View File

@ -31,11 +31,13 @@ github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0t
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e h1:MRM5ITcdelLK2j1vwZ3Je0FKVCfqOLp5zO6trqMLYs0=
github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M=
golang.org/x/crypto v0.52.0 h1:RMs7fP2rXdep0CftQlK8Uf+kibLm7qkCcradZWYz988= golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI=
golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8=
golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8= golang.org/x/image v0.40.0 h1:Tw4GyDXMo+daZN1znreBRC3VayR1aLFUyUEOLUdW1a8=
golang.org/x/image v0.40.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA= golang.org/x/image v0.40.0/go.mod h1:uIc348UZMSvS5Z65CVZ7iDPaNobNFEPeJ4kbqTOszmA=
golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= golang.org/x/sys v0.44.0 h1:ildZl3J4uzeKP07r2F++Op7E9B29JRUy+a27EibtBTQ=
golang.org/x/sys v0.44.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc= golang.org/x/text v0.37.0 h1:Cqjiwd9eSg8e0QAkyCaQTNHFIIzWtidPahFWR83rTrc=
golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38= golang.org/x/text v0.37.0/go.mod h1:a5sjxXGs9hsn/AJVwuElvCAo9v8QYLzvavO5z2PiM38=

View File

@ -10,7 +10,7 @@ import (
func init() { func init() {
jsmod.Register("vision", map[string]any{ jsmod.Register("vision", map[string]any{
// 基础操作 // 基础操作
"Load": func(ctx context.Context, path string) (*jsCanvas, error) { "load": func(ctx context.Context, path string) (*jsCanvas, error) {
p, err := file.VerifyPathForSafeMode(ctx, path) p, err := file.VerifyPathForSafeMode(ctx, path)
if err != nil { if err != nil {
return nil, err return nil, err
@ -21,44 +21,38 @@ func init() {
} }
return &jsCanvas{ctx: ctx, c: c}, nil return &jsCanvas{ctx: ctx, c: c}, nil
}, },
"New": func(ctx context.Context, w, h int, bg *string) *jsCanvas { "new": func(ctx context.Context, w, h int, bg ...string) *jsCanvas {
if bg != nil { return &jsCanvas{ctx: ctx, c: New(w, h, bg...)}
return &jsCanvas{ctx: ctx, c: New(w, h, *bg)}
}
return &jsCanvas{ctx: ctx, c: New(w, h)}
}, },
"Save": func(ctx context.Context, j *jsCanvas, path string, quality *int) error { "save": func(ctx context.Context, j *jsCanvas, path string, quality ...int) error {
p, err := file.VerifyPathForSafeMode(ctx, path) p, err := file.VerifyPathForSafeMode(ctx, path)
if err != nil { if err != nil {
return err return err
} }
if quality != nil { return Save(j.c, p, quality...)
return Save(j.c, p, *quality)
}
return Save(j.c, p)
}, },
// 生成类 // 生成类
"GenerateQRCode": func(ctx context.Context, content string, size int) (*jsCanvas, error) { "generateQRCode": func(ctx context.Context, content string, size int) (*jsCanvas, error) {
c, err := GenerateQRCode(content, size) c, err := GenerateQRCode(content, size)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &jsCanvas{ctx: ctx, c: c}, nil return &jsCanvas{ctx: ctx, c: c}, nil
}, },
"GenerateBarcode": func(ctx context.Context, content string, w, h int) (*jsCanvas, error) { "generateBarcode": func(ctx context.Context, content string, w, h int) (*jsCanvas, error) {
c, err := GenerateBarcode(content, w, h) c, err := GenerateBarcode(content, w, h)
if err != nil { if err != nil {
return nil, err return nil, err
} }
return &jsCanvas{ctx: ctx, c: c}, nil return &jsCanvas{ctx: ctx, c: c}, nil
}, },
"GenerateCaptcha": func(ctx context.Context, opt *CaptchaOption) *jsCanvas { "generateCaptcha": func(ctx context.Context, opt *CaptchaOption) *jsCanvas {
return &jsCanvas{ctx: ctx, c: GenerateCaptcha(opt)} return &jsCanvas{ctx: ctx, c: GenerateCaptcha(opt)}
}, },
// 预览类 (直接写文件) // 预览类 (直接写文件)
"GenerateImagePreview": func(ctx context.Context, src, out string, w, h int) error { "generateImagePreview": func(ctx context.Context, src, out string, w, h int) error {
pSrc, err := file.VerifyPathForSafeMode(ctx, src) pSrc, err := file.VerifyPathForSafeMode(ctx, src)
if err != nil { if err != nil {
return err return err
@ -69,7 +63,7 @@ func init() {
} }
return GenerateImagePreview(pSrc, pOut, w, h) return GenerateImagePreview(pSrc, pOut, w, h)
}, },
"GenerateVideoPreview": func(ctx context.Context, src, out string, w, h int, interval *int) error { "generateVideoPreview": func(ctx context.Context, src, out string, w, h int, interval ...int) error {
pSrc, err := file.VerifyPathForSafeMode(ctx, src) pSrc, err := file.VerifyPathForSafeMode(ctx, src)
if err != nil { if err != nil {
return err return err
@ -78,14 +72,11 @@ func init() {
if err != nil { if err != nil {
return err return err
} }
if interval != nil { return GenerateVideoPreview(pSrc, pOut, w, h, interval...)
return GenerateVideoPreview(pSrc, pOut, w, h, *interval)
}
return GenerateVideoPreview(pSrc, pOut, w, h)
}, },
// 转换类 // 转换类
"Convert": func(ctx context.Context, src, dst string, quality *int) error { "convert": func(ctx context.Context, src, dst string, quality ...int) error {
pSrc, err := file.VerifyPathForSafeMode(ctx, src) pSrc, err := file.VerifyPathForSafeMode(ctx, src)
if err != nil { if err != nil {
return err return err
@ -94,12 +85,9 @@ func init() {
if err != nil { if err != nil {
return err return err
} }
if quality != nil { return Convert(pSrc, pDst, quality...)
return Convert(pSrc, pDst, *quality)
}
return Convert(pSrc, pDst)
}, },
"Optimize": func(ctx context.Context, path string, maxWidth int, quality int) error { "optimize": func(ctx context.Context, path string, maxWidth int, quality int) error {
p, err := file.VerifyPathForSafeMode(ctx, path) p, err := file.VerifyPathForSafeMode(ctx, path)
if err != nil { if err != nil {
return err return err
@ -108,8 +96,8 @@ func init() {
}, },
// 辅助工具 // 辅助工具
"LoadFonts": LoadFonts, "loadFonts": LoadFonts,
"Recognize": func(ctx context.Context, path string) (string, error) { "recognize": func(ctx context.Context, path string) (string, error) {
p, err := file.VerifyPathForSafeMode(ctx, path) p, err := file.VerifyPathForSafeMode(ctx, path)
if err != nil { if err != nil {
return "", err return "", err
@ -128,15 +116,12 @@ type jsCanvas struct {
func (j *jsCanvas) Width() int { return j.c.Width() } func (j *jsCanvas) Width() int { return j.c.Width() }
func (j *jsCanvas) Height() int { return j.c.Height() } func (j *jsCanvas) Height() int { return j.c.Height() }
func (j *jsCanvas) Save(path string, quality *int) error { func (j *jsCanvas) Save(path string, quality ...int) error {
p, err := file.VerifyPathForSafeMode(j.ctx, path) p, err := file.VerifyPathForSafeMode(j.ctx, path)
if err != nil { if err != nil {
return err return err
} }
if quality != nil { return Save(j.c, p, quality...)
return Save(j.c, p, *quality)
}
return Save(j.c, p)
} }
// 效果与绘图 (返回自身以支持链式) // 效果与绘图 (返回自身以支持链式)