diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a58ce89a7b..7199486e91 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -100,6 +100,17 @@ jobs: - name: Checkout uses: actions/checkout@v4 + - name: Set up Python ${{ env.PYTHON_VERSION }} + uses: actions/setup-python@v4 + with: + python-version: "${{ env.PYTHON_VERSION }}" + + - name: Upgrade pip + run: pip install --upgrade pip + + - name: Install cairosvg dependency + run: pip install cairosvg + - name: Set up NodeJS ${{ env.NODE_VERSION }} uses: actions/setup-node@v4 with: diff --git a/Gulpfile.js b/Gulpfile.js index 9e0611dcc7..923e36301c 100644 --- a/Gulpfile.js +++ b/Gulpfile.js @@ -6,6 +6,7 @@ const { ESLint } = require('eslint') const gulp = require('gulp') const gulpif = require('gulp-if') const imagemin = require('gulp-imagemin') +const run = require('gulp-run') const options = require('gulp-options') const path = require('path') const postcss = require('gulp-postcss') @@ -200,6 +201,17 @@ function images() { .pipe(gulp.dest('dist/')) } +// Generate PNG versions of SVG smileys. +// Output files are not optimized for size. +function convertSmileysToPng() { + const pathToScript = 'scripts/convert_smileys_to_png.py' + const pathToSvgSmileys = 'assets/smileys/svg/' + const pathToPngSmileys = 'dist/smileys/png' + const convertToPng = run(`python ${pathToScript} ${pathToSvgSmileys} ${pathToPngSmileys}`) + convertToPng.exec() + return Promise.resolve('Smileys were converted') // to fit into gulp's asynchronous system +} + function spriteImages() { return gulp.src(['dist/images/sprite*.png']) .pipe(gulpif(!fast, imagemin())) // Minify the images @@ -239,7 +251,27 @@ function watch() { } // Build the front -const build = gulp.parallel(prepareZmd, prepareEasyMde, jsPackages, js, images, errors, gulp.series(spriteCss, gulp.parallel(cssPackages, css, spriteImages)), iconFonts, textFonts) +const build = gulp.series( + convertSmileysToPng, // automatically converted files may be overwritten with manually converted files afterwards + gulp.parallel( + prepareZmd, + prepareEasyMde, + jsPackages, + js, + images, + errors, + gulp.series( + spriteCss, + gulp.parallel( + cssPackages, + css, + spriteImages + ) + ), + iconFonts, + textFonts + ) +) exports.build = build exports.watch = gulp.series(build, watch) diff --git a/assets/smileys/png/ninja.png b/assets/smileys/png/ninja.png new file mode 100644 index 0000000000..10d7542973 Binary files /dev/null and b/assets/smileys/png/ninja.png differ diff --git a/package.json b/package.json index 7759db781e..2918cd6634 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "gulp-imagemin": "7.1.0", "gulp-options": "1.1.1", "gulp-postcss": "10.0.0", + "gulp-run": "1.7.1", "gulp-terser-js": "5.2.2", "gulp.spritesmith": "6.13.1", "jdenticon": "3.3.0", diff --git a/scripts/convert_smileys_to_png.py b/scripts/convert_smileys_to_png.py new file mode 100644 index 0000000000..a854f970da --- /dev/null +++ b/scripts/convert_smileys_to_png.py @@ -0,0 +1,57 @@ +""" +Convert smileys from SVG to PNG. + +In our codebase, the reference format for smileys is SVG. However, some epub readers cannot display SVGs, +and we have chosen to fall back to PNG so that images are displayed properly with most epub readers. +In order to avoid manual generation of PNG versions, we convert them automatically from the reference SVG files. + +This file provide tools to perform the conversion using a CLI interface. +It relies on cairosvg to perform the file conversion. +""" + +import argparse +import os +import pathlib + +import cairosvg + + +def convert_folder_to_png(src_folder: pathlib.Path, dst_folder: pathlib.Path) -> int: + """ + Convert all SVGs from src_folder into PNGs and write them in dst_folder. + Create dst_folder if needed. + Existing files in dst_folder are overwritten. + Return the number of converted files. + """ + src_files = src_folder.rglob("*.svg") + os.makedirs(dst_folder, exist_ok=True) + converted_file_count = 0 + for src_file in src_files: + dst_file = dst_folder / f"{src_file.stem}.png" + cairosvg.svg2png(url=src_file.as_posix(), write_to=dst_file.as_posix()) + converted_file_count += 1 + return converted_file_count + + +def get_cli_args(): + """Get arguments from the CLI.""" + + # Build parser + parser = argparse.ArgumentParser(description="Convert a folder of SVG files to PNG") + parser.add_argument("source", help="Folder containing the SVG files to be converted") + parser.add_argument("destination", help="Folder in which the PNG files are written") + + # Parse + raw_args = parser.parse_args() + processed_args = { + "source": pathlib.Path(raw_args.source), + "destination": pathlib.Path(raw_args.destination), + } + + return processed_args + + +if __name__ == "__main__": + args = get_cli_args() + file_count = convert_folder_to_png(args["source"], args["destination"]) + print(f"{__file__}: {file_count} files converted.")