Ver código fonte

feat(color): new option pageBackgroundColor. can set canvas color e.g. to white instead of transparent. (#670)

part of #670

setting canvas.id in CanvasVexFlowBackend is necessary to extract the buffer dataUrl from outside (js).
sschmid 5 anos atrás
pai
commit
4e5043c344

+ 6 - 1
demo/index.js

@@ -115,6 +115,7 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
         var paramMeasureRangeStart = findGetParameter('measureRangeStart');
         var paramMeasureRangeStart = findGetParameter('measureRangeStart');
         var paramMeasureRangeEnd = findGetParameter('measureRangeEnd');
         var paramMeasureRangeEnd = findGetParameter('measureRangeEnd');
         var paramPageFormat = findGetParameter('pageFormat');
         var paramPageFormat = findGetParameter('pageFormat');
+        var paramPageBackgroundColor = findGetParameter('pageBackgroundColor');
         var paramBackendType = findGetParameter('backendType');
         var paramBackendType = findGetParameter('backendType');
 
 
         showHeader = (paramShowHeader !== '0');
         showHeader = (paramShowHeader !== '0');
@@ -143,6 +144,8 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
             measureRangeStart = measureRangeEnd;
             measureRangeStart = measureRangeEnd;
         }
         }
         var pageFormat = paramPageFormat ? paramPageFormat : "Endless";
         var pageFormat = paramPageFormat ? paramPageFormat : "Endless";
+        var pageBackgroundColor = paramPageBackgroundColor ? "#" + paramPageBackgroundColor : undefined; // vexflow format, see OSMDOptions. can't use # in parameters.
+        //console.log("demo: osmd pagebgcolor: " + pageBackgroundColor);
         var backendType = (paramBackendType && paramBackendType.toLowerCase) ? paramBackendType : "svg";
         var backendType = (paramBackendType && paramBackendType.toLowerCase) ? paramBackendType : "svg";
         
         
         // set the backendSelect debug controls dropdown menu selected item
         // set the backendSelect debug controls dropdown menu selected item
@@ -172,6 +175,7 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
         zoomIn = document.getElementById("zoom-in-btn");
         zoomIn = document.getElementById("zoom-in-btn");
         zoomOut = document.getElementById("zoom-out-btn");
         zoomOut = document.getElementById("zoom-out-btn");
         canvas = document.createElement("div");
         canvas = document.createElement("div");
+        //canvas.id = 'osmdCanvasDiv';
         //canvas.style.overflowX = 'auto'; // enable horizontal scrolling
         //canvas.style.overflowX = 'auto'; // enable horizontal scrolling
         nextCursorBtn = document.getElementById("next-cursor-btn");
         nextCursorBtn = document.getElementById("next-cursor-btn");
         resetCursorBtn = document.getElementById("reset-cursor-btn");
         resetCursorBtn = document.getElementById("reset-cursor-btn");
@@ -346,7 +350,8 @@ import { OpenSheetMusicDisplay } from '../src/OpenSheetMusicDisplay/OpenSheetMus
                 maintain_stem_directions: false
                 maintain_stem_directions: false
             },
             },
 
 
-            pageFormat: pageFormat
+            pageFormat: pageFormat,
+            pageBackgroundColor: pageBackgroundColor,
 
 
             // tupletsBracketed: true, // creates brackets for all tuplets except triplets, even when not set by xml
             // tupletsBracketed: true, // creates brackets for all tuplets except triplets, even when not set by xml
             // tripletsBracketed: true,
             // tripletsBracketed: true,

+ 8 - 0
src/MusicalScore/Graphical/EngravingRules.ts

