From ce8bbad26cce8b4b545dd4866ab8e4e6996ec262 Mon Sep 17 00:00:00 2001 From: Jaye Evins Date: Tue, 30 Dec 2025 00:33:17 -0500 Subject: [PATCH] Bypass Qt font metric calculations (#272) - This originally showed up as fonts rendering differently on X11 than Wayland. (#230) - Setting font size in points should be device and back end independent, however the same exact font face and size, on the same machine, sometimes results in different font metrics between the xcb and wayland Qt back ends. - Setting font size in pixels, assuming a virtual DPI of 96 pixels/inch, results in consistent font metrics and rendering between these back ends. Furthermore, this virtual DPI works for either on-screen or hi-res printer QPainter contexts. - This virtual DPI seems to work correctly with some limited testing with Windows and MacOS. - Add rendering tests to build-tests CI script. --- .github/workflows/build-tests.yml | 149 ++++++++++++++++-- glabels-batch/CMakeLists.txt | 2 +- glabels-batch/main.cpp | 3 +- glabels/main.cpp | 3 +- model/ModelTextObject.cpp | 31 +++- model/ModelTextObject.h | 2 +- test-data/simple-code39.glabels | 13 ++ test-data/simple-code39.pdf | Bin 0 -> 2742 bytes test-data/simple-shapes.glabels | 15 ++ test-data/simple-shapes.pdf | Bin 0 -> 3789 bytes test-data/simple-text-liberation-sans.glabels | 21 +++ test-data/simple-text-liberation-sans.pdf | Bin 0 -> 15670 bytes .../simple-text-liberation-serif.glabels | 72 +++++++++ test-data/simple-text-liberation-serif.pdf | Bin 0 -> 16476 bytes 14 files changed, 289 insertions(+), 22 deletions(-) create mode 100644 test-data/simple-code39.glabels create mode 100644 test-data/simple-code39.pdf create mode 100644 test-data/simple-shapes.glabels create mode 100644 test-data/simple-shapes.pdf create mode 100644 test-data/simple-text-liberation-sans.glabels create mode 100644 test-data/simple-text-liberation-sans.pdf create mode 100644 test-data/simple-text-liberation-serif.glabels create mode 100644 test-data/simple-text-liberation-serif.pdf diff --git a/.github/workflows/build-tests.yml b/.github/workflows/build-tests.yml index afd13d3..41713c1 100644 --- a/.github/workflows/build-tests.yml +++ b/.github/workflows/build-tests.yml @@ -23,23 +23,18 @@ jobs: matrix: include: - os: ubuntu-latest - build_type: Release c_compiler: gcc cpp_compiler: g++ - os: ubuntu-latest - build_type: Release c_compiler: clang cpp_compiler: clang++ - os: ubuntu-22.04 - build_type: Release c_compiler: gcc cpp_compiler: g++ - os: windows-latest - build_type: Release c_compiler: cl cpp_compiler: cl - os: macos-latest - build_type: Release c_compiler: clang cpp_compiler: clang++ @@ -105,7 +100,7 @@ jobs: with: version: '6.2.*' install-deps: 'true' - archives: 'qtbase qtsvg qttools icu qttranslations' + archives: 'qtbase qtsvg qttools icu qttranslations qtwayland' - name: Set reusable strings id: strings @@ -118,32 +113,162 @@ jobs: cmake -B ${{ steps.strings.outputs.build-output-dir }} -DCMAKE_CXX_COMPILER=${{ matrix.cpp_compiler }} -DCMAKE_C_COMPILER=${{ matrix.c_compiler }} - -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} + -DCMAKE_BUILD_TYPE=Release -DCMAKE_TOOLCHAIN_FILE=${{ env.TOOLCHAIN_FILE }} -S ${{ github.workspace }} - name: Build - run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config ${{ matrix.build_type }} + run: cmake --build ${{ steps.strings.outputs.build-output-dir }} --config Release - name: Test (Ubuntu) if: startsWith( matrix.os, 'ubuntu-' ) working-directory: ${{ steps.strings.outputs.build-output-dir }} run: | - xvfb-run ./glabels/glabels-qt --Version - xvfb-run ctest --build-config ${{ matrix.build_type }} + xvfb-run -a ./glabels/glabels-qt --Version + xvfb-run -a ctest --build-config Release - name: Test (Windows) if: startsWith( matrix.os, 'windows-' ) working-directory: ${{ steps.strings.outputs.build-output-dir }} + env: + QT_ASSUME_STDERR_HAS_CONSOLE: 1 run: | - ctest --build-config ${{ matrix.build_type }} + ./glabels-batch/Release/glabels-batch-qt --Version + ctest --build-config Release - name: Test (MacOS) if: startsWith( matrix.os, 'macos-' ) working-directory: ${{ steps.strings.outputs.build-output-dir }} run: | ./glabels/glabels-qt --Version - ctest --build-config ${{ matrix.build_type }} + ctest --build-config Release + + - name: Install render test dependencies (Ubuntu-latest) + if: startsWith( matrix.os, 'ubuntu-latest' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + run: | + sudo apt-get -y install xwayland-run + sudo apt-get -y install comparepdf + + - name: Install render test dependencies (Windows) + if: startsWith( matrix.os, 'windows' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + run: | + choco install diff-pdf + + - name: Install render test dependencies (MacOS) + if: startsWith( matrix.os, 'macos' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + run: | + brew install diff-pdf + + - name: Render tests (Ubuntu-latest) + if: startsWith( matrix.os, 'ubuntu-latest' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + shell: bash + env: + TEST_DIR: ${{ github.workspace }}/test-data + run: | + set +e + run-x() { xvfb-run -a "$@"; } + run-w() { wlheadless-run -c weston --log=/dev/null -- "$@"; } + # + # + echo "================" + echo "X11 render tests" + echo "================" + run-x ./glabels-batch/glabels-batch-qt --Version + # + # echo "-- Available fonts (X) -------------------------------------------------" + # run-x fc-list : family + # echo "------------------------------------------------------------------------" + # + echo "-----------------------------------" + run-x ./glabels-batch/glabels-batch-qt -o simple-shapes-x.pdf "$TEST_DIR/simple-shapes.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-shapes.pdf" simple-shapes-x.pdf + echo "-----------------------------------" + run-x ./glabels-batch/glabels-batch-qt -o simple-code39-x.pdf "$TEST_DIR/simple-code39.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-code39.pdf" simple-code39-x.pdf + echo "-----------------------------------" + run-x ./glabels-batch/glabels-batch-qt -o simple-text-liberation-sans-x.pdf "$TEST_DIR/simple-text-liberation-sans.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-text-liberation-sans.pdf" simple-text-liberation-sans-x.pdf + echo "-----------------------------------" + run-x ./glabels-batch/glabels-batch-qt -o simple-text-liberation-serif-x.pdf "$TEST_DIR/simple-text-liberation-serif.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-text-liberation-serif.pdf" simple-text-liberation-serif-x.pdf + echo "-----------------------------------" + # + # + echo "====================" + echo "Wayland render tests" + echo "====================" + run-w ./glabels-batch/glabels-batch-qt --Version + # + # echo "-- Available fonts (X) -------------------------------------------------" + # run-w fc-list : family + # echo "------------------------------------------------------------------------" + # + echo "-----------------------------------" + run-w ./glabels-batch/glabels-batch-qt -o simple-shapes-w.pdf "$TEST_DIR/simple-shapes.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-shapes.pdf" simple-shapes-w.pdf + echo "-----------------------------------" + run-w ./glabels-batch/glabels-batch-qt -o simple-code39-w.pdf "$TEST_DIR/simple-code39.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-code39.pdf" simple-code39-w.pdf + echo "-----------------------------------" + run-w ./glabels-batch/glabels-batch-qt -o simple-text-liberation-sans-w.pdf "$TEST_DIR/simple-text-liberation-sans.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-text-liberation-sans.pdf" simple-text-liberation-sans-w.pdf + echo "-----------------------------------" + run-w ./glabels-batch/glabels-batch-qt -o simple-text-liberation-serif-w.pdf "$TEST_DIR/simple-text-liberation-serif.glabels" + comparepdf -ca -v2 "$TEST_DIR/simple-text-liberation-serif.pdf" simple-text-liberation-serif-w.pdf + echo "-----------------------------------" + + - name: Render tests (Windows) + if: startsWith( matrix.os, 'windows' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + shell: pwsh + env: + TEST_DIR: ${{ github.workspace }}/test-data + QT_ASSUME_STDERR_HAS_CONSOLE: 1 + run: | + set +e + ./glabels-batch/Release/glabels-batch-qt --Version + echo "-----------------------------------" + ./glabels-batch/Release/glabels-batch-qt -o simple-shapes-windows.pdf "$env:TEST_DIR/simple-shapes.glabels" 2>&1 + diff-pdf -v "$env:TEST_DIR/simple-shapes.pdf" simple-shapes-windows.pdf 2>&1 + echo "-----------------------------------" + ./glabels-batch/Release/glabels-batch-qt -o simple-code39-windows.pdf "$env:TEST_DIR/simple-code39.glabels" 2>&1 + diff-pdf -v "$env:TEST_DIR/simple-code39.pdf" simple-code39-windows.pdf 2>&1 + echo "-----------------------------------" + # + # TODO: Create text-based rendering tests using fonts available on Windows + # + + - name: Render tests (MacOS) + if: startsWith( matrix.os, 'macos' ) + working-directory: ${{ steps.strings.outputs.build-output-dir }} + shell: bash + env: + TEST_DIR: ${{ github.workspace }}/test-data + run: | + set +e + ./glabels-batch/glabels-batch-qt --Version + echo "-----------------------------------" + ./glabels-batch/glabels-batch-qt -o simple-shapes-mac.pdf "$TEST_DIR/simple-shapes.glabels" + diff-pdf -v "$TEST_DIR/simple-shapes.pdf" simple-shapes-mac.pdf + echo "-----------------------------------" + ./glabels-batch/glabels-batch-qt -o simple-code39-mac.pdf "$TEST_DIR/simple-code39.glabels" + diff-pdf -v "$TEST_DIR/simple-code39.pdf" simple-code39-mac.pdf + echo "-----------------------------------" + # + # TODO: Create text-based rendering tests using fonts available on MacOS + # + + - name: Upload render tests for manual inspection + if: always() + uses: actions/upload-artifact@v4 + with: + name: render-tests-${{ matrix.os }}-${{ matrix.cpp_compiler }}-${{ github.run_number }} + path: ${{ steps.strings.outputs.build-output-dir }}/*.pdf + # - name: Tmate # uses: mxschmitt/action-tmate@v3 diff --git a/glabels-batch/CMakeLists.txt b/glabels-batch/CMakeLists.txt index c2abedc..691bf0b 100644 --- a/glabels-batch/CMakeLists.txt +++ b/glabels-batch/CMakeLists.txt @@ -10,7 +10,7 @@ set (glabels-batch_sources #===================================== # Target #===================================== -add_executable (glabels-batch-qt WIN32 +add_executable (glabels-batch-qt ${glabels-batch_sources} ) diff --git a/glabels-batch/main.cpp b/glabels-batch/main.cpp index a15df4e..ef1cb30 100644 --- a/glabels-batch/main.cpp +++ b/glabels-batch/main.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -151,7 +152,7 @@ int main( int argc, char **argv ) // Handle verbose version option if ( parser.isSet( "Version" ) ) { - qInfo().noquote() << glabels::model::Version::details(); + QTextStream(stdout) << glabels::model::Version::details() << Qt::endl; return 0; } diff --git a/glabels/main.cpp b/glabels/main.cpp index f25cafc..817a289 100644 --- a/glabels/main.cpp +++ b/glabels/main.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -92,7 +93,7 @@ int main( int argc, char **argv ) // Handle verbose version option if ( parser.isSet( "Version" ) ) { - qInfo().noquote() << glabels::model::Version::details(); + QTextStream(stdout) << glabels::model::Version::details() << Qt::endl; return 0; } diff --git a/model/ModelTextObject.cpp b/model/ModelTextObject.cpp index b3f61db..5b22f09 100644 --- a/model/ModelTextObject.cpp +++ b/model/ModelTextObject.cpp @@ -24,11 +24,31 @@ #include "Size.h" #include +#include #include #include #include #include -#include + + +// +// Private +// +namespace +{ + /// + /// Calculate pixel size + /// + /// Assume a virtual DPI of 96 pixels/inch for all QPainter contexts. + /// Ideally, we should use pointSizes for device independence, but as + /// Qt-6.4 on X11, Wayland, and MacOS this approach has better results. + /// + int pixelSize( double pointSize ) + { + const double virtual_dpi = 96; + return qMax( 1, qRound( pointSize * virtual_dpi/72.0 ) ); + } +} namespace glabels @@ -467,7 +487,7 @@ namespace glabels { QFont font; font.setFamily( mFontFamily ); - font.setPointSizeF( mFontSize ); + font.setPixelSize( pixelSize( mFontSize ) ); font.setWeight( mFontWeight ); font.setItalic( mFontItalicFlag ); font.setUnderline( mFontUnderlineFlag ); @@ -591,7 +611,7 @@ namespace glabels { QFont font; font.setFamily( mFontFamily ); - font.setPointSizeF( mFontSize ); + font.setPixelSize( pixelSize( mFontSize ) ); font.setWeight( mFontWeight ); font.setItalic( mFontItalicFlag ); font.setUnderline( mFontUnderlineFlag ); @@ -712,7 +732,7 @@ namespace glabels QFont font; font.setFamily( mFontFamily ); - font.setPointSizeF( mTextAutoShrink ? autoShrinkFontSize( record, variables ) : mFontSize ); + font.setPixelSize( pixelSize( mTextAutoShrink ? autoShrinkFontSize( record, variables ) : mFontSize ) ); font.setWeight( mFontWeight ); font.setItalic( mFontItalicFlag ); font.setUnderline( mFontUnderlineFlag ); @@ -816,7 +836,7 @@ namespace glabels double candidateSize = mFontSize; while ( candidateSize > 1.0 ) { - font.setPointSizeF( candidateSize ); + font.setPixelSize( pixelSize( candidateSize ) ); // Line spacing is affected by font size QFontMetricsF fontMetrics( font ); @@ -860,6 +880,5 @@ namespace glabels return candidateSize; } - } } diff --git a/model/ModelTextObject.h b/model/ModelTextObject.h index 514f8eb..edaef76 100644 --- a/model/ModelTextObject.h +++ b/model/ModelTextObject.h @@ -216,7 +216,7 @@ namespace glabels double autoShrinkFontSize( const merge::Record& record, const Variables& variables ) const; - + /////////////////////////////////////////////////////////////// // Private Members diff --git a/test-data/simple-code39.glabels b/test-data/simple-code39.glabels new file mode 100644 index 0000000..3c98e97 --- /dev/null +++ b/test-data/simple-code39.glabels @@ -0,0 +1,13 @@ + + + + + + + + diff --git a/test-data/simple-code39.pdf b/test-data/simple-code39.pdf new file mode 100644 index 0000000000000000000000000000000000000000..0a9385f1f1560cc5288d63f03fad35a1c1958cc8 GIT binary patch literal 2742 zcmZWr3p`Zo7I#Wcb`hu7jT~DsU7cgz4;)RG86!u^q2wH-X=Zzb*<);F95ZrBPu0}* z7(FN@(z}!*Q%wRg8~cc0ejE=%C&Ql&{xCocKm)n~ z-hhf;Wc|_zSit5Y=w7xnnMkIQ$mm6eg^$BSFG4SO9&&LmLerh^9vnNF)FWY-oK15AyYJ3)X|Ce}@6XiXj$3 z0%R02fdvZ?bQ%jXbQB1_P%IoL;-Q?JMjWmJ0gS#T5l5!p5I=(J2FHVen1fCtgkcK=$7+TZK@WE+BnU&oLB|n< zoQNp2&>(>mg`OcB;=z0fiyn)hpItN%zrS~Xncy|uEbZ?_n_e1pcE;T<3N~C~eoZKw zx5PYZqhYdScghU$kdN&ui=FEa%xn!P&88)4s_qMyyu1M?DMO_3n&{!DxtcpocU0;k zNm7FRLSx>m$koh>zKQ0&i3$5E>Qn{Kdz_MjD{>dlwn{m;*JIN&nj+(07hK(E-+iW< z6r4n*1SAR4NIv46L}n^y^#TRIq=R<1w2CRYcjWW_h^>wrOdaIE-}F#5%4+d9GZXML z%_KRQ^E^A^=J9OaJqX(+8Cbw%oo>o)YEadMR4=vg@d<&9x3FigER5vtsf&4)wIB8i zK9O}S7neWxFe`dU3!4r(KGdAnWQBZm`OKVi+93A27<49>$m)+Dk^J%kA{S1um{#AK zwvTUeNqXRYcH-2$fuT07*JhGyZ`P8`dfc<1)HRU`_Uhh&tM9r~mi|@wqn(wEr4;5} zP|xx^(L;Cgw>tix+4n5aVRfUp7@TwZ;R&;9%kJ~@Lk{hZiY~1_^v)>1JpE2h7Q!}7 zXBe)WcDmTLDcTbU%L@(`uuZ*}0yW8XRn5|^{2rg@fd|tHQJnA7mi268 zW+&wQRBdUL;dbs+dg|>%MfA3=e76dR*0MI-W?bcqJkZgwweh6r%$3Bf<`!IdkH3@u zftZ>}5@zn!xyAKth83R z>4!c#mrP(d(NjqFR#}D^yvlv$jhZV0M$o*f<6fH1fc}L#(8_0>lZO+PkGcedFVz$R zq3Lqx!VM<*qKEa{mQ;|M{r}|s)FLx;x@gmKW=#g|)X_k@zSi(fHa!7-PuQk)d3Axq zN7U0BE+WO{2k~KNC7A>Rq%ER(Meg`C?av(A2dmA}25z!J`%I5jgRW~&)u@@B{0 z8N!t3;X5+(NmsnW_gn7`9zOgV6)!VQkL0JU+9Nj;6y>p=`a)Hee5&p0%BAmDdG};D zOuzngSJ0jf=QR{4WbvVb+56 z?sr1H%QAKs(R%%N;#;V)x*VLWJ_q-19R=74&>}CW}70Ghd8H%EFo5rM8YZNL~)@zwS zM^#oAM;$mhXq+X^nlO9RKHoQFate1%JTW+@T)RlSMPt&gP21kh_|VOGT??14l}@CL zhK&i6K6O`H$~Ecj+R9(L8U4DyNNs6U+sE>X$=6tYVG!opm)~rhFlEdZw`rME3#KWH z2d|e6&(!YLnEa-;#OJ84)xru0=zyZ3P@r#W;qtZ8`4lW#DMgXK z=xN`7we|a67~Q_FtsiJhyVtD6UCB||-j%Cte;#~&wr}`m*o#p0;9cML|K-+wl#dNsibSW7^@@*mA$s*%p=(og-3dVOir~kBKp=p%1inBp zs;_VyDv%^pghepV4?;k+lVEc|!U`xJ0STVbXrtgZ`ecol^LP;y3J^gO2^dj*><-dt zGztw21;>0ORMmBF1YT z_k9j3_4{} + + + + + + + + + diff --git a/test-data/simple-shapes.pdf b/test-data/simple-shapes.pdf new file mode 100644 index 0000000000000000000000000000000000000000..42e637d91bad8659c5731c130bbd3d87a79c2ec2 GIT binary patch literal 3789 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 literal 0 HcmV?d00001 diff --git a/test-data/simple-text-liberation-sans.glabels b/test-data/simple-text-liberation-sans.glabels new file mode 100644 index 0000000..5664c29 --- /dev/null +++ b/test-data/simple-text-liberation-sans.glabels @@ -0,0 +1,21 @@ + + + + + +

Liberation Sans 10

+
+ +

Liberation Sans 12 Bold

+
+ +

Liberation Sans 14 Italic

+
+
+ +
diff --git a/test-data/simple-text-liberation-sans.pdf b/test-data/simple-text-liberation-sans.pdf new file mode 100644 index 0000000000000000000000000000000000000000..c99461f091c44479e98be9bdbbc8e18db31b6b58 GIT binary patch literal 15670 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 literal 0 HcmV?d00001 diff --git a/test-data/simple-text-liberation-serif.glabels b/test-data/simple-text-liberation-serif.glabels new file mode 100644 index 0000000..a70e7b1 --- /dev/null +++ b/test-data/simple-text-liberation-serif.glabels @@ -0,0 +1,72 @@ + + + + + +

Liberation Serif 10

+
+ +

Liberation Serif 12

+
+ +

Liberation Serif 14

+
+ +

Liberation Serif 20

+
+ +

Liberation Serif 24

+
+ +

Liberation Serif 10

+
+ +

Liberation Serif 12

+
+ +

Liberation Serif 14

+
+ +

Liberation Serif 20

+
+ +

Liberation Serif 24

+
+ +

Liberation Serif 10

+
+ +

Liberation Serif 12

+
+ +

Liberation Serif 14

+
+ +

Liberation Serif 20

+
+ +

Liberation Serif 24

+
+ +

Liberation Serif 10

+
+ +

Liberation Serif 12

+
+ +

Liberation Serif 20

+
+ +

Liberation Serif 24

+
+ +

Liberation Serif 14

+
+
+ +
diff --git a/test-data/simple-text-liberation-serif.pdf b/test-data/simple-text-liberation-serif.pdf new file mode 100644 index 0000000000000000000000000000000000000000..40ac2ad19cab37374689efd8d12dd10cf40eed94 GIT binary patch literal 16476 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