Skip to content

Commit

Permalink
graph: fix “Download PNG” for large images (#1610)
Browse files Browse the repository at this point in the history
Summary:
When viewing large graphs in Chrome, clicking the “Download PNG” button
could the error message, “Failed - Network error”. This is because
Chrome does not support downloading large data-URLs. Chrome does,
however, support downloading large object URLs, so this patch makes the
appropriate change to use that API instead.

Test Plan:
Generate the `audio_demo` data and open the `wave:01;sine_wave` graph in
TensorBoard in Chrome. Transitively expand all node groups. Then, click
“Download PNG”. Before this patch, this consistently failed to download.
After this patch, it downloads and image with the correct contents.

Also tested in Firefox.

wchargin-branch: graph-download-png-blob
  • Loading branch information
wchargin authored and stephanwlee committed Dec 14, 2018
1 parent 334c40d commit b89bd85
Showing 1 changed file with 18 additions and 1 deletion.
19 changes: 18 additions & 1 deletion tensorboard/plugins/graph/tf_graph_common/minimap.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,24 @@ export class Minimap {
let $download = d3.select('#graphdownload');
this.download = <HTMLLinkElement>$download.node();
$download.on('click', d => {
this.download.href = this.downloadCanvas.toDataURL('image/png');
// Revoke the old URL, if any. Then, generate a new URL.
URL.revokeObjectURL(this.download.href);
// We can't use the `HTMLCanvasElement.toBlob` API because it does
// not have a synchronous variant, and we need to update this href
// synchronously. Instead, we create a blob manually from the data
// URL.
const dataUrl = this.downloadCanvas.toDataURL("image/png");
const prefix = dataUrl.slice(0, dataUrl.indexOf(","));
if (!prefix.endsWith(";base64")) {
console.warn(`non-base64 data URL (${prefix}); cannot use blob download`);
this.download.href = dataUrl;
return;
}
const data = atob(dataUrl.slice(dataUrl.indexOf(",") + 1));
const bytes =
new Uint8Array(data.length).map((_, i) => data.charCodeAt(i));
const blob = new Blob([bytes], {type: "image/png"});
this.download.href = URL.createObjectURL(blob);
});

let $svg = d3.select(this.svg);
Expand Down

0 comments on commit b89bd85

Please sign in to comment.