mirror of
https://github.com/ZeroHawkeye/wordZero.git
synced 2025-09-27 04:05:56 +08:00
- 修复文档id不是唯一的问题,遵循ooxml规范
This commit is contained in:
@@ -29,6 +29,8 @@ type Document struct {
|
|||||||
styleManager *style.StyleManager
|
styleManager *style.StyleManager
|
||||||
// 临时存储文档部件
|
// 临时存储文档部件
|
||||||
parts map[string][]byte
|
parts map[string][]byte
|
||||||
|
// 图片ID计数器,确保每个图片都有唯一的ID
|
||||||
|
nextImageID int
|
||||||
}
|
}
|
||||||
|
|
||||||
// Body 表示文档主体
|
// Body 表示文档主体
|
||||||
@@ -351,7 +353,7 @@ type NumID struct {
|
|||||||
Val string `xml:"w:val,attr"`
|
Val string `xml:"w:val,attr"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// New 创建一个新的空文档
|
// New 创建一个新的Word文档
|
||||||
func New() *Document {
|
func New() *Document {
|
||||||
Debugf("创建新文档")
|
Debugf("创建新文档")
|
||||||
|
|
||||||
@@ -361,13 +363,16 @@ func New() *Document {
|
|||||||
},
|
},
|
||||||
styleManager: style.NewStyleManager(),
|
styleManager: style.NewStyleManager(),
|
||||||
parts: make(map[string][]byte),
|
parts: make(map[string][]byte),
|
||||||
|
nextImageID: 1, // 初始化图片ID计数器,从1开始
|
||||||
documentRelationships: &Relationships{
|
documentRelationships: &Relationships{
|
||||||
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
|
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
|
||||||
Relationships: []Relationship{},
|
Relationships: []Relationship{},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 初始化文档结构
|
||||||
doc.initializeStructure()
|
doc.initializeStructure()
|
||||||
|
|
||||||
return doc
|
return doc
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -409,6 +414,7 @@ func Open(filename string) (*Document, error) {
|
|||||||
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
|
Xmlns: "http://schemas.openxmlformats.org/package/2006/relationships",
|
||||||
Relationships: []Relationship{},
|
Relationships: []Relationship{},
|
||||||
},
|
},
|
||||||
|
nextImageID: 1, // 初始化图片ID计数器
|
||||||
}
|
}
|
||||||
|
|
||||||
// 读取所有文件部件
|
// 读取所有文件部件
|
||||||
|
@@ -426,10 +426,12 @@ func (d *Document) AddImageFromData(imageData []byte, fileName string, format Im
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 生成关系ID和图片ID
|
// 使用文档级别的图片ID计数器确保ID唯一性
|
||||||
// 注意:rId1保留给styles.xml,图片从rId2开始
|
imageID := d.nextImageID
|
||||||
|
d.nextImageID++ // 递增计数器
|
||||||
|
|
||||||
|
// 生成关系ID,注意:rId1保留给styles.xml,图片从rId2开始
|
||||||
relationID := fmt.Sprintf("rId%d", len(d.documentRelationships.Relationships)+2)
|
relationID := fmt.Sprintf("rId%d", len(d.documentRelationships.Relationships)+2)
|
||||||
imageID := len(d.documentRelationships.Relationships) + 1
|
|
||||||
|
|
||||||
// 添加图片关系
|
// 添加图片关系
|
||||||
d.documentRelationships.Relationships = append(d.documentRelationships.Relationships, Relationship{
|
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
|
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 创建包含图片的段落
|
// createImageParagraph 创建包含图片的段落
|
||||||
func (d *Document) createImageParagraph(imageInfo *ImageInfo) *Paragraph {
|
func (d *Document) createImageParagraph(imageInfo *ImageInfo) *Paragraph {
|
||||||
// 计算图片显示尺寸(EMU单位)
|
// 计算图片显示尺寸(EMU单位)
|
||||||
|
@@ -3,6 +3,8 @@ package document
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -2517,11 +2519,31 @@ func (te *TemplateEngine) createImageParagraph(imageData *TemplateImageData, doc
|
|||||||
return nil, fmt.Errorf("获取图片尺寸失败: %v", err)
|
return nil, fmt.Errorf("获取图片尺寸失败: %v", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
fileName := fmt.Sprintf("image_%d.%s", len(doc.documentRelationships.Relationships)+1, string(format))
|
// 使用唯一的文件名,包含图片ID计数器
|
||||||
imageInfo, err = doc.AddImageFromData(imageData.Data, fileName, format, width, height, config)
|
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 != "" {
|
} else if imageData.FilePath != "" {
|
||||||
// 使用文件路径
|
// 使用文件路径,但需要先读取数据,然后使用AddImageFromDataWithoutElement
|
||||||
imageInfo, err = doc.AddImageFromFile(imageData.FilePath, config)
|
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 {
|
} else {
|
||||||
return nil, fmt.Errorf("图片数据和文件路径都为空")
|
return nil, fmt.Errorf("图片数据和文件路径都为空")
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user