From 2b0755969c681cca2f62e857edc17a1cd86e128e Mon Sep 17 00:00:00 2001 From: Thomas Jacob Date: Fri, 13 Apr 2018 09:50:36 +0200 Subject: [PATCH] refactor: export to png --- src/electron/menu.ts | 115 +++++++++++++++++-------------------- src/export/png-exporter.ts | 47 +++++++++++++++ 2 files changed, 101 insertions(+), 61 deletions(-) create mode 100644 src/export/png-exporter.ts diff --git a/src/electron/menu.ts b/src/electron/menu.ts index de2062ed6..a7e028f32 100644 --- a/src/electron/menu.ts +++ b/src/electron/menu.ts @@ -8,11 +8,38 @@ import { } from 'electron'; import { ElementLocationCommand } from '../store/command/element-location-command'; import * as FileExtraUtils from 'fs-extra'; +import { Page } from '../store/page/page'; import { PageElement } from '../store/page/page-element'; import * as PathUtils from 'path'; +import { PngExporter } from '../export/png-exporter'; import * as ProcessUtils from 'process'; import { Store } from '../store/store'; -const { screen, Menu, shell, app, dialog } = remote; +const { Menu, shell, app, dialog } = remote; + +function getPageFileName(): string { + return (Store.getInstance().getCurrentPage() as Page).getName(); +} + +function querySaveFilePath( + title: string, + typeName: string, + defaultName: string, + extension: string, + callback: (path: string) => void +): void { + dialog.showSaveDialog( + { + title, + defaultPath: `${defaultName}.${extension}`, + filters: [{ name: typeName, extensions: [extension] }] + }, + path => { + if (path) { + callback(path); + } + } + ); +} export function createMenu(): void { const store = Store.getInstance(); @@ -90,6 +117,32 @@ export function createMenu(): void { { type: 'separator' }, + { + label: '&Export', + submenu: [ + { + label: 'Export page as PNG', + enabled: !isSplashscreen, + click: () => { + const pageFileName = getPageFileName(); + querySaveFilePath( + 'Export PNG as', + 'PNG Image', + pageFileName, + 'png', + (path: string) => { + const webview = document.getElementById('preview') as WebviewTag; + PngExporter.exportToPng(path, webview); + } + ); + } + } + ] + }, + { + type: 'separator', + visible: process.platform !== 'darwin' + }, { label: 'Se&ttings', visible: process.platform !== 'darwin', @@ -98,66 +151,6 @@ export function createMenu(): void { shell.openItem(store.getPreferencesPath()); } }, - { - label: 'Export page as PNG', - enabled: !isSplashscreen, - click: () => { - const webview = document.getElementById('preview') as WebviewTag; - - // code that gets executed inside the webview to get - // the actual size of the preview body - const code = ` - bodyTag = document.querySelector('body'); - r = {}; - r.pageHeight = bodyTag.getBoundingClientRect().height; - r.pageWidth = bodyTag.getBoundingClientRect().width; - r; - `; - - webview.executeJavaScript(code, false, webviewSize => { - // set the height of the webview tag to the preview body height - // This is needed because capturePage can not capture anything that renders - // outside the webview area (https://github.com/electron/electron/issues/9845) - webview.style.height = webviewSize.pageHeight; - - // Delay the page capture to make sure that the style height changes are done. - // This is only needed because of the change in height in the above line - setTimeout(() => { - const scaleFactor = screen.getPrimaryDisplay().scaleFactor; - webview.capturePage( - { - x: 0, - y: 0, - // round the numbers to remove possible floating numbers - // also multiply by scaleFactor for devices with higher pixel ratio: - // https://github.com/electron/electron/issues/8314 - width: Math.round(webviewSize.pageWidth * scaleFactor), - height: Math.round(webviewSize.pageHeight * scaleFactor) - }, - capture => { - const pngBuffer: Buffer = capture.toPNG(); - - dialog.showSaveDialog( - { - filters: [{ name: 'Untitled', extensions: ['png'] }] - }, - filename => { - // reset the webview height - webview.style.height = '100%'; - - if (!filename) { - return; - } - - FileExtraUtils.writeFileSync(filename, pngBuffer); - } - ); - } - ); - }, 100); - }); - } - }, { type: 'separator', visible: process.platform !== 'darwin' diff --git a/src/export/png-exporter.ts b/src/export/png-exporter.ts new file mode 100644 index 000000000..cd4b12547 --- /dev/null +++ b/src/export/png-exporter.ts @@ -0,0 +1,47 @@ +import { remote, WebviewTag } from 'electron'; +import * as FileExtraUtils from 'fs-extra'; + +export class PngExporter { + public static exportToPng(path: string, webview: WebviewTag): void { + // code that gets executed inside the webview to get + // the actual size of the preview body + const code = ` + bodyTag = document.querySelector('body'); + ({ + pageHeight: bodyTag.getBoundingClientRect().height, + pageWidth: bodyTag.getBoundingClientRect().width + }); + `; + + webview.executeJavaScript(code, false, webviewSize => { + // set the height of the webview tag to the preview body height + // This is needed because capturePage can not capture anything that renders + // outside the webview area (https://github.com/electron/electron/issues/9845) + webview.style.height = webviewSize.pageHeight; + + // Delay the page capture to make sure that the style height changes are done. + // This is only needed because of the change in height in the above line + setTimeout(() => { + const scaleFactor = remote.screen.getPrimaryDisplay().scaleFactor; + webview.capturePage( + { + x: 0, + y: 0, + // round the numbers to remove possible floating numbers + // also multiply by scaleFactor for devices with higher pixel ratio: + // https://github.com/electron/electron/issues/8314 + width: Math.round(webviewSize.pageWidth * scaleFactor), + height: Math.round(webviewSize.pageHeight * scaleFactor) + }, + capture => { + const pngBuffer: Buffer = capture.toPNG(); + FileExtraUtils.writeFileSync(path, pngBuffer); + + // reset the webview height + webview.style.height = '100%'; + } + ); + }, 100); + }); + } +}