Переглянути джерело

merge osmd-public (needs npm install again for type updates)

mostly refactors (improved vexflow types so less `any` is needed), some bug fixes
sschmidTU 2 роки тому
батько
коміт
ad22c77d27

+ 1 - 1
package.json

@@ -69,7 +69,7 @@
   },
   "homepage": "http://opensheetmusicdisplay.org",
   "dependencies": {
-    "@types/vexflow": "^1.2.37",
+    "@types/vexflow": "^1.2.38",
     "d-path-parser": "^1.0.0",
     "jszip": "3.7.1",
     "loglevel": "^1.8.0",

+ 1 - 1
src/MusicalScore/Graphical/GraphicalMusicSheet.ts

@@ -973,7 +973,7 @@ export class GraphicalMusicSheet {
         }
         const graphicalMeasure: GraphicalMeasure = sourceStaffEntry.VerticalContainerParent.ParentMeasure.VerticalMeasureList
             [sourceStaffEntry.ParentStaff.idInMusicSheet];
-        return graphicalMeasure.findGraphicalStaffEntryFromTimestamp(sourceStaffEntry.Timestamp);
+        return graphicalMeasure?.findGraphicalStaffEntryFromTimestamp(sourceStaffEntry.Timestamp);
     }
 
     private CalculateDistance(pt1: PointF2D, pt2: PointF2D): number {

+ 3 - 1
src/MusicalScore/Graphical/PlainSkyBottomLineBatchCalculatorBackend.ts

@@ -1,3 +1,5 @@
+import Vex from "vexflow";
+import VF = Vex.Flow;
 import { EngravingRules } from "./EngravingRules";
 import { VexFlowMeasure } from "./VexFlow/VexFlowMeasure";
 import { SkyBottomLineCalculationResult } from "./SkyBottomLineCalculationResult";
@@ -30,7 +32,7 @@ export class PlainSkyBottomLineBatchCalculatorBackend extends SkyBottomLineBatch
 
     protected calculateFromCanvas(
         canvas: HTMLCanvasElement,
-        vexFlowContext: Vex.Flow.CanvasContext,
+        vexFlowContext: VF.CanvasContext,
         measures: VexFlowMeasure[],
         samplingUnit: number,
         tableConfiguration: ISkyBottomLineBatchCalculatorBackendTableConfiguration

+ 5 - 3
src/MusicalScore/Graphical/SkyBottomLineBatchCalculatorBackend.ts

@@ -1,3 +1,5 @@
+import Vex from "vexflow";
+import VF = Vex.Flow;
 import { EngravingRules } from "./EngravingRules";
 import { SkyBottomLineCalculationResult } from "./SkyBottomLineCalculationResult";
 import { CanvasVexFlowBackend } from "./VexFlow/CanvasVexFlowBackend";
@@ -117,7 +119,7 @@ export abstract class SkyBottomLineBatchCalculatorBackend {
      */
     protected abstract calculateFromCanvas(
         canvas: HTMLCanvasElement,
-        context: Vex.Flow.CanvasContext,
+        context: VF.CanvasContext,
         measures: VexFlowMeasure[],
         samplingUnit: number,
         tableConfiguration: ISkyBottomLineBatchCalculatorBackendTableConfiguration
@@ -133,7 +135,7 @@ export abstract class SkyBottomLineBatchCalculatorBackend {
         const elementHeight: number = this.elementHeight;
         const numElementsPerTable: number = numColumns * numRows;
 
-        const vexFlowContext: Vex.Flow.CanvasContext = this.canvas.getContext();
+        const vexFlowContext: VF.CanvasContext = this.canvas.getContext();
         const context: CanvasRenderingContext2D = vexFlowContext as unknown as CanvasRenderingContext2D;
         const canvasElement: HTMLCanvasElement = this.canvas.getCanvas() as HTMLCanvasElement;
 
@@ -149,7 +151,7 @@ export abstract class SkyBottomLineBatchCalculatorBackend {
 
             for (let j: number = 0; j < measures.length; ++j) {
                 const measure: VexFlowMeasure = measures[j];
-                const vsStaff: Vex.Flow.Stave = measure.getVFStave();
+                const vsStaff: VF.Stave = measure.getVFStave();
 
                 // (u, v) is the position of measure in the table
                 const u: number = j % numColumns;

+ 35 - 36
src/MusicalScore/Graphical/VexFlow/VexFlowMeasure.ts

@@ -13,7 +13,6 @@ import {VexFlowStaffEntry} from "./VexFlowStaffEntry";
 import {Beam} from "../../VoiceData/Beam";
 import {GraphicalNote} from "../GraphicalNote";
 import {GraphicalStaffEntry} from "../GraphicalStaffEntry";
-import StaveConnector = VF.StaveConnector;
 import StaveNote = VF.StaveNote;
 import StemmableNote = VF.StemmableNote;
 import NoteSubGroup = VF.NoteSubGroup;
@@ -41,7 +40,7 @@ import { GraphicalTie } from "../GraphicalTie";
 // type StemmableNote = VF.StemmableNote;
 
 export class VexFlowMeasure extends GraphicalMeasure {
-    constructor(staff: Staff, sourceMeasure: SourceMeasure = undefined, staffLine: StaffLine = undefined) {
+    constructor(staff: Staff, sourceMeasure?: SourceMeasure, staffLine?: StaffLine) {
         super(staff, sourceMeasure, staffLine);
         this.minimumStaffEntriesWidth = -1;
 
@@ -54,6 +53,8 @@ export class VexFlowMeasure extends GraphicalMeasure {
             this.rules = staffLine.ParentMusicSystem.rules;
         } else if (sourceMeasure) {
             this.rules = sourceMeasure.Rules;
+        } else {
+            this.rules = new EngravingRules();
         }
 
         this.resetLayout();
@@ -65,23 +66,23 @@ export class VexFlowMeasure extends GraphicalMeasure {
     /** The VexFlow Voices in the measure */
     public vfVoices: { [voiceID: number]: VF.Voice } = {};
     /** Call this function (if present) to x-format all the voices in the measure */
-    public formatVoices: (width: number, parent: VexFlowMeasure) => void;
+    public formatVoices?: (width: number, parent: VexFlowMeasure) => void;
     /** The VexFlow Ties in the measure */
     public vfTies: VF.StaveTie[] = [];
     /** The repetition instructions given as words or symbols (coda, dal segno..) */
     public vfRepetitionWords: VF.Repetition[] = [];
     /** The VexFlow Stave (= one measure in a staffline) */
-    protected stave: VF.Stave;
+    protected stave!: VF.Stave;
     /** VexFlow StaveConnectors (vertical lines) */
     protected connectors: VF.StaveConnector[] = [];
     /** Intermediate object to construct beams */
-    private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]][] } = {};
+    private beams: { [voiceID: number]: [Beam, VexFlowVoiceEntry[]] [] } = {};
     /** Beams created by (optional) autoBeam function. */
-    private autoVfBeams: VF.Beam[];
+    private autoVfBeams: VF.Beam[] = [];
     /** Beams of tuplet notes created by (optional) autoBeam function. */
-    private autoTupletVfBeams: VF.Beam[];
+    private autoTupletVfBeams: VF.Beam[] = [];
     /** VexFlow Beams */
-    private vfbeams: { [voiceID: number]: VF.Beam[] };
+    private vfbeams: { [voiceID: number]: VF.Beam[] } = {};
     /** Intermediate object to construct tuplets */
     protected tuplets: { [voiceID: number]: [Tuplet, VexFlowVoiceEntry[]][] } = {};
     /** VexFlow Tuplets */
@@ -187,14 +188,14 @@ export class VexFlowMeasure extends GraphicalMeasure {
     public setLineNumber(lineNumber: number): void {
         if (lineNumber !== 5) {
             if (lineNumber === 0) {
-                (this.stave as any).setNumLines(0);
+                this.stave.setNumLines(0);
                 this.stave.getBottomLineY = function(): number {
                     return this.getYForLine(this.options.num_lines);
                 };
             } else if (lineNumber === 1) {
                 // VF.Stave.setNumLines hides all but the top line.
                 // this is better
-                (this.stave.options as any).line_config = [
+                this.stave.options.line_config = [
                     { visible: false },
                     { visible: false },
                     { visible: true }, // show middle
@@ -208,7 +209,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 //lines (which isn't this case here)
                 //this.stave.options.num_lines = parseInt(lines, 10);
             } else if (lineNumber === 2) {
-                (this.stave.options as any).line_config = [
+                this.stave.options.line_config = [
                     { visible: false },
                     { visible: false },
                     { visible: true }, // show middle
@@ -219,7 +220,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                     return this.getYForLine(3);
                 };
             } else if (lineNumber === 3) {
-                (this.stave.options as any).line_config = [
+                this.stave.options.line_config = [
                     { visible: false },
                     { visible: true },
                     { visible: true }, // show middle
@@ -230,7 +231,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                     return this.getYForLine(2);
                 };
             } else {
-                (this.stave as any).setNumLines(lineNumber);
+                this.stave.setNumLines(lineNumber);
                 this.stave.getBottomLineY = function(): number {
                     return this.getYForLine(this.options.num_lines);
                 };
@@ -270,7 +271,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
         );
         if (!this.ShowTimeSignature) {
             // extends Element is missing from class StaveModifier in DefinitelyTyped definitions, so setStyle isn't found
-            (timeSig as any).setStyle({ fillStyle: "#00000000"}); // transparent. requires VexflowPatch
+            timeSig.setStyle({ fillStyle: "#00000000"}); // transparent. requires VexflowPatch
         }
         this.updateInstructionWidth();
     }
@@ -282,7 +283,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
      */
     public addClefAtEnd(clef: ClefInstruction, visible: boolean = true): void {
         const vfclef: { type: string, size: string, annotation: string } = VexFlowConverter.Clef(clef, "small");
-        if (!visible && (this.stave as any).endClef) {
+        if (!visible && this.stave.endClef) {
             return; // don't overwrite existing clef with invisible clef
         }
         this.stave.setEndClef(vfclef.type, vfclef.size, vfclef.annotation);
@@ -292,25 +293,25 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 if (modifier.getCategory() === "clefs" && modifier.getPosition() === VF.StaveModifier.Position.END) {
                     if ((modifier as any).type === vfclef.type) { // any = VF.Clef
                         const transparentStyle: string = "#12345600";
-                        const originalStyle: any = (modifier as any).getStyle();
+                        const originalStyle: any = modifier.getStyle();
                         if (originalStyle) {
                             (modifier as any).originalStrokeStyle = originalStyle.strokeStyle;
                             (modifier as any).originalFillStyle = originalStyle.fillStyle;
                         }
-                        (modifier as any).setStyle({strokeStyle: transparentStyle, fillStyle: transparentStyle});
+                        modifier.setStyle({strokeStyle: transparentStyle, fillStyle: transparentStyle});
                     }
                 }
             } else {
                 // reset invisible style
                 const originalStrokeStyle: any = (modifier as any).originalStrokeStyle;
                 const originalFillStyle: any = (modifier as any).originalFillStyle;
-                if ((modifier as any).getStyle()) {
+                if (modifier.getStyle()) {
                     if (originalStrokeStyle && originalFillStyle) {
-                        ((modifier as any).getStyle() as any).strokeStyle = originalStrokeStyle;
-                        ((modifier as any).getStyle() as any).fillStyle = originalFillStyle;
+                        modifier.getStyle().strokeStyle = originalStrokeStyle;
+                        modifier.getStyle().fillStyle = originalFillStyle;
                     } else {
-                        ((modifier as any).getStyle() as any).strokeStyle = null;
-                        ((modifier as any).getStyle() as any).fillStyle = null;
+                        modifier.getStyle().strokeStyle = null;
+                        modifier.getStyle().fillStyle = null;
                     }
                 }
             }
@@ -400,18 +401,16 @@ export class VexFlowMeasure extends GraphicalMeasure {
     public addMeasureNumber(): void {
         const text: string = this.MeasureNumber.toString();
         const position: number = StavePositionEnum.ABOVE;  //VF.StaveModifier.Position.ABOVE;
-        const options: any = {
+        this.stave.setText(text, position, {
             justification: 1,
             shift_x: 0,
             shift_y: 0,
-          };
-
-        this.stave.setText(text, position, options);
+          });
     }
 
     public addWordRepetition(repetitionInstruction: RepetitionInstruction): void {
-        let instruction: VF.Repetition.type = undefined;
-        let position: any = VF.StaveModifier.Position.END;
+        let instruction: number | undefined;
+        let position: number = VF.StaveModifier.Position.END;
         const xShift: number = this.beginInstructionsWidth;
         switch (repetitionInstruction.type) {
           case RepetitionInstructionEnum.Segno:
@@ -694,7 +693,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                     } else {
                         relPosY += 0.5; // center-align bbox
                     }
-                    const line: any = -gNote.notehead(vfnote).line; // vexflow y direction is opposite of osmd's
+                    const line: number = -gNote.notehead(vfnote).line; // vexflow y direction is opposite of osmd's
                     relPosY += line + (gNote.parentVoiceEntry.notes.last() as VexFlowGraphicalNote).notehead().line; // don't move for first note: - (-vexline)
                     gNote.PositionAndShape.RelativePosition.y = relPosY;
                 }
@@ -742,7 +741,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
      * @param voice the voice for which the ghost notes shall be searched.
      */
     protected getRestFilledVexFlowStaveNotesPerVoice(voice: Voice): GraphicalVoiceEntry[] {
-        let latestVoiceTimestamp: Fraction = undefined;
+        let latestVoiceTimestamp: Fraction;
         let gvEntries: GraphicalVoiceEntry[] = this.getGraphicalVoiceEntriesPerVoice(voice);
         for (let idx: number = 0; idx < gvEntries.length; idx++) {
             const gve: GraphicalVoiceEntry = gvEntries[idx];
@@ -908,7 +907,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                     let beamColor: string;
                     const stemColors: string[] = [];
                     for (const entry of voiceEntries) {
-                        const note: VF.StaveNote = ((<VexFlowVoiceEntry>entry).vfStaveNote as StaveNote);
+                        const note: VF.StaveNote = entry.vfStaveNote as StaveNote;
                         if (note) {
                           notes.push(note);
                           beamedNotes.push(note);
@@ -1113,7 +1112,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
      * Complete the creation of VexFlow Tuplets in this measure
      */
     public finalizeTuplets(): void {
-        // The following line resets the created Vex.Flow Tuplets and
+        // The following line resets the created VF Tuplets and
         // created them brand new. Is this needed? And more importantly,
         // should the old tuplets be removed manually from the notes?
         this.vftuplets = {};
@@ -1257,7 +1256,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 }
 
                 const vexFlowVoiceEntry: VexFlowVoiceEntry = voiceEntry as VexFlowVoiceEntry;
-                if ((vexFlowVoiceEntry.vfStaveNote as any).ticks.denominator === 0) {
+                if (vexFlowVoiceEntry.vfStaveNote.getTicks().denominator === 0) {
                     continue; // TODO not sure why the ticks aren't calculated correctly, see #1073
                     // if denominator === 0, addTickable() below goes into an infinite loop.
                 }
@@ -1472,7 +1471,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                     fretFinger.setOffsetY(offsetYSign * (ordering + shiftCount) * perFingeringShift);
                 } else if (!this.rules.FingeringInsideStafflines) { // use StringNumber for placement above/below stafflines
                     const stringNumber: VF.StringNumber = new VF.StringNumber(fingering.value);
-                    (<any>stringNumber).radius = 0; // hack to remove the circle around the number
+                    stringNumber.radius = 0; // hack to remove the circle around the number
                     stringNumber.setPosition(modifierPosition);
                     stringNumber.setOffsetY(offsetYSign * ordering * stringNumber.getWidth() * 2 / 3);
                     // Vexflow made a mess with the addModifier signature that changes through each class so we just cast to any :(
@@ -1525,7 +1524,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
                 // Remove circle from string number. Not needed for
                 // disambiguation from fingerings since we use Roman
                 // Numerals for RenderStringNumbersClassical
-                (<any>vfStringNumber).radius = 0;
+                vfStringNumber.radius = 0;
                 const offsetY: number = -this.rules.StringNumberOffsetY;
                 // if (note.sourceNote.halfTone < 50) { // place string number a little higher for notes with ledger lines below staff
                 //     // TODO also check for treble clef (adjust for viola, cello, etc)
@@ -1550,7 +1549,7 @@ export class VexFlowMeasure extends GraphicalMeasure {
      * @param lineType
      */
     public lineTo(top: VexFlowMeasure, lineType: any): void {
-        const connector: StaveConnector = new VF.StaveConnector(top.getVFStave(), this.stave);
+        const connector: VF.StaveConnector = new VF.StaveConnector(top.getVFStave(), this.stave);
         connector.setType(lineType);
         this.connectors.push(connector);
     }

+ 3 - 1
src/MusicalScore/Graphical/WebGLSkyBottomLineBatchCalculatorBackend.ts

@@ -1,3 +1,5 @@
+import Vex from "vexflow";
+import VF = Vex.Flow;
 import { EngravingRules } from "./EngravingRules";
 import { VexFlowMeasure } from "./VexFlow/VexFlowMeasure";
 import { SkyBottomLineCalculationResult } from "./SkyBottomLineCalculationResult";
@@ -167,7 +169,7 @@ export class WebGLSkyBottomLineBatchCalculatorBackend extends SkyBottomLineBatch
 
     protected calculateFromCanvas(
         canvas: HTMLCanvasElement,
-        _: Vex.Flow.CanvasContext,
+        _: VF.CanvasContext,
         measures: VexFlowMeasure[],
         samplingUnit: number,
         tableConfiguration: ISkyBottomLineBatchCalculatorBackendTableConfiguration

+ 2 - 1
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -167,8 +167,9 @@ export class OpenSheetMusicDisplay {
     /**
      * Load a MusicXML file
      * @param content is either the url of a file, or the root node of a MusicXML document, or the string content of a .xml/.mxl file
+     * @param tempTitle is used as the title for the piece if there is no title in the XML.
      */
-    public load(content: string | Document, comments?: (string|Document)[]): Promise<{}> {
+    public load(content: string | Document, tempTitle: string = "Untitled Score"): Promise<{}> {
         // Warning! This function is asynchronous! No error handling is done here.
         this.reset();
 

+ 7 - 4
src/VexFlowPatch/src/stavesection.js

@@ -35,19 +35,22 @@ export class StaveSection extends StaveModifier {
     ctx.setFont(this.font.family, this.font.size, this.font.weight);
     const text_measurements = ctx.measureText('' + this.section);
     const text_width = text_measurements.width;
-    const text_height = text_measurements.height;
+    let text_height = text_measurements.height;
+    if (!text_height) {
+      text_height = text_measurements.emHeightAscent + 2; // node canvas / generateImages fix
+    }
     let width = text_width + 6;  // add left & right padding
     if (width < 18) width = 18;
-    const height = text_height;
+    const height = text_height + this.font.size / 10; // font.size / 10: padding
     //  Seems to be a good default y
-    const y = stave.getYForTopText(3) + this.shift_y;
+    const y = stave.getYForTopText(3) + 19 - (height * 1.15) + this.shift_y;
     let x = this.x + shift_x;
     ctx.beginPath();
     ctx.lineWidth = 2;
     ctx.rect(x, y + text_height/4, width, height);
     ctx.stroke();
     x += (width - text_width) / 2;
-    ctx.fillText('' + this.section, x, y + 16);
+    ctx.fillText('' + this.section, x, y + height );
     ctx.restore();
     return this;
   }

+ 23 - 22
test/Util/generateImages_browserless.mjs

@@ -57,17 +57,17 @@ if (imageFormat !== "svg") {
 // eslint-disable-next-line @typescript-eslint/no-var-requires
 
 async function init () {
-    console.log("[OSMD.generateImages] init");
+    debug("init");
 
     const osmdTestingMode = mode.includes("osmdtesting"); // can also be --debugosmdtesting
     const osmdTestingSingleMode = mode.includes("osmdtestingsingle");
     const DEBUG = mode.startsWith("--debug");
     // const debugSleepTime = Number.parseInt(process.env.GENERATE_DEBUG_SLEEP_TIME) || 0; // 5000 works for me [sschmidTU]
     if (DEBUG) {
-        // console.log(' (note that --debug slows down the script by about 0.3s per file, through logging)')
+        // debug(' (note that --debug slows down the script by about 0.3s per file, through logging)')
         const debugSleepTimeMs = Number.parseInt(debugSleepTimeString, 10);
         if (debugSleepTimeMs > 0) {
-            console.log("debug sleep time: " + debugSleepTimeString);
+            debug("debug sleep time: " + debugSleepTimeString);
             await sleep(Number.parseInt(debugSleepTimeMs, 10));
             // [VSCode] apparently this is necessary for the debugger to attach itself in time before the program closes.
             // sometimes this is not enough, so you may have to try multiple times or increase the sleep timer. Unfortunately debugging nodejs isn't easy.
@@ -133,7 +133,7 @@ async function init () {
         };
     } catch {
         if (skyBottomLinePreference === "--webgl") {
-            console.log("WebGL image generation was requested but gl is not installed; using non-WebGL generation.");
+            debug("WebGL image generation was requested but gl is not installed; using non-WebGL generation.");
         }
     }
 
@@ -205,7 +205,7 @@ async function init () {
         }
         // eslint-disable-next-line no-useless-escape
         if (sampleFilename.match("^.*(\.xml)|(\.musicxml)|(\.mxl)$")) {
-            // console.log('found musicxml/mxl: ' + sampleFilename)
+            // debug('found musicxml/mxl: ' + sampleFilename)
             samplesToProcess.push(sampleFilename);
         } else {
             debug("discarded file/directory: " + sampleFilename, DEBUG);
@@ -248,9 +248,9 @@ async function init () {
 
     if (DEBUG) {
         osmdInstance.setLogLevel("debug");
-        // console.log(`osmd PageFormat: ${osmdInstance.EngravingRules.PageFormat.width}x${osmdInstance.EngravingRules.PageFormat.height}`)
-        console.log(`osmd PageFormat idString: ${osmdInstance.EngravingRules.PageFormat.idString}`);
-        console.log("PageHeight: " + osmdInstance.EngravingRules.PageHeight);
+        // debug(`osmd PageFormat: ${osmdInstance.EngravingRules.PageFormat.width}x${osmdInstance.EngravingRules.PageFormat.height}`)
+        debug(`osmd PageFormat idString: ${osmdInstance.EngravingRules.PageFormat.idString}`);
+        debug("PageHeight: " + osmdInstance.EngravingRules.PageHeight);
     } else {
         osmdInstance.setLogLevel("info"); // doesn't seem to work, log.debug still logs
     }
@@ -270,7 +270,7 @@ async function init () {
         }
     }
 
-    console.log("[OSMD.generateImages] done, exiting.");
+    debug("done, exiting.");
 }
 
 // eslint-disable-next-line
@@ -306,8 +306,8 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
     } else {
         loadParameter = loadParameter.toString();
     }
-    // console.log('loadParameter: ' + loadParameter)
-    // console.log('typeof loadParameter: ' + typeof loadParameter)
+    // debug('loadParameter: ' + loadParameter)
+    // debug('typeof loadParameter: ' + typeof loadParameter)
 
     // set sample-specific options for OSMD visual regression testing
     let includeSkyBottomLine = false;
@@ -356,9 +356,10 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
     }
 
     try {
-        await osmdInstance.load(loadParameter); // if using load.then() without await, memory will not be freed up between renders
+        debug("loading sample " + sampleFilename, DEBUG);
+        await osmdInstance.load(loadParameter, sampleFilename); // if using load.then() without await, memory will not be freed up between renders
     } catch (ex) {
-        console.log("couldn't load sample " + sampleFilename + ", skipping. Error: \n" + ex);
+        debug("couldn't load sample " + sampleFilename + ", skipping. Error: \n" + ex);
         return;
     }
     debug("xml loaded", DEBUG);
@@ -366,7 +367,7 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
         osmdInstance.render();
         // there were reports that await could help here, but render isn't a synchronous function, and it seems to work. see #932
     } catch (ex) {
-        console.log("renderError: " + ex);
+        debug("renderError: " + ex);
     }
     debug("rendered", DEBUG);
 
@@ -381,7 +382,7 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
                 break;
             }
             if (!canvasImage.toDataURL) {
-                console.log(`error: could not get canvas image for page ${pageNumber} for file: ${sampleFilename}`);
+                debug(`error: could not get canvas image for page ${pageNumber} for file: ${sampleFilename}`);
                 break;
             }
             dataUrls.push(canvasImage.toDataURL());
@@ -406,7 +407,7 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
         if (imageFormat === "png") {
             const dataUrl = dataUrls[pageIndex];
             if (!dataUrl || !dataUrl.split) {
-                console.log(`error: could not get dataUrl (imageData) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
+                debug(`error: could not get dataUrl (imageData) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
                 continue;
             }
             const imageData = dataUrl.split(";base64,").pop();
@@ -417,7 +418,7 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
         } else if (imageFormat === "svg") {
             const markup = markupStrings[pageIndex];
             if (!markup) {
-                console.log(`error: could not get markup (SVG data) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
+                debug(`error: could not get markup (SVG data) for page ${pageIndex + 1} of sample: ${sampleFilename}`);
                 continue;
             }
 
@@ -434,19 +435,19 @@ async function generateSampleImage (sampleFilename, directory, osmdInstance, osm
         //             maxRssFilename = pageFilename
         //         }
         //     }
-        //     console.log(entry[0] + ': ' + entry[1] / (1024 * 1024) + 'mb')
+        //     debug(entry[0] + ': ' + entry[1] / (1024 * 1024) + 'mb')
         // }
-        // console.log('maxRss: ' + (maxRss / 1024 / 1024) + 'mb' + ' for ' + maxRssFilename)
+        // debug('maxRss: ' + (maxRss / 1024 / 1024) + 'mb' + ' for ' + maxRssFilename)
     }
-    // console.log('maxRss total: ' + (maxRss / 1024 / 1024) + 'mb' + ' for ' + maxRssFilename)
+    // debug('maxRss total: ' + (maxRss / 1024 / 1024) + 'mb' + ' for ' + maxRssFilename)
 
     // await sleep(5000)
     // }) // end read file
 }
 
-function debug (msg, debugEnabled) {
+function debug (msg, debugEnabled = true) {
     if (debugEnabled) {
-        console.log(msg);
+        console.log("[generateImages] " + msg);
     }
 }
 

+ 2 - 2
test/Util/visual_regression.sh

@@ -92,9 +92,9 @@ fi
 # check that #currentImages == #blessedImages (will continue anyways)
 if [ ! "$totalCurrentImages" -eq "$totalBlessedImages" ]
 then
-  echo "Warning: Number of current images ($totalCurrentImages) is not the same as blessed images ($totalBlessedImages). Continuing anyways.\n"
+  echo "Warning: Number of current images ($totalCurrentImages) is not the same as blessed images ($totalBlessedImages). Continuing anyways."
 else
-  echo "Found $totalCurrentImages current and $totalBlessedImages blessed png files (not tested if valid). Continuing.\n"
+  echo "Found $totalCurrentImages current and $totalBlessedImages blessed png files (not tested if valid). Continuing."
 fi
 # ----------------- end of sanity checks -----------------