Skip to content

Instantly share code, notes, and snippets.

@oeway
Last active May 18, 2020 10:43
Show Gist options
  • Save oeway/8855530815ece9ecaa27bab95e4aac00 to your computer and use it in GitHub Desktop.
Save oeway/8855530815ece9ecaa27bab95e4aac00 to your computer and use it in GitHub Desktop.
<docs lang="markdown">
## Porting Arbitrary Style Transfer to the Browser
https://magenta.tensorflow.org/blog/2018/12/20/style-transfer-js/
```
/**
* Copyright 2018 Google Inc. All Rights Reserved.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
```
</docs>
<config lang="json">
{
"name": "StyleTransfer",
"type": "window",
"tags": [],
"ui": "",
"version": "0.1.0",
"cover": "",
"description": "Arbitrary Style Transfer",
"icon": "extension",
"inputs": null,
"outputs": null,
"api_version": "0.1.8",
"env": "",
"permissions": [],
"requirements": ["https://cdn.jsdelivr.net/npm/@magenta/[email protected]/dist/magentaimage.min.js"],
"dependencies": [],
"defaults": {"w": 20, "h": 10}
}
</config>
<script lang="javascript">
const model = new mi.ArbitraryStyleTransferNetwork();
const canvas = document.getElementById('stylized');
const ctx = canvas.getContext('2d');
const contentImg = document.getElementById('content');
const styleImg = document.getElementById('style');
const loading = document.getElementById('loading');
const notLoading = document.getElementById('ready');
function setupDemo() {
model.initialize().then(() => {
stylize();
});
}
async function clearCanvas() {
// Don't block painting until we've reset the state.
await mi.tf.nextFrame();
ctx.clearRect(0, 0, canvas.width, canvas.height);
await mi.tf.nextFrame();
}
async function stylize() {
await clearCanvas();
// Resize the canvas to be the same size as the source image.
canvas.width = contentImg.width;
canvas.height = contentImg.height;
// This does all the work!
model.stylize(contentImg, styleImg).then((imageData) => {
stopLoading();
ctx.putImageData(imageData, 0, 0);
});
}
function loadImage(event, imgElement) {
const reader = new FileReader();
reader.onload = (e) => {
imgElement.src = e.target.result;
startLoading();
stylize();
};
reader.readAsDataURL(event.target.files[0]);
}
window.loadContent = function(event) {
loadImage(event, contentImg);
}
window.loadStyle = function(event) {
loadImage(event, styleImg);
}
function startLoading() {
loading.hidden = false;
notLoading.hidden = true;
canvas.style.opacity = 0;
}
function stopLoading() {
loading.hidden = true;
notLoading.hidden = false;
canvas.style.opacity = 1;
}
class ImJoyPlugin {
async setup() {
api.log('initialized')
}
async run(ctx) {
setupDemo();
}
}
api.export(new ImJoyPlugin())
</script>
<window lang="html">
<div>
<div class="container">
<div class="left">
<h1>
<b>Arbitrary</b> Style Transfer with <a href="https://www.npmjs.com/package/@magenta/image">magenta.js</a>
</h1>
</div>
</div>
<div class="container">
<div class="left">
<div class="frame">
<h2>Step 1. <label>upload photo <input type="file" onchange="loadContent(event)"></label></h2>
<img id="content" class="image" crossorigin="anonymous" src="https://cdn.glitch.com/93893683-46da-4058-829c-a05792722f2b%2Fcontent.jpg?1545163443723"/>
</div>
<div class="right">
<div class="frame">
<h2>Step 2. <label>upload style <input type="file" onchange="loadStyle(event)"></label></h2>
<img id="style" class="image" crossorigin="anonymous" src="https://cdn.glitch.com/93893683-46da-4058-829c-a05792722f2b%2Fstyle.jpg?1545163447216" />
</div>
</div>
</div>
<div class="frame">
<h2 class="dark">Step 3. <span id="loading">Transmogrifying ...</span><span id="ready" hidden>Profit!</span></h2>
<canvas id="stylized" height="250px"></canvas>
</div>
</div>
</div>
</window>
<style lang="css">
* {box-sizing: border-box; }
body {
font-family: "Helvetica Neue", helvetica, arial, sans-serif;
margin: 0;
background: #f7f1f8;
color: white;
}
h1 {
padding: 0 14px;
font-weight: 100;
}
h2 {
margin-top: 0;
padding-top: 0;
}
a:link, a:visited {
color: white;
font-weight: bold;
}
.dark {
color: #2d1832;
}
.container {
display: flex;
flex-direction: row;
align-items: flex-start;
width: 100%;
}
.left {
width: 50vw;
max-width: 800px;
background: #2d1832;
text-align: center;
}
.bottom {
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.frame {
color: white;
padding: 24px;
margin: 12px;
}
.frame.flex {
display: flex;
flex-direction: column;
}
.frame label {
cursor: pointer;
border: none;
vertical-align: middle;
background: #f7f1f8;
color: #2d1832;
font-weight: 600;
text-transform: uppercase;
margin: 0 16px;
padding: 8px 24px;
font-size: 14px;
text-align: center;
border-radius: 3px;
transition: all 0.25s ease-in 0s;
}
input[type="file"] {
width: 0;
height: 0;
opacity: 0;
cursor: pointer;
display: none;
}
.image {
height: 256px; /* TODO */
margin: 0 auto;
display: block;
}
canvas {
margin-bottom: 100px;
}
#loading {
animation: pulsing-fade 1.2s ease-in-out infinite;
}
@keyframes pulsing-fade {
50% { opacity: 0.3; }
}
@media screen and (max-width: 1000px) {
.right {
width: 50vw;
}
}
@media screen and (max-width: 700px) {
.container {
flex-direction: column;
overflow-x: hidden;
}
.left, .right {
width: 100vw;
}
.frame {
text-align: center;
width: 100%;
}
}
</style>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment