Open bhardwick opened 12 years ago
My work-around was to remove the tag from the DOM and re-add it, before re-initializing jCrop:
$('#cropImage').replaceWith('<img id="cropImage" src="' + source + '"/>');
$('#cropImage').Jcrop({...});
+1
The workaround only works for very simple cases / img elements - any number of other properties (e.g. unique IDs, CSS classes, data attributes, etc) could be destroyed.
IMHO jCrop shouldn't need to modify the image at all, it should store the height & width using jQuery data(), which will in turn use data- attributes when available, and otherwise use jQuery's internal data storage system.
These values should also be automatically removed during destroy().
+1 Add 'visibility' to this list
Yep just hit this issue. Is there a robust work around for this?
I doubt this could be classified as "robust", but this has been working for me:
jcrop_api.destroy();
$('.imagePreviewLarge').removeAttr('style');
That is working for me too
jcrop_api.destroy();
$('.imagePreviewLarge').removeAttr('style');
thanks a lot
yes, this worked fine. and as per my analysis it is the workaround needed. jcrop_api.destroy(); $('.imagePreviewLarge').removeAttr('style');
I'm running up against this too. I had used setImage previously, but for some reason that's not working for me anymore.
+1
+1
I'm removing the style attribute too. I don't know why jCrop wouldn't return the DOM as it was before.
I'm signing in just to up this comment:
tomatohater commented 9 months ago
I doubt this could be classified as "robust", but this has been working for me:
jcrop_api.destroy();
$('.imagePreviewLarge').removeAttr('style');
And many thanks to the topic creator.
zx
+1, removeAttr is old school but it works.
This (the removeAttr("style");) worked for me as well. BUT, only on Chrome. Firefox still doesn't properly destroy, nor the attribute gets removed. :( Has anyone tested on those two browsers?
My original suggestion, to remove the tag from the DOM and add it again, although not ideal, was working in Firefox. It is not as clean as some of the other solutions though.
@talofo My recent tests show that the destroy/removeAttr method does work in Chrome/FF/Safari/IE11. Are you sure nothing else is bombing out?
I whipped up a barebones example that compares the default behavior with the removeAttr workaround: http://jcrop-issue-46.herokuapp.com/
I do believe that this cleanup would be better off in the .destroy() method itself. But until then...
No dice. :( It's so frustrating. I have all a crop php plugin based on this, and it keeps showing two images with visibility: visible, instead of one, and it keeps putting the second image with the wrong withs and heights. I'm completely lost on all this code already, with no clear way to solve this.
It is really frustrating. Took a long way to understand what was happening, Tried to fix, but no use. Please let me know when this issue will be fixed.
work for me
jQuery(function($) {
function showCoords(c) {
// variables can be accessed here as
// c.x, c.y, c.x2, c.y2, c.w, c.h
};
function readURL(input) {
if (input.files && input.files[0]) {
var reader = new FileReader();
reader.onload = function(e) {
//remove current jcrop
$('.jcrop-holder').replaceWith('');
//replace with new image
$('#avatar-crop').replaceWith('<img id="avatar-crop" src="' + e.target.result + '" width="100%"/>');
//run jcrop again
$("#avatar-crop").Jcrop({
onSelect: showCoords,
onChange: showCoords
});
}
reader.readAsDataURL(input.files[0]);
}
}
// first run jcrop
$("#avatar-crop").Jcrop({
onSelect: showCoords,
onChange: showCoords
});
//input file
$("#user_avatar").change(function() {
readURL(this);
});
});
tested: jquery.Jcrop.js v0.9.12
+1
+1
+1
+1
+1
I've given up on Jcrop and am switching to using Cropper instead - play with the demo, it's fantastic!
+1, p.s. @MarcusJT thanks for the link
Unfortunately Cropper is a disaster on cell phones (running Opera or Chrome) and pans the image instead of the cropping area when using the cursor keys on a PC (running Opera or Chrome). I found that Jcrop has much better compatibility.
Strange, CropperJS works perfectly for me in Chrome on Android, I just tried it.
As for cursor keys panning the image rather than the cropping area, that's an implementation decision which surely you could either fork and change, or there may even be a fully supported way to change this (i.e. by configuring something or writing a little code to override the default keypress event handler)
Anyway, I've not needed to crop images since I last posted and I'm unlikely to again, so I'm going to bow out of & unsubscribe from this thread, all the best!
Hello Folks,
I had to develop an application using a Webcam as well as Upload File along with JCrop - that with toggle options between Cam and the Upload File.
What worked for me was to reset the canvas height and width while Cropping the image - see $('#btnCrop').click
Here is the entire code:
<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml">
<head >
<title>Upload Image</title>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/css/bootstrap.min.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.0/umd/popper.min.js"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.5.2/js/bootstrap.min.js"></script>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/jquery-jcrop/0.9.9/js/jquery.Jcrop.min.js"></script>
<style>
.center {
text-align: center;
}
</style>
<script type="text/javascript">
$(function () {
//Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
//#region WebCam
// Grab elements, create settings, etc.
let video = document.getElementById('video');
// Get access to the camera!
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
// Not adding `{ audio: true }` since we only want video now
navigator.mediaDevices.getUserMedia({ video: true }).then(function (stream) {
//video.src = window.URL.createObjectURL(stream);
video.srcObject = stream;
video.play();
});
}
// Elements for taking the snapshot
let canvas = document.getElementById('canvas');
let context = canvas.getContext('2d');
// Trigger photo take
document.getElementById("btnCapture").addEventListener("click", function () {
//Set Ratio
var ratio;
var width = 600;//window.innerWidth;
var height = 600;//window.innerHeight;
if (video.width > width) {
ratio = width / video.width;
}
else if (video.height > height) {
ratio = height / video.height;
}
else {
ratio = 1;
}
context.drawImage(video, 0, 0, video.width * ratio, video.height * ratio);
console.log('Video w:' + video.width * ratio);
console.log('Video h:' + video.height * ratio);
//Set the canvas to Image1
$("#Image1")[0].src = canvas.toDataURL();
$("#Image1").show();
$("#canvas").hide();
// destroy Jcrop if it is existed
if (typeof jcrop_api != 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
}
$('#Image1').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates
},
function () {
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
});
});
//#endregion WebCam
//#region FileUpload, Resize, JCrop, Crop & Clear
$('#FileUpload1').change(function (event) {
try {
var files = event.target.files;
var file = files[0];
console.log('FileUpload1 Length:' + files.length);
if (file) {
$('#Image1').hide();
var reader = new FileReader();
reader.onload = function (e) {
//$('#Image1').show();
$('#Image1').attr("src", e.target.result);
};
reader.readAsDataURL($(this)[0].files[0]);
//#region Resize & JCrop
var reader = new FileReader();
// Set the image for the FileReader
reader.onload = function (e) {
var img = document.createElement("img");
img.src = e.target.result;
// Create your canvas
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 400;
var MAX_HEIGHT = 400;
let width = img.width;
let height = img.height;
console.log('Image w & h:' + width + '-' + height);
if (width == 0 && height == 0) {
throw new UserException("An internal error occured - please try again or contact your administrator!");
return;
}
// Add the resizing logic
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
//Specify the resizing result
canvas.width = width;
canvas.height = height;
console.log('Canvas w & h:' + canvas.width + '-' + canvas.height);
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
dataurl = canvas.toDataURL(file.type);
document.getElementById("Image1").src = dataurl;
$('#Image1').show();
// destroy Jcrop if it is existed
if (typeof jcrop_api != 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
}
$('#Image1').Jcrop({
onChange: SetCoordinates,
onSelect: SetCoordinates
},
function () {
// use the Jcrop API to get the real image size
var bounds = this.getBounds();
boundx = bounds[0];
boundy = bounds[1];
// Store the Jcrop API in the jcrop_api variable
jcrop_api = this;
});
};
reader.readAsDataURL(file);
//#endregion Resize & JCrop
}
}
catch (err) {
alert(err.message);
}
});
$('#btnCrop').click(function () {
var x1 = $('#imgX1').val();
var y1 = $('#imgY1').val();
var width = $('#imgWidth').val();
var height = $('#imgHeight').val();
var canvas = $("#canvas")[0];
var context = canvas.getContext('2d');
var img = new Image();
img.onload = function () {
canvas.height = height;
canvas.width = width;
context.drawImage(img, x1, y1, width, height, 0, 0, width, height);
$('#imgCropped').val(canvas.toDataURL());
$("#capturedImage")[0].src = canvas.toDataURL();
document.getElementById("<%=ImgExSrc.ClientID%>").value = canvas.toDataURL();
document.getElementById("btnSubmit").disabled = true;
$('#btnSubmit').show();
$('#lblTermsConditions').show();
$('#chkApprove').show();
//Reset the canvas height & width
console.log('before:' + canvas.height + '-' + canvas.width);
canvas.height = 380;
canvas.width = 380;
console.log('after:' + canvas.height + '-' + canvas.width);
};
img.src = $('#Image1').attr("src");
$("#canvas").hide();
});
$('#btnClear').click(function () {
Clear();
});
//#endregion FileUpload, Resize, JCrop, Crop & Clear
});
function Clear() {
$('#Image1').attr('src', 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///ywAAAAAAQABAAACAUwAOw==');
$("div.jcrop-holder").remove();
$("div.jcrop-tracker").remove();
$('#btnCrop').hide();
$('#btnClear').hide();
}
function SetCoordinates(c) {
$('#imgX1').val(c.x);
$('#imgY1').val(c.y);
$('#imgWidth').val(c.w);
$('#imgHeight').val(c.h);
$('#btnCrop').show();
$('#btnClear').show();
};
function UserException(message) {
alert(message);
console.log(message);
}
</script>
</head>
<body>
<form id="form2" >
<div class="container">
<div class="jumbotron">
<h1>Upload Image</h1>
<p class="lead">This application offer to capture image along with crop functionality using either a Live Camera or an Upload File Control.</p>
</div>
<div class="row">
<div class="col-md-4" style="background-color: lavender;">
<div class="center">
<p><b>Live Camera</b></p>
<video id="video" width="400" height="400" autoplay></video>
<br />
<input type="button" id="btnCapture" value="Capture" />
<br />
<br />
</div>
</div>
<div class="col-md-4" style="background-color: orange;">
<div class="center">
<p><b>Upload File</b></p>
<input type="file" id="FileUpload1" accept=".jpg,.png,.gif" />
<br />
<br />
</div>
<table class="table" border="0">
<tbody>
<tr>
<td>
<img id="Image1" src="" style="display: none" />
</td>
<td>
<canvas id="canvas" height="380" width="380"></canvas>
</td>
</tr>
</tbody>
</table>
<br />
<input type="hidden" name="imgX1" id="imgX1" />
<input type="hidden" name="imgY1" id="imgY1" />
<input type="hidden" name="imgWidth" id="imgWidth" />
<input type="hidden" name="imgHeight" id="imgHeight" />
<input type="hidden" name="imgCropped" id="imgCropped" />
<div class="align-items-center">
<input type="button" id="btnCrop" value="Crop" style="display: none" />
<input type="button" id="btnClear" value="Clear" style="display: none" />
<br />
<br />
</div>
</div>
<div class="col-md-4" style="background-color: lavender;">
<div class="center">
<p><b>Captured Image</b></p>
<img id="capturedImage" src="" />
<asp:HiddenField runat="server" ID="ImgExSrc" />
<br />
<br />
<input type="checkbox" id="chkApprove" onchange="document.getElementById('btnSubmit').disabled = !this.checked;" style="display: none">
<asp:Label ID="lblTermsConditions" runat="server" Style="display: none" Text="I have read and understood the declaration of consent. I agree to the terms and conditions."></asp:Label>
<br />
<br />
<asp:Button ID="btnSubmit" OnClientClick="alert('Submitted successfully!'); return false;" runat="server" Text="Submit" Style="display: none" />
<br />
<br />
</div>
</div>
</div>
</div>
</form>
</body>
</html>
MOVED FROM GOOGLE CODE
What steps will reproduce the problem?
What is the expected output? What do you see instead? You'll see that the image is now stretched to the dimensions of the previous image.
What version of the product are you using? On what operating system? 0.9.9
Please provide any additional information below. The reason this happens is because when JCrop is first initialized, it attaches height and width attributes to the tag that you initialize it with. However, after calling destroy(), the height and width attributes are still present, so you can't just update the source and open JCrop again. The fix would be to remove the height and width attributes (or reset them to their original values) in the destroy() method.