Algorithmia Blog

One-page Web Tool: Transfer Style from One Image to Another in JavaScript alone

You may have already seen how to do style transfer via the StyleThief microservice in Python, but let’s take a different approach: what if I wanted to create a one-page website out of the service, without having to create any backend? That’s right: using only JavaScript and HTML, we’ll make it possible for website visitors to make their own images look like a Van Gogh, a Picasso, or any other piece of art they can find a digital photo of.

Step 1: Get an API Key

If you don’t already have an Algorithmia account, head to algorithmia.com/signup and get 5,000 free credits each month!

Next, go to algorithmia.com/user#credentials and copy your API key (the strange-looking text starting with “sim”). We will use this in Step 3.

Step 2: Build a Simple Webpage

Our visitors need to be able to specify two images: one which they want to “steal” the style of, and an image to which they want that style applied. We’ll keep this simple for now, and just add two input fields (with example values) where they can paste the image URLs, plus a button to trigger the service.

We’ll include Bootstrap 4 for styling, and jQuery to make our lives a little easier. We also need the Algorithmia JavaScript library, and a reference to the custom JavaScript (“style-thief.js”) that we’ll write in step 3.

<html>
    <head>
        <title>Style Thief</title>
        <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" >
        <script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" type="text/javascript"></script>
        <script src="https://algorithmia.com/v1/clients/js/algorithmia-0.2.0.js" type="text/javascript"></script>
        <script src="style-thief.js" type="text/javascript"></script>
    </head>
    <body class="col-11 mx-auto">
        <h1>Style Thief Demo</h1>
        <hr />
        <div class="row">
            <div class="col-3">Image to restyle:</div>
            <input class="col-9" type="text" id="source" value="https://www.commerce.gov/sites/commerce.gov/files/styles/scalecrop_200x200/public/media/images/2015/sperling.jpg" />
        </div>
        <div class="row">
            <div class="col-3">Style sample:</div>
            <input type="text" class="col-9" id="style" value="data://bkyan/StyleThief/default_style.jpg" />
        </div>
        <div class="row">
            <div class="col-3">
                <button id="run" onclick="run()">restyle</button>
                <img id="loading" style="display:none;" src="loading.gif">
            </div>
            <div class="col-9"><div id="message"></div><img id="output"></div>
        </div>
    </body>
</html>

Step 3: Write the JavaScript

You may want to take a peek at the Algorithmia JavaScript Client documentation, but for now let’s check out the code:

var client = Algorithmia.client("your_api_key");
var algo_stylethief = client.algo("algo://bkyan/StyleThief/0.2.13?timeout=3000");
var algo_cat64 = client.algo("algo://util/Data2Base64/0.1.0");

var run = function() {
  var filename = new Date().getTime()+".jpg";
  var outputURI = "data://.algo/bkyan/StyleThief/temp/"+filename;
  var input = {
    "source": $("#source").val(),
    "style": $("#style").val(),
    "output": filename,
    "iterations": 800,
    "log_channel": "style-thief-demo"
  };
  $("#message").text("This will take 5-50 minutes, so please be patient!");
  $('#output').attr('src','');
  $("#run").hide();
  $("#loading").show();
  algo_stylethief.pipe(input).then(function(response) {
    $("#loading").hide();
    $("#run").show();
    if(response.error) {
      $("#message").text(response.error.message);
    } else {
      algo_cat64.pipe(outputURI).then(function(response2) {
        $("#message").empty();
        $('#output').attr('src','data:image/jpeg;base64,'+response2.result);
      });
    }
  });

In the first line, replace “your_api_key” with you own API Key from step 1. After that, you don’t need to make any specific changes, but here’s what’s happening:

First, we prepare the two algorithms we’ll be using. bkyan/StyleThief does the majority of the work, accepting the images and generating a new, styled image. This can take some time, so note how we’ve adjusted the timeout to the maximum (50 minutes) by adding the parameter “?timeout=3000”.

Since StyleThief gives us back the URI of the image, but not the content itself, we now need to retrieve the image content. util/Data2Base64 does just this, taking in the URI and giving us back the base64-encoded file content.

Now we implement the run() function which will be called when the button is clicked. We create a temporary filename (the current time in milliseconds isn’t guaranteed to be unique: a GUID would be a better option). The algorithm will place this file into the data directory “data://.algo/bkyan/StyleThief/temp/”, so we’ll remember the file’s eventual location as “outputURI” for later use.

Next, we construct the JSON which StyleThief expects as input (see the algorithm’s documentation for details).

Before firing off the actual microservice call, we’ll also clear out any output from prior runs, and show a “loading” image (available here) so the user knows something is happening.

Lastly, the actual work: we pipe our JSON into the StyleThief microservice. When it is completed, the callback function checks for any errors (“response.error”); if there are none, it calls Data2Base64 to retrieve the image content. Prepending “data:image/jpeg;base64,” allows us to use it as the SRC value of our image tag.

Step 4: Test and Deploy!

That’s all! Open style-thief.htm in a browser and try it out. Tweak the settings to find the right balance of speed vs quality. Make the page prettier, and maybe even add some presets such as a gallery of style images they might choose from. Then, upload your files to cheap, static file hosting (like S3)… you don’t need any backend capabilities or a high-powered server, because Algorithmia does all the heavy lifting!

Grab the complete code from the GitHub repo, and have fun!