tdf168886 EMF FILESAVE: Fix precision of DPI calculation in EMF+ header

The previous implementation used integer math with a factor of 25,
leading to significant rounding errors. For example, a standard
96 DPI image was incorrectly calculated as 94 DPI.

This patch improves precision by:
- Using a double-precision factor of 25.4 (2540.0 to account for
  coordinate scaling).
- Using std::round() instead of truncation to find the nearest
  integer DPI.
- Adding a safety check to prevent division by zero if
  rMtfSizeLog dimensions are missing.

This ensures that EMF+ files exported from LibreOffice have
the correct physical scale metadata.

Change-Id: I82c8b8f7e2137f6713b1081ec3e0e596453c741a
Reviewed-on: https://gerrit.libreoffice.org/c/core/+/202537
Tested-by: Jenkins
Reviewed-by: Bartosz Kosiorek <gang65@poczta.onet.pl>
This commit is contained in:
Bartosz Kosiorek
2026-03-24 15:43:56 +01:00
parent b0a679f447
commit b84b64a8e1
+6 -12
View File
@@ -168,16 +168,10 @@ void EMFWriter::ImplPlusRecord( EmfPlusRecordType nType, sal_uInt16 nFlags )
void EMFWriter::WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSizeLog )
{
ImplBeginCommentRecord( WIN_EMR_COMMENT_EMFPLUS );
sal_Int32 nDPIX = rMtfSizePix.Width()*25;
sal_Int32 nDivX = rMtfSizeLog.Width()/100;
if (nDivX)
nDPIX /= nDivX; // DPI X
sal_Int32 nDPIY = rMtfSizePix.Height()*25;
sal_Int32 nDivY = rMtfSizeLog.Height()/100;
if (nDivY)
nDPIY /= nDivY; // DPI Y
const sal_Int32 nDivX = (rMtfSizeLog.Width() == 0) ? 1 : rMtfSizeLog.Width();
const sal_uInt32 nDPIX = basegfx::fround(static_cast<double>(rMtfSizePix.Width()) * 2540.0 / nDivX);
const sal_Int32 nDivY = (rMtfSizeLog.Height() == 0) ? 1 : rMtfSizeLog.Height();
const sal_uInt32 nDPIY = basegfx::fround(static_cast<double>(rMtfSizePix.Height()) * 2540.0 / nDivY);
m_rStm.WriteInt16( sal_Int16(EmfPlusRecordType::Header) );
m_rStm.WriteInt16( 0x01 ) // Flags - Dual Mode
@@ -185,8 +179,8 @@ void EMFWriter::WriteEMFPlusHeader( const Size &rMtfSizePix, const Size &rMtfSiz
.WriteInt32( 0x10 ) // Data Size
.WriteInt32( 0xdbc01002 ) // (lower 12bits) 1-> v1 2-> v1.1 // TODO: Check this
.WriteInt32( 0x01 ) // Video display
.WriteInt32( nDPIX )
.WriteInt32( nDPIY );
.WriteUInt32(nDPIX)
.WriteUInt32(nDPIY);
ImplEndCommentRecord();
// Write more properties