Browse Source

fix: support windows certificate fonts

main
ywlmac 2 months ago
parent
commit
6220e863e3
  1. 3
      SDK_USAGE.md
  2. 44
      pkg/zxchainsdk/certificate.go
  3. 4
      pkg/zxchainsdk/certificate_flow.go

3
SDK_USAGE.md

@ -26,6 +26,7 @@ if err != nil {
- `COS_PUBLIC_BASE_URL`:证书公开访问基础地址。
- `COS_SECRET_ID`:COS 访问密钥 ID。
- `COS_SECRET_KEY`:COS 访问密钥。
- `ZXCHAIN_CERTIFICATE_FONT_PATH`:可选。证书绘制使用的中文字体路径;Windows 可用 `C:/Windows/Fonts/msyh.ttc`
## 存证和生成证书并一起返回
@ -58,6 +59,7 @@ result, err := client.CreateSimpleHashAttestationCertificate(context.Background(
CompletedAt: "2026.5.11 15:20:01",
WorkPreviewURL: "https://your-cdn/path/work-preview.jpg",
EvidenceHash: "作品hash", //可选参数,可以不传
FontPath: "C:/Windows/Fonts/msyh.ttc", // 可选;Windows 推荐微软雅黑,或配置 ZXCHAIN_CERTIFICATE_FONT_PATH
CertificateStorage: &zxchainsdk.COSCertificateStorage{ //可选参数,可以不传
BucketURL: os.Getenv("COS_BUCKET_URL"),
@ -88,6 +90,7 @@ fmt.Println("zxChainCertURL:", result.ZXChainCertURL)
- `CompletedAt`:作品完成时间。
- `WorkPreviewURL`:作品图片 URL。
- `EvidenceHash`:可选。作品文件哈希;不传时 SDK 会从 `WorkPreviewURL` 下载内容并自行计算hash值。
- `FontPath`:可选。中文字体路径;不传时 SDK 会自动查找 Windows/macOS/Linux 常见中文字体,也可以用 `ZXCHAIN_CERTIFICATE_FONT_PATH` 环境变量指定。Windows 常见可用路径:`C:/Windows/Fonts/msyh.ttc`、`C:/Windows/Fonts/simhei.ttf`、`C:/Windows/Fonts/simsun.ttc`。
- `CertificateStorage`:可选。COS 上传配置。
返回字段:

44
pkg/zxchainsdk/certificate.go

@ -393,16 +393,39 @@ func containImage(src image.Image, boxWidth, boxHeight int) image.Image {
func resolveCertificateFont(explicitPath string) (string, error) {
if explicitPath != "" {
if _, err := os.Stat(explicitPath); err != nil {
return validateCertificateFont(explicitPath)
}
if envPath := os.Getenv("ZXCHAIN_CERTIFICATE_FONT_PATH"); envPath != "" {
return validateCertificateFont(envPath)
}
candidates := certificateFontCandidates()
for _, candidate := range candidates {
if fontPath, err := validateCertificateFont(candidate); err == nil {
return fontPath, nil
}
}
return "", errors.New("missing certificate font, set HashCertificateRequest.FontPath or ZXCHAIN_CERTIFICATE_FONT_PATH to a Chinese TTF/TTC/OTF font")
}
func validateCertificateFont(fontPath string) (string, error) {
if _, err := os.Stat(fontPath); err != nil {
return "", err
}
if _, err := gg.LoadFontFace(explicitPath, 25); err != nil {
return "", fmt.Errorf("load certificate font %s: %w", explicitPath, err)
if _, err := gg.LoadFontFace(fontPath, 25); err != nil {
return "", fmt.Errorf("load certificate font %s: %w", fontPath, err)
}
return explicitPath, nil
return fontPath, nil
}
func certificateFontCandidates() []string {
candidates := []string{
"C:/Windows/Fonts/msyh.ttc",
"C:/Windows/Fonts/msyhbd.ttc",
"C:/Windows/Fonts/simhei.ttf",
"C:/Windows/Fonts/simsun.ttc",
"C:/Windows/Fonts/simkai.ttf",
"/System/Library/Fonts/Supplemental/Arial Unicode.ttf",
"/System/Library/Fonts/Supplemental/Arial.ttf",
"/System/Library/Fonts/Supplemental/Microsoft Sans Serif.ttf",
@ -414,15 +437,14 @@ func resolveCertificateFont(explicitPath string) (string, error) {
"/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc",
"/usr/share/fonts/truetype/noto/NotoSansCJK-Regular.ttc",
}
for _, candidate := range candidates {
if _, err := os.Stat(candidate); err != nil {
continue
}
if _, err := gg.LoadFontFace(candidate, 25); err == nil {
return candidate, nil
if windowsDir := firstNonEmpty(os.Getenv("WINDIR"), os.Getenv("SystemRoot")); windowsDir != "" {
windowsDir = strings.TrimRight(windowsDir, `\/`)
for _, name := range []string{"msyh.ttc", "msyhbd.ttc", "simhei.ttf", "simsun.ttc", "simkai.ttf"} {
candidates = append(candidates, windowsDir+"/Fonts/"+name)
}
}
return "", errors.New("missing certificate font, set HashCertificateRequest.FontPath to a Chinese TTF/TTC font")
return candidates
}
func certificateImageObjectKey(evidenceID, certNo string) string {

4
pkg/zxchainsdk/certificate_flow.go

@ -62,6 +62,7 @@ type SimpleHashAttestationCertificateRequest struct {
CompletedAt string `json:"completed_at"` // CompletedAt 表示作品完成时间
WorkPreviewURL string `json:"work_preview_url"` // WorkPreviewURL 表示作品预览图 URL
EvidenceHash string `json:"evidence_hash,omitempty"` // EvidenceHash 表示作品文件哈希,可选。如果不传,SDK 将从 WorkPreviewURL 下载并计算哈希
FontPath string `json:"font_path,omitempty"` // FontPath 表示用于绘制证书的中文字体路径,可选
// 可选:如果不传,将使用内置默认值
CertificateStorage *COSCertificateStorage `json:"certificate_storage,omitempty"` // CertificateStorage 表示 COS 上传配置
@ -204,6 +205,7 @@ func (c *SDKClient) CreateSimpleHashAttestationCertificate(ctx context.Context,
CompletedAt: req.CompletedAt,
WorkPreviewURL: req.WorkPreviewURL,
EvidenceHash: evidenceHash,
FontPath: req.FontPath,
CertificateStorage: req.CertificateStorage,
}
@ -372,7 +374,7 @@ func UploadCertificatePNGToCOS(ctx context.Context, pngBytes []byte, defaultObje
_, err = client.Object.Put(ctx, objectKey, bytes.NewReader(pngBytes), &cos.ObjectPutOptions{
ObjectPutHeaderOptions: &cos.ObjectPutHeaderOptions{
ContentType: "image/png",
ContentLength: int64(len(pngBytes)),
ContentLength: len(pngBytes),
CacheControl: "public, max-age=31536000, immutable",
},
})

Loading…
Cancel
Save