Skip to content

Instantly share code, notes, and snippets.

@traderd65
Last active September 25, 2017 14:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save traderd65/4d2d3b321934cf7a32dd78f6f7c6516f to your computer and use it in GitHub Desktop.
Save traderd65/4d2d3b321934cf7a32dd78f6f7c6516f to your computer and use it in GitHub Desktop.
Cloudinary Style Transfer
<h3 class="presents"><a href='http://cloudinary.com/'>
<img alt="Cloudinary Logo" class="dark-logo" height="38" src="https://cloudinary-res.cloudinary.com/image/asset/dpr_2.0/logo-e0df892053afd966cc0bfe047ba93ca4.png" /></a><span class="presents-text">Presents</span></h3>
<h3 class="oh-yes dark" style="margin-bottom: 0">Neural Artwork</h3>
<h3 class="oh-yes">Style Transfer</h3>
<hr class="separator" />
<div class="show-me">
<div class="third-ish">
<div class="third-ish-title">
<span class="numero-pill">1</span>Input Artistic Style as SOURCE image
</div>
<div class="third-ish-image">
<span id="let-me-source-span" class=""><img id="let-me-source-image" data-imgname="sailing_angel" src="https://res.cloudinary.com/faas/image/upload/w_200,h_200,c_fill,dpr_2.0/sailing_angel.jpg" /></span>
</div>
<div class="third-ish-gogogo">
<div class="outer-border jiggle border-active" id="let-me-source-container">
<button id="let-me-source">
<span class="decoration">
<svg class="innerjiggle" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24px" height="24px" viewBox="0 0 340.533 340.533" xml:space="preserve" style="transform:rotate(90deg); vertical-align:middle;">
<g>
<path d="M145.768,290.197c-6.137,0-12.25-5.831-13.412-7.002c-4.194-3.092-115.082-86.691-127.269-98.856 c-4.422-4.444-5.203-8.894-5.074-11.856c0.288-7.089,5.768-11.935,6.389-12.463L129.738,57.946 c1.351-1.474,7.617-7.611,13.577-7.611c2.717,0,9.031,1.243,9.031,12.691v52.623H326.47c0.486-0.081,1.135-0.156,1.903-0.156 c2.03,0,12.16,0.774,12.16,15.976v80.87c0,11.187-7.927,14.153-12.118,14.153H156.012v48.23 C156.012,288.191,149.593,290.197,145.768,290.197z M145.768,280.451v4.87V280.451L145.768,280.451z" fill="currentColor"/>
</g>
</svg>
</span>
<span class="button-action" id="let-me-source-text">Try it! Upload a style</span>
</button>
</div>
</div>
</div>
<div class="third-ish">
<div class="third-ish-title">
<span class="numero-pill">2</span>Input Original Photo as TARGET image
</div>
<div class="third-ish-image">
<span><img id="let-me-target-image" data-imgname="" src="https://res.cloudinary.com/faas/image/upload/w_200,h_200,c_fill,dpr_2.0/coffee_cup" /></span>
</div>
<div class="third-ish-gogogo">
<div class="outer-border" id="let-me-target-container">
<button id="let-me-target">
<span class="decoration">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24px" height="24px" viewBox="0 0 340.533 340.533" xml:space="preserve" style="transform:rotate(90deg); vertical-align:middle;">
<g>
<path d="M145.768,290.197c-6.137,0-12.25-5.831-13.412-7.002c-4.194-3.092-115.082-86.691-127.269-98.856 c-4.422-4.444-5.203-8.894-5.074-11.856c0.288-7.089,5.768-11.935,6.389-12.463L129.738,57.946 c1.351-1.474,7.617-7.611,13.577-7.611c2.717,0,9.031,1.243,9.031,12.691v52.623H326.47c0.486-0.081,1.135-0.156,1.903-0.156 c2.03,0,12.16,0.774,12.16,15.976v80.87c0,11.187-7.927,14.153-12.118,14.153H156.012v48.23 C156.012,288.191,149.593,290.197,145.768,290.197z M145.768,280.451v4.87V280.451L145.768,280.451z" fill="currentColor"/>
</g>
</svg>
</span>
<span class="button-action" id="let-me-target-text">Upload a target image</span>
</button>
</div>
</div>
</div>
<div class="third-ish">
<div class="third-ish-title">
<span class="numero-pill">3</span>Apply Cloudinary's Style Transfer
</div>
<div class="third-ish-image">
<span><img id="let-me-result" data-imgname="" src="https://res.cloudinary.com/faas/image/upload/e_style_transfer,l_sailing_angel/coffee_cup.jpg" /></span>
</div>
<div class="third-ish-gogogo start-hidden" id="let-me-submit-contest">
<div class="outer-border" id="let-me-submit-container">
<button id="let-me-submit">
<span class="decoration">
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="24px" height="24px" viewBox="0 0 340.533 340.533" xml:space="preserve" style="transform:rotate(90deg); vertical-align:middle;">
<g>
<path d="M145.768,290.197c-6.137,0-12.25-5.831-13.412-7.002c-4.194-3.092-115.082-86.691-127.269-98.856 c-4.422-4.444-5.203-8.894-5.074-11.856c0.288-7.089,5.768-11.935,6.389-12.463L129.738,57.946 c1.351-1.474,7.617-7.611,13.577-7.611c2.717,0,9.031,1.243,9.031,12.691v52.623H326.47c0.486-0.081,1.135-0.156,1.903-0.156 c2.03,0,12.16,0.774,12.16,15.976v80.87c0,11.187-7.927,14.153-12.118,14.153H156.012v48.23 C156.012,288.191,149.593,290.197,145.768,290.197z M145.768,280.451v4.87V280.451L145.768,280.451z" fill="currentColor"/>
</g>
</svg>
</span>
<span class="button-action">Enter Contest Here...</span>
</button>
</div>
</div>
</div>
</div>
<hr class="separator" />
<h3 class="oh-yes">What's going on?</h3>
<div class="details">
<p>
Cloudinary is a cloud-based service that provides solutions for image and video management, including server or client-side upload, on-the-fly image and video manipulations, quick CDN delivery, and a variety of asset management options.
</p>
<p>
The Neural Artwork Style Transfer add-on takes Cloudinary image transformations to a new level with the <b>style_transfer</b> effect. This effect applies a complex deep learning algorithm, based on <a href="https://arxiv.org/abs/1703.06868"
target="_blank">Xun Huange and Serge Belongie's</a> enhancement of a <a href="http://www.robots.ox.ac.uk/~vgg/research/very_deep/"
target="_blank">VGG 16 neural network</a>, algorithm, which extracts artistic styles from a source image and applies them to the content of a target photograph.
</p>
<p>
More details are in the <a href="http://cloudinary.com/blog/from_photos_to_art_with_style_transfer" target="_blank">Cloudinary announcement of the style transfer feature</a> and in the <a href="http://cloudinary.com/documentation/neural_artwork_style_transfer_addon"
target="_blank">Cloudinary Neural Artwork add-on documentation</a>.
</p>
</div>
<div id="progress" class="start-none" style="">
<hr class="separator" />
<h4 class="oh-yes">What Actions You've Taken</h4>
<div class="progress-details" style="margin: auto;">
<span class="progress-info">Input Artistic Style as SOURCE image </span><input class="progress-field" id="progress-source"></input><br />
<span class="progress-info">Input Original Photo as TARGET image </span><input class="progress-field" id="progress-target"></input><br />
<span class="progress-info">Apply Cloudinary's Style Transfer </span><input class="progress-field" id="progress-result"></input><br />
</div>
</div>
<div id="contest-dialog" title="Cloudinary Style Transfer Contest">
<div id="contest-dialog-inner">
<div id="contest-dialog-invite">
<p>We love your picture too! To submit your contest entry and vote on the best neural artwork (except your own, of course!), please enter your email address. We will send you an email to remind you to vote (voting deadline is <span class="end-date"></span>).</p>
<div id="contest-dialog-error" class="start-none"></div>
<form>
<input id="submit-email" style="width: 90%; padding: 0, 10px;" type="email" name="email" placeholder=" Email Address (required)" /><br />
<input id="submit-mrktg" style="margin-top: 20px;" type="checkbox" name="marketing-okay" /> Please also add me to the Cloudinary feature update list!<br />
<!-- Keyboard submission nominally hidden -->
<input type="submit" tabindex="-1" style="position:absolute; top:-1000px">
</form>
</div>
<div id="contest-dialog-submitted">
</div>
</div>
</div>
<!-- see https://codepen.io/aurer/pen/jEGbA for loading SVG inspiration-->
<div class="start-hidden">
<img id="loading-image" src="https://res.cloudinary.com/faas/image/upload/v1503522957/style-transfer-loading.svg"
/>
</div>
/*
* c 2017 Cloudinary
*/
$(document).ready(function() {
/* connect the upload widget with straight javascript */
var uploadSource = function() {
cloudinary.openUploadWidget({ cloud_name: 'faas', upload_preset: 'styletransfer', sources: ['local','url','camera'], stylesheet: '#cloudinary-widget { width: 100% !important; left: 0 !important; }' },
function(error, result) {
console.log(error, result);
if (!error) {
// add a loader image
let source_image = $('#let-me-source-image');
source_image.attr('src', $("#loading-image").attr('src'));
// TODO: add jiggle only if the image hasn't already been uploaded
// show progress and debug information at the bottom of the page
$('#let-me-target-container').addClass('jiggle border-active').find('svg').addClass('innerjiggle');
$('#progress-source').val(result[0].secure_url);
$('#progress').removeClass('start-none');
// update the style source image, noting this could take a while on a slow connection
source_image.attr('src', result[0].secure_url).data('imgname', result[0].public_id).addClass('sourced');
$('#let-me-source-text').html("Nice Artwork!");
$('#let-me-source-container').removeClass('jiggle').find('svg').removeClass('innerjiggle');
applyStyleTransfer();
}
}
);
}
document.getElementById("let-me-source").addEventListener("click", uploadSource, false);
document.getElementById("let-me-source-image").addEventListener("click", uploadSource, false);
/* TODO: change to jquery style upload widget to demo different widget styles */
var uploadTarget = function() {
$('#let-me-source-container, #let-me-target-container').removeClass('jiggle').find('svg').removeClass('innerjiggle');
cloudinary.openUploadWidget({ cloud_name: 'faas', upload_preset: 'styletransfer', sources: ['local', 'url', 'camera'], stylesheet: '#cloudinary-widget { width: 100% !important; left: 0 !important; }'},
function(error, result) {
console.log(error, result);
if (!error) {
// add a loader image
let target_image = $('#let-me-target-image');
target_image.attr('src', $("#loading-image").attr('src'));
$('#let-me-result').attr('src', $("#loading-image").attr('src'));
$('#let-me-submit-container').addClass('jiggle border-active').find('svg').addClass('innerjiggle');
$('#progress-target').val(result[0].secure_url);
$('#progress').removeClass('start-none');
// use the source image, regardless of upload state
$('#let-me-source-image').addClass('sourced');
target_image.attr('src', result[0].secure_url).data('imgname', result[0].public_id + '.' + result[0].format).addClass('sourced');
$('#let-me-target-text').html("Cool Photo!");
$('#let-me-target-container').addClass('border-active');
applyStyleTransfer();
}
}
);
};
var applyStyleTransfer = function() {
var source = $('#let-me-source-image').data('imgname');
var target = $('#let-me-target-image').data('imgname');
if (source != "" && target != "") {
var result_img = "https://res.cloudinary.com/faas/image/upload/e_style_transfer,l_" + source + "/" + target;
$('#let-me-result').attr('src', result_img).addClass('sourced');
$('#let-me-submit-contest').removeClass('start-hidden');
$('#progress-result').val(result_img);
}
};
document.getElementById("let-me-target").addEventListener("click", uploadTarget, false);
document.getElementById("let-me-target-image").addEventListener("click", uploadTarget, false);
var resetContestDialog = function() {
$('#contest-dialog-invite').removeClass('start-none');
$('#contest-dialog-error').addClass('start-none');
$('#contest-dialog-submitted').addClass('start-none');
$('.contest-dialog-button-submit').removeClass('start-none');
$('.contest-dialog-button-close').addClass('start-none');
}
var enterContest = function() {
var entry = {};
entry.url = $('#let-me-result').attr('src');
entry.email = $('#submit-email').val().trim();
entry.marketing = $('#submit-mrktg').is(':checked') ? "1" : "0";
$.ajax({
type: "POST",
url: webtask_url + "/submit",
data: JSON.stringify(entry),
dataType: "json",
contentType: 'application/json; charset=utf-8',
success: function(data) {
if (data.error && data.error !== "") {
$('#contest-dialog-error').html(data.error).removeClass('start-none');
} else {
$('#contest-dialog-invite').addClass('start-none');
$('#contest-dialog-error').addClass('start-none');
$('#contest-dialog-submitted').html(data.message).removeClass('start-none');
$('.contest-dialog-button-submit').addClass('start-none');
$('.contest-dialog-button-close').removeClass('start-none');
$('#let-me-submit-contest').addClass('start-hidden');
}
},
failure: function(errMsg) {
$('#contest-dialog-error').html(errMsg).removeClass('start-none');
}
});
return true;
}
var submit_dialog = $("#contest-dialog").dialog({
autoOpen: false,
height: 'auto',
width: Math.floor($('body').width() * 0.8) + 'px',
modal: true,
dialogClass: 'contest-modal',
position: { my: 'top', at: 'top', of: window },
buttons: [
{
text: 'Enter the Contest',
click: enterContest,
class: 'contest-dialog-button-submit'
},
{
text: 'Got it',
click: function() { $(this).dialog('close') },
class: 'contest-dialog-button-close start-none'
}
],
close: function() {
submit_form[0].reset();
}
});
var submit_form = submit_dialog.find('form').on('submit', function(e) {
e.preventDefault();
enterContest();
});
$("#let-me-submit").on("click", function() {
$('body').scrollTop(0);
$('#let-me-submit-container').removeClass('jiggle').find('svg').removeClass('innerjiggle');
resetContestDialog();
submit_dialog.dialog("open");
});
// Adjust dates for the contest start and end nominally on load
$.get(webtask_url + '/date/start',
function(data) {$('.start-date').html(data);});
$.get(webtask_url + '/date/end',
function(data) {$('.end-date').html(data);});
});
const webtask_url = "https://faas-cloudinary.com/wt-60a287cd40c53f6e56bd60ac8922bc3e-0/style-transfer";
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
<script src="https://widget.cloudinary.com/global/all.js"></script>
// @see cloudinary.com/assets
$CLDorange: #F4B21B;
$CLDdarkorange: #DB8226;
$CLDblue: #0071BA;
$CLDdarkblue: #0E2F5A;
$borderwidth: 8px;
$borderradius: $borderwidth * 4;
// layout boundaries
$sm: 768px;
$md: 1024px;
$lr: 1400px;
$mq_xs: "(max-width: #{$sm - 1px})";
$mq_sm: "(min-width: #{$sm}) and (max-width: #{$md - 1px})";
$mq_md: "(min-width: #{$md}) and (max-width: #{$lr - 1px})";
$mq_lr: "(min-width: #{$lr})";
// mixins
@mixin l_xs { @media #{$mq_xs} { @content } }
@mixin l_sm { @media #{$mq_sm} { @content } }
@mixin l_md { @media #{$mq_md} { @content } }
@mixin l_lr { @media #{$mq_lr} { @content } }
body {
background-color: cream;
color: black;
text-align: center;
font-family: 'Roboto', Arial, Helvetica, sans-serif;
font-size: 18px;
}
.presents {
color: $CLDblue;
font-size: 24px;
margin-bottom: 0;
}
.presents .dark-logo {
padding-right: 10px;
margin-bottom: 14px;
}
.oh-yes {
text-transform: uppercase;
color: $CLDorange;
font-family: 'Bowlby One SC', cursive;
margin: 0 0 0 0.1em;
font-weight: normal;
}
h1.oh-yes {
font-size: 5em;
@include l_xs {
font-size: 2.8em;
}
}
h3.oh-yes {
font-size: 3em;
margin-bottom: 32px;
@include l_xs {
font-size: 3em;
}
@include l_sm {
font-size: 2.8em;
}
}
h4.oh-yes {
margin-bottom: 30px;
}
hr.separator {
border-color: $CLDorange;
height: 0;
color: cream;
width: 88%;
margin-bottom: 40px;
}
.show-me {
margin: 30px 0 50px;
@include l_xs {
margin: 30px 0 20px;
}
}
#leaderboard {
width: 35%;
margin: auto;
& .third-ish {
width: 100%;
}
}
.third-ish {
width: 33%;
display: inline-block;
text-align: center;
vertical-align: middle;
margin-bottom: 40px;
@include l_xs {
margin-bottom: 2em;
width: 100%;
}
@include l_sm {
margin-bottom: 40px;
width: 100%;
}
}
.third-ish-title {
text-align: left;
width: 90%;
margin: auto;
}
.third-ish img {
border: $borderwidth solid grey;
margin: 20px 20px 0;
width: 25vw;
height: 25vw;
&.component {
border-top: none;
width: 12.5vw;
height: 12.5vw;
padding: 0;
margin: 0;
&.component-left {
border-right: 0;
}
}
@include l_xs {
width: 80vw;
height: 80vw;
margin: 0;
&.component {
width: 40vw;
height: 40vw;
}
}
@include l_sm {
width: 70vw;
height: 70vw;
margin: 0;
&.component {
width: 35vw;
height: 35vw;
}
}
}
.third-ish img.sourced {
border: $borderwidth solid $CLDdarkorange;
&.component {
border-top: none;
}
}
.component-images,
.third-ish-image {
margin: 0 auto;
}
.details {
text-align: center;
margin: 20px 0 0 0;
}
.details p {
margin: auto;
width: 80%;
margin-bottom: 20px;
text-align: justify;
}
.numero-pill {
color: white;
background-color: $CLDorange;
padding: 6px 15px;
border-radius: 50%;
display: inline-block;
min-height: 20px;
min-width: 20px;
text-align: center;
margin: 0 16px 0 20px;
float: left;
clear: both;
font-weight: bold;
}
// buttons for uploading
.outer-border {
width: 70%;
border: $borderwidth solid grey;
padding: 0;
border-radius: $borderwidth * 5;
background-color: grey;
margin: auto;
@include l_sm {
width: 50%;
}
}
button {
border: $borderwidth solid $CLDorange;
padding: 0.3em 0.2em 0.4em 0.1em;
border-radius: $borderradius;
font-size: 20px;
font-weight: bold;
color: $CLDblue;
background-color: white;
text-transform: uppercase;
width: 100%;
text-align: center;
@include l_xs {
font-size: 16px;
}
@include l_sm {
font-size: 14px;
}
@include l_lr {
text-align: left;
}
}
@keyframes jiggle {
0% { transform: rotate(-2deg) translateX(3px); }
5% { transform: rotate(2deg) translateX(-3px); }
10% { transform: rotate(-2deg) translate(3px); }
15% { transform: rotate(2deg) translate(-3px); }
20% { transform: rotate(0deg) translate(0); }
}
.decoration {
border: 4px solid $CLDdarkorange;
border-radius: 20px;
padding: 2px 0px 6px 6px;
margin: 0 6px 0 4px;
background-color: white;
@include l_xs {
display: none;
}
@include l_sm {
padding: 5px 0 7px 3px;
}
@include l_md {
display: none;
}
}
@keyframes innerjiggle {
0% {transform:rotate(90deg); }
5% { transform: rotate(80deg); }
10% { transform: rotate(98deg); }
15% { transform: rotate(80deg); }
20% { transform: rotate(98deg); }
25% { transform: rotate(90deg); }
}
.button-action {
font-size: 19px;
vertical-align: middle;
@include l_md {
font-size: 16px;
margin: auto;
padding-left: 10px;
}
}
.innerjiggle {
animation: innerjiggle 2s infinite;
}
.third-ish-gogogo {
margin-top: -40px;
text-align: center;
}
.border-active {
background-color: $CLDdarkorange;
border-color: $CLDdarkorange;
}
.jiggle {
animation: jiggle 2s infinite;
}
#contest-dialog {
text-align: left;
}
#contest-dialog-inner {
& a {
color: $CLDblue;
}
}
.ui-dialog.contest-modal {
border: 5px solid $CLDorange;
}
.contest-modal .ui-dialog-titlebar {
background-color: $CLDorange;
color: white;
}
#contest-dialog-error {
padding: 0 0 1px;
font-weight: bold;
color: red;
}
.start-hidden {
visibility: hidden;
}
.start-none {
display: none;
}
#progress {
margin: auto;
}
.progress-details {
text-align: center;
width: 90%;
margin: auto;
font-size: 80%;
}
.progress-info {
min-width: 300px;
text-align: right;
display: inline-block;
padding-right: 10px;
font-weight: bold;
}
.progress-field {
display: inline-block;
min-width: 60%;
padding: 0 6px;
margin-bottom: 10px;
border: none;
}
.candidate-vote {
text-align: center;
}
.vote-message {
padding: 0px 20px 20px;
}
.vote-details {
padding: 0.4em 0.2em 0.4em 0.1em;
font-size: 20px;
font-weight: bold;
color: $CLDblue;
text-transform: uppercase;
width: 100%;
text-align: center;
margin-top: 50px;
@include l_xs {
margin-top: 50px;
}
@include l_sm {
margin-top: 50px;
}
}
.vote-flash {
position: fixed;
bottom: 0;
left: 0;
right: 0;
padding: 30px;
background-color: $CLDorange;
color: white;
text-align: center;
text-transform: uppercase;
transform: translateY(100%);
}
.vote-flash-is-showing {
animation: popup 3s 1;
}
@keyframes popup {
0% { transform: translateY(100%); }
10% { transform: translateY(0); }
90% { transform: translateY(0); }
99% { transform: translateY(100%); }
}
#vote-header {
display: block;
margin-top: -10px;
}
a.vote-header {
float: left;
width: 24%;
margin-bottom: 10px;
@include l_xs {
width: 100%;
float: none;
}
&.selected {
color: $CLDblue;
}
}
#leaderboard .numero-pill {
color: white;
background-color: $CLDorange;
padding: 14px 30px;
border-radius: 50%;
border: $borderwidth solid $CLDdarkorange;
display: inline-block;
min-height: 20px;
min-width: 20px;
text-align: right;
margin: 0px 16px 0 -80px;
clear: both;
font-size: 30px;
font-weight: bold;
vertical-align: bottom;
float: none;
}
.error-message {
width: 80%;
margin: auto;
padding: .5rem;
border: 8px solid #C00;
border-radius: 2em;
color: #C00;
font-weight: bold;
}
<link href="https://code.jquery.com/ui/1.12.1/themes/base/jquery-ui.css" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Roboto:500,400italic,300,700,500italic,400" rel="stylesheet" />
<link href="https://fonts.googleapis.com/css?family=Bowlby+One+SC" rel="stylesheet" />
<link href="https://cloudinary.com/stylesheets/g/cloudinary_public.css?1500989656" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment