Use the Photo Editor as an embedded image processing widget — load images, apply filter chains, and export results, all controlled from the parent page.
This demo shows how to build a custom image filter toolbar on top of the embedded Photo Editor.
<iframe id="ip-demo" src="/online/webapp/photo-editor" width="100%" height="600" frameborder="0" style="border:1px solid #ccc; border-radius:4px;"></iframe>
<script>window._wsConnect('ip-demo', 'ipSocket');</script>
<div style="padding:12px 0; display:flex; flex-wrap:wrap; gap:6px; align-items:center;">
Presets:
</div><div style="padding:6px 0; display:flex; flex-wrap:wrap; gap:6px; align-items:center;">
Effects:
</div><div style="padding:6px 0; display:flex; flex-wrap:wrap; gap:6px; align-items:center;">
Transform:
</div><div style="padding:6px 0; display:flex; flex-wrap:wrap; gap:6px; align-items:center;">
Export:
</div><img id="ip-preview" style="max-width:300px;margin:8px 0;display:none;border:1px solid #ddd;border-radius:4px;"><pre id="ip-info" style="background:#f6f8fa;padding:8px;font-size:12px;display:inline-block;min-height:1em;"></pre>
A fully custom image editing UI built on top of the Photo Editor widget:
All buttons are simple socket.fire() calls — the Photo Editor handles all the pixel processing.
<!DOCTYPE html>
<html>
<head><title>My Image Editor</title></head>
<body>
<div id="toolbar">
<button id="vintage">Vintage</button>
<button id="bw">Black & White</button>
<button id="undo">Undo</button>
<button id="download">Download</button>
</div>
<iframe id="editor" src="https://sgapps.io/online/webapp/photo-editor"
width="100%" height="600" frameborder="0"></iframe>
<script src="https://sgapps.io/components/application-prototype/ApplicationPrototype.js"></script>
<script src="https://sgapps.io/components/window-socket/index.js"></script>
<script>
var socket = new WindowSocket();
socket.start();
var ready = false;
socket.on("webapp::connection::ping", function () {
ready = true;
socket.fire("webapp::instance::embed-mode", true);
});
function req(event) {
if (!ready) return;
var args = Array.prototype.slice.call(arguments);
socket.fire.apply(socket, ["webapp::instance::request"].concat(args));
}
document.getElementById('vintage').onclick = function () {
req("history:save");
req("applyFilters", [
{ name: "sepia", params: { level: 0.5 } },
{ name: "hsl-adjustment", params: { hue: -30, saturation: 40, lightness: 0 } }
]);
};
document.getElementById('bw').onclick = function () {
req("history:save");
req("applyFilters", [
{ name: "grayscale", params: { level: 1 } },
{ name: "contrast", params: { level: 0.5 } }
]);
};
document.getElementById('undo').onclick = function () {
req("history:undo");
};
document.getElementById('download').onclick = function () {
req("getDataBase64", "image/png", function (err, dataUrl) {
var a = document.createElement("a");
a.href = dataUrl;
a.download = "edited.png";
a.click();
});
};
</script>
</body>
</html>