@@ -230,9 +291,7 @@
diff --git a/main.js b/main.js
index 4c88716..9d286d5 100644
--- a/main.js
+++ b/main.js
@@ -2,49 +2,64 @@ let canvas;
let video;
let ctx;
/*
- * theses settings correspond to a css-filter. you can specify an optional
- * filter attribute to modify the value from the input element.
- */
+ * theses settings correspond to a css-filter. you can specify an optional
+ * filter attribute to modify the value from the input element.
+ */
let settings = {
"brightness": {},
"saturate": {},
"contrast": {},
- "hue-rotate": { filter: value => value + "deg" },
+ "hue-rotate": { filter: (value) => value + "deg" },
"grayscale": {},
"sepia": {},
"invert": {},
- "blur": { filter: value => value * canvas.width / 100 + 'px' }
+ "blur": { filter: (value) => (value * canvas.width) / 100 + "px" },
};
const img = new Image();
let lensflare_active = false;
let cursor = {
x: 0,
- y: 0
+ y: 0,
};
// wait for site to be parsed so element can be found
-document.addEventListener("DOMContentLoaded", function() {
+document.addEventListener("DOMContentLoaded", function () {
canvas = document.getElementById("myCanvas");
ctx = canvas.getContext("2d");
video = document.getElementById("video");
- document.getElementById("back").addEventListener("click", () => document.body.className = "import-active");
+ document
+ .getElementById("back")
+ .addEventListener(
+ "click",
+ () => (document.body.className = "import-active"),
+ );
// bind listeners
- document.getElementById("viewport").addEventListener("drop", drop_handler);
- document.getElementById("viewport").addEventListener("dragover", event => event.preventDefault());
- document.getElementById("take-picture").addEventListener("click", use_camera);
- document.getElementById("cheese").addEventListener("click", take_picture);
- document.getElementById("upload-image").addEventListener("change", upload_image)
+ document
+ .getElementById("viewport")
+ .addEventListener("drop", drop_handler);
+ document
+ .getElementById("viewport")
+ .addEventListener("dragover", (event) => event.preventDefault());
+ document
+ .getElementById("take-picture")
+ .addEventListener("click", use_camera);
+ document
+ .getElementById("cheese")
+ .addEventListener("click", take_picture);
+ document
+ .getElementById("upload-image")
+ .addEventListener("change", upload_image);
for (let element of document.getElementsByClassName("save-image")) {
- element.addEventListener("click", save_image)
+ element.addEventListener("click", save_image);
}
for (let element of document.getElementsByClassName("share-image")) {
- element.addEventListener("click", share_image)
+ element.addEventListener("click", share_image);
}
for (let element of document.getElementsByClassName("lensflare")) {
- element.addEventListener("click", function(event) {
+ element.addEventListener("click", function (event) {
event.preventDefault();
lensflare_active = !lensflare_active;
if (lensflare_active) {
@@ -56,19 +71,23 @@ document.addEventListener("DOMContentLoaded", function() {
});
}
- document.getElementById("viewport").addEventListener("mousemove", function(event) {
- if (event.buttons === 1 && lensflare_active) {
- cursor.x = (event.clientX - canvas.offsetLeft) / canvas.clientWidth - 0.5;
- cursor.y = (event.clientY - canvas.offsetTop) / canvas.clientWidth - 0.5;
- console.log(cursor);
- draw(true);
- }
- });
+ document
+ .getElementById("viewport")
+ .addEventListener("mousemove", function (event) {
+ if (event.buttons === 1 && lensflare_active) {
+ cursor.x =
+ (event.clientX - canvas.offsetLeft) / canvas.clientWidth - 0.5;
+ cursor.y =
+ (event.clientY - canvas.offsetTop) / canvas.clientWidth - 0.5;
+ console.log(cursor);
+ draw(true);
+ }
+ });
- window.addEventListener("deviceorientation", function(event) {
+ window.addEventListener("deviceorientation", function (event) {
if (lensflare_active) {
- cursor.x = event.gamma / 360 * 4;
- cursor.y = (event.beta - 90) / 360 * 4;
+ cursor.x = (event.gamma / 360) * 4;
+ cursor.y = ((event.beta - 90) / 360) * 4;
console.log(cursor);
// draw(true);
}
@@ -78,22 +97,22 @@ document.addEventListener("DOMContentLoaded", function() {
if (lensflare_active) {
draw(true);
}
- requestAnimationFrame(animation)
- };
+ requestAnimationFrame(animation);
+ }
animation();
- window.addEventListener("resize", () => draw(true))
+ window.addEventListener("resize", () => draw(true));
- video.addEventListener("canplay", function() {
+ video.addEventListener("canplay", function () {
const width = 320;
let height = video.videoHeight / (video.videoWidth / width);
// Firefox currently has a bug where the height can't be read from
// the video, so we will make assumptions if this happens.
- if (isNaN(height)) {
- height = width / (4 / 3);
- }
+ if (isNaN(height)) {
+ height = width / (4 / 3);
+ }
video.width = width;
video.height = height;
});
@@ -103,7 +122,7 @@ document.addEventListener("DOMContentLoaded", function() {
const elements = [...document.getElementsByClassName(setting)];
settings[setting].elements = elements;
// if filter is not definded, use identity function
- settings[setting].filter ||= value => value;
+ settings[setting].filter ||= (value) => value;
for (let element of elements) {
element.addEventListener("input", settings_apply);
}
@@ -116,10 +135,10 @@ document.addEventListener("DOMContentLoaded", function() {
});
/**
- * Reset all inputs of a setting back to the default value
- *
- * @param {string} setting - key of the settings object to reset
- */
+ * Reset all inputs of a setting back to the default value
+ *
+ * @param {string} setting - key of the settings object to reset
+ */
function reset_all(setting) {
console.log("reseting " + setting);
for (let element of settings[setting].elements) {
@@ -129,9 +148,9 @@ function reset_all(setting) {
}
/**
- * Request camera access and on succhess, show camera feed on video-element and
- * switch to camera-active view
- */
+ * Request camera access and on succhess, show camera feed on video-element and
+ * switch to camera-active view
+ */
function use_camera() {
navigator.mediaDevices
.getUserMedia({ video: true, audio: false })
@@ -146,9 +165,9 @@ function use_camera() {
}
/**
- * Take a still frame of the video-element showing the camera-feed and load it
- * to the img to be rendered by canvas and switch to editor-active view
- */
+ * Take a still frame of the video-element showing the camera-feed and load it
+ * to the img to be rendered by canvas and switch to editor-active view
+ */
function take_picture() {
canvas.width = video.width;
canvas.height = video.height;
@@ -160,9 +179,9 @@ function take_picture() {
}
/**
- * Load selected file by input element to img to be rendered by canvas and
- * switch to editor-active view
- */
+ * Load selected file by input element to img to be rendered by canvas and
+ * switch to editor-active view
+ */
function upload_image() {
document.body.className = "editor-active";
@@ -173,13 +192,13 @@ function upload_image() {
}
/**
- * Get file that is dropped into the website and load it to img to be rendered
- * by canvas and switch to editor-active view.
- *
- * @param {DragEvent} ev -supplier by event listener
- *
- * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
- */
+ * Get file that is dropped into the website and load it to img to be rendered
+ * by canvas and switch to editor-active view.
+ *
+ * @param {DragEvent} ev -supplier by event listener
+ *
+ * https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
+ */
function drop_handler(ev) {
ev.preventDefault();
let file;
@@ -199,28 +218,28 @@ function drop_handler(ev) {
}
/**
- * Creates a download of the edited image in full resolution by creating a link
- * and virtually clicking it.
- *
- * @param {PointerEvent} event - supplied by event listener
- */
+ * Creates a download of the edited image in full resolution by creating a link
+ * and virtually clicking it.
+ *
+ * @param {PointerEvent} event - supplied by event listener
+ */
function save_image(event) {
event.preventDefault();
draw(false);
const dataUrl = canvas.toDataURL("image/png");
// downloading only works with links but not window.open
- const link = document.createElement('a');
+ const link = document.createElement("a");
link.href = dataUrl;
- link.download = 'imagine.png';
+ link.download = "imagine.png";
link.click();
}
/**
- * Uses the navigator.share API to share the edited image in full reslution.
- *
- * @param {PointerEvent} event - supplied by event listener
- */
+ * Uses the navigator.share API to share the edited image in full reslution.
+ *
+ * @param {PointerEvent} event - supplied by event listener
+ */
function share_image(event) {
event.preventDefault();
if (!navigator.share) {
@@ -230,21 +249,21 @@ function share_image(event) {
canvas.toBlob(async (blob) => {
if (!blob) return;
- const file = new File([blob], 'imagine.png', {type: 'image/png'});
+ const file = new File([blob], "imagine.png", { type: "image/png" });
try {
- await navigator.share({files: [file]});
+ await navigator.share({ files: [file] });
} catch (error) {
- console.log('Error sharing:', error);
+ console.log("Error sharing:", error);
}
- }, 'image/png');
+ }, "image/png");
}
/**
- * Set all inputs of a setting to the value of the input that changed it.
- *
- * @param {Event} event - supplied by event listener
- */
+ * Set all inputs of a setting to the value of the input that changed it.
+ *
+ * @param {Event} event - supplied by event listener
+ */
function settings_apply(event) {
const changed_setting = event.target.id;
const new_value = event.target.value;
@@ -259,12 +278,12 @@ function settings_apply(event) {
}
/**
- * Render a lensflare shader for every pixel on the canvas.
- *
- * @param {number} pos_x - x position of the lensflare in the range [-0.5,0.5]
- * @param {number} pos_y - y position of the lensflare in the range [-0.5,0.5]
- * https://www.shadertoy.com/view/ldSXWK
- */
+ * Render a lensflare shader for every pixel on the canvas.
+ *
+ * @param {number} pos_x - x position of the lensflare in the range [-0.5,0.5]
+ * @param {number} pos_y - y position of the lensflare in the range [-0.5,0.5]
+ * https://www.shadertoy.com/view/ldSXWK
+ */
function lensflare(pos_x, pos_y) {
const imgdata = ctx.getImageData(0, 0, canvas.width, canvas.height);
const pixel_count = imgdata.data.length / 4;
@@ -272,8 +291,8 @@ function lensflare(pos_x, pos_y) {
for (let i = 0; i < pixel_count; i++) {
const x = i % canvas.width;
const y = i / canvas.width;
- const u = (x / canvas.width - .5) * aspect_ratio;
- const v = y / canvas.height - .5;
+ const u = (x / canvas.width - 0.5) * aspect_ratio;
+ const v = y / canvas.height - 0.5;
const intensity = 1.5 * 255;
const uv_len = u * u + v * v;
@@ -283,76 +302,81 @@ function lensflare(pos_x, pos_y) {
const uvd_pos_x = uvd_x + pos_x;
const uvd_pos_y = uvd_y + pos_y;
- let temp = uvd_pos_x * uvd_pos_x + uvd_pos_y * uvd_pos_y
- const f2 = Math.max(1.0 / (1.0 + 32.0 * temp * .64), .0) * 0.1;
- const f22 = Math.max(1.0 / (1.0 + 32.0 * temp * .72), .0) * 0.08;
- const f23 = Math.max(1.0 / (1.0 + 32.0 * temp * .81), .0) * 0.06;
+ let temp = uvd_pos_x * uvd_pos_x + uvd_pos_y * uvd_pos_y;
+ const f2 = Math.max(1.0 / (1.0 + 32.0 * temp * 0.64), 0.0) * 0.1;
+ const f22 = Math.max(1.0 / (1.0 + 32.0 * temp * 0.72), 0.0) * 0.08;
+ const f23 = Math.max(1.0 / (1.0 + 32.0 * temp * 0.81), 0.0) * 0.06;
let uvx_x = u * (1 + 0.5) + uvd_x * 0.5;
let uvx_y = v * (1 + 0.5) + uvd_y * 0.5;
let uvx_pos_x = uvx_x + pos_x;
let uvx_pos_y = uvx_y + pos_y;
- temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y
- const f4 = Math.max(0.01 - temp * .16, .0) * 6.0;
- const f42 = Math.max(0.01 - temp * .20, .0) * 5.0;
- const f43 = Math.max(0.01 - temp * .25, .0) * 3.0;
+ temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y;
+ const f4 = Math.max(0.01 - temp * 0.16, 0.0) * 6.0;
+ const f42 = Math.max(0.01 - temp * 0.2, 0.0) * 5.0;
+ const f43 = Math.max(0.01 - temp * 0.25, 0.0) * 3.0;
uvx_x = u * (1 + 0.4) + uvd_x * 0.4;
uvx_y = v * (1 + 0.4) + uvd_y * 0.4;
uvx_pos_x = uvx_x + pos_x;
uvx_pos_y = uvx_y + pos_y;
- temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y
- const f5 = Math.max(0.01 - temp * .04, .0) * 2.0;
- const f52 = Math.max(0.01 - temp * .16, .0) * 2.0;
- const f53 = Math.max(0.01 - temp * .36, .0) * 2.0;
+ temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y;
+ const f5 = Math.max(0.01 - temp * 0.04, 0.0) * 2.0;
+ const f52 = Math.max(0.01 - temp * 0.16, 0.0) * 2.0;
+ const f53 = Math.max(0.01 - temp * 0.36, 0.0) * 2.0;
uvx_x = u * (1 + 0.5) + uvd_x * 0.5;
uvx_y = v * (1 + 0.5) + uvd_y * 0.5;
uvx_pos_x = uvx_x - pos_x;
uvx_pos_y = uvx_y - pos_y;
- temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y
- const f6 = Math.max(0.01 - temp * .9, .0) * 6.0;
- const f62 = Math.max(0.01 - temp * .1, .0) * 3.0;
- const f63 = Math.max(0.01 - temp * .12, .0) * 5.0;
+ temp = uvx_pos_x * uvx_pos_x + uvx_pos_y * uvx_pos_y;
+ const f6 = Math.max(0.01 - temp * 0.9, 0.0) * 6.0;
+ const f62 = Math.max(0.01 - temp * 0.1, 0.0) * 3.0;
+ const f63 = Math.max(0.01 - temp * 0.12, 0.0) * 5.0;
- imgdata.data[4 * i + 0] += 1.2 * ((f2 + f4 + f5 + f6) * 1.3 - uvd_len * .05) * intensity;
- imgdata.data[4 * i + 1] += 1.5 * ((f22 + f42 + f52 + f62) * 1.3 - uvd_len * .05) * intensity;
- imgdata.data[4 * i + 2] += 1.3 * ((f23 + f43 + f53 + f63) * 1.3 - uvd_len * .05) * intensity;
+ imgdata.data[4 * i + 0] +=
+ 1.2 * ((f2 + f4 + f5 + f6) * 1.3 - uvd_len * 0.05) * intensity;
+ imgdata.data[4 * i + 1] +=
+ 1.5 * ((f22 + f42 + f52 + f62) * 1.3 - uvd_len * 0.05) * intensity;
+ imgdata.data[4 * i + 2] +=
+ 1.3 * ((f23 + f43 + f53 + f63) * 1.3 - uvd_len * 0.05) * intensity;
imgdata.data[4 * i + 3] = 255;
}
ctx.putImageData(imgdata, 0, 0);
}
/**
- * Amply filters and lensflare to the optionally scaled image, to only
- * calculate on pixels the user can see.
- *
- * @param {bool} viewport_scale - render image scaled to viewport or in full
- * resolution
- */
+ * Amply filters and lensflare to the optionally scaled image, to only
+ * calculate on pixels the user can see.
+ *
+ * @param {bool} viewport_scale - render image scaled to viewport or in full
+ * resolution
+ */
function draw(viewport_scale) {
const filter = Object.entries(settings)
- .map(([setting, { elements, filter }]) => `${setting}(${filter(elements[0].value)})`)
- .join(" ")
+ .map(
+ ([setting, { elements, filter }]) =>
+ `${setting}(${filter(elements[0].value)})`,
+ )
+ .join(" ");
// set the resolution to the original and then scale down to the viewport to
- // only calculate the filter on pixels the user can see.
+ // only calculate the filter on pixels the user can see.
canvas.height = img.naturalHeight;
canvas.width = img.naturalWidth;
if (viewport_scale) {
canvas.height = canvas.clientHeight;
canvas.width = canvas.clientWidth;
}
- ctx.filter = filter
+ ctx.filter = filter;
console.log(filter);
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
- ctx.filter = '';
+ ctx.filter = "";
if (lensflare_active) {
lensflare(cursor.x, cursor.y);
}
}
-
diff --git a/style.css b/style.css
index 4798e74..ba59bf6 100644
--- a/style.css
+++ b/style.css
@@ -4,8 +4,9 @@ body {
padding-top: 100dvh;
}
-canvas, video {
- max-width: 100%;
+canvas,
+video {
+ max-width: 100%;
max-height: 100%;
}
@@ -30,21 +31,21 @@ body.import-active .is-hidden-import {
}
#settings-button {
- position: absolute;
+ position: absolute;
right: 30px;
- bottom: 30px
+ bottom: 30px;
}
#back {
- position: absolute;
+ position: absolute;
left: 30px;
- top: 30px
+ top: 30px;
}
#cheese {
- position: absolute;
- bottom: 30px;
- left: 30px;
+ position: absolute;
+ bottom: 30px;
+ left: 30px;
right: 30px;
}