Jcrop does not refresh newly selected image - javascript

I work a form that would let users to select an image on their computer, crop it and finally upload as profile image. I use JCrop to crop the photo. After a lot of struggles, now everything seems to work fine, except that if the user changes its mind and would like to browse in a second image, the image is not replaced on my form. I do replace the src attribute of the 'preview' image, but it seems that somehow JCrop still stores the previous image and this somehow "covers" the new image. I tried to use the JCrop setImage method to replace the image, but it does not seem to work. Any hints on how to fix this? Please see the code samples below.
var currentFile;
var file;
var options;
// convert bytes into friendly format
function bytesToSize(bytes) {
var sizes = ['Bytes', 'KB', 'MB'];
if (bytes == 0) return 'n/a';
var i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024)));
return (bytes / Math.pow(1024, i)).toFixed(1) + ' ' + sizes[i];
};
// check for selected crop region
function checkForm() {
if (parseInt($('#w').val())) return true;
jQuery('.error').html('Please select a crop region and then press Upload').show();
return false;
};
// update info by cropping (onChange and onSelect events handler)
function updateInfo(e) {
jQuery('#x1').val(e.x);
jQuery('#y1').val(e.y);
jQuery('#x2').val(e.x2);
jQuery('#y2').val(e.y2);
jQuery('#w').val(e.w);
jQuery('#h').val(e.h);
};
// clear info by cropping (onRelease event handler)
function clearInfo() {
jQuery('.info #w').val('');
jQuery('.info #h').val('');
};
function fileSelectHandler(evt) {
// hide all errors
jQuery('.error').hide();
// grabbing image
evt.preventDefault()
var target = evt.target
file = target && target.files && target.files[0]
if (!file) {
jQuery('.error').html('Image not found.').show();
jQuery('#main_photo').val('');
return;
}
var oFile = target.files[0];
// check for image type (jpg is allowed)
var rFilter = /^(image\/jpeg)$/i;
if (! rFilter.test(oFile.type)) {
jQuery('.error').html('Please select a valid image file (jpg)').show();
jQuery('#main_photo').val('');
return;
}
// check for file size
if (oFile.size > 5 * 1024 * 1024) {
jQuery('.error').html('You have selected too big file (max: 5 MB), please select a one smaller image file').show();
jQuery('#main_photo').val('');
return;
}
//setting options for image loader
options = {
orientation: true,
maxWidth: 400
}
// preview element
var oImage = document.getElementById('preview');
// adding onload event handler to initialize JCrop
oImage.onload = function () {
// Create variables (in this scope) to hold the Jcrop API and image size
var jcrop_api, boundx, boundy;
console.log(oImage);
// destroy Jcrop if it is existed
if (typeof jcrop_api != 'undefined') {
jcrop_api.destroy();
jcrop_api = null;
}
// initialize Jcrop
jQuery('#preview').Jcrop({
minSize: [32, 32], // min crop size
aspectRatio : 200/250, // keep aspect ratio 1:1
bgFade: true, // use fade effect
bgOpacity: .3, // fade opacity
trueSize: [oImage.naturalWidth,oImage.naturalHeight],
onChange: updateInfo,
onSelect: updateInfo,
onRelease: clearInfo
}, 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;
console.log(jQuery('#preview').attr('src'));
jcrop_api.setImage(jQuery('#preview').attr('src'));
});
};
displayImage(file, options);
}
/**
* Updates the results view
*
* #param {*} img Image or canvas element
* #param {object} [data] Meta data object
*/
function updateResults(img, data) {
var fileName = currentFile.name
var href = img.src
var dataURLStart
var content
if (!(img.src || img instanceof HTMLCanvasElement)) {
content = jQuery('<span>Loading image file failed</span>')
} else {
if (!href) {
href = img.toDataURL(currentFile.type + 'REMOVEME')
// Check if file type is supported for the dataURL export:
dataURLStart = 'data:' + currentFile.type
if (href.slice(0, dataURLStart.length) !== dataURLStart) {
fileName = fileName.replace(/\.\w+$/, '.png')
}
}
content = jQuery('<a target="_blank">')
.append(img)
.attr('download', fileName)
.attr('href', href)
}
jQuery('#preview').attr("src", href);
}
/**
* Displays the image
*
* #param {File|Blob|string} file File or Blob object or image URL
* #param {object} [options] Options object
*/
function displayImage(file, options) {
currentFile = file
if (!loadImage(file, updateResults, options)) {
jQuery('.error').html('Incompatible browser. Image cannot be displayed.').show();
jQuery('#main_photo').val('');
return;
}
}

I created a wrapper like this
<div id="wrapper_img">
<img id="img">
</div>
and clean de wrapper and recreate de img to reload new image
$('#wrapper_img').empty();
var img = $('<img id="img">');
img.attr('src', 'my_image.png');
img.appendTo('#wrapper_img');
after that y create a new JCrop
img.Jcrop({....})

Related

Fabric.js: Error when loading image from parameterized URL

