From 5d1fd593cd1ef61838e8390902152f3c486b47a8 Mon Sep 17 00:00:00 2001 From: xiaoqidun Date: Mon, 12 Oct 2026 19:18:25 +0800 Subject: [PATCH] =?UTF-8?q?feat(=E5=9B=BE=E5=83=8F=E7=AD=BE=E7=AB=A0):=20?= =?UTF-8?q?=E5=AE=8C=E5=96=84=E5=9B=BE=E5=83=8F=E5=8F=96=E6=B6=88=E4=B8=8E?= =?UTF-8?q?=E7=AD=BE=E7=AB=A0=E7=BC=93=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ofdgo_editor_images.go | 20 ++++++++++++---- ofdgo_render_compile_image.go | 14 ++++++++--- ofdgo_render_pattern.go | 32 +++++++++++++++++++++---- ofdgo_renderer_stamp_canvas.go | 43 ++++++++++++++++++++++++++++++---- 4 files changed, 91 insertions(+), 18 deletions(-) diff --git a/ofdgo_editor_images.go b/ofdgo_editor_images.go index 33c0b15..828eeab 100644 --- a/ofdgo_editor_images.go +++ b/ofdgo_editor_images.go @@ -19,6 +19,7 @@ import ( "context" "fmt" "image" + "io" "math" ) @@ -90,7 +91,7 @@ func (e *Editor) ImportImages(ctx context.Context, sources []ImagePageSource, at if err := ctx.Err(); err != nil { return err } - page, err := e.addImagePage(data, options) + page, err := e.addImagePage(ctx, data, options) if err != nil { return fmt.Errorf("image %q: %w", source.Name, err) } @@ -107,9 +108,12 @@ func (e *Editor) ImportImages(ctx context.Context, sources []ImagePageSource, at } // addImagePage 保留原图并按方向、物理尺寸与纸张选项建页 -// 入参: data 图片数据, options 建页选项 +// 入参: ctx 取消上下文, data 图片数据, options 建页选项 // 返回: int 从0开始的页面索引, error 错误信息 -func (e *Editor) addImagePage(data []byte, options ImagePageOptions) (int, error) { +func (e *Editor) addImagePage(ctx context.Context, data []byte, options ImagePageOptions) (int, error) { + if err := ctx.Err(); err != nil { + return 0, err + } config, format, err := decodeImageConfigData(data) if err != nil { return 0, err @@ -119,9 +123,12 @@ func (e *Editor) addImagePage(data []byte, options ImagePageOptions) (int, error } var decoded image.Image if format == "bmp" || format == "tiff" { - decoded, _, err = decodeImageData(data) + decoded, _, err = decodeImageDataContext(ctx, data) } else { - decoded, _, err = image.Decode(bytes.NewReader(data)) + decoded, _, err = image.Decode(imageInput{ReadCloser: io.NopCloser(bytes.NewReader(data)), context: ctx}) + } + if cancelErr := ctx.Err(); cancelErr != nil { + return 0, cancelErr } if err != nil { return 0, err @@ -144,6 +151,9 @@ func (e *Editor) addImagePage(data []byte, options ImagePageOptions) (int, error if !finite(w) || !finite(h) || w <= 0 || h <= 0 { return 0, fmt.Errorf("invalid image page dimensions") } + if err := ctx.Err(); err != nil { + return 0, err + } resource, err := e.addImage(data, config, format, decoded) if err != nil { return 0, err diff --git a/ofdgo_render_compile_image.go b/ofdgo_render_compile_image.go index ac71141..3cc987f 100644 --- a/ofdgo_render_compile_image.go +++ b/ofdgo_render_compile_image.go @@ -16,6 +16,7 @@ package ofdgo import ( "bytes" + "context" "fmt" "image" "math" @@ -158,20 +159,27 @@ func (c *semanticCompiler) drawStampContent(stamp Stamp) error { if c.textOnly || c.measure || len(stamp.Data) == 0 { return nil } + ctx := c.renderer.pageContext + if ctx == nil { + ctx = context.Background() + } + if err := ctx.Err(); err != nil { + return err + } if stamp.Type == "ofd" { reader, err := NewReader(bytes.NewReader(stamp.Data), int64(len(stamp.Data))) if err != nil { return err } defer reader.Close() - document, err := reader.Doc() + document, err := reader.DocContext(ctx) if err != nil { return err } renderer := c.renderer.childRenderer(reader) renderer.TransparentBackground = true for _, reference := range document.Pages.Page { - content, err := reader.PageContent(reference) + content, err := reader.PageContentContext(ctx, reference) if err != nil { return err } @@ -218,7 +226,7 @@ func (c *semanticCompiler) drawStampContent(stamp Stamp) error { } return nil } - img, _, err := decodeImageData(stamp.Data) + img, _, err := decodeImageDataContext(ctx, stamp.Data) if err != nil { return err } diff --git a/ofdgo_render_pattern.go b/ofdgo_render_pattern.go index 65793b5..12d96a7 100644 --- a/ofdgo_render_pattern.go +++ b/ofdgo_render_pattern.go @@ -15,6 +15,7 @@ package ofdgo import ( + "context" "crypto/sha256" "fmt" "slices" @@ -62,6 +63,13 @@ func (c *semanticCompiler) sharedStamp(stamp Stamp, compile func(*semanticCompil return nil } r := c.renderer + ctx := r.pageContext + if ctx == nil { + ctx = context.Background() + } + if err := ctx.Err(); err != nil { + return err + } state, _ := r.backendStates[stampContentStateKey{}].(*stampContentState) config := r.backends if state == nil || !sameBackend(state.config.Fonts, config.Fonts) || !sameBackend(state.config.Geometry, config.Geometry) || @@ -80,17 +88,31 @@ func (c *semanticCompiler) sharedStamp(stamp Stamp, compile func(*semanticCompil local.Box.X, local.Box.Y = 0, 0 page := &RasterPage{Width: c.page.Width, Height: c.page.Height, DPI: c.page.DPI} child := &semanticCompiler{renderer: r, geometry: c.geometry, page: page, patterns: c.patterns} - if err := compile(child, local); err != nil { + err := compile(child, local) + if cancelErr := ctx.Err(); cancelErr != nil { + return cancelErr + } + if err != nil { return err } commands = page.Commands cost := 0 for _, command := range commands { - cost += rasterCommandCost(command) - if command.Image != nil { - bounds := command.Image.Bounds() - cost += bounds.Dx() * bounds.Dy() * 4 + part := rasterCommandCost(command) + if part < 0 || part > state.cache.limit-cost { + cost = state.cache.limit + 1 + break } + cost += part + if command.Image != nil { + cost += imageResourceCost(command.Image, state.cache.limit-cost) + } + if cost > state.cache.limit { + break + } + } + if err := ctx.Err(); err != nil { + return err } state.cache.put(key, commands, cost) } diff --git a/ofdgo_renderer_stamp_canvas.go b/ofdgo_renderer_stamp_canvas.go index b40cbb1..3446894 100644 --- a/ofdgo_renderer_stamp_canvas.go +++ b/ofdgo_renderer_stamp_canvas.go @@ -16,6 +16,7 @@ package ofdgo import ( "bytes" + "context" "image" "github.com/tdewolff/canvas" @@ -27,6 +28,19 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) { if r.textOnly { return } + pageContext := r.pageContext + if pageContext == nil { + pageContext = context.Background() + } + defer func() { + if err := pageContext.Err(); err != nil { + r.renderError = err + } + }() + if err := pageContext.Err(); err != nil { + r.renderError = err + return + } if s.Type == "ofd" && len(s.Data) > 0 { if s.Clip != nil { if img := r.renderOFDStampImage(s.Data); img != nil { @@ -37,12 +51,15 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) { reader, err := NewReader(bytes.NewReader(s.Data), int64(len(s.Data))) if err == nil { defer reader.Close() - doc, err := reader.Doc() + doc, err := reader.DocContext(pageContext) if err == nil { renderer := r.childRenderer(reader) for _, pageRef := range doc.Pages.Page { - content, err := reader.PageContent(pageRef) + content, err := reader.PageContentContext(pageContext, pageRef) if err != nil { + if pageContext.Err() != nil { + return + } continue } sealBox, err := renderer.GetPageBox(content) @@ -64,7 +81,7 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) { } } if len(s.Data) > 0 { - img, _, err := decodeImageData(s.Data) + img, _, err := decodeImageDataContext(pageContext, s.Data) if err == nil { if r.decodeImages { img = imagePixelSource(img) @@ -79,12 +96,25 @@ func (r *Renderer) renderStamp(ctx *canvas.Context, s Stamp, pageH float64) { // 入参: data OFD印章数据 // 返回: image.Image 印章图像 func (r *Renderer) renderOFDStampImage(data []byte) image.Image { + ctx := r.pageContext + if ctx == nil { + ctx = context.Background() + } + defer func() { + if err := ctx.Err(); err != nil { + r.renderError = err + } + }() + if err := ctx.Err(); err != nil { + r.renderError = err + return nil + } reader, err := NewReader(bytes.NewReader(data), int64(len(data))) if err != nil { return nil } defer reader.Close() - doc, err := reader.Doc() + doc, err := reader.DocContext(ctx) if err != nil { return nil } @@ -92,8 +122,11 @@ func (r *Renderer) renderOFDStampImage(data []byte) image.Image { renderer.decodeImages = true renderer.TransparentBackground = true for _, pageRef := range doc.Pages.Page { - content, err := reader.PageContent(pageRef) + content, err := reader.PageContentContext(ctx, pageRef) if err != nil { + if ctx.Err() != nil { + return nil + } continue } img, err := renderer.RenderToImage(content)