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 0000000..0a9385f Binary files /dev/null and b/test-data/simple-code39.pdf differ diff --git a/test-data/simple-shapes.glabels b/test-data/simple-shapes.glabels new file mode 100644 index 0000000..1ffce14 --- /dev/null +++ b/test-data/simple-shapes.glabels @@ -0,0 +1,15 @@ + + + + + + + + + + diff --git a/test-data/simple-shapes.pdf b/test-data/simple-shapes.pdf new file mode 100644 index 0000000..42e637d Binary files /dev/null and b/test-data/simple-shapes.pdf differ 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 0000000..c99461f Binary files /dev/null and b/test-data/simple-text-liberation-sans.pdf differ 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 0000000..40ac2ad Binary files /dev/null and b/test-data/simple-text-liberation-serif.pdf differ