Explorar o código

add script to generate PNG images of scores locally (npm run generatePNG) (#670)

part of #670

needs npm i, puppeteer is 100MB with chromium, alternative is puppeteer-core

eslint throws way too many warnings to be reasonable to fix for this script,
so for a build and commit eslint is foregone for now
sschmid %!s(int64=5) %!d(string=hai) anos
pai
achega
bf154e1a4b
Modificáronse 2 ficheiros con 120 adicións e 2 borrados
  1. 7 2
      package.json
  2. 113 0
      test/Util/generateDiffImagesPuppeteerLocalhost.js

+ 7 - 2
package.json

@@ -8,7 +8,7 @@
     "docs": "typedoc --out ./build/docs --name OpenSheetMusicDisplay --module commonjs --target ES5 --ignoreCompilerErrors --mode file ./src",
     "eslint": "eslint .",
     "tslint": "tslint --project tsconfig.json \"src/**/*.ts\" \"test/**/*.ts\"",
-    "lint": "npm-run-all eslint tslint",
+    "lint": "npm-run-all tslint",
     "test": "karma start --single-run --no-auto-watch",
     "test:watch": "karma start --no-single-run --auto-watch --browsers ChromeNoSecurity",
     "prepare": "npm run build",
@@ -18,10 +18,13 @@
     "build:webpack-dev": "webpack --progress --colors --config webpack.dev.js",
     "build:webpack-sourcemap": "webpack --progress --colors --config webpack.sourcemap.js",
     "start": "webpack-dev-server --progress --colors --config webpack.dev.js",
+    "generatePNG": "node ./test/Util/generateDiffImagesPuppeteerLocalhost.js ../../build ./data/images/current",
+    "generate:current": "node ./test/Util/generateDiffImages.js ../../build ./data/images/current",
+    "generate:blessed": "node ./test/Util/generateDiffImages.js ../../build ./data/images/blessed",
     "fix-memory-limit": "cross-env NODE_OPTIONS=--max_old_space_size=4096"
   },
   "pre-commit": [
-    "lint"
+    "tslint"
   ],
   "files": [
     "build/dist/src",
@@ -63,6 +66,7 @@
     "@types/node": "^13.1.0",
     "chai": "^4.1.0",
     "clean-webpack-plugin": "^1.0.1",
+    "cross-blob": "^1.2.0",
     "cross-env": "^7.0.0",
     "cz-conventional-changelog": "^3.0.0",
     "eslint": "^6.2.2",
@@ -85,6 +89,7 @@
     "mocha": "^7.0.1",
     "npm-run-all": "^4.1.2",
     "pre-commit": "^1.2.2",
+    "puppeteer": "^2.1.1",
     "ts-loader": "^4.1.0",
     "tslint": "^5.14.0",
     "tslint-loader": "^3.5.3",

+ 113 - 0
test/Util/generateDiffImagesPuppeteerLocalhost.js

@@ -0,0 +1,113 @@
+/*
+  Render each OSMD sample, grab the generated images, and
+  dump them into a local directory as PNG files.
+
+  inspired by Vexflow's generate_png_images and vexflow-tests.js
+
+  This is meant to be used with the visual regression test system in
+  `tools/visual_regression.sh`. (TODO)
+*/
+
+// function sleep(ms) {
+//     return new Promise((resolve) => {
+//       setTimeout(resolve, ms);
+//     });
+// }
+
+// main function
+async function init() {
+    console.log("init");
+
+    const fs = require('fs');
+    const [scriptDir, imageDir] = process.argv.slice(2, 4);
+    const sampleDir = './test/data/';
+
+    // Create the image directory if it doesn't exist.
+    fs.mkdirSync(imageDir, { recursive: true });
+
+    const samples = {
+        "Clementi, M. - Sonatina Op.36 No.1 Pt.1": "MuzioClementi_SonatinaOpus36No1_Part1.xml",
+        //"Hello World": "HelloWorld.xml",
+        // "Beethoven, L.v. - An die ferne Geliebte": "Beethoven_AnDieFerneGeliebte.xml",
+        // "Clementi, M. - Sonatina Op.36 No.1 Pt.2": "MuzioClementi_SonatinaOpus36No1_Part2.xml",
+    }
+    const sampleKeys = Object.keys(samples);
+    const sampleValues = Object.values(samples);
+
+    const puppeteer = require('puppeteer');
+    const browser = await puppeteer.launch({headless: true});
+    const page = await browser.newPage(); // TODO set width/height
+    const sampleFileName = sampleKeys[0]; // TODO for loop over samples / take filenames from script arguments
+    const sampleParameter = `&url=${sampleFileName}&endUrl`;
+    console.log("puppeteer: going to url");
+    await page.goto("http://localhost:8000/?showHeader=0&debugControls=0&backendType=canvas&pageBackgroundColor=FFFFFF" + sampleParameter, {waitUntil: 'networkidle2'});
+    console.log("goto done");
+
+    {
+        // fix navigation error
+        var response_event_occurred = false;
+        var response_handler = function(event){ response_event_occurred = true; };
+        
+        var response_watcher = new Promise(function(resolve, reject){
+            setTimeout(function(){
+            if (!response_event_occurred) {
+                resolve(true); 
+            } else {
+                setTimeout(function(){ resolve(true); }, 30000);
+            }
+            page.removeListener('response', response_handler);
+            }, 500);
+        });
+        
+        page.on('response', response_handler);
+
+        var navigation_watcher = page.waitForNavigation();
+
+        await Promise.race([response_watcher, navigation_watcher]);
+    }
+    console.log("navigation race done");
+
+    const getDataUrl = async () => {
+        return await page.evaluate(async () => {
+            return await new Promise(resolve => {
+                const canvasImage = document.getElementById("osmdCanvasVexFlowBackendCanvas");
+                var imageData = canvasImage.toDataURL();
+                // TODO fetch multiple pages from multiple OSMD backends
+                resolve(imageData);
+            })
+        })
+    }
+    const dataUrl = await getDataUrl();
+    //console.log("dataUrl: " + dataUrl);
+    const imageData = dataUrl.split(';base64,').pop();
+    const imageBuffer = Buffer.from(imageData, 'base64');
+
+    var fileName = `${imageDir}/${sampleFileName}.png`;
+    console.log("got image data, saving to: " + fileName);
+    fs.writeFileSync(fileName, imageBuffer, { encoding: 'base64' });
+
+    //const html = await page.content();
+    //console.log("page content: " + html);
+    browser.close();
+    console.log("puppeteer browser closed. exiting.");
+    return;
+}
+
+// function start() {
+//     // await (async () => {
+//     //     init();
+//     // });
+
+//     (async function(){
+//         await init();
+//         // more code here or the await is useless
+//     })();
+// }
+
+function resizeCanvas(elementId, width, height) {
+    $('#' + elementId).width(width);
+    $('#' + elementId).attr('width', width);
+    $('#' + elementId).attr('height', height);
+}
+
+init();