From 576f448864f1746e0fa47e68c3783be7e9bc3f46 Mon Sep 17 00:00:00 2001
From: omsuneri <142336291+omsuneri@users.noreply.github.com>
Date: Tue, 21 Jan 2025 20:54:33 +0530
Subject: [PATCH] Exporting Blocks artwork in PNG (#4280)
* Update toolbar.js for PNG saver
* Update activity.js PNG saver
* Update index.html for adding new link for exporting as png
* Update toolbar.js
* creating fun printBlockPng
* Update SaveInterface.js calling block artwork png
* Removing extra Spaces
* Update activity.js
* Update activity.js
---
index.html | 1 +
js/SaveInterface.js | 14 ++++++++++++++
js/activity.js | 44 ++++++++++++++++++++++++++++++++++++++++++--
js/toolbar.js | 12 +++++++++++-
4 files changed, 68 insertions(+), 3 deletions(-)
diff --git a/index.html b/index.html
index 241cb17bc3..cbc707c960 100644
--- a/index.html
+++ b/index.html
@@ -890,6 +890,7 @@
+
diff --git a/js/SaveInterface.js b/js/SaveInterface.js
index fb98fff0f5..e46d7f6c80 100644
--- a/js/SaveInterface.js
+++ b/js/SaveInterface.js
@@ -311,6 +311,20 @@ class SaveInterface {
const svg = "data:image/svg+xml;utf8," + activity.printBlockSVG();
activity.save.download("svg", svg, null);
}
+
+ /**
+ * This method is to save BlockArtwork and download the PNG representation of block artwork from the provided activity.
+ *
+ * @param {SaveInterface} activity - The activity object containing block artwork to save.
+ * @returns {void}
+ * @method
+ * @instance
+ */
+ saveBlockArtworkPNG(activity) {
+ activity.printBlockPNG().then((pngDataUrl) => {
+ activity.save.download("png", pngDataUrl, null);
+ })
+ }
/**
* Save audio recording in WAV format.
diff --git a/js/activity.js b/js/activity.js
index acd2f818f8..ed4a6cd6a0 100644
--- a/js/activity.js
+++ b/js/activity.js
@@ -1052,6 +1052,44 @@ class Activity {
encodeURIComponent(svg)
);
};
+
+ /**
+ * @returns {PNG} returns PNG of block artwork
+ */
+ this.printBlockPNG = async () => {
+ // Setps to convert the SVG to PNG of BlockArtwork
+ // Step 1: Generate the SVG content
+ // Step 2: Create a Canvas element
+ // Step 3: Convert SVG to an Image object
+ // Step 4: Draw SVG on the Canvas and export as PNG
+
+ const svgContent = this.printBlockSVG();
+ const canvas = document.createElement('canvas');
+ const ctx = canvas.getContext('2d');
+ const parser = new DOMParser();
+ const svgDoc = parser.parseFromString(decodeURIComponent(svgContent), "image/svg+xml");
+ const svgElement = svgDoc.documentElement;
+ const width = parseInt(svgElement.getAttribute('width'), 10);
+ const height = parseInt(svgElement.getAttribute('height'), 10);
+ canvas.width = width;
+ canvas.height = height;
+ const img = new Image();
+ const svgBlob = new Blob([decodeURIComponent(svgContent)], { type: "image/svg+xml;charset=utf-8" });
+ const url = URL.createObjectURL(svgBlob);
+ return new Promise((resolve, reject) => {
+ img.onload = () => {
+ ctx.drawImage(img, 0, 0);
+ URL.revokeObjectURL(url);
+ const pngDataUrl = canvas.toDataURL("image/png");
+ resolve(pngDataUrl);
+ };
+ img.onerror = (err) => {
+ URL.revokeObjectURL(url);
+ reject(err);
+ };
+ img.src = url;
+ });
+ };
/*
* Clears "canvas"
@@ -1525,7 +1563,8 @@ class Activity {
activity.save.afterSaveLilypondLY.bind(activity.save),
activity.save.saveAbc.bind(activity.save),
activity.save.saveMxml.bind(activity.save),
- activity.save.saveBlockArtwork.bind(activity.save)
+ activity.save.saveBlockArtwork.bind(activity.save),
+ activity.save.saveBlockArtworkPNG.bind(activity.save)
);
// Regenerate palettes
@@ -6645,7 +6684,8 @@ class Activity {
this.save.saveLilypond.bind(this.save),
this.save.saveAbc.bind(this.save),
this.save.saveMxml.bind(this.save),
- this.save.saveBlockArtwork.bind(this.save)
+ this.save.saveBlockArtwork.bind(this.save),
+ this.save.saveBlockArtworkPNG.bind(this.save)
);
this.toolbar.renderPlanetIcon(this.planet, doOpenSamples);
this.toolbar.renderMenuIcon(showHideAuxMenu);
diff --git a/js/toolbar.js b/js/toolbar.js
index c581fed5a3..f4fe0df0d6 100644
--- a/js/toolbar.js
+++ b/js/toolbar.js
@@ -85,6 +85,7 @@ class Toolbar {
["save-ly", _("Save sheet music as Lilypond"), "innerHTML"],
["save-mxml", _("Save sheet music as MusicXML"), "innerHTML"],
["save-blockartwork-svg", _("Save block artwork as SVG"), "innerHTML"],
+ ["save-blockartwork-png", _("Save block artwork as PNG"), "innerHTML"],
["new-project", _("Confirm"), "innerHTML"],
["enUS", _("English (United States)"), "innerHTML"],
["enUK", _("English (United Kingdom)"), "innerHTML"],
@@ -144,6 +145,7 @@ class Toolbar {
_("Save sheet music as ABC"),
_("Save sheet music as Lilypond"),
_("Save block artwork as SVG"),
+ _("Save block artwork as PNG"),
_("Confirm"),
_("Select language"),
_("Save project as HTML"),
@@ -152,6 +154,7 @@ class Toolbar {
_("Save turtle artwork as SVG"),
_("Save turtle artwork as PNG"),
_("Save block artwork as SVG"),
+ _("Save block artwork as PNG"),
_("Confirm"),
_("English (United States)"),
_("English (United Kingdom)"),
@@ -208,6 +211,7 @@ class Toolbar {
["save-svg", _("Save turtle artwork as SVG"), "innerHTML"],
["save-png", _("Save turtle artwork as PNG"), "innerHTML"],
["save-blockartwork-svg", _("Save block artwork as SVG"), "innerHTML"],
+ ["save-blockartwork-png", _("Save block artwork as PNG"), "innerHTML"],
["new-project", _("Confirm"), "innerHTML"],
["enUS", _("English (United States)"), "innerHTML"],
["enUK", _("English (United Kingdom)"), "innerHTML"],
@@ -265,6 +269,7 @@ class Toolbar {
_("Save turtle artwork as SVG"),
_("Save turtle artwork as PNG"),
_("Save block artwork as SVG"),
+ _("Save block artwork as PNG"),
_("Confirm"),
_("English (United States)"),
_("English (United Kingdom)"),
@@ -571,7 +576,8 @@ class Toolbar {
ly_onclick,
abc_onclick,
mxml_onclick,
- blockartworksvg_onclick
+ blockartworksvg_onclick,
+ blockartworkpng_onclick
) {
const saveButton = docById('saveButton');
const saveButtonAdvanced = docById('saveButtonAdvanced');
@@ -681,6 +687,10 @@ class Toolbar {
saveArtworkSVG.onclick = () => {
blockartworksvg_onclick(this.activity);
};
+ const saveArtworkPNG = docById('save-blockartwork-png');
+ saveArtworkPNG.onclick = () => {
+ blockartworkpng_onclick(this.activity);
+ };
}
}
}