123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498 |
- import Blob from "cross-blob";
- import FS from "fs";
- import jsdom from "jsdom";
- import OSMD from "../../build/opensheetmusicdisplay.min.js";
- function sleep (ms) {
- return new Promise((resolve) => {
- setTimeout(resolve, ms);
- });
- }
- let [osmdBuildDir, sampleDir, imageDir, imageFormat, pageWidth, pageHeight, filterRegex, mode, debugSleepTimeString, skyBottomLinePreference] = process.argv.slice(2, 12);
- imageFormat = imageFormat?.toLowerCase();
- if (!osmdBuildDir || !sampleDir || !imageDir || (imageFormat !== "png" && imageFormat !== "svg")) {
- console.log("usage: " +
-
- "node test/Util/generateImages_browserless.mjs osmdBuildDir sampleDirectory imageDirectory svg|png [width|0] [height|0] [filterRegex|all|allSmall] [--debug|--osmdtesting] [debugSleepTime]");
- console.log(" (use pageWidth and pageHeight 0 to not divide the rendering into pages (endless page))");
- console.log(' (use "all" to skip filterRegex parameter. "allSmall" with --osmdtesting skips two huge OSMD samples that take forever to render)');
- console.log("example: node test/Util/generateImages_browserless.mjs ../../build ./test/data/ ./export png");
- console.log("Error: need osmdBuildDir, sampleDir, imageDir and svg|png arguments. Exiting.");
- process.exit(1);
- }
- let pageFormat;
- if (!mode) {
- mode = "";
- }
- async function init () {
- debug("init");
- const osmdTestingMode = mode.includes("osmdtesting");
- const osmdTestingSingleMode = mode.includes("osmdtestingsingle");
- const DEBUG = mode.startsWith("--debug");
-
- if (DEBUG) {
-
- const debugSleepTimeMs = Number.parseInt(debugSleepTimeString, 10);
- if (debugSleepTimeMs > 0) {
- debug("debug sleep time: " + debugSleepTimeString);
- await sleep(Number.parseInt(debugSleepTimeMs, 10));
-
-
- }
- }
- debug("sampleDir: " + sampleDir, DEBUG);
- debug("imageDir: " + imageDir, DEBUG);
- debug("imageFormat: " + imageFormat, DEBUG);
- pageFormat = "Endless";
- pageWidth = Number.parseInt(pageWidth, 10);
- pageHeight = Number.parseInt(pageHeight, 10);
- const endlessPage = !(pageHeight > 0 && pageWidth > 0);
- if (!endlessPage) {
- pageFormat = `${pageWidth}x${pageHeight}`;
- }
-
-
- const dom = new jsdom.JSDOM("<!DOCTYPE html></html>");
-
-
-
-
-
- global.window = dom.window;
-
- global.document = window.document;
-
- global.HTMLElement = window.HTMLElement;
- global.HTMLAnchorElement = window.HTMLAnchorElement;
- global.XMLHttpRequest = window.XMLHttpRequest;
- global.DOMParser = window.DOMParser;
- global.Node = window.Node;
- if (imageFormat === "png") {
- global.Canvas = window.Canvas;
- }
-
-
-
- try {
- const { default: headless_gl } = await import("gl");
- const oldCreateElement = document.createElement.bind(document);
- document.createElement = function (tagName, options) {
- if (tagName.toLowerCase() === "canvas") {
- const canvas = oldCreateElement(tagName, options);
- const oldGetContext = canvas.getContext.bind(canvas);
- canvas.getContext = function (contextType, contextAttributes) {
- if (contextType.toLowerCase() === "webgl" || contextType.toLowerCase() === "experimental-webgl") {
- const gl = headless_gl(canvas.width, canvas.height, contextAttributes);
- gl.canvas = canvas;
- return gl;
- } else {
- return oldGetContext(contextType, contextAttributes);
- }
- };
- return canvas;
- } else {
- return oldCreateElement(tagName, options);
- }
- };
- } catch {
- if (skyBottomLinePreference === "--webgl") {
- debug("WebGL image generation was requested but gl is not installed; using non-WebGL generation.");
- }
- }
-
- global.Blob = Blob;
- const div = document.createElement("div");
- div.id = "browserlessDiv";
- document.body.appendChild(div);
-
-
- const zoom = 1.0;
-
- let width = pageWidth * zoom;
-
- if (endlessPage) {
- width = 1440;
- }
- let height = pageHeight;
- if (endlessPage) {
- height = 32767;
- }
- div.width = width;
- div.height = height;
-
-
-
-
-
- div.setAttribute("width", width);
- div.setAttribute("height", height);
- div.setAttribute("offsetWidth", width);
-
-
-
- Object.defineProperties(window.HTMLElement.prototype, {
- offsetLeft: {
- get: function () { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
- },
- offsetTop: {
- get: function () { return parseFloat(window.getComputedStyle(this).marginTop) || 0; }
- },
- offsetHeight: {
- get: function () { return height; }
- },
- offsetWidth: {
- get: function () { return width; }
- }
- });
- debug("div.offsetWidth: " + div.offsetWidth, DEBUG);
- debug("div.height: " + div.height, DEBUG);
-
-
-
- FS.mkdirSync(imageDir, { recursive: true });
- const sampleDirFilenames = FS.readdirSync(sampleDir);
- let samplesToProcess = [];
- for (const sampleFilename of sampleDirFilenames) {
- if (osmdTestingMode && filterRegex === "allSmall") {
- if (sampleFilename.match("^(Actor)|(Gounod)")) {
- debug("filtering big file: " + sampleFilename, DEBUG);
- continue;
- }
- }
-
- if (sampleFilename.match("^.*(\.xml)|(\.musicxml)|(\.mxl)$")) {
-
- samplesToProcess.push(sampleFilename);
- } else {
- debug("discarded file/directory: " + sampleFilename, DEBUG);
- }
- }
-
- if (filterRegex && filterRegex !== "" && filterRegex !== "all" && !(osmdTestingMode && filterRegex === "allSmall")) {
- debug("filtering samples for regex: " + filterRegex, DEBUG);
- samplesToProcess = samplesToProcess.filter((filename) => filename.match(filterRegex));
- debug(`found ${samplesToProcess.length} matches: `, DEBUG);
- for (let i = 0; i < samplesToProcess.length; i++) {
- debug(samplesToProcess[i], DEBUG);
- }
- }
- const backend = imageFormat === "png" ? "canvas" : "svg";
- const osmdInstance = new OSMD.OpenSheetMusicDisplay(div, {
- autoResize: false,
- backend: backend,
- pageBackgroundColor: "#FFFFFF",
- pageFormat: pageFormat
-
-
- });
-
-
-
-
-
-
-
-
-
-
-
-
-
- if (DEBUG) {
- osmdInstance.setLogLevel("debug");
-
- debug(`osmd PageFormat idString: ${osmdInstance.EngravingRules.PageFormat.idString}`);
- debug("PageHeight: " + osmdInstance.EngravingRules.PageHeight);
- } else {
- osmdInstance.setLogLevel("info");
- }
- debug("[OSMD.generateImages] starting loop over samples, saving images to " + imageDir, DEBUG);
- for (let i = 0; i < samplesToProcess.length; i++) {
- const sampleFilename = samplesToProcess[i];
- debug("sampleFilename: " + sampleFilename, DEBUG);
- await generateSampleImage(sampleFilename, sampleDir, osmdInstance, osmdTestingMode, {}, DEBUG);
- if (osmdTestingMode && !osmdTestingSingleMode && sampleFilename.startsWith("Beethoven") && sampleFilename.includes("Geliebte")) {
-
- await generateSampleImage(sampleFilename, sampleDir, osmdInstance, osmdTestingMode, {skyBottomLine: true}, DEBUG);
-
- await generateSampleImage(sampleFilename, sampleDir, osmdInstance, osmdTestingMode, {boundingBoxes: "VexFlowGraphicalNote"}, DEBUG);
- }
- }
- debug("done, exiting.");
- }
- async function generateSampleImage (sampleFilename, directory, osmdInstance, osmdTestingMode,
- options = {}, DEBUG = false) {
- function makeSkyBottomLineOptions() {
- const preference = skyBottomLinePreference ?? "";
- if (preference === "--batch") {
- return {
- preferredSkyBottomLineBatchCalculatorBackend: 0,
- skyBottomLineBatchCriteria: 0,
- };
- } else if (preference === "--webgl") {
- return {
- preferredSkyBottomLineBatchCalculatorBackend: 1,
- skyBottomLineBatchCriteria: 0,
- };
- } else {
- return {
- preferredSkyBottomLineBatchCalculatorBackend: 0,
- skyBottomLineBatchCriteria: Infinity,
- };
- }
- }
- const samplePath = directory + "/" + sampleFilename;
- let loadParameter = FS.readFileSync(samplePath);
- if (sampleFilename.endsWith(".mxl")) {
- loadParameter = await OSMD.MXLHelper.MXLtoXMLstring(loadParameter);
- } else {
- loadParameter = loadParameter.toString();
- }
-
-
-
- let includeSkyBottomLine = false;
- let drawBoundingBoxString;
- let isTestOctaveShiftInvisibleInstrument;
- let isTestInvisibleMeasureNotAffectingLayout;
- if (osmdTestingMode) {
- const isFunctionTestAutobeam = sampleFilename.startsWith("OSMD_function_test_autobeam");
- const isFunctionTestAutoColoring = sampleFilename.startsWith("OSMD_function_test_auto-custom-coloring");
- const isFunctionTestSystemAndPageBreaks = sampleFilename.startsWith("OSMD_Function_Test_System_and_Page_Breaks");
- const isFunctionTestDrawingRange = sampleFilename.startsWith("OSMD_function_test_measuresToDraw_");
- const defaultOrCompactTightMode = sampleFilename.startsWith("OSMD_Function_Test_Container_height") ? "compacttight" : "default";
- const isTestFlatBeams = sampleFilename.startsWith("test_drum_tuplet_beams");
- const isTestEndClefStaffEntryBboxes = sampleFilename.startsWith("test_end_measure_clefs_staffentry_bbox");
- const isTestPageBreakImpliesSystemBreak = sampleFilename.startsWith("test_pagebreak_implies_systembreak");
- const isTestPageBottomMargin0 = sampleFilename.includes("PageBottomMargin0");
- const isTestTupletBracketTupletNumber = sampleFilename.includes("test_tuplet_bracket_tuplet_number");
- const isTestCajon2NoteSystem = sampleFilename.includes("test_cajon_2-note-system");
- isTestOctaveShiftInvisibleInstrument = sampleFilename.includes("test_octaveshift_first_instrument_invisible");
- const isTextOctaveShiftExtraGraphicalMeasure = sampleFilename.includes("test_octaveshift_extragraphicalmeasure");
- isTestInvisibleMeasureNotAffectingLayout = sampleFilename.includes("test_invisible_measure_not_affecting_layout");
- const isTestWedgeMultilineCrescendo = sampleFilename.includes("test_wedge_multiline_crescendo");
- const isTestWedgeMultilineDecrescendo = sampleFilename.includes("test_wedge_multiline_decrescendo");
- const isTestTabs4Strings = sampleFilename.includes("test_tabs_4_strings");
- osmdInstance.EngravingRules.loadDefaultValues();
- if (isTestEndClefStaffEntryBboxes) {
- drawBoundingBoxString = "VexFlowStaffEntry";
- } else {
- drawBoundingBoxString = options.boundingBoxes;
- }
- osmdInstance.setOptions({
- autoBeam: isFunctionTestAutobeam,
- coloringMode: isFunctionTestAutoColoring ? 2 : 0,
-
- coloringSetCustom: isFunctionTestAutoColoring ? ["#d82c6b", "#F89D15", "#FFE21A", "#4dbd5c", "#009D96", "#43469d", "#76429c", "#ff0000"] : undefined,
- colorStemsLikeNoteheads: isFunctionTestAutoColoring,
- drawingParameters: defaultOrCompactTightMode,
- drawFromMeasureNumber: isFunctionTestDrawingRange ? 9 : 1,
- drawUpToMeasureNumber: isFunctionTestDrawingRange ? 12 : Number.MAX_SAFE_INTEGER,
- newSystemFromXML: isFunctionTestSystemAndPageBreaks,
- newSystemFromNewPageInXML: isTestPageBreakImpliesSystemBreak,
- newPageFromXML: isFunctionTestSystemAndPageBreaks,
- pageBackgroundColor: "#FFFFFF",
- pageFormat: pageFormat,
- ...makeSkyBottomLineOptions()
- });
-
-
- osmdInstance.EngravingRules.AlwaysSetPreferredSkyBottomLineBackendAutomatically = false;
- includeSkyBottomLine = options.skyBottomLine ? options.skyBottomLine : false;
- osmdInstance.drawSkyLine = includeSkyBottomLine;
- osmdInstance.drawBottomLine = includeSkyBottomLine;
- osmdInstance.setDrawBoundingBox(drawBoundingBoxString, false);
- if (isTestFlatBeams) {
- osmdInstance.EngravingRules.FlatBeams = true;
-
- osmdInstance.EngravingRules.FlatBeamOffset = 10;
- osmdInstance.EngravingRules.FlatBeamOffsetPerBeam = 10;
- } else {
- osmdInstance.EngravingRules.FlatBeams = false;
- }
- if (isTestPageBottomMargin0) {
- osmdInstance.EngravingRules.PageBottomMargin = 0;
- }
- if (isTestTupletBracketTupletNumber) {
- osmdInstance.EngravingRules.TupletNumberLimitConsecutiveRepetitions = true;
- osmdInstance.EngravingRules.TupletNumberMaxConsecutiveRepetitions = 2;
- osmdInstance.EngravingRules.TupletNumberAlwaysDisableAfterFirstMax = true;
- }
- if (isTestCajon2NoteSystem) {
- osmdInstance.EngravingRules.PercussionUseCajon2NoteSystem = true;
- }
- if (isTextOctaveShiftExtraGraphicalMeasure ||
- isTestOctaveShiftInvisibleInstrument ||
- isTestWedgeMultilineCrescendo ||
- isTestWedgeMultilineDecrescendo) {
- osmdInstance.EngravingRules.NewSystemAtXMLNewSystemAttribute = true;
- }
- if (isTestTabs4Strings) {
- osmdInstance.EngravingRules.TabKeySignatureSpacingAdded = false;
- osmdInstance.EngravingRules.TabTimeSignatureSpacingAdded = false;
-
- }
- }
- try {
- debug("loading sample " + sampleFilename, DEBUG);
- await osmdInstance.load(loadParameter, sampleFilename);
- if (isTestOctaveShiftInvisibleInstrument) {
- osmdInstance.Sheet.Instruments[0].Visible = false;
- }
- if (isTestInvisibleMeasureNotAffectingLayout) {
- if (osmdInstance.Sheet.Instruments[1]) {
- osmdInstance.Sheet.Instruments[1].Visible = false;
- }
- }
- } catch (ex) {
- debug("couldn't load sample " + sampleFilename + ", skipping. Error: \n" + ex);
- return;
- }
- debug("xml loaded", DEBUG);
- try {
- osmdInstance.render();
-
- } catch (ex) {
- debug("renderError: " + ex);
- }
- debug("rendered", DEBUG);
- const markupStrings = [];
- const dataUrls = [];
- let canvasImage;
- for (let pageNumber = 1; pageNumber < Number.POSITIVE_INFINITY; pageNumber++) {
- if (imageFormat === "png") {
- canvasImage = document.getElementById("osmdCanvasVexFlowBackendCanvas" + pageNumber);
- if (!canvasImage) {
- break;
- }
- if (!canvasImage.toDataURL) {
- debug(`error: could not get canvas image for page ${pageNumber} for file: ${sampleFilename}`);
- break;
- }
- dataUrls.push(canvasImage.toDataURL());
- } else if (imageFormat === "svg") {
- const svgElement = document.getElementById("osmdSvgPage" + pageNumber);
- if (!svgElement) {
- break;
- }
-
- svgElement.setAttribute("xmlns", "http://www.w3.org/2000/svg");
- markupStrings.push(svgElement.outerHTML);
- }
- }
- for (let pageIndex = 0; pageIndex < Math.max(dataUrls.length, markupStrings.length); pageIndex++) {
- const pageNumberingString = `${pageIndex + 1}`;
- const skybottomlineString = includeSkyBottomLine ? "skybottomline_" : "";
- const graphicalNoteBboxesString = drawBoundingBoxString ? "bbox" + drawBoundingBoxString + "_" : "";
-
- const pageFilename = `${imageDir}/${sampleFilename}_${skybottomlineString}${graphicalNoteBboxesString}${pageNumberingString}.${imageFormat}`;
- if (imageFormat === "png") {
- const dataUrl = dataUrls[pageIndex];
- if (!dataUrl || !dataUrl.split) {
- debug(`error: could not get dataUrl (imageData) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
- continue;
- }
- const imageData = dataUrl.split(";base64,").pop();
- const imageBuffer = Buffer.from(imageData, "base64");
- debug("got image data, saving to: " + pageFilename, DEBUG);
- FS.writeFileSync(pageFilename, imageBuffer, { encoding: "base64" });
- } else if (imageFormat === "svg") {
- const markup = markupStrings[pageIndex];
- if (!markup) {
- debug(`error: could not get markup (SVG data) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
- continue;
- }
- debug("got svg markup data, saving to: " + pageFilename, DEBUG);
- FS.writeFileSync(pageFilename, markup, { encoding: "utf-8" });
- }
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
-
- }
- function debug (msg, debugEnabled = true) {
- if (debugEnabled) {
- console.log("[generateImages] " + msg);
- }
- }
- init();
|