I'm trying to load an image from an external URL. The image is retrieved dynamically from a database and is therefore not a direct path. An example of such URL is: http://192.192.168.12:8080/api/imageServer?file=imageName.jpeg. The response in an actual jpeg image; when I add the URL to an image tag or directly in the browser the image is shown. When I try to load the image into Fabric.js I only get the console message "Error loading " without any other message.
This is part of our code:
var updateCanvas = function () {
self.canvas.clear();
if (self.selectedImage() && self.canvas) {
try {
fabric.Image.fromURL(self.selectedImage().imageUrl, function (oImg) {
if (oImg._element == null) {
stickyToast(translations().Error, translations().img_bind_error, "error");
return;
}
self.canvas.clear();
var canvasHeight = 500;
var ratio = canvasHeight / oImg.height;
var canvasWidth = oImg.width * ratio;
//Define all filters that will be used on image
oImg.filters[0] = new fabric.Image.filters.Brightness({
brightness: 0
});
...
I've tried upgrading to the latest version of fabric.js but to no avail. Is there another method I need to use download the image?

Simulate drag and drop of file to upload in Protractor

I want to test file upload, by dragging file to the drop zone in the page, however I can't find a way to simulate file dragging from the desktop folder.
The only way I managed to found is the following one -
desktop.browser.actions().dragAndDrop(elem,target).mouseUp().perform();(Protractor)
However as far as I can understand, it drags only css element.
This is a working example to simulate a file drop from the desktop to a drop area:
const dropFile = require("./drop-file.js");
const EC = protractor.ExpectedConditions;
browser.ignoreSynchronization = true;
describe('Upload tests', function() {
it('should drop a file to a drop area', function() {
browser.get('http://html5demos.com/file-api');
// drop an image file on the drop area
dropFile($("#holder"), "./image.png");
// wait for the droped image to be displayed in the drop area
browser.wait(EC.presenceOf($("#holder[style*='data:image']")));
});
});
The content of drop-file.js :
var fs = require('fs');
var path = require('path');
var JS_BIND_INPUT = function (target) {
var input = document.createElement('input');
input.type = 'file';
input.style.display = 'none';
input.addEventListener('change', function () {
target.scrollIntoView(true);
var rect = target.getBoundingClientRect(),
x = rect.left + (rect.width >> 1),
y = rect.top + (rect.height >> 1),
data = { files: input.files };
['dragenter','dragover','drop'].forEach(function (name) {
var event = document.createEvent('MouseEvent');
event.initMouseEvent(name, !0, !0, window, 0, 0, 0, x, y, !1, !1, !1, !1, 0, null);
event.dataTransfer = data;
target.dispatchEvent(event);
});
document.body.removeChild(input);
}, false);
document.body.appendChild(input);
return input;
};
/**
* Support function to drop a file to a drop area.
*
* #view
* <div id="drop-area"></div>
*
* #example
* dropFile($("#drop-area"), "./image.png");
*
* #param {ElementFinder} drop area
* #param {string} file path
*/
module.exports = function (dropArea, filePath) {
// get the full path
filePath = path.resolve(filePath);
// assert the file is present
fs.accessSync(filePath, fs.F_OK);
// resolve the drop area
return dropArea.getWebElement().then(function (element) {
// bind a new input to the drop area
browser.executeScript(JS_BIND_INPUT, element).then(function (input) {
// upload the file to the new input
input.sendKeys(filePath);
});
});
};
You cannot drag an element from your desktop using protractor, its actions are limited to the browser capabilities.
You may have to consider dragging from the desktop to work (unless you want to test your operating system), and check that once the file is given to the HTML element, everything works correctly.
One way to achieve that is with the following:
dropElement.sendKeys(path);
For instance if that element is, as usual, an input of type file:
$('input[type="file"]').sendKeys(path);
Note that path should be the absolute path to the file you want to upload, such as /Users/me/foo/bar/myFile.json or c:\foo\bar\myFile.json.

Validating Image upload

I'm trying to validate the image before being uploaded. I restrict the size and pixels but the problem is that I can still upload the image even though it doesn't apply to the restrictions. How can I stop the user or disable the upload as this validation is done with the onchange command.
var myFile = document.getElementById('file');
myFile.addEventListener('change', function() {
image = new Image();
if(this.files[0].size > 800000)
{
alert("File size too big. Please upload a smaller image");
return false;
}
else
{
var reader = new FileReader();
//Read the contents of Image File.
reader.readAsDataURL(this.files[0]);
reader.onload = function (e)
{
//Initiate the JavaScript Image object.
var image = new Image();
//Set the Base64 string return from FileReader as source.
image.src = e.target.result;
image.onload = function () {
//Determine the Height and Width.
var height = this.height;
var width = this.width;
if (height > 500 || width > 375) {
alert("Height and Width must not exceed 500px(h) and 375px(w).");
return false;
}
else
{
alert("Uploaded image has valid Height and Width.");
return true;
}
};
}
}
});
You can reset the value of the file input element if your validation fails
var myFile = document.getElementById('file');
...
myFile.value=""
And then show validation to the user in page.
Here's what I did as an alternative. I didn't know this was possible until I came upon this. You just add this to the relevant alert/return false section and it disables the submit button.
jQuery("input[type='submit']").attr("disabled", 'disabled');

drag and drop images from `dropbox` account to html canvas - `not working in chrome`

This code is to drag images from image gallery and drop inside canvas (fabric.js is used) and also drag and drop images from dropbox account which is opend in another tab. This works fine in firefox, I can drag images from my drop box account and drop in inside canvas. But not in chrome. e.dataTransfer.getData("Text") gives an empty value in chrome. I thought it's a problem of same-origin-policy and tried a lot to fix it. But no luck. Please help me to get a work around for this.
function handleDrop(e) {
e.stopPropagation();
e.preventDefault();
// handle local images
if(e.dataTransfer.files.length > 0){
var files = e.dataTransfer.files;
for (var i = 0, f; f = files[i]; i++) {
// Only process image files.
if (f.type.match('image.*')) {
// Read the File objects in this FileList.
var reader = new FileReader();
// listener for the onload event
reader.onload = function(evt) {
// create img element
var img = document.createElement('img');
img.src= evt.target.result;
// put image on canvas
var newImage = new fabric.Image(img, {
width: img.width,
height: img.height,
// Set the center of the new object based on the event coordinates relative to the canvas container.
left: e.layerX,
top: e.layerY
});
canvas.add(newImage);
};
// Read in the image file as a data URL.
reader.readAsDataURL(f);
}
}
}
// handle dropbox images
else{
var img = e.dataTransfer.getData("Text");
console.log(img);
var img = e.dataTransfer.getData("Text");
if (img.indexOf('jpg')>0 ||img.indexOf('png')>0){
var temp = '<img draggable="true" src="'+img+'" width="250" height="250"></img>';
$('#before').append(temp);
var i = document.querySelector('img[src="'+img+'"]');
console.log('i: ',i);
var nI = new fabric.Image(i,{
width: i.width,
height:i.height,
left:e.layerX,
top:e.layerY
});
canvas.add(nI);
}
}
return false;
}

Save google map as an image - using javascript (able to take screenshot)

I referred to the following SO questions to capture a screenshot of google maps using javascript (html2canvas). feedback.js, screen-capturing-using-html2canvas, create-screen-shot, capture-div-into-image, html2canvas-github.
I used static maps to get the image, but I have close to 150 markers and the total length of the URL went way beyond the 2048 character limit.
I am able to capture a screenshot using event listeners in javascript. The code I used to capture the image is below. I tried using window.save, but there is no such method in html2canvas.js. Any suggestions on how to save the image to the local filesystem?
function takeImage() {
html2canvas($("#map-canvas"), {
onrendered: function( canvas ) {
var img = canvas.toDataURL("image/png")
window.open(img);
//window.save(img); /*does not work.*/
}
});
}
The event listener:
google.maps.event.addListener(map, 'tilesloaded', function() {
takeImage();
});
I had problems with IE9 and, in Chrome, some images are downloaded but they are corrupted. The only solution I found for IE9 was opening the image on a new tab, then I was able to right click and save as.
I made the next code for download the div area (container of the map) as an image using html2canvas.
function download_image() {
if($.browser.safari) {// Fix for Chrome
var transform=$(".gm-style>div:first>div").css("transform");
var comp=transform.split(","); //split up the transform matrix
var mapleft=parseFloat(comp[4]); //get left value
var maptop=parseFloat(comp[5]); //get top value
$(".gm-style>div:first>div").css({ //get the map container. not sure if stable
"transform":"none",
"left":mapleft,
"top":maptop,
});
}
html2canvas([$("#div_id")[0]], {
logging: false,
useCORS: true,
onrendered: function (canvas) {
if ($("#downloadimg").length > 0)
$("#downloadimg").remove();
var fileName = "file_name.png";
if (/\bMSIE|Trident\b/.test(navigator.userAgent) && $.browser.version.match(/9.0|10.0|11.0/)) {//Only for IE 9, 10 and 11
download_image_IE(canvas, fileName);
}
else {
$("body").append("<a id='downloadimg' download='" + fileName + "' href='" + canvas.toDataURL("image/png").replace("image/png", "image/octet-stream") + "'><a/>");
}
if ($("#downloadimg").length > 0)
$("#downloadimg")[0].click();
if($.browser.safari) {// Fix for Chrome
$(".gm-style>div:first>div").css({
left:0,
top:0,
"transform":transform
});
}
}
});
}
function download_image_IE(canvas, filename) {
if ($.browser.version.match(/9.0/)){ //Only for IE9
var w = window.open();
$(w.document.body).html('<img src="'+ canvas.toDataURL() +'"/>');
}
else{
var image = canvas.toDataURL();
image = image.substring(22); // remove data stuff
var byteString = atob(image);
var buffer = new ArrayBuffer(byteString.length);
var intArray = new Uint8Array(buffer);
for (var i = 0; i < byteString.length; i++) {
intArray[i] = byteString.charCodeAt(i);
}
var blob = new Blob([buffer], { type: "image/png" });
window.navigator.msSaveOrOpenBlob(blob, filename);
}
}

Categories