@@ -214,6 +214,7 @@ export class EngravingRules {
     private fingeringPosition: PlacementEnum;
     private fingeringPosition: PlacementEnum;
     private fingeringInsideStafflines: boolean;
     private fingeringInsideStafflines: boolean;
     private pageFormat: PageFormat;
     private pageFormat: PageFormat;
+    private pageBackgroundColor: string; // vexflow-color-string (#FFFFFF). Default undefined/transparent.
 
 
     private fixStafflineBoundingBox: boolean; // TODO temporary workaround
     private fixStafflineBoundingBox: boolean; // TODO temporary workaround
 
 
@@ -442,6 +443,7 @@ export class EngravingRules {
         this.fixStafflineBoundingBox = false; // TODO temporary workaround
         this.fixStafflineBoundingBox = false; // TODO temporary workaround
 
 
         this.pageFormat = PageFormat.UndefinedPageFormat; // default: undefined / 'infinite' height page, using the canvas'/container's width and height
         this.pageFormat = PageFormat.UndefinedPageFormat; // default: undefined / 'infinite' height page, using the canvas'/container's width and height
+        this.pageBackgroundColor = undefined; // default: transparent. half-transparent white: #FFFFFF88"
 
 
         this.populateDictionaries();
         this.populateDictionaries();
         try {
         try {
@@ -1559,6 +1561,12 @@ export class EngravingRules {
     public set PageFormat(value: PageFormat) {
     public set PageFormat(value: PageFormat) {
         this.pageFormat = value;
         this.pageFormat = value;
     }
     }
+    public get PageBackgroundColor(): string {
+        return this.pageBackgroundColor;
+    }
+    public set PageBackgroundColor(value: string) {
+        this.pageBackgroundColor = value;
+    }
 
 
     /**
     /**
      * This method maps NoteDurations to Distances and DistancesScalingFactors.
      * This method maps NoteDurations to Distances and DistancesScalingFactors.

+ 10 - 0
src/MusicalScore/Graphical/VexFlow/CanvasVexFlowBackend.ts

@@ -7,6 +7,7 @@ import {RectangleF2D} from "../../../Common/DataObjects/RectangleF2D";
 import {PointF2D} from "../../../Common/DataObjects/PointF2D";
 import {PointF2D} from "../../../Common/DataObjects/PointF2D";
 import {VexFlowConverter} from "./VexFlowConverter";
 import {VexFlowConverter} from "./VexFlowConverter";
 import {BackendType} from "../../../OpenSheetMusicDisplay";
 import {BackendType} from "../../../OpenSheetMusicDisplay";
+import {EngravingRules} from "../EngravingRules";
 
 
 export class CanvasVexFlowBackend extends VexFlowBackend {
 export class CanvasVexFlowBackend extends VexFlowBackend {
     public getVexflowBackendType(): Vex.Flow.Renderer.Backends {
     public getVexflowBackendType(): Vex.Flow.Renderer.Backends {
@@ -19,6 +20,7 @@ export class CanvasVexFlowBackend extends VexFlowBackend {
 
 
     public initialize(container: HTMLElement): void {
     public initialize(container: HTMLElement): void {
         this.canvas = document.createElement("canvas");
         this.canvas = document.createElement("canvas");
+        this.canvas.id = "osmdCanvasVexFlowBackendCanvas"; // needed to extract image buffer from js
         this.inner = document.createElement("div");
         this.inner = document.createElement("div");
         this.inner.style.position = "relative";
         this.inner.style.position = "relative";
         this.canvas.style.zIndex = "0";
         this.canvas.style.zIndex = "0";
@@ -47,6 +49,14 @@ export class CanvasVexFlowBackend extends VexFlowBackend {
 
 
     public clear(): void {
     public clear(): void {
         (<any>this.ctx).clearRect(0, 0, (<any>this.canvas).width, (<any>this.canvas).height);
         (<any>this.ctx).clearRect(0, 0, (<any>this.canvas).width, (<any>this.canvas).height);
+
+        // set background color if not transparent
+        if (EngravingRules.Rules.PageBackgroundColor !== undefined) {
+            this.ctx.save();
+            this.ctx.setFillStyle(EngravingRules.Rules.PageBackgroundColor);
+            this.ctx.fillRect(0, 0, (this.canvas as any).width, (this.canvas as any).height);
+            this.ctx.restore();
+        }
     }
     }
 
 
     public scale(k: number): void {
     public scale(k: number): void {

+ 9 - 0
src/MusicalScore/Graphical/VexFlow/SvgVexFlowBackend.ts

@@ -50,6 +50,15 @@ export class SvgVexFlowBackend extends VexFlowBackend {
         while (svg.lastChild) {
         while (svg.lastChild) {
             svg.removeChild(svg.lastChild);
             svg.removeChild(svg.lastChild);
         }
         }
+
+        // set background color if not transparent
+        if (EngravingRules.Rules.PageBackgroundColor !== undefined) {
+            this.ctx.save();
+            this.ctx.setFillStyle(EngravingRules.Rules.PageBackgroundColor);
+
+            this.ctx.fillRect(0, 0, this.canvas.offsetWidth, this.canvas.offsetHeight);
+            this.ctx.restore();
+        }
     }
     }
 
 
     public scale(k: number): void {
     public scale(k: number): void {

+ 7 - 1
src/OpenSheetMusicDisplay/OSMDOptions.ts

@@ -34,7 +34,7 @@ export interface IOSMDOptions {
      * Only considered before loading a sample, not before render.
      * Only considered before loading a sample, not before render.
      * To change the color after loading a sample and before render, use note(.sourceNote).NoteheadColor.
      * To change the color after loading a sample and before render, use note(.sourceNote).NoteheadColor.
      * The format is Vexflow format, either "#rrggbb" or "#rrggbbtt" where <tt> is transparency. All hex values.
      * The format is Vexflow format, either "#rrggbb" or "#rrggbbtt" where <tt> is transparency. All hex values.
-     * E.g., a half-transparent red would be "#FF000080", invisible would be "#00000000" or "#12345600".
+     * E.g., a half-transparent red would be "#FF000080", invisible/transparent would be "#00000000" or "#12345600".
      */
      */
     defaultColorNotehead?: string;
     defaultColorNotehead?: string;
     /** Default color for a note stem. Default black (undefined). */
     /** Default color for a note stem. Default black (undefined). */
@@ -114,6 +114,12 @@ export interface IOSMDOptions {
      *   Uses OpenSheetMusicDisplay.StringToPageFormat(). Unfortunately it would be error-prone to set a PageFormat type directly.
      *   Uses OpenSheetMusicDisplay.StringToPageFormat(). Unfortunately it would be error-prone to set a PageFormat type directly.
      */
      */
     pageFormat?: string;
     pageFormat?: string;
+    /** A custom page/canvas background color. Default undefined/transparent.
+     *  Example: "#FFFFFF" = white. "#12345600" = transparent.
+     *  This can be useful when you want to export an image with e.g. white background color instead of transparent,
+     *  from a CanvasBackend.
+     */
+    pageBackgroundColor?: string;
 }
 }
 
 
 export enum AlignRestOption {
 export enum AlignRestOption {

+ 6 - 0
src/OpenSheetMusicDisplay/OpenSheetMusicDisplay.ts

@@ -183,6 +183,7 @@ export class OpenSheetMusicDisplay {
 
 
         // Set page width
         // Set page width
         const width: number = this.container.offsetWidth;
         const width: number = this.container.offsetWidth;
+        //console.log("[OSMD] container width: " + width);
         this.sheet.pageWidth = width / this.zoom / 10.0;
         this.sheet.pageWidth = width / this.zoom / 10.0;
         if (EngravingRules.Rules.PageFormat && !EngravingRules.Rules.PageFormat.IsUndefined) {
         if (EngravingRules.Rules.PageFormat && !EngravingRules.Rules.PageFormat.IsUndefined) {
             EngravingRules.Rules.PageHeight = this.sheet.pageWidth / EngravingRules.Rules.PageFormat.aspectRatio;
             EngravingRules.Rules.PageHeight = this.sheet.pageWidth / EngravingRules.Rules.PageFormat.aspectRatio;
@@ -218,6 +219,7 @@ export class OpenSheetMusicDisplay {
             // Update the cursor position
             // Update the cursor position
             this.cursor.update();
             this.cursor.update();
         }
         }
+        //console.log("[OSMD] render finished");
     }
     }
 
 
     private createOrRefreshRenderBackend(): void {
     private createOrRefreshRenderBackend(): void {
@@ -244,6 +246,7 @@ export class OpenSheetMusicDisplay {
             } else {
             } else {
                 backend.resize(width, (page.PositionAndShape.Size.height + 15) * this.zoom * 10.0);
                 backend.resize(width, (page.PositionAndShape.Size.height + 15) * this.zoom * 10.0);
             }
             }
+            backend.clear(); // set bgcolor if defined (EngravingRules.Rules.PageBackgroundColor, see OSMDOptions)
             this.drawer.Backends.push(backend);
             this.drawer.Backends.push(backend);
         }
         }
     }
     }
@@ -423,6 +426,9 @@ export class OpenSheetMusicDisplay {
         if (options.pageFormat !== undefined) { // only change this option if it was given, see above
         if (options.pageFormat !== undefined) { // only change this option if it was given, see above
             EngravingRules.Rules.PageFormat = OpenSheetMusicDisplay.StringToPageFormat(options.pageFormat);
             EngravingRules.Rules.PageFormat = OpenSheetMusicDisplay.StringToPageFormat(options.pageFormat);
         }
         }
+        if (options.pageBackgroundColor !== undefined) {
+            EngravingRules.Rules.PageBackgroundColor = options.pageBackgroundColor;
+        }
     }
     }
 
 
     public setColoringMode(options: IOSMDOptions): void {
     public setColoringMode(options: IOSMDOptions): void {