mirror of
https://github.com/ZeroHawkeye/wordZero.git
synced 2025-09-26 20:01:17 +08:00
- 修复大量ooxml规范问题,所有验证切换到word(wps会自动修复一些问题导致无法即使观察到)
- 修复添加图片word会打不开的问题
This commit is contained in:
28
README.md
28
README.md
@@ -1,4 +1,10 @@
|
||||
# WordZero - Golang Word Document Library
|
||||
<div align="center">
|
||||
<img src="docs/logo-banner.svg" alt="WordZero Logo" width="400"/>
|
||||
|
||||
<h1>WordZero - Golang Word Document Library</h1>
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://golang.org)
|
||||
[](LICENSE)
|
||||
@@ -7,6 +13,8 @@
|
||||
[](https://github.com/ZeroHawkeye/wordZero/wiki/en-Performance-Benchmarks)
|
||||
[](https://deepwiki.com/ZeroHawkeye/wordZero)
|
||||
|
||||
</div>
|
||||
|
||||
**English** | [中文](README_zh.md)
|
||||
|
||||
## Project Introduction
|
||||
@@ -288,11 +296,29 @@ wordZero/
|
||||
├── examples/ # Usage examples
|
||||
├── test/ # Integration tests
|
||||
├── benchmark/ # Performance benchmarks
|
||||
├── docs/ # Documentation and assets
|
||||
│ ├── logo.svg # Main logo with performance indicators
|
||||
│ ├── logo-banner.svg # Banner version for README headers
|
||||
│ └── logo-simple.svg # Simplified icon version
|
||||
└── wordZero.wiki/ # Complete documentation
|
||||
```
|
||||
|
||||
👉 **View detailed structure description**: [Project Structure](https://github.com/ZeroHawkeye/wordZero/wiki/en-Project-Structure)
|
||||
|
||||
### Logo and Branding
|
||||
|
||||
The project includes multiple logo variations for different use cases:
|
||||
|
||||
<div align="center">
|
||||
|
||||
| Logo Type | Usage | Preview |
|
||||
|-----------|-------|---------|
|
||||
| **Banner** | README headers, documentation | <img src="docs/logo-banner.svg" alt="Banner Logo" width="200"/> |
|
||||
| **Main** | General branding | <img src="docs/logo.svg" alt="Main Logo" width="120"/> |
|
||||
| **Simple** | Icons, favicons | <img src="docs/logo-simple.svg" alt="Simple Logo" width="32"/> |
|
||||
|
||||
</div>
|
||||
|
||||
## Contributing
|
||||
|
||||
Issues and Pull Requests are welcome! Please ensure before submitting code:
|
||||
|
28
README_zh.md
28
README_zh.md
@@ -1,4 +1,10 @@
|
||||
# WordZero - Golang Word操作库
|
||||
<div align="center">
|
||||
<img src="docs/logo-banner.svg" alt="WordZero Logo" width="400"/>
|
||||
|
||||
<h1>WordZero - Golang Word操作库</h1>
|
||||
</div>
|
||||
|
||||
<div align="center">
|
||||
|
||||
[](https://golang.org)
|
||||
[](LICENSE)
|
||||
@@ -7,6 +13,8 @@
|
||||
[](https://github.com/ZeroHawkeye/wordZero/wiki/13-%E6%80%A7%E8%83%BD%E5%9F%BA%E5%87%86%E6%B5%8B%E8%AF%95)
|
||||
[](https://deepwiki.com/ZeroHawkeye/wordZero)
|
||||
|
||||
</div>
|
||||
|
||||
[English](README.md) | **中文**
|
||||
|
||||
## 项目介绍
|
||||
@@ -288,11 +296,29 @@ wordZero/
|
||||
├── examples/ # 使用示例
|
||||
├── test/ # 集成测试
|
||||
├── benchmark/ # 性能基准测试
|
||||
├── docs/ # 文档和资源文件
|
||||
│ ├── logo.svg # 主Logo带性能指标
|
||||
│ ├── logo-banner.svg # 横幅版本用于README标题
|
||||
│ └── logo-simple.svg # 简化图标版本
|
||||
└── wordZero.wiki/ # 完整文档
|
||||
```
|
||||
|
||||
👉 **查看详细结构说明**: [项目结构详解](https://github.com/ZeroHawkeye/wordZero/wiki/15-项目结构详解)
|
||||
|
||||
### Logo设计
|
||||
|
||||
项目包含多种Logo变体,适用于不同使用场景:
|
||||
|
||||
<div align="center">
|
||||
|
||||
| Logo类型 | 使用场景 | 预览 |
|
||||
|----------|----------|------|
|
||||
| **横幅版** | README标题、文档头部 | <img src="docs/logo-banner.svg" alt="横幅Logo" width="200"/> |
|
||||
| **主版本** | 通用品牌展示 | <img src="docs/logo.svg" alt="主Logo" width="120"/> |
|
||||
| **简化版** | 图标、网站标识 | <img src="docs/logo-simple.svg" alt="简化Logo" width="32"/> |
|
||||
|
||||
</div>
|
||||
|
||||
## 贡献指南
|
||||
|
||||
欢迎提交 Issue 和 Pull Request!在提交代码前请确保:
|
||||
|
99
docs/logo-banner.svg
Normal file
99
docs/logo-banner.svg
Normal file
@@ -0,0 +1,99 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="400" height="120" viewBox="0 0 400 120" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- 背景渐变 -->
|
||||
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00ADD8;stop-opacity:0.05" />
|
||||
<stop offset="100%" style="stop-color:#00ADD8;stop-opacity:0.15" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Go语言蓝色渐变 -->
|
||||
<linearGradient id="goBlue" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#00ADD8;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#0077BE;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- 文档页面渐变 -->
|
||||
<linearGradient id="pageGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#f8f9fa;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- 背景 -->
|
||||
<rect width="400" height="120" fill="url(#bgGradient)" rx="12"/>
|
||||
|
||||
<!-- 左侧图标区域 -->
|
||||
<g transform="translate(20, 20)">
|
||||
<!-- 层叠文档效果 -->
|
||||
<rect x="4" y="8" width="40" height="52" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1.5" rx="3"/>
|
||||
<rect x="8" y="4" width="40" height="52" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1.5" rx="3"/>
|
||||
<rect x="12" y="0" width="40" height="52" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1.5" rx="3"/>
|
||||
|
||||
<!-- 主文档内容 -->
|
||||
<line x1="18" y1="12" x2="46" y2="12" stroke="url(#goBlue)" stroke-width="3" stroke-linecap="round"/>
|
||||
<line x1="18" y1="18" x2="42" y2="18" stroke="url(#goBlue)" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="18" y1="24" x2="44" y2="24" stroke="url(#goBlue)" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="18" y1="30" x2="40" y2="30" stroke="url(#goBlue)" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="18" y1="36" x2="45" y2="36" stroke="url(#goBlue)" stroke-width="1.5" stroke-linecap="round"/>
|
||||
|
||||
<!-- Zero符号 -->
|
||||
<circle cx="65" cy="26" r="12" fill="none" stroke="url(#goBlue)" stroke-width="4"/>
|
||||
<circle cx="65" cy="26" r="6" fill="url(#goBlue)" opacity="0.4"/>
|
||||
</g>
|
||||
|
||||
<!-- 主标题 -->
|
||||
<g transform="translate(120, 45)">
|
||||
<text x="0" y="0" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="36" font-weight="700" fill="#2c3e50">Word</text>
|
||||
<text x="90" y="0" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="36" font-weight="300" fill="url(#goBlue)">Zero</text>
|
||||
|
||||
<!-- 副标题 -->
|
||||
<text x="0" y="25" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="14" font-weight="400" fill="#7f8c8d" letter-spacing="1px">
|
||||
高性能 Golang Word 文档操作库
|
||||
</text>
|
||||
|
||||
<!-- 特性标签 -->
|
||||
<g transform="translate(0, 40)">
|
||||
<rect width="60" height="18" fill="#00ADD8" rx="9" opacity="0.9"/>
|
||||
<text x="30" y="12" font-family="'Segoe UI', sans-serif"
|
||||
font-size="10" font-weight="600" fill="white" text-anchor="middle">
|
||||
⚡ 2.62ms
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(70, 40)">
|
||||
<rect width="70" height="18" fill="#27ae60" rx="9" opacity="0.9"/>
|
||||
<text x="35" y="12" font-family="'Segoe UI', sans-serif"
|
||||
font-size="10" font-weight="600" fill="white" text-anchor="middle">
|
||||
🚀 零依赖
|
||||
</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(150, 40)">
|
||||
<rect width="80" height="18" fill="#e74c3c" rx="9" opacity="0.9"/>
|
||||
<text x="40" y="12" font-family="'Segoe UI', sans-serif"
|
||||
font-size="10" font-weight="600" fill="white" text-anchor="middle">
|
||||
📄 OOXML
|
||||
</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- 右侧装饰元素 -->
|
||||
<g transform="translate(320, 20)" opacity="0.6">
|
||||
<!-- Go语言风格的几何图案 -->
|
||||
<polygon points="0,10 8,0 16,10 8,20" fill="#00ADD8" opacity="0.8"/>
|
||||
<polygon points="20,25 28,15 36,25 28,35" fill="#00ADD8" opacity="0.6"/>
|
||||
<polygon points="10,40 18,30 26,40 18,50" fill="#00ADD8" opacity="0.4"/>
|
||||
<polygon points="30,55 38,45 46,55 38,65" fill="#00ADD8" opacity="0.3"/>
|
||||
|
||||
<!-- 性能指示器 -->
|
||||
<g transform="translate(50, 30)">
|
||||
<circle cx="0" cy="0" r="3" fill="#27ae60"/>
|
||||
<circle cx="0" cy="10" r="2" fill="#f39c12"/>
|
||||
<circle cx="0" cy="18" r="1.5" fill="#e74c3c"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 4.4 KiB |
43
docs/logo-simple.svg
Normal file
43
docs/logo-simple.svg
Normal file
@@ -0,0 +1,43 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="64" height="64" viewBox="0 0 64 64" xmlns="http://www.w3.org/2000/svg">
|
||||
<defs>
|
||||
<!-- Go语言蓝色渐变 -->
|
||||
<linearGradient id="goBlue" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00ADD8;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#0077BE;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- 文档渐变 -->
|
||||
<linearGradient id="docGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#f8f9fa;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- 背景圆形 -->
|
||||
<circle cx="32" cy="32" r="30" fill="url(#goBlue)" opacity="0.1" stroke="url(#goBlue)" stroke-width="2"/>
|
||||
|
||||
<!-- 文档图标 -->
|
||||
<g transform="translate(16, 12)">
|
||||
<!-- 主文档 -->
|
||||
<rect x="0" y="8" width="20" height="28" fill="url(#docGradient)" stroke="#e1e5e9" stroke-width="1.5" rx="2"/>
|
||||
|
||||
<!-- 文档内容线条 -->
|
||||
<line x1="4" y1="14" x2="16" y2="14" stroke="url(#goBlue)" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="4" y1="18" x2="14" y2="18" stroke="url(#goBlue)" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="4" y1="22" x2="15" y2="22" stroke="url(#goBlue)" stroke-width="1" stroke-linecap="round"/>
|
||||
<line x1="4" y1="26" x2="13" y2="26" stroke="url(#goBlue)" stroke-width="1" stroke-linecap="round"/>
|
||||
|
||||
<!-- Zero符号 -->
|
||||
<circle cx="26" cy="16" r="6" fill="none" stroke="url(#goBlue)" stroke-width="3"/>
|
||||
<circle cx="26" cy="16" r="2" fill="url(#goBlue)"/>
|
||||
</g>
|
||||
|
||||
<!-- 字母W和Z -->
|
||||
<g transform="translate(8, 44)">
|
||||
<text x="0" y="0" font-family="'Segoe UI', Arial, sans-serif"
|
||||
font-size="16" font-weight="700" fill="#2c3e50">W</text>
|
||||
<text x="38" y="0" font-family="'Segoe UI', Arial, sans-serif"
|
||||
font-size="16" font-weight="300" fill="url(#goBlue)">Z</text>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.0 KiB |
86
docs/logo.svg
Normal file
86
docs/logo.svg
Normal file
@@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg width="200" height="80" viewBox="0 0 200 80" xmlns="http://www.w3.org/2000/svg">
|
||||
<!-- 背景 -->
|
||||
<defs>
|
||||
<linearGradient id="bgGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#00ADD8;stop-opacity:0.1" />
|
||||
<stop offset="100%" style="stop-color:#00ADD8;stop-opacity:0.05" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- 文档页面渐变 -->
|
||||
<linearGradient id="pageGradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
||||
<stop offset="0%" style="stop-color:#ffffff;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#f8f9fa;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
|
||||
<!-- Go语言蓝色 -->
|
||||
<linearGradient id="goBlue" x1="0%" y1="0%" x2="100%" y2="0%">
|
||||
<stop offset="0%" style="stop-color:#00ADD8;stop-opacity:1" />
|
||||
<stop offset="100%" style="stop-color:#0077BE;stop-opacity:1" />
|
||||
</linearGradient>
|
||||
</defs>
|
||||
|
||||
<!-- 背景矩形 -->
|
||||
<rect width="200" height="80" fill="url(#bgGradient)" rx="8"/>
|
||||
|
||||
<!-- 左侧图标区域 -->
|
||||
<g transform="translate(12, 12)">
|
||||
<!-- 文档页面 -->
|
||||
<rect x="2" y="4" width="24" height="32" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1" rx="2"/>
|
||||
<rect x="6" y="2" width="24" height="32" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1" rx="2"/>
|
||||
<rect x="10" y="0" width="24" height="32" fill="url(#pageGradient)" stroke="#e1e5e9" stroke-width="1" rx="2"/>
|
||||
|
||||
<!-- 文档内容线条 -->
|
||||
<line x1="14" y1="6" x2="30" y2="6" stroke="#00ADD8" stroke-width="2" stroke-linecap="round"/>
|
||||
<line x1="14" y1="10" x2="28" y2="10" stroke="#00ADD8" stroke-width="1.5" stroke-linecap="round"/>
|
||||
<line x1="14" y1="14" x2="26" y2="14" stroke="#00ADD8" stroke-width="1" stroke-linecap="round"/>
|
||||
<line x1="14" y1="18" x2="29" y2="18" stroke="#00ADD8" stroke-width="1" stroke-linecap="round"/>
|
||||
|
||||
<!-- 零符号 (表示Zero) -->
|
||||
<circle cx="40" cy="16" r="8" fill="none" stroke="url(#goBlue)" stroke-width="3"/>
|
||||
<circle cx="40" cy="16" r="4" fill="url(#goBlue)" opacity="0.3"/>
|
||||
</g>
|
||||
|
||||
<!-- 文字Logo -->
|
||||
<g transform="translate(60, 25)">
|
||||
<!-- Word文字 -->
|
||||
<text x="0" y="0" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="22" font-weight="700" fill="#2c3e50">Word</text>
|
||||
|
||||
<!-- Zero文字 -->
|
||||
<text x="55" y="0" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="22" font-weight="300" fill="url(#goBlue)">Zero</text>
|
||||
|
||||
<!-- 副标题 -->
|
||||
<text x="0" y="20" font-family="'Segoe UI', 'Helvetica Neue', Arial, sans-serif"
|
||||
font-size="9" font-weight="400" fill="#7f8c8d" letter-spacing="0.5px">
|
||||
GOLANG WORD LIBRARY
|
||||
</text>
|
||||
|
||||
<!-- 性能标识 -->
|
||||
<g transform="translate(0, 28)">
|
||||
<rect width="32" height="12" fill="#00ADD8" rx="6" opacity="0.9"/>
|
||||
<text x="16" y="8" font-family="'Segoe UI', sans-serif"
|
||||
font-size="7" font-weight="600" fill="white" text-anchor="middle">2.62ms</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(36, 28)">
|
||||
<rect width="28" height="12" fill="#27ae60" rx="6" opacity="0.9"/>
|
||||
<text x="14" y="8" font-family="'Segoe UI', sans-serif"
|
||||
font-size="7" font-weight="600" fill="white" text-anchor="middle">ZERO</text>
|
||||
</g>
|
||||
|
||||
<g transform="translate(68, 28)">
|
||||
<rect width="24" height="12" fill="#e74c3c" rx="6" opacity="0.9"/>
|
||||
<text x="12" y="8" font-family="'Segoe UI', sans-serif"
|
||||
font-size="7" font-weight="600" fill="white" text-anchor="middle">DEPS</text>
|
||||
</g>
|
||||
</g>
|
||||
|
||||
<!-- 装饰性元素 - Go语言风格的几何图形 -->
|
||||
<g opacity="0.6">
|
||||
<polygon points="180,20 185,15 190,20 185,25" fill="#00ADD8"/>
|
||||
<polygon points="175,30 180,25 185,30 180,35" fill="#00ADD8" opacity="0.7"/>
|
||||
<polygon points="185,40 190,35 195,40 190,45" fill="#00ADD8" opacity="0.5"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 3.9 KiB |
@@ -183,6 +183,7 @@ WordZero 专注于现代的 Office Open XML (OOXML) 格式(.docx 文件),
|
||||
if err != nil {
|
||||
var docErr *document.DocumentError
|
||||
if errors.As(err, &docErr) {
|
||||
Errorf("文档操作失败 - 操作: %s, 错误: %v", docErr.Operation, docErr.Cause)
|
||||
fmt.Printf("操作: %s, 错误: %v\n", docErr.Operation, docErr.Cause)
|
||||
}
|
||||
}
|
||||
|
@@ -101,11 +101,11 @@ type ParagraphProperties struct {
|
||||
XMLName xml.Name `xml:"w:pPr"`
|
||||
ParagraphStyle *ParagraphStyle `xml:"w:pStyle,omitempty"`
|
||||
NumberingProperties *NumberingProperties `xml:"w:numPr,omitempty"`
|
||||
Spacing *Spacing `xml:"w:spacing,omitempty"`
|
||||
Justification *Justification `xml:"w:jc,omitempty"`
|
||||
Indentation *Indentation `xml:"w:ind,omitempty"`
|
||||
Tabs *Tabs `xml:"w:tabs,omitempty"`
|
||||
ParagraphBorder *ParagraphBorder `xml:"w:pBdr,omitempty"`
|
||||
Tabs *Tabs `xml:"w:tabs,omitempty"`
|
||||
Spacing *Spacing `xml:"w:spacing,omitempty"`
|
||||
Indentation *Indentation `xml:"w:ind,omitempty"`
|
||||
Justification *Justification `xml:"w:jc,omitempty"`
|
||||
}
|
||||
|
||||
// ParagraphBorder 段落边框
|
||||
@@ -151,19 +151,20 @@ type Run struct {
|
||||
}
|
||||
|
||||
// RunProperties 文本属性
|
||||
// 注意:字段顺序必须符合OpenXML标准,w:rFonts必须在w:color之前
|
||||
type RunProperties struct {
|
||||
XMLName xml.Name `xml:"w:rPr"`
|
||||
FontFamily *FontFamily `xml:"w:rFonts,omitempty"`
|
||||
Bold *Bold `xml:"w:b,omitempty"`
|
||||
BoldCs *BoldCs `xml:"w:bCs,omitempty"`
|
||||
Italic *Italic `xml:"w:i,omitempty"`
|
||||
ItalicCs *ItalicCs `xml:"w:iCs,omitempty"`
|
||||
Underline *Underline `xml:"w:u,omitempty"`
|
||||
Strike *Strike `xml:"w:strike,omitempty"`
|
||||
Color *Color `xml:"w:color,omitempty"`
|
||||
FontSize *FontSize `xml:"w:sz,omitempty"`
|
||||
FontSizeCs *FontSizeCs `xml:"w:szCs,omitempty"`
|
||||
Color *Color `xml:"w:color,omitempty"`
|
||||
Highlight *Highlight `xml:"w:highlight,omitempty"`
|
||||
FontFamily *FontFamily `xml:"w:rFonts,omitempty"`
|
||||
}
|
||||
|
||||
// Bold 粗体
|
||||
@@ -600,6 +601,10 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
||||
runProps := &RunProperties{}
|
||||
|
||||
if format != nil {
|
||||
if format.FontFamily != "" {
|
||||
runProps.FontFamily = &FontFamily{ASCII: format.FontFamily}
|
||||
}
|
||||
|
||||
if format.Bold {
|
||||
runProps.Bold = &Bold{}
|
||||
}
|
||||
@@ -608,19 +613,15 @@ func (d *Document) AddFormattedParagraph(text string, format *TextFormat) *Parag
|
||||
runProps.Italic = &Italic{}
|
||||
}
|
||||
|
||||
if format.FontSize > 0 {
|
||||
// Word中字体大小是半磅为单位,所以需要乘以2
|
||||
runProps.FontSize = &FontSize{Val: strconv.Itoa(format.FontSize * 2)}
|
||||
}
|
||||
|
||||
if format.FontColor != "" {
|
||||
// 确保颜色格式正确(移除#前缀)
|
||||
color := strings.TrimPrefix(format.FontColor, "#")
|
||||
runProps.Color = &Color{Val: color}
|
||||
}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
runProps.FontFamily = &FontFamily{ASCII: format.FontFamily}
|
||||
if format.FontSize > 0 {
|
||||
// Word中字体大小是半磅为单位,所以需要乘以2
|
||||
runProps.FontSize = &FontSize{Val: strconv.Itoa(format.FontSize * 2)}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -762,6 +763,10 @@ func (p *Paragraph) AddFormattedText(text string, format *TextFormat) {
|
||||
runProps := &RunProperties{}
|
||||
|
||||
if format != nil {
|
||||
if format.FontFamily != "" {
|
||||
runProps.FontFamily = &FontFamily{ASCII: format.FontFamily}
|
||||
}
|
||||
|
||||
if format.Bold {
|
||||
runProps.Bold = &Bold{}
|
||||
}
|
||||
@@ -770,17 +775,13 @@ func (p *Paragraph) AddFormattedText(text string, format *TextFormat) {
|
||||
runProps.Italic = &Italic{}
|
||||
}
|
||||
|
||||
if format.FontSize > 0 {
|
||||
runProps.FontSize = &FontSize{Val: strconv.Itoa(format.FontSize * 2)}
|
||||
}
|
||||
|
||||
if format.FontColor != "" {
|
||||
color := strings.TrimPrefix(format.FontColor, "#")
|
||||
runProps.Color = &Color{Val: color}
|
||||
}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
runProps.FontFamily = &FontFamily{ASCII: format.FontFamily}
|
||||
if format.FontSize > 0 {
|
||||
runProps.FontSize = &FontSize{Val: strconv.Itoa(format.FontSize * 2)}
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -788,7 +788,7 @@ func (d *Document) addSettingsRelationship() {
|
||||
relationship := Relationship{
|
||||
ID: relationshipID,
|
||||
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/settings",
|
||||
Target: "settings.xml",
|
||||
Target: "word/settings.xml",
|
||||
}
|
||||
d.relationships.Relationships = append(d.relationships.Relationships, relationship)
|
||||
}
|
||||
|
@@ -296,8 +296,9 @@ type PicElement struct {
|
||||
|
||||
// NvPicPr 非可视图片属性
|
||||
type NvPicPr struct {
|
||||
XMLName xml.Name `xml:"pic:nvPicPr"`
|
||||
CNvPr *CNvPr `xml:"pic:cNvPr"`
|
||||
XMLName xml.Name `xml:"pic:nvPicPr"`
|
||||
CNvPr *CNvPr `xml:"pic:cNvPr"`
|
||||
CNvPicPr *CNvPicPr `xml:"pic:cNvPicPr"`
|
||||
}
|
||||
|
||||
// CNvPr 通用非可视属性
|
||||
@@ -309,6 +310,19 @@ type CNvPr struct {
|
||||
Title string `xml:"title,attr,omitempty"`
|
||||
}
|
||||
|
||||
// CNvPicPr 图片特定非可视属性
|
||||
type CNvPicPr struct {
|
||||
XMLName xml.Name `xml:"pic:cNvPicPr"`
|
||||
PicLocks *PicLocks `xml:"a:picLocks,omitempty"`
|
||||
}
|
||||
|
||||
// PicLocks 图片锁定属性
|
||||
type PicLocks struct {
|
||||
XMLName xml.Name `xml:"a:picLocks"`
|
||||
NoChangeAspect string `xml:"noChangeAspect,attr,omitempty"`
|
||||
NoChangeArrowheads string `xml:"noChangeArrowheads,attr,omitempty"`
|
||||
}
|
||||
|
||||
// BlipFill 图片填充
|
||||
type BlipFill struct {
|
||||
XMLName xml.Name `xml:"pic:blipFill"`
|
||||
@@ -375,25 +389,31 @@ type AvLst struct {
|
||||
|
||||
// AddImageFromFile 从文件添加图片到文档
|
||||
func (d *Document) AddImageFromFile(filePath string, config *ImageConfig) (*ImageInfo, error) {
|
||||
Debugf("开始添加图片文件: %s", filePath)
|
||||
|
||||
// 读取图片文件
|
||||
imageData, err := os.ReadFile(filePath)
|
||||
if err != nil {
|
||||
Errorf("读取图片文件失败 %s: %v", filePath, err)
|
||||
return nil, fmt.Errorf("读取图片文件失败: %v", err)
|
||||
}
|
||||
|
||||
// 检测图片格式
|
||||
format, err := detectImageFormat(imageData)
|
||||
if err != nil {
|
||||
Errorf("检测图片格式失败 %s: %v", filePath, err)
|
||||
return nil, fmt.Errorf("检测图片格式失败: %v", err)
|
||||
}
|
||||
|
||||
// 获取图片尺寸
|
||||
width, height, err := getImageDimensions(imageData, format)
|
||||
if err != nil {
|
||||
Errorf("获取图片尺寸失败 %s: %v", filePath, err)
|
||||
return nil, fmt.Errorf("获取图片尺寸失败: %v", err)
|
||||
}
|
||||
|
||||
fileName := filepath.Base(filePath)
|
||||
Infof("成功读取图片: %s (格式: %s, 尺寸: %dx%d, 大小: %d字节)", fileName, format, width, height, len(imageData))
|
||||
return d.AddImageFromData(imageData, fileName, format, width, height, config)
|
||||
}
|
||||
|
||||
@@ -723,6 +743,11 @@ func (d *Document) createImageGraphic(imageInfo *ImageInfo, displayWidth, displa
|
||||
Descr: altText,
|
||||
Title: title,
|
||||
},
|
||||
CNvPicPr: &CNvPicPr{
|
||||
PicLocks: &PicLocks{
|
||||
NoChangeAspect: "1",
|
||||
},
|
||||
},
|
||||
},
|
||||
BlipFill: &BlipFill{
|
||||
Blip: &Blip{
|
||||
@@ -979,6 +1004,28 @@ func (d *Document) SetImageAlignment(imageInfo *ImageInfo, alignment AlignmentTy
|
||||
imageInfo.Config = &ImageConfig{}
|
||||
}
|
||||
|
||||
// 更新配置
|
||||
imageInfo.Config.Alignment = alignment
|
||||
return nil
|
||||
|
||||
// 查找包含此图片的段落并更新其对齐方式
|
||||
for _, element := range d.Body.Elements {
|
||||
if paragraph, ok := element.(*Paragraph); ok {
|
||||
// 检查段落中是否包含指定的图片
|
||||
for _, run := range paragraph.Runs {
|
||||
if run.Drawing != nil && run.Drawing.Inline != nil {
|
||||
// 检查docPr ID是否匹配
|
||||
if run.Drawing.Inline.DocPr != nil && run.Drawing.Inline.DocPr.ID == imageInfo.ID {
|
||||
// 更新段落对齐方式
|
||||
if paragraph.Properties == nil {
|
||||
paragraph.Properties = &ParagraphProperties{}
|
||||
}
|
||||
paragraph.Properties.Justification = &Justification{Val: string(alignment)}
|
||||
return nil
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return fmt.Errorf("找不到包含图片ID %s的段落", imageInfo.ID)
|
||||
}
|
||||
|
@@ -846,6 +846,12 @@ func (t *Table) SetCellFormattedText(row, col int, text string, format *TextForm
|
||||
if format != nil {
|
||||
run.Properties = &RunProperties{}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
run.Properties.FontFamily = &FontFamily{
|
||||
ASCII: format.FontFamily,
|
||||
}
|
||||
}
|
||||
|
||||
if format.Bold {
|
||||
run.Properties.Bold = &Bold{}
|
||||
}
|
||||
@@ -854,21 +860,15 @@ func (t *Table) SetCellFormattedText(row, col int, text string, format *TextForm
|
||||
run.Properties.Italic = &Italic{}
|
||||
}
|
||||
|
||||
if format.FontSize > 0 {
|
||||
run.Properties.FontSize = &FontSize{
|
||||
Val: fmt.Sprintf("%d", format.FontSize*2),
|
||||
}
|
||||
}
|
||||
|
||||
if format.FontColor != "" {
|
||||
run.Properties.Color = &Color{
|
||||
Val: format.FontColor,
|
||||
}
|
||||
}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
run.Properties.FontFamily = &FontFamily{
|
||||
ASCII: format.FontFamily,
|
||||
if format.FontSize > 0 {
|
||||
run.Properties.FontSize = &FontSize{
|
||||
Val: fmt.Sprintf("%d", format.FontSize*2),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -904,6 +904,12 @@ func (t *Table) AddCellFormattedText(row, col int, text string, format *TextForm
|
||||
if format != nil {
|
||||
run.Properties = &RunProperties{}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
run.Properties.FontFamily = &FontFamily{
|
||||
ASCII: format.FontFamily,
|
||||
}
|
||||
}
|
||||
|
||||
if format.Bold {
|
||||
run.Properties.Bold = &Bold{}
|
||||
}
|
||||
@@ -912,21 +918,15 @@ func (t *Table) AddCellFormattedText(row, col int, text string, format *TextForm
|
||||
run.Properties.Italic = &Italic{}
|
||||
}
|
||||
|
||||
if format.FontSize > 0 {
|
||||
run.Properties.FontSize = &FontSize{
|
||||
Val: fmt.Sprintf("%d", format.FontSize*2),
|
||||
}
|
||||
}
|
||||
|
||||
if format.FontColor != "" {
|
||||
run.Properties.Color = &Color{
|
||||
Val: format.FontColor,
|
||||
}
|
||||
}
|
||||
|
||||
if format.FontFamily != "" {
|
||||
run.Properties.FontFamily = &FontFamily{
|
||||
ASCII: format.FontFamily,
|
||||
if format.FontSize > 0 {
|
||||
run.Properties.FontSize = &FontSize{
|
||||
Val: fmt.Sprintf("%d", format.FontSize*2),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -2,7 +2,6 @@ package document
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"regexp"
|
||||
)
|
||||
|
||||
@@ -33,14 +32,14 @@ func (tr *TemplateRenderer) SetLogging(enabled bool) {
|
||||
// logInfo 记录信息日志
|
||||
func (tr *TemplateRenderer) logInfo(format string, args ...interface{}) {
|
||||
if tr.logger.enabled {
|
||||
log.Printf("[模板引擎] "+format, args...)
|
||||
Infof("[模板引擎] "+format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
// logError 记录错误日志
|
||||
func (tr *TemplateRenderer) logError(format string, args ...interface{}) {
|
||||
if tr.logger.enabled {
|
||||
log.Printf("[模板引擎-错误] "+format, args...)
|
||||
Errorf("[模板引擎] "+format, args...)
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -56,17 +56,18 @@ type Next struct {
|
||||
}
|
||||
|
||||
// ParagraphProperties 段落样式属性
|
||||
// 注意:字段顺序必须符合OpenXML标准
|
||||
type ParagraphProperties struct {
|
||||
XMLName xml.Name `xml:"w:pPr"`
|
||||
Spacing *Spacing `xml:"w:spacing,omitempty"`
|
||||
Justification *Justification `xml:"w:jc,omitempty"`
|
||||
Indentation *Indentation `xml:"w:ind,omitempty"`
|
||||
KeepNext *KeepNext `xml:"w:keepNext,omitempty"`
|
||||
KeepLines *KeepLines `xml:"w:keepLines,omitempty"`
|
||||
PageBreak *PageBreak `xml:"w:pageBreakBefore,omitempty"`
|
||||
OutlineLevel *OutlineLevel `xml:"w:outlineLvl,omitempty"`
|
||||
ParagraphBorder *ParagraphBorder `xml:"w:pBdr,omitempty"`
|
||||
Shading *Shading `xml:"w:shd,omitempty"`
|
||||
Spacing *Spacing `xml:"w:spacing,omitempty"`
|
||||
Indentation *Indentation `xml:"w:ind,omitempty"`
|
||||
Justification *Justification `xml:"w:jc,omitempty"`
|
||||
OutlineLevel *OutlineLevel `xml:"w:outlineLvl,omitempty"`
|
||||
}
|
||||
|
||||
// ParagraphBorder 段落边框
|
||||
@@ -95,15 +96,16 @@ type Shading struct {
|
||||
}
|
||||
|
||||
// RunProperties 字符样式属性
|
||||
// 注意:字段顺序必须符合OpenXML标准,w:rFonts必须在w:color之前
|
||||
type RunProperties struct {
|
||||
XMLName xml.Name `xml:"w:rPr"`
|
||||
FontFamily *FontFamily `xml:"w:rFonts,omitempty"`
|
||||
Bold *Bold `xml:"w:b,omitempty"`
|
||||
Italic *Italic `xml:"w:i,omitempty"`
|
||||
Underline *Underline `xml:"w:u,omitempty"`
|
||||
Strike *Strike `xml:"w:strike,omitempty"`
|
||||
FontSize *FontSize `xml:"w:sz,omitempty"`
|
||||
Color *Color `xml:"w:color,omitempty"`
|
||||
FontFamily *FontFamily `xml:"w:rFonts,omitempty"`
|
||||
FontSize *FontSize `xml:"w:sz,omitempty"`
|
||||
Highlight *Highlight `xml:"w:highlight,omitempty"`
|
||||
}
|
||||
|
||||
|
Reference in New Issue
Block a user