Last active
June 27, 2023 02:36
-
-
Save eightants/6286d8a69cccf9304871c867a9144e19 to your computer and use it in GitHub Desktop.
Spotify Duotone Filter with HTML Canvas and Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Spotify Duotone Filter with HTML Canvas and Javascript | |
// by Anthony Teo | |
/* | |
This function generates a duotone version of an image on an HTML Canvas element using Javascript. | |
It makes use of the newer canvas functions, including filter and the globalCompositeOperations, making it | |
less code-heavy compared to existing implementations in canvas. | |
The benefit of using this method compared to CSS filters is the ability to convert the canvas to an image to be saved. | |
Libraries like HTMLtoCanvas state in their documentation that CSS filters are not supported, so it is probably not possible | |
to do so in CSS. This is a purely JS and Canvas implementation. | |
*/ | |
function Duotone(id, src, primaryClr, secondaryClr, actions = (ctx) => null) { | |
let canvas = document.getElementById(id); | |
let ctx = canvas.getContext("2d"); | |
let downloadedImg = new Image(); | |
downloadedImg.crossOrigin = ""; // to allow us to manipulate the image without tainting canvas | |
downloadedImg.onload = function () { | |
ctx.drawImage(downloadedImg, 0, 0, canvas.width, canvas.height); // draws image to canvas on load | |
// Converts to grayscale by averaging the values of each pixel | |
imageData = ctx.getImageData(0, 0, 800, 800); | |
const pixels = imageData.data; | |
for (let i = 0; i < pixels.length; i += 4) { | |
const red = pixels[i]; | |
const green = pixels[i + 1]; | |
const blue = pixels[i + 2]; | |
// Using relative luminance to convert to grayscale | |
const avg = Math.round((0.299 * red + 0.587 * green + 0.114 * blue) * 1); | |
pixels[i] = avg; | |
pixels[i + 1] = avg; | |
pixels[i + 2] = avg; | |
} | |
// Puts the grayscaled image data back into the canvas | |
ctx.putImageData(imageData, 0, 0); | |
// puts the duotone image into canvas with multiply and lighten | |
ctx.globalCompositeOperation = "multiply"; | |
ctx.fillStyle = primaryClr; // colour for highlights | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// lighten | |
ctx.globalCompositeOperation = "lighten"; | |
ctx.fillStyle = secondaryClr; // colour for shadows | |
ctx.fillRect(0, 0, canvas.width, canvas.height); | |
// calls any other draws that you want through the function parameter passed in | |
actions(ctx); | |
}; | |
downloadedImg.src = src; // source for the image | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!DOCTYPE html> | |
<html> | |
<head> | |
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" /> | |
<title>Spotify Duotone Filter with HTML Canvas and Javascript</title> | |
<script type="text/javascript" src="Duotone.js"></script> | |
<style> | |
body { | |
margin: 0; | |
font-size: 16px; | |
font-family: "Helvetica Neue", Helvetica; | |
} | |
#main { | |
width: 600px; | |
margin: 50px auto; | |
text-align: center; | |
} | |
p { | |
text-align: left; | |
margin: 40px; | |
} | |
button { | |
font-weight: 600; | |
margin: 20px 10px; | |
padding: 15px 30px; | |
border: 2px solid black; | |
background-color: white; | |
border-radius: 10px; | |
color: black; | |
transition: all 0.3s ease; | |
text-transform: uppercase; | |
} | |
button:hover { | |
cursor: pointer; | |
background-color: black; | |
color: white; | |
} | |
</style> | |
</head> | |
<body> | |
<div id="main"> | |
<p>This is the canvas generated with the Duotone function. Use the "Convert to Image" button to convert the canvas into a png image below, which can be saved on desktop and mobile.</p> | |
<canvas id="duotone" width="600" height="600"></canvas> | |
<button onclick="randomizeColors()">Change Colours</button> | |
<button onclick="downloadImage()">Convert to Image</button> | |
<img id="image"> | |
</div> | |
<script type="text/javascript" src="scripts.js"></script> | |
</body> | |
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Script to use the Duotone function | |
function randomIndex() { | |
return Math.floor(Math.random() * 3); | |
} | |
function drawText(ctx) { | |
// Draws text on top of the duotone image | |
ctx.fillStyle = "#FFFFFF"; | |
ctx.font = "bold 96px Arial"; | |
ctx.textBaseline = "bottom"; | |
ctx.fillText("Avicii", 100, 480); // draws text | |
ctx.fillRect(0, 430, 80, 12); // draws the line | |
ctx.textBaseline = "top"; | |
} | |
function randomizeColors() { | |
// Arrays of colors, with a random index chosen when clicked. | |
let primary = ["#f65e35", "#00ff36", "#77acd4"]; | |
let secondary = ["#1e3265", "#23278a", "#033dc5"]; | |
let ind = randomIndex(); | |
// Duotone called with the appropriate arguments | |
Duotone( | |
"duotone", | |
"https://i.imgur.com/WQ1Iydl.jpeg", | |
primary[ind], | |
secondary[ind], | |
drawText | |
); | |
} | |
function downloadImage() { | |
// function to convert the canvas into a png image and set it as the src of the img tag | |
document.querySelector("#image").src = document | |
.querySelector("#duotone") | |
.toDataURL("image/png"); | |
} | |
// initial call | |
randomizeColors(); |
Hello my friend today was my birthday
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
That's pretty cool! 👍