- 修复大量ooxml规范问题,所有验证切换到word(wps会自动修复一些问题导致无法即使观察到)

- 修复添加图片word会打不开的问题
This commit is contained in:
zero
2025-06-06 11:35:47 +08:00
parent e0be01cbd9
commit 31c885e81a
12 changed files with 382 additions and 52 deletions

View File

@@ -1,5 +1,11 @@
# 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">
[![Go Version](https://img.shields.io/badge/Go-1.19+-00ADD8?style=flat&logo=go)](https://golang.org)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/Tests-Passing-green.svg)](#testing)
@@ -7,6 +13,8 @@
[![Performance](https://img.shields.io/badge/Performance-Golang%20Winner-brightgreen.svg)](https://github.com/ZeroHawkeye/wordZero/wiki/en-Performance-Benchmarks)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](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:

View File

@@ -1,5 +1,11 @@
# 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">
[![Go Version](https://img.shields.io/badge/Go-1.19+-00ADD8?style=flat&logo=go)](https://golang.org)
[![License](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
[![Tests](https://img.shields.io/badge/Tests-Passing-green.svg)](#测试)
@@ -7,6 +13,8 @@
[![Performance](https://img.shields.io/badge/Performance-Golang%20优胜-brightgreen.svg)](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)
[![Ask DeepWiki](https://deepwiki.com/badge.svg)](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
View 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
View 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
View 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

View File

@@ -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)
}
}

View File

@@ -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)}
}
}

View File

@@ -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)
}

View File

@@ -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)
}

View File

@@ -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),
}
}
}

View File

@@ -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...)
}
}

View File

@@ -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"`
}