I was wondering if there is any way to save image original + Draggable blur mask over image
Here is an example of a draggable blur mask over the image : https://codepen.io/netsi1964/pen/AXRabW
$(function() {
$("#mask").draggable({
containment: "parent"
});
});
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
#mask {
width: 50px;
height: 50px;
border-radius: 100%;
overflow: hidden;
position: absolute;
top: calc(50% - 25px);
left: calc(50% - 25px);
}
#unblurred {
position: absolute;
top: 0;
left: 0;
z-index: 999;
width: 100%;
height: 100%;
overflow: hidden;
-webkit-filter: blur(0px);
}
#unblurred img {
position: fixed;
left: 0;
top: 0;
}
#blurred {
-webkit-filter: blur(20px);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.11.4/jquery-ui.min.js"></script>
<div id="mask">
<div id="unblurred">
<img src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
</div>
</div>
<img id="blurred" src="https://i.ytimg.com/vi/LRVsxe5OJVY/maxresdefault.jpg">
Wanted to save image with draggable blur mask over image... Maybe using canvas or something of the type
I think that I have a some what working solution, here is the JS code:
function saveMask() {
$("#blurred").hide()
html2canvas(document.querySelector("#mask"), {allowTaint: true}).then(h2c => {
var pos = $("#mask")[0].getBoundingClientRect();
$("#mask").hide()
var image = document.getElementById('blurred');
var canvas = document.createElement("canvas");
canvas.height = image.height;
canvas.width = image.width;
var ctx = canvas.getContext('2d')
ctx.filter = 'blur(20px)'
ctx.drawImage(image, 0, 0);
ctx.filter = 'none'
ctx.drawImage(h2c, pos.x, pos.y);
document.body.appendChild(canvas);
});
}
My idea here is to get as the mask using html2canvas and then we create a canvas with the blurred image and "paste" the mask on top of that.
I have a fully functional example here:
https://raw.githack.com/heldersepu/hs-scripts/master/HTML/html2canvas.html
Related
I am trying to create a full screen responsive background image (like css background-size:cover) that contains divs that keep there exact position on the image whilst being scaled via a browser resize.
<div class="full_Screen_background">
<div class="image_to_fill_and_scale_fullscreen">
<div class="content_to_be_scaled_with_window_resizing">
</div>
</div>
</div>
And the css:
.content_to_be_scaled_with_window_resizing{
border:5px solid #000;
position:absolute;
top:30%;
left:40%;
height:10%;
width:10%;
}
.image_to_fill_and_scale_fullscreen{
background: url(../4706825697_c0367e6dee_b.jpg);
position: relative;
background-size: cover;
background-position: center;
background-attachment: scroll;
height: 100vh;
background-repeat: no-repeat;
}
The desired outcome is to have the div perfectly scale proportionally with the image as the browser is resized.
Any ideas would be much appreciated?
https://jsfiddle.net/sfLgvyz0/
I tried it with a canvas. Hope that works for you. I fixed the rectangle to the head of the biker.
window.onload = drawFullImage;
window.onresize = drawFullImage;
function drawFullImage() {
var c = document.getElementById("myCanvas");
var imageDiv = c.parentNode;
c.width = imageDiv.getBoundingClientRect().width;
c.height = imageDiv.getBoundingClientRect().height;
var ctx = c.getContext("2d");
ctx.clearRect(0, 0, c.width, c.height);
var img = document.getElementById("imagetorender");
ctx.drawImage(img, 0, 0, c.width, c.height);
ctx.strokeRect(c.width / 100 * 75, c.height / 100 * 30, c.width / 100 * 10, c.height / 100 * 10);
}
body {
width: 100vw;
position: relative;
margin: 0;
}
#imagetorender {
visibility: hidden;
max-height: 100%;
width: 100%;
}
#myCanvas {
position: absolute;
top: 0;
left: 0;
}
<div id="wrapper">
<img id="imagetorender" src="http://farm5.static.flickr.com/4005/4706825697_c0367e6dee_b.jpg" />
<canvas id="myCanvas"></canvas>
</div>
Edit: I used a hidden image to get the aspect ratio right.
I tried pretty much everything I could find on the google and still can't get the solution in canvas.
Because the zoom affects positioning differently in different browsers, I want to use CSS 2d translate() will typically provide better FPS than position: absolute top & left.
https://jsfiddle.net/p0L9ztw8/
const dpr = window.devicePixelRatio || window.webkitDevicePixelRatio || window.mozDevicePixelRatio || 1;
const chineseSize = 60
const scale = 2
HanziWriter.create($('#test1')[0], '龍', {
renderer: 'canvas',
width: chineseSize * dpr * scale,
height: chineseSize * dpr * scale,
padding: 2
});
HanziWriter.create($('#test2')[0], '龍', {
renderer: 'canvas',
width: chineseSize * dpr * scale,
height: chineseSize * dpr * scale,
padding: 2
});
html, body {
margin: 0;
padding: 0;
}
div {
position: absolute;
transform-origin: left top;
}
canvas {
width: 60px;
height: 60px;
}
#test1 {
left: 0;
transform: scale(2);
}
#test2 {
left: 50%;
zoom: 200%;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/hanzi-writer#3.2.0/dist/index.cjs.min.js"></script>
<div id="test1"></div>
<div id="test2"></div>
Have you tried pixelated image rendering in css? It may be what is needed on the canvas and each div to be scaled.
canvas {
image-rendering: -moz-crisp-edges;image-rendering: -webkit-crisp-edges;image-rendering: pixelated;image-rendering: crisp-edges;
width: 60px;
height: 60px;
}
I have a customized seekbar for my HTML5 video player. But I need to highlight some predefined portions of the seekbar, say seconds 2-5 and 7-8. How can I do that?
Basically, I need it to be something like this:
Here is my simple code so far:
<!DOCTYPE html>
<html>
<head>
<style>
.body{
background-color:black;
}
.video-player {
position: relative;
width: 66%;
height: 66%;
}
.video-player img {
width: 100%;
height: 100%;
}
.video-player video {
position: fixed;
top: 0;
left: 0;
min-width: 66%;
min-height: 66%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
.video-player .controls {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.video-player .controls .progress-bar {
position: absolute;
margin-left: 28%;
bottom: 10%;
color: orange;
font-size: 12px;
width: 40%;
height: 8%;
border: none;
background: #434343;
border-radius: 9px;
vertical-align: middle;
cursor: pointer;
}
.video-player .controls progress::-moz-progress-bar {
color: orange;
background: #434343;
}
.video-player .controls progress[value]::-webkit-progress-bar {
background-color: #434343;
border-radius: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}
.video-player .controls progress[value]::-webkit-progress-value {
background-color: orange;
}
video#backgroundvid {
position: absolute;
right: 0;
bottom: 0;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
</style>
</head>
<body>
<div class="video-player">
<video preload="auto" autoplay loop id="backgroundvid">
<source src="mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<img src="top2.png" style="object-fit:cover" alt="" id="backgroundvid">
<div class="controls">
<progress class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
</div>
</div>
<script>
const player = document.querySelector('.video-player');
const video = player.querySelector('video');
const progressBar = player.querySelector('.progress-bar');
video.addEventListener('timeupdate', updateProgressBar, false);
progressBar.addEventListener('click', seek);
function updateProgressBar() {
var percentage = Math.floor((100 / video.duration) * video.currentTime);
progressBar.value = percentage;
progressBar.innerHTML = percentage + '% played';
}
function seek(e) {
let percent = e.offsetX / this.offsetWidth;
video.currentTime = percent * video.duration;
e.target.value = Math.floor(percent / 100);
e.target.innerHTML = progressBar.value + '% played';
}
</script>
</body>
</html>
You can use a canvas that you will superimpose on top of your progress-bar,
Then you will have just to draw the markers in this canvas.
Just making slight changes in the html (adding an id to the progress-bar id="progress-bar"):
<progress id="progress-bar" class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
Adding the CSS to style place the canvas (same CSS property than your progress-bar)
#markers{
position: absolute;
bottom: 10%;
margin-left: 28%;
border-radius: 9px;
pointer-events: none;
}
Note the pointer-events: none; If you don't put it, you can't have access to the control of your progress-bar.
And so, the javascript to create & insert the canvas, and then place the markers on it.
// We need the metadata 'duration', so we wrap the code in an event listener to be sure we execute our code when the metadata is loaded
video.addEventListener('loadedmetadata', function () {
// Get the dimension of the progress-bar
const progressbar = document.getElementById('progress-bar');
const widthProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("width");
const heightProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("height");
// Create the canvas
const canvas = document.createElement('canvas');
const w = canvas.width = parseFloat(widthProgressBar);
const h = canvas.height = parseFloat(heightProgressBar);
canvas.id = 'markers';
const progressBar = document.getElementById("progress-bar");
// Insert the canvas in the DOM
progressBar.parentNode.insertBefore(canvas, progressBar.nextSibling)
// Define the context
const ctx = canvas.getContext('2d');
// Calcul how many px will represent 1s
const videoDuration = video.duration;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
// Define the markers
const markers = {
'marker1': [2, 5],
'marker2': [7, 8]
};
// Function to draw the markers
function setMarkers(markers, ratioPxSec, height) {
for (marker in markers) {
let x = markers[marker][0] * ratioPxSec; // Start x position of the marker
let y = 0; // Start y position of the marker
let w = (markers[marker][1] - markers[marker][0]) * ratioPxSec; // Width of the marker
let h = parseFloat(height); // Height of the marker
ctx.fillStyle = "#7f3302"; // Set the color of the marker
ctx.fillRect(x, y, w, h); // Draw a rectangle
}
}
setMarkers(markers, ratioPxBySeconds, h); // Call the function
});
const player = document.querySelector('.video-player');
const video = player.querySelector('video');
const progressBar = player.querySelector('.progress-bar');
video.addEventListener('timeupdate', updateProgressBar, false);
progressBar.addEventListener('click', seek);
function updateProgressBar() {
var percentage = Math.floor((100 / video.duration) * video.currentTime);
progressBar.value = percentage;
progressBar.innerHTML = percentage + '% played';
}
function seek(e) {
let percent = e.offsetX / this.offsetWidth;
video.currentTime = percent * video.duration;
e.target.value = Math.floor(percent / 100);
e.target.innerHTML = progressBar.value + '% played';
}
// We need the metadata 'duration', so we wrap the code in an event listener to be sure we execute our code when the metadata is loaded
video.addEventListener('loadedmetadata', function() {
// Get the dimension of the progress-bar
const progressbar = document.getElementById('progress-bar');
const widthProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("width");
const heightProgressBar = window.getComputedStyle(progressbar, null).getPropertyValue("height");
// Create the canvas
const canvas = document.createElement('canvas');
const w = canvas.width = parseFloat(widthProgressBar);
const h = canvas.height = parseFloat(heightProgressBar);
canvas.id = 'markers';
const progressBar = document.getElementById("progress-bar");
// Insert the canvas in the DOM
progressBar.parentNode.insertBefore(canvas, progressBar.nextSibling)
// Define the context
const ctx = canvas.getContext('2d');
// Calcul how many px will represent 1s
const videoDuration = video.duration;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
// Define the markers
const markers = {
'marker1': [2, 5],
'marker2': [7, 8]
};
// Function to draw the markers
function setMarkers(markers, ratioPxSec, height) {
for (marker in markers) {
let x = markers[marker][0] * ratioPxSec; // Start x position of the marker
let y = 0; // Start y position of the marker
let w = (markers[marker][1] - markers[marker][0]) * ratioPxSec; // Width of the marker
let h = parseFloat(height); // Height of the marker
ctx.fillStyle = "rgb(127, 51, 2, 0.9)"; // Set the color of the marker
ctx.fillRect(x, y, w, h); // Draw a rectangle
}
}
setMarkers(markers, ratioPxBySeconds, h); // Call the function
// Calculate the new dimensions & redraw
function resize(){
const progressBar = document.getElementById('progress-bar');
const w = canvas.width = progressBar.clientWidth;
const h = canvas.height = progressBar.clientHeight;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
setMarkers(markers, ratioPxBySeconds, h);
}
// On page resize, call the resize() function
window.addEventListener("resize", resize, false);
});
body {
background-color: black;
}
.video-player {
position: relative;
width: 66%;
height: 66%;
}
.video-player img {
width: 100%;
height: 100%;
}
.video-player video {
position: fixed;
top: 0;
left: 0;
min-width: 66%;
min-height: 66%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
.video-player .controls {
position: absolute;
width: 100%;
height: 100%;
top: 0;
left: 0;
}
.video-player .controls .progress-bar {
position: absolute;
margin-left: 28%;
bottom: 10%;
color: orange;
font-size: 12px;
width: 40%;
height: 8%;
border: none;
background: #434343;
border-radius: 9px;
vertical-align: middle;
cursor: pointer;
}
#markers {
position: absolute;
bottom: 10%;
margin-left: 28%;
border-radius: 9px;
pointer-events: none;
}
.video-player .controls progress::-moz-progress-bar {
color: orange;
background: #434343;
}
.video-player .controls progress[value]::-webkit-progress-bar {
background-color: #434343;
border-radius: 2px;
box-shadow: 0 2px 5px rgba(0, 0, 0, 0.25) inset;
}
.video-player .controls progress[value]::-webkit-progress-value {
background-color: orange;
}
video#backgroundvid {
position: absolute;
right: 0;
bottom: 0;
min-width: 100%;
min-height: 100%;
width: auto;
height: auto;
z-index: -100;
background-repeat: no-repeat;
}
<div class="video-player">
<video preload="auto" autoplay loop id="backgroundvid">
<source src="https://www.w3schools.com/html/mov_bbb.mp4" type="video/mp4">
Your browser does not support HTML5 video.
</video>
<img src="https://i.stack.imgur.com/gmK7P.png" style="object-fit:cover" alt="" id="backgroundvid">
<div class="controls">
<progress id="progress-bar" class="progress-bar" style="object-fit:cover; z-index=10000" min="0" max="100" value="0">0% played</progress>
</div>
</div>
Edit:
Added a resize() function to update the markers when the screen resize
(typically, it will happen when you put the video in full screen)
// Calculate the new dimensions & redraw
function resize(){
const progressBar = document.getElementById('progress-bar');
const w = canvas.width = progressBar.clientWidth;
const h = canvas.height = progressBar.clientHeight;
const ratioPxBySeconds = parseFloat(w) / videoDuration;
setMarkers(markers, ratioPxBySeconds, h);
}
// On page resize, call the resize() function
window.addEventListener("resize", resize, false);
I have two overlapped images, here an example:
This is the HTML:
<div class='image-wrapper drag-area fade1' id='cupcategory-productname-1' style='width: 300px; top: 50%; left: 50%'>
<div class='mydiv' id='drag-fronte'>
<div id='logo-container-fronte' class='mydivheader logo'>
<img id='cupcategory-productname-fronte' name='logo-container' style='width: 300px; top: 50%; left: 50%' src='../img/esempio_logo.png' onclick='saveImageWithLogo(this)'>
</div>
</div>
<div>
<img id='cupcategory-productname-fronte-fade' src='".$file."' alt='Candia Image' style='width:100%' class='image-one'>
</div>
</div>
This code is generated by PHP.
This is the CSS:
.image-wrapper {
/*position: relative;*/
z-index: 1;
/*cursor:pointer;*/
background-size:contain;
background-repeat:no-repeat;
display:inline-block;
/*width:200px;height:140px;*/
-webkit-transition: all 100ms ease-in;
-moz-transition: all 100ms ease-in;
transition: all 100ms ease-in;
-webkit-filter: brightness(1) grayscale(.5) opacity(1);
-moz-filter: brightness(1) grayscale(.5) opacity(1);
filter: brightness(1) grayscale(.5) opacity(1);
}
.image-wrapper .image-one {
/*border: 1px solid black;*/
/*position: relative;*/
width: 100%;
}
.image-wrapper .image-fronte {
/*width:151px;height:113px;*/
/*width: 15%; height: 15%;*/
/*width: 65px; height: 65px;*/
/*border: 1px solid black;*/
position: absolute;
top: 53%;
left: 50%;
transform: translate(-50%, 0);
}
.image-wrapper .logo {
/*width:151px;height:113px;*/
/*width: 15%; height: 15%;*/
/*width: 65px; height: 65px;*/
/*border: 1px solid black;*/
position: absolute;
top: 53%;
left: 50%;
transform: translate(-50%, 0);
}
.mydiv {
top: 50%;
left: 50%;
position: absolute;
z-index: 9;
text-align: center;
/*border: 1px solid #d3d3d3;*/
}
.mydivheader {
padding: 10px;
height: 100px;
width: 100px;
cursor: pointer;
z-index: 10;
/*border: 1px solid black;*/
}
And this is the JS:
function saveImageWithLogo(web_element)
{
var c=document.getElementById("myCanvas");
var image1 = web_element;
var image2 = document.getElementById(web_element.id + '-fade');
console.log(image2);
var ctx=c.getContext("2d");
var imageObj1 = new Image();
var imageObj2 = new Image();
imageObj1.src = image1.src;
imageObj1.onload = function() {
ctx.drawImage(imageObj1, 0, 0, 100, 100);
imageObj2.src = image2.src;
imageObj2.onload = function() {
ctx.drawImage(imageObj2, 0, 0, 300, 300);
var img = c.toDataURL("image/png");
image1.src = img;
//document.write('<img src="' + img + '" width="328" height="526"/>');
}
};
}
The image1 is the cup and it comes from my server, the image2 is the overlapped image that should be the logo of my user. Now, the scenario is this: The user sees the cup, upload his logo and wants to go ahead buying this cup with his logo. My problem is to show this Cup with logo on it in the recap page but I also need to save it on server because other reasons.
How can I do? I tryed with canvas drawing two images starting from coords 0, 0 but image2 cover the image1.
Edit
I've tried to do this:
var image_wrapper = document.getElementsByClassName('image-wrapper')[0];
console.log(image_wrapper);
html2canvas(image_wrapper, {
onrendered: function (canvas) {
console.log('saving...');
console.log(canvas);
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("gardenia-mug-fronte-fade").appendChild(myImg);
$('#hidden_input').val(myImg.src);
},
});
But anything happens, the function doesn't start. What I wrong?
Edit 2
Ok now I've solved in this way:
var image_wrapper = document.getElementsByClassName('image-wrapper')[0];
console.log(image_wrapper);
html2canvas(image_wrapper).then(function(canvas) {
console.log(canvas);
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("gardenia-mug-fronte-fade").appendChild(myImg);
$('#hidden_input').val(myImg.src)
});
But what I get is a white image. I need to get both images within the div with 'image-wrapper' class, of course I've to get them as shown in the above picture
I did that before with a friend, but idid the part of uploading the user image, then capture it as base:64 new image, and he was responsible for storing the output in the server.
i used html2canvas
a nice javascript library to capture any html content into an image, and it has a lot of good options
and that was an example of what the logic we did : -
capture the html content
then save it as base:64
print the image link inside a hidden input
user can submit the form, finally u receive that data
and here a piece of code i made for capture the image and print the output link inside hidden input
html2canvas($('.imgs_wrapper'), {
onrendered: function (canvas) {
var myImg = new Image();
myImg.src = canvas.toDataURL();
document.getElementById("image_reply").appendChild(myImg);
$('.hidden_input').val(myImg.src)
},
});
My code allows scrolling vertically in the bottom section to control scrolling horizontally in the top section.
My jsfiddle
You'll see the colors shift through a gradient. Works pretty well. Problem is that I can't quite seem to get the inverse to work. Scrolling horizontally in the top controls scrolling in the bottom.
Any ideas?
Here's the script that makes it work:
// Add event listener for scrolling
$("#bottom").on("scroll", function bottomScroll() {
var scrolledleft = parseInt($("#bottom").scrollTop()) * 1;
console.log(scrolledleft + scrolledright)
$("#top").scrollLeft(scrolledleft + scrolledright)
})
//Move right column to bottom initially
$("#top").scrollLeft($("#top").height())
//Get actual distance scrolled
var scrolledright = parseInt($("#top").scrollLeft())
Your event handlers need to temporarily cancel each other so that they don't both fire at once. You want to calculate your position percentage based on the current scrollLeft / (width of child div - width of container), then apply that percentage to the other element, and likewise for top/height. Also I changed the height of #top to 50% in CSS.
var handler = function (e) {
var src = e.target;
// the first element that triggers this function becomes the active one, until it's done
if (!activeScroller) activeScroller = src.id;
else if (activeScroller != src.id) return;
var $b = $("#bottom");
var $t = $("#top");
var scrollH = $("#bottom-content").height() - $b.height();
var scrollW = $("#top-content").width() - $t.width();
var scrollPct = 0;
if (src.id == "top") {
if (scrollW > 0) {
scrollPct = $t.scrollLeft() / scrollW;
}
$b.scrollTop(scrollH * scrollPct);
} else {
if (scrollH > 0) {
scrollPct = $b.scrollTop() / scrollH;
}
$t.scrollLeft(scrollW * scrollPct);
}
// give all animations a chance to finish
setTimeout(function () { activeScroller = ""; }, 100);
};
var activeScroller = "";
$("#top,#bottom").on("scroll", handler);
#top {
position: absolute;
margin: auto;
top: 0;
right: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: red;
}
#top-content {
height: 100%;
width: 2000px;
background: linear-gradient(90deg, red, blue);
}
#bottom {
position: absolute;
margin: auto;
right: 0;
bottom: 0;
left: 0;
width: 100%;
height: 50%;
position: fixed;
overflow: auto;
background: green;
z-index: 100;
}
#bottom-content {
height: 2000px;
width: 100%;
background: linear-gradient(0deg, orange, green);
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="top">
<div id="top-content"></div>
</div>
<div id="bottom">
<div id="bottom-content"></div>
</div>
Check out this:
https://jsfiddle.net/1p7gp72h/1/
I'm not sure what your end goal is here.
$("#top").on("scroll", function topScroll() {
var scrolledleft = parseInt($("#top").scrollTop()) * 1;
$("#bottom").scrollLeft(scrolledleft + scrolledright)
});
#top {
top: 0;
right: 0;
left: 0;
width: 5000px;
height: 100%;
overflow: auto;
background: red;
overflow-x: scroll;
overflow-y: hidden;
white-space:nowrap;
}
Scroll to left ::
$('div').scrollLeft(1000);
Scroll back to normal/ scroll to right ::
$('div.slick-viewport').scrollLeft(-1000);