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