Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error taking png screenshot on web-ui #1506

Open
GonzChav opened this issue May 31, 2024 · 4 comments · May be fixed by #1534
Open

Error taking png screenshot on web-ui #1506

GonzChav opened this issue May 31, 2024 · 4 comments · May be fixed by #1534

Comments

@GonzChav
Copy link

GNS3 Version: GNS3 v2.2.46
Operating System: Linux, Windows

When I try to take screenshot from the web-ui I am getting an error, attached below.
error.txt

The error begins with Uncaught (in promise): There was an error loading the data URI as an image on the following SVG and continues with a segment of a svg.

Researching the error I found that this is from the npm package saveSvgAsPng.

In an issue on saveSvgAsPng's github I found that the error is caused when you try to convert to png an incorrect svg file.
On src\app\components\project-map\project-map-menu\project-map-menu.component.ts I see that when the function saveImage is called and the type of image is png, first is created and svg and then it is saved as png with saveSvgAsPng, so I suspect that the issue is on the generated SVG to be converted to png.

I found that I can only add VPCS and Cloud nodes to my topology and take a screenshot successfully.
screenshot-1717119097396

When I add an ethernet switch or a custom template of VPCS with the icon changed the error start to generate, as shown in the following picture, a message appears but can't be seen, the attached file is the text that I can copy from that withe rectangle.
errorexporting

I tried with version 2.2.27 and 2.2.46 on Linux and Windows and the behavior is the same.

@grossmj
Copy link
Member

grossmj commented Jun 17, 2024

Thanks, have you used Firefox?

@cristian-ciobanu
Copy link

cristian-ciobanu commented Dec 22, 2024

I see on Linux Screenshot export to PNG is disabled and it will allow only Windows according to this

this.isPngAvailable = this.electronService.isWindows || this.deviceService.getDeviceInfo().os === 'Windows';

If I change it to this.isPngAvailable = true the option becomes available but still receive the exception.

Below is a diff file with some changed code which fixes the error and allows me to export screenshots as PNG. Not sure if it is the best way or if it can be optimized but it works for me now. Tested on a Firefox based browser in Linux for the GNS3 web ui version 3.0.0.

diff --git a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts
index xxxxxxx..xxxxxxx 100644
--- a/src/app/components/project-map/project-map-menu/project-map-menu.component.ts
+++ b/src/app/components/project-map/project-map-menu/project-map-menu.component.ts
@@ -98,25 +98,42 @@ export class ProjectMapMenuComponent {
 
   private async saveImage(screenshotProperties: Screenshot) {
     if (screenshotProperties.filetype === 'png') {
-      let splittedSvg = document.getElementsByTagName('svg')[0].outerHTML.split('image');
-      let i = 1;
-
-      while (i < splittedSvg.length) {
-        let splittedImage = splittedSvg[i].split('"');
-        let splittedUrl = splittedImage[1].split('/');
-
-        let elem = await this.symbolService.raw(this.controller, splittedUrl[7]).toPromise();
-        let splittedElement = elem.split('-->');
-        splittedSvg[i] = splittedElement[1].substring(2);
-        i += 2;
+      try {
+        // Get the SVG element and clone it to avoid modifying the original
+        const originalSvg = document.getElementsByTagName('svg')[0];
+        const svgClone = originalSvg.cloneNode(true) as SVGElement;
+        
+        // Process any embedded images
+        const images = svgClone.getElementsByTagName('image');
+        for (let i = 0; i < images.length; i++) {
+          const image = images[i];
+          const href = image.getAttribute('href') || image.getAttribute('xlink:href');
+          if (href) {
+            const urlParts = href.split('/');
+            const symbolId = urlParts[urlParts.length - 1];
+            try {
+              const rawSvg = await this.symbolService.raw(this.controller, symbolId).toPromise();
+              if (rawSvg) {
+                // Extract SVG content, fallback to raw content if parsing fails
+                const svgContent = rawSvg.includes('-->') ? 
+                  rawSvg.split('-->')[1].trim() : 
+                  rawSvg.trim();
+                image.outerHTML = svgContent;
+              }
+            } catch (err) {
+              console.warn(`Failed to process embedded image: ${symbolId}`, err);
+            }
+          }
+        }
+
+        // Create a temporary container and save as PNG
+        const container = document.createElement('div');
+        container.appendChild(svgClone);
+        svg.saveSvgAsPng(svgClone, `${screenshotProperties.name}.png`);
+      } catch (err) {
+        console.error('Failed to save PNG:', err);
+        throw err;
       }
-      let svgString = splittedSvg.join();
-
-      let placeholder = document.createElement('div');
-      placeholder.innerHTML = svgString;
-      let element = placeholder.firstChild;
-
-      svg.saveSvgAsPng(element, `${screenshotProperties.name}.png`);
     } else {
       var svg_el = select('svg').attr('version', 1.1).attr('xmlns', 'http://www.w3.org/2000/svg').node();
       downloadSvg(select('svg').node(), `${screenshotProperties.name}`);
     }
   }

diff --git a/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts b/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts
index xxxxxxx..xxxxxxx 100644
--- a/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts
+++ b/src/app/components/project-map/screenshot-dialog/screenshot-dialog.component.ts
@@ -25,7 +25,7 @@ export class ScreenshotDialogComponent implements OnInit {
     this.nameForm = this.formBuilder.group({
       screenshotName: new UntypedFormControl(`screenshot-${Date.now()}`, [Validators.required]),
     });
-    this.isPngAvailable = this.electronService.isWindows || this.deviceService.getDeviceInfo().os === 'Windows';
+    this.isPngAvailable = true;
   }
 
   ngOnInit() {}

@grossmj grossmj linked a pull request Dec 23, 2024 that will close this issue
@grossmj
Copy link
Member

grossmj commented Dec 26, 2024

I have created a PR based on your diff however I do not get the intended result when taking a PNG screenshot.

This is the topology in the web-ui:

Screenshot from 2024-12-26 22-51-07

This is the PNG:

test png

I tested on Linux + Chrome.

@cristian-ciobanu
Copy link

Sorry I rushed a little bit. After doing some more tests I'm experiencing similar issues.
Initially when I tested and had only 2 or 3 nodes with default symbols but if I change symbols or use custom ones things do not work as expected anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants