From e08362a9b1550656f4c16b99af10e852536d7581 Mon Sep 17 00:00:00 2001 From: Steven Geens <2096958-StevenGeens@users.noreply.gitlab.com> Date: Sun, 2 Nov 2025 13:25:53 +0100 Subject: [PATCH 1/2] Fix EMF save with wrong dimensions Fix for https://gitlab.com/inkscape/inbox/-/issues/8300 libuemf drawing_size function only supports full millimeter sizes. EMF standard (https://winprotocoldoc.z19.web.core.windows.net/MS-EMF/%5bMS-EMF%5d.pdf 2.2.9 Header Object) states that that it can be saved in 100ths of milimeter. Imported 3th party libeumf library modified with new drawing_size_100th method to allow extra precision. --- src/3rdparty/libuemf/uemf.c | 31 ++++++++++++++++++++++++++++ src/3rdparty/libuemf/uemf.h | 3 ++- src/extension/internal/emf-print.cpp | 4 ++-- 3 files changed, 35 insertions(+), 3 deletions(-) diff --git a/src/3rdparty/libuemf/uemf.c b/src/3rdparty/libuemf/uemf.c index fa7689bb6e..f4c0bcf5b9 100644 --- a/src/3rdparty/libuemf/uemf.c +++ b/src/3rdparty/libuemf/uemf.c @@ -1541,6 +1541,37 @@ int drawing_size( return(0); } +/** + \brief Set up fields for an EMR_HEADER for drawing by physical size in 100th of mm and dots per millimeter. + Technically rclBounds is supposed to be the extent of the drawing within the EMF, but libUEMF has no way + of knowing this since it never actually draws anything. Instead this is set to the full drawing size. + Coordinates are inclusive inclusive, so 297 -> 0,29699. + \return 0 for success, >=1 for failure. + \param x100thmm Drawing width in 100ths of millimeter + \param y100thmm Drawing height in 100ths of millimeter + \param dpmm Dots per millimeter + \param rclBounds Drawing size structure in pixels + \param rclFrame Drawing size structure in mm +*/ +int drawing_size_100th( + const int x100thmm, + const int y100thmm, + const float dpmm, + U_RECTL *rclBounds, + U_RECTL *rclFrame + ){ + if(x100thmm < 0 || y100thmm < 0 || dpmm < 0)return(1); + rclBounds->left = 0; + rclBounds->top = 0; + rclBounds->right = U_ROUND((float) x100thmm * dpmm / 100.) - 1; // because coordinate system is 0,0 in upper left, N,M in lower right + rclBounds->bottom = U_ROUND((float) y100thmm * dpmm / 100.) - 1; + rclFrame->left = 0; + rclFrame->top = 0; + rclFrame->right = U_ROUND((float) x100thmm ) - 1; + rclFrame->bottom = U_ROUND((float) y100thmm ) - 1; + return(0); +} + /** \brief Set a U_COLORREF value from separate R,G,B values. \param red Red component diff --git a/src/3rdparty/libuemf/uemf.h b/src/3rdparty/libuemf/uemf.h index 3a51e39e29..da514e2983 100644 --- a/src/3rdparty/libuemf/uemf.h +++ b/src/3rdparty/libuemf/uemf.h @@ -3375,7 +3375,8 @@ int DIB_to_RGBA(const char *px, const U_RGBQUAD *ct, int numCt, char *RGBA_to_RGBA(char *rgba_px, int w, int h, int sl, int st, int *ew, int *eh); int device_size(const int xmm, const int ymm, const float dpmm, U_SIZEL *szlDev, U_SIZEL *szlMm); -int drawing_size(const int xmm, const int yum, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame); +int drawing_size(const int xmm, const int ymm, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame); +int drawing_size_100th(const int x100thmm, const int y100thmm, const float dpmm, U_RECTL *rclBounds, U_RECTL *rclFrame); int emf_start(const char *name, const uint32_t initsize, const uint32_t chunksize, EMFTRACK **et); int emf_finish(EMFTRACK *et, EMFHANDLES *eht); diff --git a/src/extension/internal/emf-print.cpp b/src/extension/internal/emf-print.cpp index 0fc7355206..efd79cd061 100644 --- a/src/extension/internal/emf-print.cpp +++ b/src/extension/internal/emf-print.cpp @@ -182,8 +182,8 @@ unsigned int PrintEmf::begin(Inkscape::Extension::Print *mod, SPDocument *doc) float dwInchesX = d.width(); float dwInchesY = d.height(); - // dwInchesX x dwInchesY in micrometer units, 1200 dpi/25.4 -> dpmm - (void) drawing_size((int) ceil(dwInchesX * 25.4), (int) ceil(dwInchesY * 25.4),1200.0/25.4, &rclBounds, &rclFrame); + // dwInchesX x dwInchesY in 100th of millimeter units, 1200 dpi/25.4 -> dpmm + (void) drawing_size_100th((int) ceil(dwInchesX * 25.4 * 100.), (int) ceil(dwInchesY * 25.4 * 100.),1200.0/25.4, &rclBounds, &rclFrame); // set up the reference device as 100 X A4 horizontal, (1200 dpi/25.4 -> dpmm). Extra digits maintain dpi better in EMF int MMX = 216; -- GitLab From 8f48796efdb67f19edf807a15788193c9de953f4 Mon Sep 17 00:00:00 2001 From: Steven Geens <2096958-StevenGeens@users.noreply.gitlab.com> Date: Mon, 3 Nov 2025 17:06:56 +0100 Subject: [PATCH 2/2] cli_tests for Fix EMF save with wrong dimensions --- testfiles/cli_tests/CMakeLists.txt | 7 +++ testfiles/cli_tests/testcases/emf-100thmm.svg | 45 ++++++++++++++++++ .../testcases/export-emf-100thmm_expected.emf | Bin 0 -> 656 bytes 3 files changed, 52 insertions(+) create mode 100644 testfiles/cli_tests/testcases/emf-100thmm.svg create mode 100644 testfiles/cli_tests/testcases/export-emf-100thmm_expected.emf diff --git a/testfiles/cli_tests/CMakeLists.txt b/testfiles/cli_tests/CMakeLists.txt index 2d9f9202b5..ded28daddd 100644 --- a/testfiles/cli_tests/CMakeLists.txt +++ b/testfiles/cli_tests/CMakeLists.txt @@ -1091,6 +1091,13 @@ add_cli_test(actions-sequential-export-id-only_svg OUTPUT_FILENAME actions-sequential-export-id-only.svg REFERENCE_FILENAME export-id_export-id-only_expected.svg) +# EMF exports should be exact to a 100th of a milimeter (not increase to the next highest whole millimeter) +# https://gitlab.com/inkscape/inkscape/-/issues/8300 +add_cli_test(export-emf-100thmm + INPUT_FILENAME emf-100thmm.svg + PARAMETERS --export-type=emf --export-extension=org.inkscape.output.emf + OUTPUT_FILENAME export-emf-100thmm.emf + REFERENCE_FILENAME export-emf-100thmm_expected.emf) ########################### ### pdf input support ### diff --git a/testfiles/cli_tests/testcases/emf-100thmm.svg b/testfiles/cli_tests/testcases/emf-100thmm.svg new file mode 100644 index 0000000000..9f510174c2 --- /dev/null +++ b/testfiles/cli_tests/testcases/emf-100thmm.svg @@ -0,0 +1,45 @@ + + + + + + + + + + diff --git a/testfiles/cli_tests/testcases/export-emf-100thmm_expected.emf b/testfiles/cli_tests/testcases/export-emf-100thmm_expected.emf new file mode 100644 index 0000000000000000000000000000000000000000..65340a8577523bfbe3de1a6bcced223bf05613da GIT binary patch literal 656 zcmZQ%U|`??5eyKZ&%nR{!Vn$Xh8vD744w>m4A~6D49N_M3zM?!dTA&q|i{$pu$kkAU79e zj}VeOgrRJZePU3y1Oo#D2!q@TQZE7(=Vf4Eh-YA6uz>mjB!_~P7{UI7iLt>L3=9ma zP%}W$W(8%lFfcG!gVF{A1A{aJ1A_q6UXV63B)$Oy1A`4zodc2@kh=d+05hM1fuTVI UYCgy=J_ZH`ko!SuK^T;_0E)^$c>n+a literal 0 HcmV?d00001 -- GitLab