- 修复文档id不是唯一的问题,遵循ooxml规范

This commit is contained in:
zero
2025-06-06 12:15:29 +08:00
parent 1568633d69
commit 6e28fef1b7
3 changed files with 86 additions and 8 deletions

View File

@@ -29,6 +29,8 @@ type Document struct {
styleManager *style.StyleManager
// 临时存储文档部件
parts map[string][]byte
// 图片ID计数器确保每个图片都有唯一的ID
nextImageID int
}
// Body 表示文档主体
@@ -351,7 +353,7 @@ type NumID struct {
Val string `xml:"w:val,attr"`
}
// New 创建一个新的文档
// New 创建一个新的Word文档
func New() *Document {
Debugf("创建新文档")
@@ -361,13 +363,16 @@ func New() *Document {
},
styleManager: style.NewStyleManager(),
parts: make(map[string][]byte),
nextImageID: 1, // 初始化图片ID计数器从1开始
documentRelationships: &Relationships{
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
Relationships: []Relationship{},
},
}
// 初始化文档结构
doc.initializeStructure()
return doc
}
@@ -409,6 +414,7 @@ func Open(filename string) (*Document, error) {
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
Relationships: []Relationship{},
},
nextImageID: 1, // 初始化图片ID计数器
}
// 读取所有文件部件

View File

@@ -426,10 +426,12 @@ func (d *Document) AddImageFromData(imageData []byte, fileName string, format Im
}
}
// 生成关系ID和图片ID
// 注意rId1保留给styles.xml图片从rId2开始
// 使用文档级别的图片ID计数器确保ID唯一性
imageID := d.nextImageID
d.nextImageID++ // 递增计数器
// 生成关系ID注意rId1保留给styles.xml图片从rId2开始
relationID := fmt.Sprintf("rId%d", len(d.documentRelationships.Relationships)+2)
imageID := len(d.documentRelationships.Relationships) + 1
// 添加图片关系
d.documentRelationships.Relationships = append(d.documentRelationships.Relationships, Relationship{
@@ -465,6 +467,54 @@ func (d *Document) AddImageFromData(imageData []byte, fileName string, format Im
return imageInfo, nil
}
// AddImageFromDataWithoutElement 从数据添加图片到文档但不创建段落元素
// 此方法供模板引擎等需要自行管理图片段落的场景使用
func (d *Document) AddImageFromDataWithoutElement(imageData []byte, fileName string, format ImageFormat, width, height int, config *ImageConfig) (*ImageInfo, error) {
if d.documentRelationships == nil {
d.documentRelationships = &Relationships{
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
Relationships: []Relationship{},
}
}
// 使用文档级别的图片ID计数器确保ID唯一性
imageID := d.nextImageID
d.nextImageID++ // 递增计数器
// 生成关系ID注意rId1保留给styles.xml图片从rId2开始
relationID := fmt.Sprintf("rId%d", len(d.documentRelationships.Relationships)+2)
// 添加图片关系
d.documentRelationships.Relationships = append(d.documentRelationships.Relationships, Relationship{
ID: relationID,
Type: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
Target: fmt.Sprintf("media/%s", fileName),
})
// 存储图片数据
if d.parts == nil {
d.parts = make(map[string][]byte)
}
d.parts[fmt.Sprintf("word/media/%s", fileName)] = imageData
// 更新内容类型
d.addImageContentType(format)
// 创建图片信息
imageInfo := &ImageInfo{
ID: strconv.Itoa(imageID),
RelationID: relationID,
Format: format,
Width: width,
Height: height,
Data: imageData,
Config: config,
}
// 注意:这个方法不创建段落元素,由调用者负责管理
return imageInfo, nil
}
// createImageParagraph 创建包含图片的段落
func (d *Document) createImageParagraph(imageInfo *ImageInfo) *Paragraph {
// 计算图片显示尺寸EMU单位

View File

@@ -3,6 +3,8 @@ package document
import (
"fmt"
"os"
"path/filepath"
"reflect"
"regexp"
"strconv"
@@ -2517,11 +2519,31 @@ func (te *TemplateEngine) createImageParagraph(imageData *TemplateImageData, doc
return nil, fmt.Errorf("获取图片尺寸失败: %v", err)
}
fileName := fmt.Sprintf("image_%d.%s", len(doc.documentRelationships.Relationships)+1, string(format))
imageInfo, err = doc.AddImageFromData(imageData.Data, fileName, format, width, height, config)
// 使用唯一的文件名包含图片ID计数器
fileName := fmt.Sprintf("image_%d.%s", doc.nextImageID, string(format))
// 使用不创建段落元素的方法,由模板引擎自行管理段落
imageInfo, err = doc.AddImageFromDataWithoutElement(imageData.Data, fileName, format, width, height, config)
} else if imageData.FilePath != "" {
// 使用文件路径
imageInfo, err = doc.AddImageFromFile(imageData.FilePath, config)
// 使用文件路径但需要先读取数据然后使用AddImageFromDataWithoutElement
data, readErr := os.ReadFile(imageData.FilePath)
if readErr != nil {
return nil, fmt.Errorf("读取图片文件失败: %v", readErr)
}
var format ImageFormat
format, err = detectImageFormat(data)
if err != nil {
return nil, fmt.Errorf("检测图片格式失败: %v", err)
}
var width, height int
width, height, err = getImageDimensions(data, format)
if err != nil {
return nil, fmt.Errorf("获取图片尺寸失败: %v", err)
}
fileName := filepath.Base(imageData.FilePath)
imageInfo, err = doc.AddImageFromDataWithoutElement(data, fileName, format, width, height, config)
} else {
return nil, fmt.Errorf("图片数据和文件路径都为空")
}