I am using jcrop for the first time. ANd I have a problem with image size and cropping. When user upload image 1366x768 or larger I preview it on my page. I also have crop selection preview and it works fine. When I submit positions it crops fine (it's when I use original image size).
But I don't want to display so large original images on page. User must see original image, preview and submit buttons in one view. So I need to make image smaller if image is 1366x768 I wan't to display it like 683x368. But here is the problem. When I set width and height on image tag crop not works fine anymore. I paste my code and image preview of my problem:
jQuery(window).load(function () {
jQuery('#cropbox').Jcrop({
onChange: showPreview,
onSelect: showPreview,
setSelect: [0, 0, 540, 300],
allowResize: true,
aspectRatio: 2
});
});
function showPreview(coords) {
if (parseInt(coords.w) > 0) {
var rx = 540 / coords.w;
var ry = 300 / coords.h;
jQuery('#preview').css({
width: Math.round(rx * 683) + 'px',
height: Math.round(ry * 368) + 'px',
marginLeft: '-' + Math.round(rx * coords.x) + 'px',
marginTop: '-' + Math.round(ry * coords.y) + 'px'
});
}
$('#x').val(coords.x);
$('#y').val(coords.y);
$('#w').val(coords.w);
$('#h').val(coords.h);
}
</script>
</head>
<body>
<div>
<p style="width: 540px; height: 300px; overflow: hidden; float:left;">
<img id="preview" src="../../Content/Images/Full/Leopard.jpg" />
</p>
<p style="float:left;">
<img id="cropbox" width="683px" height="368px" src="../../Content/Images/Full/Leopard.jpg" />
</p>
<p>
#using (#Html.BeginForm("PostPicture", "Home"))
{
<input type="hidden" id="x" name="x" />
<input type="hidden" id="y" name="y" />
<input type="hidden" id="w" name="w" />
<input type="hidden" id="h" name="h" />
<button type="submit">
Send</button>
}
</p>
This is second error: After I multiply X and Y with 2.
This is asp.net back end code:
public ImageResult PostPicture(int x, int y, int h, int w)
{
x = x * 2;
y = y * 2;
Image image = Image.FromFile(Path.Combine(this.Request.PhysicalApplicationPath, "Content\\Images\\Full\\Leopard.jpg"));
Bitmap cropedImage = new Bitmap(w, h, image.PixelFormat);
Graphics g = Graphics.FromImage(cropedImage);
Rectangle rec = new Rectangle(0, 0,
w,
h);
g.DrawImage(image, rec, x, y, w, h, GraphicsUnit.Pixel);
image.Dispose();
g.Dispose();
string savedFileName = Path.Combine(
AppDomain.CurrentDomain.BaseDirectory,
"Content", "Images", "Full",
Path.GetFileName("cropped.jpg"));
cropedImage.Save(savedFileName);
return new ImageResult { Image = cropedImage, ImageFormat = ImageFormat.Jpeg };
}
Maybe try setting the image size in css style attribute:
<img id="cropbox" style="width:683px;height:368px" src="../../Content/Images/Full/Leopard.jpg" />
Perhaps a better solution is to resize the image on the server to your desired dimensions, then display the resized image to the user instead of the full original image. This will also reduce download time for the browser since the image will be smaller.
You'll have to adjust the crop coordinates that are passed. You need to adjust them according to the ratio by which you resized your image for preview. So if you shrank your image preview to 50% of what it was originally, the actual coordinates of the crop will be twice what they come in as or (x*2, y*2).
Related
I'm actually working on a project which overlay two image, with one that the user upload it and the second is by default.
My only problem is when the uploaded image is a rectangle and not a square, the canvas is resizing it. I need that the canvas crop my image, and be a square. Then I can apply the filter.
Here is my code:
$('.file1, .file2').on('change', function() {
var reader = new FileReader(),
imageSelector = $(this).data('image-selector');
if (this.files && this.files[0]) {
reader.onload = function(e) {
imageIsLoaded(e, imageSelector)
};
reader.readAsDataURL(this.files[0]);
}
});
$('.btn-merge').on('click', merge);
function imageIsLoaded(e, imageSelector) {
$(imageSelector).attr('src', e.target.result);
$(imageSelector).removeClass('hidden');
};
function merge() {
var canvas = document.getElementById('canvas'),
ctx = canvas.getContext('2d'),
imageObj1 = new Image(),
imageObj2 = new Image();
canvas.width = 300;
canvas.height = 300;
imageObj1.src = $('.image1').attr('src');
imageObj1.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj1, 0, 0, 300, 300);
imageObj2.src = $('.image2').attr('src');
imageObj2.onload = function() {
ctx.globalAlpha = 1;
ctx.drawImage(imageObj2, 0, 0, 300, 300);
var img = canvas.toDataURL('img/png');
$('.merged-image').attr('src', img);
var mergedimage = document.getElementById('mergedimage');
$('.merged-image').removeClass('hidden');
$("#downloadfinal").attr("href", mergedimage.src);
}
};
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.2.0/jquery.min.js"></script>
<div class="container-fluid shadow">
<div class="container d-flex flex-column justify-content-center">
<div class="row mb-1 ">
<h2>Votre photo ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file1" type="file" data-image-selector=".image1" />Selectionner un fichier</label>
</div>
<img class="image1 hidden mb-4" alt="abs" width="200px" height="auto" />
<div class="row">
<h2 class="mr-2 ">Filtre par défaut : </h2>
<img alt="abs image3" width="200px" height="auto" src="img/filtre.png" />
</div>
<div class="otherfilter">
<div class="row mt-5 mb-5">
<h2 class="">Mettez un autre filtre ici : </h2>
<label class="custom ml-3 hover-underline-animation"> <input class="ml-2 file2" type="file" data-image-selector=".image2" />Selectionner un fichier</label>
</div>
<img class="hidden image2" alt="ab" width="200px" height="auto" src="img/filtre.png">
</div>
</div>
<br />
<div class="text-center mb-5">
<input class="btn-merge mb-3" type="button" value="Appliquer le filtre" />
<br />
<img class="merged-image hidden mb-3" id="mergedimage" alt="merged image" />
<canvas id="canvas" class="hidden"></canvas>
<br>
<a class="btn-dl" id="downloadfinal" role="button" href="#" download="photo_profil_modifie">
<i class="mr-2 bi bi-download"></i>Télécharger
</a>
</div>
Thanks for read this, hope my english is good, if you don't understand tell me.
To do this you need to scale the input image to fit the canvas either horizontally or vertically while maintaining it's aspect ratio.
That's not hard to do as things are a bit easier since the canvas is squarish. Say we have a canvas of 300 x 300 pixel and we want to draw a non-square image of 400 x 300 onto. First we take the width or height of the canvas - it does not really matter as it's the same - and divide it by the bigger side of the image - 400 in this case.
300 / 400 == 0.75
This is the scale we need to multiply both the width and height of the image before drawing it onto the canvas.
Here's an example:
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width > imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
#canvas {
background: blue;
}
<canvas id="canvas" width="300" height="300"></canvas>
If you prefer to not have unused area on your canvas and stretch the image to the whole canvas and crop the exceess, you simply divide the smaller side of your image by the canvas width/height.
For example:
//ctx.drawImage(imageObj1, 0, 0, 300, 300);let image = new Image();
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
let imageObj1 = new Image();
imageObj1.crossOrigin = 'anonymous';
imageObj1.crossOrigin = 'anonymous';
imageObj1.onload = () => {
let scale = imageObj1.width < imageObj1.height ? canvas.width / imageObj1.width : canvas.height / imageObj1.height;
context.drawImage(imageObj1, canvas.width / 2 - imageObj1.width * scale / 2, canvas.height / 2 - imageObj1.height * scale / 2, imageObj1.width * scale, imageObj1.height * scale);
}
imageObj1.src = 'https://api.codetabs.com/v1/proxy?quest=https://picsum.photos/id/237/300/400';
<canvas id="canvas" width="300" height="300"></canvas>
I am working on a photo editor and I want to add a download button that will download the image after the user makes the necessary changes. The changes are working fine but I am not able to figure out how to download the image (Please keep in mind that the filter value depends on the user and is not constant). Does anyone have any ideas on how I can proceed further?
(P.S. I searched all over Stack Overflow and tried to implement every solution in my code but nothing's working)
Here's my HTML:
<!-- upload image button -->
<p><input type="file" accept="image/*" name="image" id="file" onchange="loadFile(event)" style="display: none;"></p>
<p><label for="file" style="cursor: pointer;" id="fileBtn">UPLOAD IMAGE</label></p>
<p><img id="img"></p>
<!-- side nav -->
<div class="sidenav">
<label for="filter-select">FILTER AND ADJUST</label>
<div class="slider">
<p style="color: aliceblue;">Sepia</p>
<input id="sepia" type="range" oninput="setSepia(this);" value="0" step="0.1" min="0" max="1"><span id="Amount" style="color: white;"> 0</span><br/><br>
<p style="color: aliceblue;">Grayscale</p>
<input id="Grayscale" type="range" oninput="setGs(this);" value="0" step="0.1" min="0" max="1"><span id="Amount2" style="color: white;"> 0</span><br/><br>
</div>
<label onclick = "RotateImg()">ROTATE</label>
<label onclick = "flipping()">FLIP</label>
<label onclick = "invert()">INVERT COLOURS</label>
<label onclick = "original()">ORIGINAL</label>
</div>
Here's my JavaScript:
function loadFile(event) {
var image = document.getElementById('img');
image.src = URL.createObjectURL(event.target.files[0]);
}
const options = {
sepia: 0,
grayscale: 0,
rotation: 0,
scale: 1,
invertVal: 0
};
function setSepia(e){
options.sepia = e.value;
document.getElementById('Amount').innerHTML= e.value;
redraw();
}
function setGs(e){
options.grayscale = e.value;
document.getElementById('Amount2').innerHTML= e.value;
redraw();
}
let rotation = 0;
function RotateImg(){
rotation += 90;
if (rotation == 360) {
rotation = 0;
}
options.rotation = rotation;
redraw();
}
let scale = 1
function flipping() {
scale -= 2
if (scale <= -2) {
scale = 1;
}
options.scale = scale;
redraw();
}
let invertVal = 0
function invert() {
invertVal += 100
if (invertVal > 100) {
invertVal = 0
}
options.invertVal = invertVal;
redraw();
}
function original() {
document.getElementById("img").style["webkitFilter"] ="sepia(0) grayscale(0)";
document.querySelector("img").style.transform = "rotate(0deg) scaleX(1)";
}
function redraw() {
document.getElementById("img").style["webkitFilter"] ="sepia(" + options.sepia + ") grayscale(" + options.grayscale + ");
document.querySelector("img").style.transform = `rotate(${options.rotation}deg) scaleX(${options.scale})`;
}
Your best bet would be to use the Canvas API to apply your edits and then use toDataURL to set up the download.
Here's a proof of concept fiddle:
<div id="container">
<img src="//placekitten.com/400/400" crossorigin="anonymous"/>
<canvas width="400" height="400" />
</div>
const canvas = document.querySelector('canvas');
const image = document.querySelector('img');
image.addEventListener('load', () => {
const ctx = canvas.getContext('2d');
// draw the image into the canvas with a sepia filter:
ctx.filter = 'sepia(1)';
ctx.drawImage(image, 0, 0);
// set up the download link
addDownload(canvas);
})
function addDownload (canvas) {
// create an <a>
const a = document.createElement('a');
// set it up to download instead of navigating
a.setAttribute('download', 'kitten.jpg');
a.innerHTML = "download";
// set the href to a data url for the image
a.href = canvas.toDataURL('image/jpg');
// append it to the dom
container.appendChild(a);
}
I'm looking to get some help on a progress bar that goes around an image. I have provided my code below. If anyone can help it is highly appreciated!
Example Of what I need (The red Circles are the "images" and the green bars are the percentage bars that revolve around the image):
CODE:
<div class="imgmeter">
<div class="img-percent-bar">
<td class="usrimg">
<img src="assets/img/img.png">
<div class="bar"></div>
</div>
<div class="percentage">
<i><b>50.00%</b></i>
</div>
</div>
This can be done using an svg element with a circle that has a stroke-dasharray property in its styling. You can then use JavaScript to set the 'stroke-dasharray' property for the circle.
var circle = document.getElementById("circle_loader"),
percentage = document.getElementById("percentage"),
radius = document.getElementById("radius");
document.getElementById("percentage").addEventListener("change", function() { //when the percentage changes
var dasharray = (Number(percentage.value) * 2 * Number((Number(radius.value) * Math.PI))) + ", " + ((1 - Number(percentage.value)) * 2 * Number((Number(radius.value) * Math.PI)));
circle.style.strokeDasharray = dasharray; //sets the dasharray
});
radius.addEventListener("change", function() { //when the radius changes
var dasharray = (Number(percentage.value) * 2 * (Number(radius.value) * Math.PI)) + ", " + ((1 - Number(percentage.value)) * 2 * (Number(radius.value) * Math.PI));
circle.style.strokeDasharray = dasharray; //sets the dasharray
circle.setAttribute("r", radius.value); //sets the radius
circle.style.strokeDashoffset = Number(radius.value) * Math.PI * 0.5; //sets the starting point of the stroke to the top of the circle
});
#svg_circle_loader {
background: none;
border: none;
margin: none;
padding: none;
}
#circle_loader {
fill: none;
stroke: #F00;
stroke-width: 10px;
/* rotates the circle's stroke so that the start is at the top */
stroke-dashoffset: 78.5;
/* the 0 is the length of the arc filled by the stroke, and the 314 is the diameter (2 times the circle radius) times pi (3.14...) which is the "gap" between the coloured stroke arcs */
stroke-dasharray: 0, 314;
/* not necessary, but makes it look smoother */
transition: all 0.2s linear;
}
<form>
<!-- to demonstrate the system -->
<input id="radius" type="range" min="10" max="100" value="50" step="1" name="radius">
<br><span>radius</span>
<br>
<input id="percentage" type="range" min="0" max="1" value="0" step="0.01" name="percentage">
<br><span>percent complete</span>
</form>
<!-- the loader itself -->
<svg id="svg_circle_loader" width="200" height="200">
<!-- example values for dimensions -->
<circle cx="100" cy="100" r="50" id="circle_loader"></circle>
</svg>
This example is slightly complex, but I think that it is better to try and demonstrate with different radii rather than forcing you to use one that I have determined.
I have an SVG element
<svg id='win-frame' style='height: 500px; width: 500px;'>
</svg>
Say that the mouse is hovering over the svg element. Is there a way to display the coordinates of the point being hovered over by the mouse, either in a tooltip, or a div below the svg? This would preferably use javascript. Thanks!
Add text field to show coordinates:
<input type="text" id="coords" readonly></input>
Then handle the mousemove and mouseout events to fill the coords input with coordinates:
/* create an svg drawing */
var draw = SVG('win-frame');
/* draw rectangle */
var rect = draw.rect(200, 200).fill('#f09')
var coordsDiv = document.getElementById('coords');
rect.mousemove(function(evt) {
coordsDiv.value = evt.clientX + ' ' + evt.clientY;
}).mouseout(function() {
coordsDiv.value = '';
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/svg.js/2.0.5/svg.js"></script>
<div id="win-frame"></div>
<input type="text" id="coords" readonly />
EDIT: Pure javascript solution
HTML part:
<svg id='win-frame' style='height: 200px; width: 200px;' >
<rect width="100%" height="100%" style="fill:rgb(0,0,255);" />
</svg>
<input type="text" id="coords" readonly />
And javascript part:
var coordsDiv = document.getElementById('coords');
var el1 = document.getElementById('win-frame');
el1.onmousemove = function(evt) {
coordsDiv.value = evt.clientX + ' ' + evt.clientY;
}
Demo fiddle: http://jsfiddle.net/7fh68sb5/2/
I want to increase height and width of my svg image same as canvas height and width so that it look like background image of canvas. When I press Set Background button, one svg image will be set to canvas from my directory. I want to scale this image up to canvas height and width dynamically.
Expected Output: I want this
Html
<h1>canvas</h1>
<canvas style="left: -300px; border: 1px dotted;" height="385" width="400" id="c"></canvas>
<input type="button" id="svg3" value="set background" />
Script
$(document).ready(function(){
var canvas = new fabric.Canvas('c');
var colorSet="red";
$("#svg3").click(function(){
fabric.loadSVGFromURL('http://upload.wikimedia.org/wikipedia/en/c/cd/-Islandshreyfingin.svg', function (objects, options) {
var shape = fabric.util.groupSVGElements(objects, options);
shape.set({
left: 150,
top:200,
//height: 700,
//width: 700,
scaleX: .35,
scaleY:.35
});
if (shape.isSameColor && shape.isSameColor() || !shape.paths) {
shape.setFill(colorSet);
} else if (shape.paths) {
for (var i = 0; i < shape.paths.length; i++) {
shape.paths[i].setFill(colorSet);
}
}
canvas.add(shape);
canvas.renderAll();
});
});
});
Here is my FIDDLE Demo.
Does anybody have an idea how to do this?
You know your canvas width and height. So this will work:
shape.set({
top: canvas.height/2,
left: canvas.width/2,
scaleY: canvas.height / shape.height,
scaleX: canvas.width / shape.width
});
I finally got the solution:
HTML
<h1>canvas</h1>
<canvas style="left: -300px; border: 1px dotted;" height="585" width="400" id="c"></canvas>
<input type="button" id="svg3" value="set background" />
<input type="button" id="color" value="Change Image Color" />
JavaScript
function setBackgroundColor(color) {
if (background.isSameColor && background.isSameColor() || !background.paths) {
background.setFill(color);
} else if (background.paths) {
for (var i = 0; i < background.paths.length; i++) {
background.paths[i].setFill(color);
}
}
}
var canvas = new fabric.Canvas('c');
var background;
$("#svg3").click(function() {
fabric.loadSVGFromURL('http://upload.wikimedia.org/wikipedia/en/c/cd/-Islandshreyfingin.svg',
function (objects, options) {
background = fabric.util.groupSVGElements(objects, options);
background.set({
left: canvas.width/2,
top: canvas.height/2,
scaleY: canvas.height / background.width,
scaleX: canvas.width / background.width,
selectable: false
});
setBackgroundColor('red');
canvas.add(background);
canvas.renderAll();
});
});
$("#color").click(function(){
setBackgroundColor('blue');
canvas.renderAll();
});
working Demo Fidddle