feat(渲染编辑): 补全替换图解析渲染与保存
build.yaml / build (push) Successful in 44s

This commit is contained in:
xiaoqidun committed 2026-10-09 23:50:29 +08:00
1 parent f96ef65741
commit 0ad34ee2b1
8 files changed
+54 -19

No files matched your search

+5
View File
@@ -847,6 +847,11 @@ func (v *editorValidation) prepareObject(id string, object GraphicObject) (Graph
if _, err := e.editorImage(obj.ResourceID); err != nil { if _, err := e.editorImage(obj.ResourceID); err != nil {
return GraphicObject{}, err return GraphicObject{}, err
} }
if obj.Substitution != "" {
if _, err := e.editorImage(obj.Substitution); err != nil {
return GraphicObject{}, err
}
}
if obj.ImageMask != "" { if obj.ImageMask != "" {
if _, err := e.editorImage(obj.ImageMask); err != nil { if _, err := e.editorImage(obj.ImageMask); err != nil {
return GraphicObject{}, err return GraphicObject{}, err
+1
View File
@@ -462,6 +462,7 @@ func collectObjectReferences(object GraphicObject, used map[string]bool) {
actions = object.PathObject.Actions actions = object.PathObject.Actions
case "ImageObject": case "ImageObject":
used[object.ImageObject.ResourceID], used[object.ImageObject.ImageMask] = true, true used[object.ImageObject.ResourceID], used[object.ImageObject.ImageMask] = true, true
used[object.ImageObject.Substitution] = true
if object.ImageObject.Border != nil { if object.ImageObject.Border != nil {
collectPaintReferences((*FillColor)(object.ImageObject.Border.BorderColor), used) collectPaintReferences((*FillColor)(object.ImageObject.Border.BorderColor), used)
} }
+2 -2
View File
@@ -307,7 +307,7 @@ func editorXMLSupported(node *editorXML) bool {
children += " Clips" children += " Clips"
} }
case "ImageObject": case "ImageObject":
allowed, children = "ID Boundary CTM ResourceID ImageMask Visible Alpha", "Clips" allowed, children = "ID Boundary CTM ResourceID Substitution ImageMask Visible Alpha", "Clips"
case "TextCode": case "TextCode":
allowed = "X Y DeltaX DeltaY" allowed = "X Y DeltaX DeltaY"
case "FillColor", "StrokeColor": case "FillColor", "StrokeColor":
@@ -344,7 +344,7 @@ func editorXMLTransformable(node *editorXML) bool {
case "PathObject": case "PathObject":
attrs = "ID Boundary CTM DrawParam LineWidth MiterLimit Join Cap Rule DashPattern DashOffset Visible Stroke Fill Alpha" attrs = "ID Boundary CTM DrawParam LineWidth MiterLimit Join Cap Rule DashPattern DashOffset Visible Stroke Fill Alpha"
case "ImageObject": case "ImageObject":
attrs = "ID Boundary CTM ResourceID ImageMask Visible Alpha" attrs = "ID Boundary CTM ResourceID Substitution ImageMask Visible Alpha"
case "CompositeObject", "CompositeGraphicUnit": case "CompositeObject", "CompositeGraphicUnit":
attrs = "ID Boundary CTM ResourceID DrawParam Visible Alpha" attrs = "ID Boundary CTM ResourceID DrawParam Visible Alpha"
default: default:
+32
View File
@@ -94,6 +94,38 @@ func (r *Renderer) ImageResource(id string) (image.Image, error) {
return r.cachedImageResource(path) return r.cachedImageResource(path)
} }
// imageObjectResource 读取主图,无法读取或解码时使用对象声明的替换图
// 入参: object 图像对象
// 返回: image.Image 图片资源, error 读取或解码错误
func (r *Renderer) imageObjectResource(object ImageObject) (image.Image, error) {
read := func(id string) (image.Image, error) {
img, err := r.ImageResource(id)
if err == nil && (r.decodeImages || object.Substitution != "") {
pixels, decodeErr := imagePixelData(img)
err = decodeErr
if r.decodeImages {
img = pixels
}
}
return img, err
}
img, err := read(object.ResourceID)
if err == nil || object.Substitution == "" || object.Substitution == object.ResourceID {
return img, err
}
if r.pageContext != nil && r.pageContext.Err() != nil {
return nil, r.pageContext.Err()
}
if r.OutputContext != nil && r.OutputContext.Err() != nil {
return nil, r.OutputContext.Err()
}
img, substituteErr := read(object.Substitution)
if substituteErr != nil {
return nil, fmt.Errorf("image resource %q: %w; substitution %q: %w", object.ResourceID, err, object.Substitution, substituteErr)
}
return img, nil
}
// newEncodedImage 接管编码数据并读取头信息 // newEncodedImage 接管编码数据并读取头信息
// 入参: data 原始编码 // 入参: data 原始编码
// 返回: *EncodedImage 惰性图片, error 头信息或格式错误 // 返回: *EncodedImage 惰性图片, error 头信息或格式错误
+11 -10
View File
@@ -240,16 +240,17 @@ type ShdColor struct {
// ImageObject 图片对象 // ImageObject 图片对象
type ImageObject struct { type ImageObject struct {
ID string `xml:"ID,attr"` ID string `xml:"ID,attr"`
Boundary string `xml:"Boundary,attr"` Boundary string `xml:"Boundary,attr"`
ResourceID string `xml:"ResourceID,attr"` ResourceID string `xml:"ResourceID,attr"`
ImageMask string `xml:"ImageMask,attr"` Substitution string `xml:"Substitution,attr"`
CTM string `xml:"CTM,attr"` ImageMask string `xml:"ImageMask,attr"`
Alpha *int `xml:"Alpha,attr"` CTM string `xml:"CTM,attr"`
Visible *bool `xml:"Visible,attr"` Alpha *int `xml:"Alpha,attr"`
Border *ImageBorder `xml:"Border"` Visible *bool `xml:"Visible,attr"`
Clips *Clips `xml:"Clips"` Border *ImageBorder `xml:"Border"`
Actions []Action `xml:"Actions>Action"` Clips *Clips `xml:"Clips"`
Actions []Action `xml:"Actions>Action"`
} }
// ImageBorder 图像边框 // ImageBorder 图像边框
+1 -1
View File
@@ -59,7 +59,7 @@ func (c *semanticCompiler) imageObject(object ImageObject, state RenderState) er
return err return err
} }
} else { } else {
img, err := c.renderer.ImageResource(object.ResourceID) img, err := c.renderer.imageObjectResource(object)
if err != nil { if err != nil {
return err return err
} }
+1 -6
View File
@@ -38,12 +38,7 @@ func (r *Renderer) renderImage(ctx *canvas.Context, obj ImageObject, pageH float
if obj.Visible != nil && !*obj.Visible || obj.Alpha != nil && *obj.Alpha == 0 { if obj.Visible != nil && !*obj.Visible || obj.Alpha != nil && *obj.Alpha == 0 {
return return
} }
resPath, ok := resourceValue(r.Reader.ResMap, obj.ResourceID) img, err := r.imageObjectResource(obj)
if !ok {
r.renderError = fmt.Errorf("image resource %q not found", obj.ResourceID)
return
}
img, err := r.decodeImageResource(resPath)
if err != nil { if err != nil {
r.renderError = err r.renderError = err
return return
+1
View File
@@ -849,6 +849,7 @@ func (x *ofdXML) object(object GraphicObject, root bool) {
attrs.add("CTM", obj.CTM) attrs.add("CTM", obj.CTM)
attrs.add("ResourceID", obj.ResourceID) attrs.add("ResourceID", obj.ResourceID)
attrs.add("ImageMask", obj.ImageMask) attrs.add("ImageMask", obj.ImageMask)
attrs.add("Substitution", obj.Substitution)
attrs.flag("Visible", obj.Visible) attrs.flag("Visible", obj.Visible)
attrs.alpha(obj.Alpha) attrs.alpha(obj.Alpha)
actions = obj.Actions actions = obj.Actions