fix(pdfengines): correctly update the indexes if the bookmarks form field (map format) is given

This commit is contained in:
Julien Neuhart
2026-03-04 22:45:58 +01:00
parent caea81501d
commit 874e78c6cd
12 changed files with 257 additions and 24 deletions

View File

@@ -222,6 +222,42 @@ func (multi *multiPdfEngines) WriteMetadata(ctx context.Context, logger *zap.Log
return fmt.Errorf("write PDF metadata with multi PDF engines: %w", err)
}
type pageCountResult struct {
pageCount int
err error
}
// PageCount returns the number of pages in a PDF file using the first available
// engine that supports metadata reading.
func (multi *multiPdfEngines) PageCount(ctx context.Context, logger *zap.Logger, inputPath string) (int, error) {
var err error
var mu sync.Mutex // to safely append errors.
for _, engine := range multi.readMetadataEngines {
resultChan := make(chan pageCountResult, 1)
go func(engine gotenberg.PdfEngine) {
pageCount, err := engine.PageCount(ctx, logger, inputPath)
resultChan <- pageCountResult{pageCount: pageCount, err: err}
}(engine)
select {
case result := <-resultChan:
if result.err != nil {
mu.Lock()
err = multierr.Append(err, result.err)
mu.Unlock()
} else {
return result.pageCount, nil
}
case <-ctx.Done():
return 0, ctx.Err()
}
}
return 0, fmt.Errorf("page count with multi PDF engines: %w", err)
}
type readBookmarksResult struct {
bookmarks []gotenberg.Bookmark
err error

View File

@@ -292,6 +292,21 @@ func WriteMetadataStub(ctx *api.Context, engine gotenberg.PdfEngine, metadata ma
return nil
}
func shiftBookmarks(bookmarks []gotenberg.Bookmark, offset int) []gotenberg.Bookmark {
if offset == 0 {
return bookmarks
}
shifted := make([]gotenberg.Bookmark, len(bookmarks))
for i, b := range bookmarks {
shifted[i] = gotenberg.Bookmark{
Title: b.Title,
Page: b.Page + offset,
Children: shiftBookmarks(b.Children, offset),
}
}
return shifted
}
// WriteBookmarksStub writes the bookmarks into PDF files. If no bookmarks, it
// does nothing.
func WriteBookmarksStub(ctx *api.Context, engine gotenberg.PdfEngine, bookmarks any, inputPaths []string) error {
@@ -402,13 +417,6 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
return fmt.Errorf("validate form data: %w", err)
}
if b, ok := bookmarks.(map[string][]gotenberg.Bookmark); ok {
err = WriteBookmarksStub(ctx, engine, b, inputPaths)
if err != nil {
return fmt.Errorf("write bookmarks: %w", err)
}
}
outputPath := ctx.GeneratePath(".pdf")
err = engine.Merge(ctx, ctx.Log(), inputPaths, outputPath)
if err != nil {
@@ -425,8 +433,27 @@ func mergeRoute(engine gotenberg.PdfEngine) api.Route {
return fmt.Errorf("embed files into PDFs: %w", err)
}
var finalBookmarks []gotenberg.Bookmark
if b, ok := bookmarks.([]gotenberg.Bookmark); ok {
err = WriteBookmarksStub(ctx, engine, b, outputPaths)
finalBookmarks = b
} else if b, ok := bookmarks.(map[string][]gotenberg.Bookmark); ok {
offset := 0
for _, inputPath := range inputPaths {
filename := filepath.Base(inputPath)
if fileBookmarks, ok := b[filename]; ok {
finalBookmarks = append(finalBookmarks, shiftBookmarks(fileBookmarks, offset)...)
}
pageCount, err := engine.PageCount(ctx, ctx.Log(), inputPath)
if err != nil {
return fmt.Errorf("get page count of '%s': %w", filename, err)
}
offset += pageCount
}
}
if len(finalBookmarks) > 0 {
err = WriteBookmarksStub(ctx, engine, finalBookmarks, outputPaths)
if err != nil {
return fmt.Errorf("write bookmarks: %w", err)
}