I am new to JS, for last few days I am stuck at compressing image at client side. What I want to do is, User drops bunch of images (can be more than 10) at dropzone they should be compressed using JIC and once user clicks a button to upload all the compressed files get uploaded to the server.
So far my code is able to compress and upload only if one image is dropped, but when I drop multiple images all images remain uncompressed but one. I am not sure what wrong I am doing. I have tried to follow the solutions from this post but couldn't achieve my goal. Code I am using is as follows:
Dropzone.autoDiscover=false;
var myDropZone=new Dropzone("#dropzonePreview",{
url:"/dragdrop",
autoProcessQueue:false,
acceptedFiles: 'image/*',
parallelUploads: 10,
init:function(){
this.on('addedfile', function(file){
_this = this;
////console.log("Added File");
$('#userphoto').css('color', "transparent");
EXIF.getData(file, function(){ // async call
var lat=EXIF.getTag(this,"GPSLatitude");
var lon=EXIF.getTag(this,"GPSLongitude");
geocoder.geocode( { 'latLng': temp }, function(results, status) { // another async call });
}
});
myReader2 = new FileReader(); // Reading image for compression purpose
myReader2.onload = function(event) {
console.log(file.status);
// var i = new Image();
var i = document.getElementById("source_image");
i.src = event.target.result;
i.onload = function() {
var source_image = document.getElementById('source_image');
var quality = 70;
comp = jic.compress(source_image, 70, "jpg"); // Link to function can be found at the end of code.
var editedFile = base64ToFile(comp.src, file); // same function used in mentioned stackoverflow post.
// Replace original with resized
var origFileIndex = myDropZone.files.indexOf(file);
myDropZone.files[origFileIndex] = editedFile;
editedFile.status = Dropzone.ADDED;
myDropZone.enqueueFile(editedFile);
delete source_image;
};
};
myReader2.readAsDataURL(file);
});
this.on("sending",function(file,xhr,formData){
//appending some data to formData
});
this.on("complete", function(file){
// processing like removing objects of file from drop zone
});
}
});
$('#upload').click(function(evt){ // Button that triggers uploading file
myDropZone.processQueue();
}
Link to function. Your help would be really appreciated. Thank you.
I have found this issue solution. it's work for me.
Please check
function base64ToFile(dataURI, origFile) {
var byteString, mimestring;
if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
byteString = atob(dataURI.split(',')[1]);
} else {
byteString = decodeURI(dataURI.split(',')[1]);
}
mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0];
var content = new Array();
for (var i = 0; i < byteString.length; i++) {
content[i] = byteString.charCodeAt(i);
}
var newFile = new File(
[new Uint8Array(content)], origFile.name, {type: mimestring}
);
// Copy props set by the dropzone in the original file
var origProps = [
"upload", "status", "previewElement", "previewTemplate", "accepted"
];
$.each(origProps, function(i, p) {
newFile[p] = origFile[p];
});
return newFile;
}
Dropzone.autoDiscover = false;
jQuery(document).ready(function($) {
var myDropZone=new Dropzone("#dropzonePreview",{
url:"/dragdrop",
autoProcessQueue:false,
acceptedFiles: 'image/*',
parallelUploads: 10,
init:function(){
this.on("sending",function(file,xhr,formData){
});
this.on("complete", function(file){
});
}
});
myDropZone.on("addedfile", function(file) {
var reader = new FileReader();
reader.addEventListener("load", function(event) {
var origImg = new Image();
origImg.src = event.target.result;
origImg.addEventListener("load", function(event) {
comp = jic.compress(origImg, 30, "jpg");
var resizedFile = base64ToFile(comp.src, file);
var origFileIndex = myDropZone.files.indexOf(file);
myDropZone.files[origFileIndex] = resizedFile;
myDropZone.enqueueFile(resizedFile);
});
});
reader.readAsDataURL(file);
});
$('#upload').click(function(e){ // Button that triggers uploading file
e.preventDefault();
myDropZone.processQueue();
});
});
Related
I'm having a difficult time trying to get the below code to work in IE. The code works as expected in Firefox, Chrome, and Edge; but not in IE. I would ignore it not working in IE, but it's the default browser used at work.
The code is written to upload multiple files into a specific SharePoint document library. I got the code from this post https://social.msdn.microsoft.com/Forums/office/en-US/bb590f35-da1b-4905-baa0-fb85a275abf6/multiple-files-upload-in-document-library-using-javascript-object-model?forum=appsforsharepoint. It's the last post, and it does work great in the mentioned browsers. Any suggestions on how to get it to work in IE will greatly be appreciated. Thank you in advance.
Script is below:
jQuery(document).ready(function() {
fileInput = $("#getFile");
SP.SOD.executeFunc('sp.js', 'SP.ClientContext', registerClick);
});
function registerClick() {
//Register File Upload Click Event
jQuery("#addFileButton").on('click', readFile);
}
var arrayBuffer;
function readFile() {
//Get File Input Control and read th file name
var element = document.getElementById("getFile");
var fileCount = element.files.length;
var filesUploaded = 0;
for (var i = 0; i < fileCount; i++) {
let file = element.files[i];
var reader = new FileReader();
reader._NAME = element.files[i].name
reader.onload = function(e) {
let fileactualName = e.target._NAME;
uploadFile(e.target.result, fileactualName);
}
reader.onerror = function(e) {
alert(e.target.error);
}
reader.readAsArrayBuffer(file);
}
}
function uploadFile(arrayBuffer, fileName) {
//Get Client Context,Web and List object.
var clientContext = new SP.ClientContext();
var oWeb = clientContext.get_web();
var oList = oWeb.get_lists().getByTitle('Comms Shared Files');
//Convert the file contents into base64 data
var bytes = new Uint8Array(arrayBuffer);
var i, length, out = '';
for (i = 0, length = bytes.length; i < length; i += 1) {
out += String.fromCharCode(bytes[i]);
}
var base64 = btoa(out);
//Create FileCreationInformation object using the read file data
var createInfo = new SP.FileCreationInformation();
createInfo.set_content(base64);
createInfo.set_url(fileName);
//Add the file to the library
var uploadedDocument = oList.get_rootFolder().get_files().add(createInfo)
//Load client context and execcute the batch
clientContext.load(uploadedDocument);
clientContext.executeQueryAsync(QuerySuccess, QueryFailure);
}
function QuerySuccess() {
alert('File Uploaded Successfully.');
}
function QueryFailure(sender, args) {
console.log('Request failed with error message - ' + args.get_message());
}
In SharePoint 2010, we can use SharePoint designer to open the v4.master(defualt), and add "IE=11" in "X-UA-Compatible".
<meta http-equiv="X-UA-Compatible" content="IE=8,IE=11"/>
In SharePoint 2013/2016/2019/online, we can use REST API to upload the files to document library with jQuery code.
<input id="inputFile" type="file" multiple="multiple"/>
<input id="uploadDocumentButton" type="Button" value="Upload Document">
<script src="https://code.jquery.com/jquery-1.12.4.min.js" type="text/javascript"></script>
<script type="text/javascript">
var libraryTitle="DL";
$(function(){
$("#uploadDocumentButton").click(function () {
if (document.getElementById("inputFile").files.length === 0) {
alert("Select a file!");
return;
}
for(var i = 0; i < document.getElementById("inputFile").files.length; i++){
var file = document.getElementById("inputFile").files[i];
uploadFileSync(libraryTitle, file.name, file);
}
alert("upload complete.");
});
});
function uploadFileSync(folderUrl, filename, file){
var reader = new FileReader();
reader.onloadend = function(evt){
if (evt.target.readyState == FileReader.DONE){
var buffer = evt.target.result;
var completeUrl =_spPageContextInfo.webAbsoluteUrl
+ "/_api/web/GetFolderByServerRelativeUrl('"+folderUrl+"')/Files/add(url='" + filename + "',overwrite=true)";
$.ajax({
url: completeUrl,
type: "POST",
data: buffer,
async: false,
processData: false,
headers: {
"accept": "application/json;odata=verbose",
"X-RequestDigest": $("#__REQUESTDIGEST").val(),
"content-length": buffer.byteLength
},
complete: function (data) {
//alert("upload complete.");
//console.log(data.responseJSON.d.ServerRelativeUrl);
},
error: function (err) {
alert('failed');
}
});
}
};
reader.readAsArrayBuffer(file);
}
</script>
I've been having a battle with dropzone.js. No matter what setting I change the plugin will only upload one or two of the files dragged into the dropzone.
Interestingly enough though if I step through all the code using debugger points I can see it going through and uploading each file. And they do upload. Every one of them.
Could this be the plugin working faster than the backend? It is getting to the success function each time so this has be utterly confused.
I have tried all the tricks.
I have the paralleUplads and maxFiles set
parallelUploads: 5,
maxFilesize: 5,
maxFiles: 5,
and I have tried setting these in the init section as well for the queue section as well
init: function() {
this.on("queuecomplete", function() {
this.options.autoProcessQueue = false;
});
this.on("processing", function() {
this.options.autoProcessQueue = true;
});
},
Without the added code above my dropzone function looks like this
$(".somediv").dropzone({
url: 'someurl',
async: false,
clickable: false,
sending: function(file, xhr, formData) {
var fileType = file.type;
var form_data = new FormData(file);
fileType = fileType.substring(fileType.indexOf("/") + 1);
formData.append("data", file);
formData.append("documentID", 0);
formData.append("dataTypeCode", fileType);
formData.append("dataDescription", file.name);
formData.append('filepart', form_data)
},
addedfile: function(file) {
var _this = this,
reader = new FileReader();
reader.onload = function(event) {
_this.processQueue()
};
reader.readAsDataURL(file);
},
success: function(data) {
var fileType = data.type;
fileType = fileType.substring(fileType.indexOf("/") + 1);
iconImg(fileType)
console.log('uploaded ' + data)
var statusCode = 'AD'
var text = "'Attachment Added' by " + currentUser.employeeId
statusCodeChange(statusCode, brCode, incidentId, text)
var randomNum = Math.random() * 20
table.row.add({
"dataDescription": data.name,
"dataTypeCode": fileType,
"documentTimeStamp": formatDate(new Date()),
"documentID": randomNum
}).draw(false)
.node();
growl("Attachment Uploaded!", {});
}
});
I am having problem in sending my base64 image from phonegap (ios) to firebase storage. The main problem is firebase storage only accepted BLOB or File as attachment.
Heres my code for the camera function. Cordova-plugin-camera
function GetCamera(){
navigator.camera.getPicture( cameraSuccess, cameraError, {quality :50,
destinationType: Camera.DestinationType.DATA_URL,
encodingType: Camera.EncodingType.JPEG,
saveToPhotoAlbum: true});}
function to convert base 64 to blob
function b64toblob(b64_data, content_type) {
content_type = content_type || '';
var slice_size = 512;
var byte_characters = atob(b64_data);
var byte_arrays = [];
for(var offset = 0; offset < byte_characters.length; offset += slice_size) {
var slice = byte_characters.slice(offset, offset + slice_size);
var byte_numbers = new Array(slice.length);
for(var i = 0; i < slice.length; i++) {
byte_numbers[i] = slice.charCodeAt(i);
}
var byte_array = new Uint8Array(byte_numbers);
byte_arrays.push(byte_array);
}
var blob = new Blob(byte_arrays, {type: content_type});
return blob;};
Camera success function. take note that imageblob is a global variable
function cameraSuccess(imageData){
document.getElementById('Attachment1').innerHTML = "Attachment: True";
var image = imageData;
imageblob = b64toblob(image,"image/jpeg");}
putting the blob to firebase storage
try{
var storageRef = storage.ref().child('fire');
var uploadTask = storageRef.put(imageblob);
uploadTask.on('state_changed',null, null, function(){
var downloadURL = uploadTask.snapshot.downloadURL;
console.log("downloadURL :"+downloadURL);
});
i have tried every single thing, but its not working. Really need your guys help.. i am out of ideas
Cordova camera plugin doesn't return file object. That is problem with plugin.
But it returns all details about image. By using that you can create a blob or file object.
Reference for creating blob from file url.
var getFileBlob = function (url, cb) {
var xhr = new XMLHttpRequest();
xhr.open("GET", url);
xhr.responseType = "blob";
xhr.addEventListener('load', function() {
cb(xhr.response);
});
xhr.send();
};
var blobToFile = function (blob, name) {
blob.lastModifiedDate = new Date();
blob.name = name;
return blob;
};
var getFileObject = function(filePathOrUrl, cb) {
getFileBlob(filePathOrUrl, function (blob) {
cb(blobToFile(blob, 'test.jpg')); // Second argument is name of the image
});
};
Calling function for get file blob
getFileObject('img/test.jpg', function (fileObject) { // First argument is path of the file
console.log(fileObject);
});
In your camera success function try this.
function cameraSuccess(imageData){
document.getElementById('Attachment1').innerHTML = "Attachment: True";
getFileObject(imageData.nativeURL, function(fileObject) {
console.log(fileObject);
var imgName = fileObject.name;
var metadata = { contentType: fileObject.type };
var uploadFile = storageRef.child("images/" + imgName).put(fileObject, metadata);
uploadFile.on(firebase.storage.TaskEvent.STATE_CHANGED, function(snapshot) {
var progress = (snapshot.bytesTransferred / snapshot.totalBytes) * 100;
console.log(progress);
}, function(error) {
console.log(error);
}, function() {
var imgFirebaseURL = uploadFile.snapshot.downloadURL;
console.log(imgFirebaseURL);
});
});
}
I'm trying to make a small snippet to preview images before uploading them:
$.fn.previewImg=function($on){
var input = this;
try{
if (this.is("input[type='file']")) {
input.change(function(){
var reader = new FileReader();
reader.onloadend = function(){
for (var i = 0; i < $on.length; i++) {
if (/img/i.test($on[i].tagName)) $on[i].src = reader.result;
else $on[i].style.bakgroundImage = "url("+reader.result+")";
}
};
});
}else throw new exception("Trying to preview image from an element that is not a file input!");
}catch(x){
console.log(x);
}
};
I'm calling it like:
$("#file").previewImg($(".preview_img"));
but the onloadend function is never called.
FIDDLE
Actually , you got to specify the file and instruct the fileReader to read it.
Below is the corrected code.
$.fn.previewImg=function($on){
var input = this;
try{
if (this.is("input[type='file']")) {
input.change(function(evt){
var reader = new FileReader();
console.log("Input changed");
reader.onloadend = function(){
console.log("onloadend triggered");
for (var i = 0; i < $on.length; i++) {
if (/img/i.test($on[i].tagName)) $on[i].src = reader.result;
else $on[i].style.bakgroundImage = "url("+reader.result+")";
}
};
//get the selected file
var files = evt.target.files;
//instruct reader to read it
reader.readAsDataURL(files[0]);
});
}else throw new exception("Trying to preview image from an element that is not a file input!");
}catch(x){
console.log(x);
}
};
$("#file").previewImg($(".preview_img"));
I have a file drop class. User drop images on (as many as they wish) and these are then uploaded.
I call the class via from my main class:
this.fileDrop = new lx.FileDrop();
Here's the class:
(function(){
"use strict";
var FileDrop = function() {
this.init();
};
p.init = function() {
this._initEvents();
};
p._initEvents = function() {
$(window).on('drop', this.onDrop.bind(this)).on('dragover', this.onDragOver);
};
p.onDrop = function(e) {
e.preventDefault();
var self = this;
var files = e.originalEvent.dataTransfer.files;
$.each(files, function(index, file){
self.readFile(file).done(function(data) {
//how to return the data?
});
});
};
p.onDragOver = function(e) {
e.preventDefault();
};
p.readFile = function(file) {
var fileReader = new FileReader();
var deferred = $.Deferred();
fileReader.onload = function(event) {
deferred.resolve(event.target.result);
};
fileReader.onerror = function() {
deferred.reject(this);
};
fileReader.readAsDataURL(file);
return deferred.promise();
};
lx.FileDrop = FileDrop;
}(window));
My question concerns returning the image data to the main class. How can I return it? How can I store it - I wish to store everything that is returned into an array in the main class. How would this work when uploading multiple images. Would some sort of deferred work?
How about something like this:
var dfd = $.Deferred(),
images = [];
$.each(files, function(index, file){
self.readFile(file).done(function(data) {
dfd.progress(data);
images.push(data);
if(files.length === ++index)
dfd.resolve(images);
}).fail(dfd.reject);
});
Handle the deferred object where ever you like:
dfd.progress(function(file){
console.log('file successfully uploaded', file);
}).done(function(images){
console.log('all files successfully uploaded', images);
}).fail(function(){
console.log('something went wrong while uploading an image');
});
Another example:
function FileDrop(){
this.uploadCount = 0;
this.images = [];
}
FileDrop.prototype.getImages = function(){
var dfd = $.Deferred(),
size = 3,
that = this;
for(var i = 0; i < size; i++){
this.getImage(i*500, function(image){
var dummyImage = $('<img/>');
// should be 'image' from the callback in your case
that.images.push(dummyImage);
dfd.notify(dummyImage);
if(that.uploadCount === size){
dfd.resolve(that.images);
}
});
}
return dfd.promise();
};
FileDrop.prototype.getImage = function(timeout, callback){
var that = this;
setTimeout(function(){
that.uploadCount++;
callback();
}, timeout);
};
var fd = new FileDrop();
fd.getImages().progress(function(image){
console.log('progress', image);
}).done(function(imageArray){
// preferred way:
//access the array when you know it's complete in the callback
console.log('done', imageArray);
});
setTimeout(function(){
// I think this is what you asked for, however, you must make an
// assumption when the images are completed, which is a bad idea
console.log(fd.images);
}, 2000);
http://jsfiddle.net/Nm5vK/2/