diff options
| author | Chris Lamb <chris@chris-lamb.co.uk> | 2018-03-17 22:48:29 +0000 |
|---|---|---|
| committer | Chris Lamb <chris@chris-lamb.co.uk> | 2018-03-18 23:27:50 +0000 |
| commit | be95e05da2adb84b210c3048522d222073002ac5 (patch) | |
| tree | 9cd6745adcf70e77bca408850c0c9b3de280c267 /src | |
| parent | Removing sample meson build files. (diff) | |
| download | inkscape-be95e05da2adb84b210c3048522d222073002ac5.tar.gz inkscape-be95e05da2adb84b210c3048522d222073002ac5.zip | |
Make the command-line PDF output reproducible.
Whilst working on the Reproducible Builds effort [0], we noticed
that inkscape generates output that is not reproducible:
$ cp /usr/share/icons/gnome/scalable/places/debian-swirl.svg .
$ inkscape -z debian-swirl.svg --export-width=25 --export-pdf=a.pdf
$ sleep 1
$ inkscape -z debian-swirl.svg --export-width=25 --export-pdf=b.pdf
$ sha1sum *.pdf
bee6f300a8fce628e94febd0700fa97f90aa7b37 a.pdf
32f26595ec1957c7e714174e007c452f6cb5dd79 b.pdf
This is affecting (at least) the "debian-astro" package:
│ │ │ ├── ./usr/share/pixmaps/Debian-Astro-logo.pdf
│ │ │ │ ├── pdftk {} output - uncompress
│ │ │ │ │ @@ -357,15 +357,15 @@
│ │ │ │ │ <<
│ │ │ │ │ /Type /Catalog
│ │ │ │ │ /Pages 1 0 R
│ │ │ │ │ >>
│ │ │ │ │ endobj
│ │ │ │ │ 6 0 obj
│ │ │ │ │ <<
│ │ │ │ │ -/CreationDate (D:20180315093948-12'00)
│ │ │ │ │ +/CreationDate (D:20190418180346+14'00)
│ │ │ │ │ /Producer (cairo 1.15.10 \(http://cairographics.org\))
│ │ │ │ │ >>
│ │ │ │ │ endobj xref
After applying this patch (which uses SOURCE_DATE_EPOCH [1]):
$ export SOURCE_DATE_EPOCH=1521324801
$ […]
$ sha1sum *.pdf
620bf8469600ab744ffa6fcc3eee4c6845f4f159 a.pdf
620bf8469600ab744ffa6fcc3eee4c6845f4f159 b.pdf
This was originally filed in Debian as #893314 [2].
[0] https://reproducible-builds.org/
[1] https://reproducible-builds.org/specs/source-date-epoch/
[2] https://bugs.debian.org/893314
Signed-off-by: Chris Lamb <chris@chris-lamb.co.uk>
Diffstat (limited to 'src')
| -rw-r--r-- | src/extension/internal/cairo-render-context.cpp | 43 |
1 files changed, 43 insertions, 0 deletions
diff --git a/src/extension/internal/cairo-render-context.cpp b/src/extension/internal/cairo-render-context.cpp index 1878b2c89..f42fe5214 100644 --- a/src/extension/internal/cairo-render-context.cpp +++ b/src/extension/internal/cairo-render-context.cpp @@ -26,7 +26,10 @@ #include <signal.h> +#include <limits.h> #include <errno.h> +#include <time.h> +#include <stdlib.h> #include <2geom/pathvector.h> #include <glib.h> @@ -796,6 +799,12 @@ CairoRenderContext::setupSurface(double width, double height) cairo_surface_t *surface = NULL; cairo_matrix_t ctm; cairo_matrix_init_identity (&ctm); + char buffer[25]; + char *endptr; + char *source_date_epoch; + time_t now; + struct tm *build_time; + unsigned long long epoch; switch (_target) { case CAIRO_SURFACE_TYPE_IMAGE: surface = cairo_image_surface_create(_target_format, (int)ceil(width), (int)ceil(height)); @@ -804,6 +813,40 @@ CairoRenderContext::setupSurface(double width, double height) case CAIRO_SURFACE_TYPE_PDF: surface = cairo_pdf_surface_create_for_stream(Inkscape::Extension::Internal::_write_callback, _stream, width, height); cairo_pdf_surface_restrict_to_version(surface, (cairo_pdf_version_t)_pdf_level); +#if CAIRO_VERSION >= CAIRO_VERSION_ENCODE(1, 15, 4) + source_date_epoch = getenv("SOURCE_DATE_EPOCH"); + if (source_date_epoch) { + errno = 0; + epoch = strtoull(source_date_epoch, &endptr, 10); + if ((errno == ERANGE && (epoch == ULLONG_MAX || epoch == 0)) + || (errno != 0 && epoch == 0)) { + g_printerr ("Environment variable $SOURCE_DATE_EPOCH: strtoull: %s\n", + strerror(errno)); + exit (1); + } + if (endptr == source_date_epoch) { + g_printerr ("Environment variable $SOURCE_DATE_EPOCH: No digits were found: %s\n", + endptr); + exit (1); + } + if (*endptr != '\0') { + g_printerr ("Environment variable $SOURCE_DATE_EPOCH: Trailing garbage: %s\n", + endptr); + exit (1); + } + if (epoch > ULONG_MAX) { + g_printerr ("Environment variable $SOURCE_DATE_EPOCH: must be <= %lu but saw: %llu\n", + ULONG_MAX, epoch); + exit (1); + } + now = (time_t)epoch; + build_time = gmtime(&now); + strftime(buffer, 25, "%Y-%m-%dT%H:%M:%S%z", build_time); + cairo_pdf_surface_set_metadata (surface, + CAIRO_PDF_METADATA_CREATE_DATE, + buffer); +#endif + } break; #endif #ifdef CAIRO_HAS_PS_SURFACE |
