mirror of
https://github.com/gotenberg/gotenberg.git
synced 2026-08-17 12:42:16 +01:00
chore(deps): update pdfcpu to v0.15.0 (#1628)
This commit is contained in:
2
Makefile
2
Makefile
@@ -91,7 +91,7 @@ PDFENGINES_WATERMARK_ENGINES=pdfcpu,pdftk
|
|||||||
PDFENGINES_STAMP_ENGINES=pdfcpu,pdftk
|
PDFENGINES_STAMP_ENGINES=pdfcpu,pdftk
|
||||||
PDFENGINES_ENCRYPT_ENGINES=qpdf,pdfcpu,pdftk
|
PDFENGINES_ENCRYPT_ENGINES=qpdf,pdfcpu,pdftk
|
||||||
PDFENGINES_ROTATE_ENGINES=pdfcpu,pdftk
|
PDFENGINES_ROTATE_ENGINES=pdfcpu,pdftk
|
||||||
PDFENGINES_EMBED_ENGINES=qpdf,pdfcpu
|
PDFENGINES_EMBED_ENGINES=pdfcpu,qpdf
|
||||||
PDFENGINES_EMBED_METADATA_ENGINES=qpdf
|
PDFENGINES_EMBED_METADATA_ENGINES=qpdf
|
||||||
PDFENGINES_FACTUR_X_ENGINES=qpdf
|
PDFENGINES_FACTUR_X_ENGINES=qpdf
|
||||||
PROMETHEUS_NAMESPACE=gotenberg
|
PROMETHEUS_NAMESPACE=gotenberg
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ ARG GOLANG_VERSION=1.26.5
|
|||||||
FROM golang:$GOLANG_VERSION AS pdfcpu-binary-stage
|
FROM golang:$GOLANG_VERSION AS pdfcpu-binary-stage
|
||||||
|
|
||||||
# See https://github.com/pdfcpu/pdfcpu/releases.
|
# See https://github.com/pdfcpu/pdfcpu/releases.
|
||||||
ARG PDFCPU_VERSION=v0.13.0
|
ARG PDFCPU_VERSION=v0.15.0
|
||||||
ENV CGO_ENABLED=0
|
ENV CGO_ENABLED=0
|
||||||
|
|
||||||
# Define the working directory outside of $GOPATH (we're using go modules).
|
# Define the working directory outside of $GOPATH (we're using go modules).
|
||||||
|
|||||||
@@ -115,18 +115,29 @@ func buildExifToolWriteArgs(metadata map[string]any) ([]string, error) {
|
|||||||
return nil, fmt.Errorf("write PDF metadata with ExifTool: invalid metadata key %q: %w", key, gotenberg.ErrPdfEngineMetadataValueNotSupported)
|
return nil, fmt.Errorf("write PDF metadata with ExifTool: invalid metadata key %q: %w", key, gotenberg.ErrPdfEngineMetadataValueNotSupported)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tag := key
|
||||||
|
if key == "Trapped" {
|
||||||
|
// ExifTool writes the document info /Trapped entry as a malformed
|
||||||
|
// name-in-a-string, e.g. "(/Unknown)". pdfcpu's stricter validation
|
||||||
|
// (as of v0.15) rejects it, which breaks later pdfcpu operations on
|
||||||
|
// the file such as embedding. Writing Trapped to XMP keeps the value
|
||||||
|
// readable without the invalid document info entry.
|
||||||
|
// See https://github.com/gotenberg/gotenberg/issues/1628.
|
||||||
|
tag = "XMP-pdf:Trapped"
|
||||||
|
}
|
||||||
|
|
||||||
switch val := value.(type) {
|
switch val := value.(type) {
|
||||||
case string:
|
case string:
|
||||||
if err := validateMetadataValue(key, val); err != nil {
|
if err := validateMetadataValue(key, val); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args = append(args, fmt.Sprintf("-%s=%s", key, val))
|
args = append(args, fmt.Sprintf("-%s=%s", tag, val))
|
||||||
case []string:
|
case []string:
|
||||||
for _, s := range val {
|
for _, s := range val {
|
||||||
if err := validateMetadataValue(key, s); err != nil {
|
if err := validateMetadataValue(key, s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args = append(args, fmt.Sprintf("-%s=%s", key, s))
|
args = append(args, fmt.Sprintf("-%s=%s", tag, s))
|
||||||
}
|
}
|
||||||
case []any:
|
case []any:
|
||||||
// See https://github.com/gotenberg/gotenberg/issues/1048.
|
// See https://github.com/gotenberg/gotenberg/issues/1048.
|
||||||
@@ -138,18 +149,18 @@ func buildExifToolWriteArgs(metadata map[string]any) ([]string, error) {
|
|||||||
if err := validateMetadataValue(key, s); err != nil {
|
if err := validateMetadataValue(key, s); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
args = append(args, fmt.Sprintf("-%s=%s", key, s))
|
args = append(args, fmt.Sprintf("-%s=%s", tag, s))
|
||||||
}
|
}
|
||||||
case bool:
|
case bool:
|
||||||
args = append(args, fmt.Sprintf("-%s=%t", key, val))
|
args = append(args, fmt.Sprintf("-%s=%t", tag, val))
|
||||||
case int:
|
case int:
|
||||||
args = append(args, fmt.Sprintf("-%s=%d", key, val))
|
args = append(args, fmt.Sprintf("-%s=%d", tag, val))
|
||||||
case int64:
|
case int64:
|
||||||
args = append(args, fmt.Sprintf("-%s=%d", key, val))
|
args = append(args, fmt.Sprintf("-%s=%d", tag, val))
|
||||||
case float32:
|
case float32:
|
||||||
args = append(args, fmt.Sprintf("-%s=%g", key, val))
|
args = append(args, fmt.Sprintf("-%s=%g", tag, val))
|
||||||
case float64:
|
case float64:
|
||||||
args = append(args, fmt.Sprintf("-%s=%g", key, val))
|
args = append(args, fmt.Sprintf("-%s=%g", tag, val))
|
||||||
default:
|
default:
|
||||||
return nil, fmt.Errorf("write PDF metadata with ExifTool: unsupported type %T for key %q: %w", value, key, gotenberg.ErrPdfEngineMetadataValueNotSupported)
|
return nil, fmt.Errorf("write PDF metadata with ExifTool: unsupported type %T for key %q: %w", value, key, gotenberg.ErrPdfEngineMetadataValueNotSupported)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ func (mod *PdfEngines) Descriptor() gotenberg.ModuleDescriptor {
|
|||||||
fs.StringSlice("pdfengines-read-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the read metadata feature - empty means all")
|
fs.StringSlice("pdfengines-read-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the read metadata feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-write-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the write metadata feature - empty means all")
|
fs.StringSlice("pdfengines-write-metadata-engines", []string{"exiftool"}, "Set the PDF engines and their order for the write metadata feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-encrypt-engines", []string{"qpdf", "pdftk", "pdfcpu"}, "Set the PDF engines and their order for the password protection feature - empty means all")
|
fs.StringSlice("pdfengines-encrypt-engines", []string{"qpdf", "pdftk", "pdfcpu"}, "Set the PDF engines and their order for the password protection feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-embed-engines", []string{"pdfcpu"}, "Set the PDF engines and their order for the file embedding feature - empty means all")
|
fs.StringSlice("pdfengines-embed-engines", []string{"pdfcpu", "qpdf"}, "Set the PDF engines and their order for the file embedding feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-embed-metadata-engines", []string{"qpdf"}, "Set the PDF engines and their order for the embed metadata feature - empty means all")
|
fs.StringSlice("pdfengines-embed-metadata-engines", []string{"qpdf"}, "Set the PDF engines and their order for the embed metadata feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-read-bookmarks-engines", []string{"pdfcpu"}, "Set the PDF engines and their order for the read bookmarks feature - empty means all")
|
fs.StringSlice("pdfengines-read-bookmarks-engines", []string{"pdfcpu"}, "Set the PDF engines and their order for the read bookmarks feature - empty means all")
|
||||||
fs.StringSlice("pdfengines-write-bookmarks-engines", []string{"pdfcpu"}, "Set the PDF engines and their order for the write bookmarks feature - empty means all")
|
fs.StringSlice("pdfengines-write-bookmarks-engines", []string{"pdfcpu"}, "Set the PDF engines and their order for the write bookmarks feature - empty means all")
|
||||||
|
|||||||
@@ -419,17 +419,57 @@ func (engine *QPdf) Encrypt(ctx context.Context, logger *slog.Logger, inputPath
|
|||||||
}
|
}
|
||||||
|
|
||||||
// EmbedFiles is not available in this implementation.
|
// EmbedFiles is not available in this implementation.
|
||||||
|
// EmbedFiles embeds the given files into a PDF as attachments using qpdf's
|
||||||
|
// --add-attachment. It is a fallback for pdfcpu: qpdf reads PDFs whose document
|
||||||
|
// info pdfcpu's stricter validation rejects (for example a non-conformant
|
||||||
|
// /Trapped value written by ExifTool). See
|
||||||
|
// https://github.com/gotenberg/gotenberg/issues/1628.
|
||||||
func (engine *QPdf) EmbedFiles(ctx context.Context, logger *slog.Logger, filePaths []string, inputPath string) error {
|
func (engine *QPdf) EmbedFiles(ctx context.Context, logger *slog.Logger, filePaths []string, inputPath string) error {
|
||||||
_, span := gotenberg.Tracer().Start(ctx, "qpdf.EmbedFiles",
|
ctx, span := gotenberg.Tracer().Start(ctx, "qpdf.EmbedFiles",
|
||||||
trace.WithSpanKind(trace.SpanKindClient),
|
trace.WithSpanKind(trace.SpanKindClient),
|
||||||
trace.WithAttributes(engine.spanAttrs()...),
|
trace.WithAttributes(engine.spanAttrs()...),
|
||||||
)
|
)
|
||||||
defer span.End()
|
defer span.End()
|
||||||
|
|
||||||
err := fmt.Errorf("embed files with QPDF: %w", gotenberg.ErrPdfEngineMethodNotSupported)
|
if len(filePaths) == 0 {
|
||||||
span.RecordError(err)
|
span.SetStatus(codes.Ok, "")
|
||||||
span.SetStatus(codes.Error, err.Error())
|
return nil
|
||||||
return err
|
}
|
||||||
|
|
||||||
|
fail := func(err error) error {
|
||||||
|
span.RecordError(err)
|
||||||
|
span.SetStatus(codes.Error, err.Error())
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each --add-attachment group must be terminated by "--", so qpdf attaches
|
||||||
|
// one file per invocation. Chain them, writing to a temporary file and
|
||||||
|
// moving it back over the input each time.
|
||||||
|
outputPath := inputPath + "~embed"
|
||||||
|
for _, filePath := range filePaths {
|
||||||
|
args := make([]string, 0, 6+len(engine.globalArgs))
|
||||||
|
args = append(args, engine.globalArgs...)
|
||||||
|
args = append(args, "--add-attachment", filePath, "--key="+filepath.Base(filePath))
|
||||||
|
args = append(args, "--", inputPath, outputPath)
|
||||||
|
|
||||||
|
cmd, err := gotenberg.CommandContext(ctx, logger, engine.binPath, args...)
|
||||||
|
if err != nil {
|
||||||
|
return fail(fmt.Errorf("create command: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
_, err = cmd.Exec()
|
||||||
|
if err != nil {
|
||||||
|
return fail(fmt.Errorf("embed files with QPDF: %w", err))
|
||||||
|
}
|
||||||
|
|
||||||
|
err = os.Rename(outputPath, inputPath)
|
||||||
|
if err != nil {
|
||||||
|
return fail(fmt.Errorf("embed files with QPDF: replace input: %w", err))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
span.SetStatus(codes.Ok, "")
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// EmbedFilesMetadata sets metadata on already-embedded files in a PDF using
|
// EmbedFilesMetadata sets metadata on already-embedded files in a PDF using
|
||||||
|
|||||||
Reference in New Issue
Block a user