Hi I'm currently developing ionic app with firebase.
I'm trying to upload multiple files with resizing.
It is weired that when I call resize method input image is different but once I finish my uploading, it ends up uploading duplicated images(last image of array).
I console.loged dataURL of it everytime it resize and found that DataURL is always the same.
following code is to upload multiple files.
multipleUpload: function(key, folder, files, targetWidth) {
var q = $q.defer();
var ct = Date.now();
var urls = [];
var recursive = function (n, args) {
var arg = args[n];
ImageService.resize(arg.file, targetWidth)
.then(function(file) {
upload(ct + '' + n + key, folder + '/' + key, file, CONFIG.MESSAGE.FILE_UPLOAD + (n + 1) + '번 파일')
.then(function(url) {
urls.push(url);
if (++n < args.length) {
recursive(n, args);
} else {
q.resolve(urls);
}
}), function(error) {
q.reject(error);
};
})
}
recursive(0, files);
return q.promise;
},
Following code is resizing method
resize: function(file, targetWidth) {
var q = $q.defer();
// Resizing Image
var img = new Image();
img.setAttribute('crossOrigin', 'anonymous');
img.onload = function(){
var canvas = document.createElement("canvas"),
ctx = canvas.getContext("2d");
canvas.width = targetWidth;
canvas.height = canvas.width * (img.height / img.width);
ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
// Data URL to BLOB
var dataURL = canvas.toDataURL();
console.log(dataURL); // Returns same dataURL all the time.
dataURLtoBlob(dataURL, Date.now())
.then(function(blob) {
q.resolve(blob);
});
};
img.src = file;
return q.promise;
},
Firstly I found one thing weird that it worked fine on ios but android.
I started to digging plugin options and disabled allow-edit then it works fine. I believe it is an issue from the plugin.
Related
I'm trying to create a JavaScript function that will return a dataURL from a JPEG. This function is intended to be called multiple times in the creation of a pdf document in a Vue.js application.
The following is code I've managed to cobble together from various web sites in seeking code examples for jsPDF use.
async loadImg (url) {
var dataURL = null
var toDataURL = async function (url) {
var img = new Image()
img.onError = function () {
alert('Cannot load image: "' + url + '"')
}
img.onload = async function () {
var canvas = document.createElement('canvas')
var context = canvas.getContext('2d')
canvas.height = this.naturalHeight
canvas.width = this.naturalWidth
context.drawImage(this, 0, 0)
dataURL = canvas.toDataURL('image/jpeg')
console.log('onload ' + dataURL)
}
img.src = url
}
await toDataURL(url)
console.log('end of function ' + dataURL)
return dataURL
}
I've tried using a callback approach, but no matter how what I've done I ultimately end up in the same state the console shows the 'end of function' as a null and then a few milliseconds later the onload remark shows up with a long string, which I assume is the dataURL of the graphic (jpg)
OK I thought async / await construct was the same as using promise.. but just to be on the safe side I rewrote my code using promise
toDataURL (url) {
return new Promise(function (resolve, reject) {
var img = new Image()
img.onError = function () {
reject(Error('Cannot load image: "' + url + '"'))
}
img.onload = async function () {
var canvas = document.createElement('canvas')
var context = canvas.getContext('2d')
canvas.height = this.naturalHeight
canvas.width = this.naturalWidth
context.drawImage(this, 0, 0)
resolve(canvas.toDataURL('image/jpeg'))
}
img.src = url
})
}
// in the function to create the pdf
imageData = toDataURL(url).then(function (response) {
console.log('Success!', response)
}, function (error) {
console.error('Failed!', error)
})
}
There are three jpgs that the main is trying to include in the pdf
In the console I see:
Report.vue?./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options:277 Promise {<pending>}
Report.vue?./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options:277 Promise {<pending>}
Report.vue?./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options:277 Promise {<pending>}
Report.vue?./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options:284 841.89 595.28
Report.vue?./node_modules/babel-loader/lib!./node_modules/vue-loader/lib??vue-loader-options:272 Success! data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAMCAgICAgMCAgIDAwMDBAYEBAQEBAgGBgUGCQgKCgkICQkKDA8MCgsOCwkJDRENDg8QEBEQCgwSExIQEw8QEBD/2wBDAQMDAwQDBAgEBAgQCwkLEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBD/wAARCALaBEcDASIAAhEBAxEB/8QAHgAAAAcBAQEBAAAAAAAAAAAAAAIDBAUGBw ...
There are two additional Success! data:image/ ...
My interpretation is while the results are different in that I get a promise object, which is pending then I get the image data. I'm still no further ahead.
I am trying to build a simple image uploader/gallery viewer for a webpage using PhotoSwipe. The gallery viewer plugin works without issues and needs an array (items in the code below) with the image src and the width and height per image. The function readImageDimensions() gets the data and later saves it to items.
When I'm debugging the code it runs flawlessly and the gallery gets the data, but if I skip the debugger the item variable has indexed two objects, but the src, w, h all have null values. Is it something in the code that runs asynchronously or otherwise disrupt the flow when the code isn't running through the debug process?
Code for uploading and presenting the images:
var thumbsDiv = "";
var items = [];
document.addEventListener("DOMContentLoaded", init, false);
function init() {
document.querySelector('.file-uploader').addEventListener('change', onFilesSelected, false);
thumbsDiv = document.querySelector(".thumbs-div");
}
function onFilesSelected(e) {
if (!e.target.files || !window.FileReader) return;
thumbsDiv.innerHTML = "";
var width = 0;
var height = 0;
items = [];
function readImageDimensions(data) {
var image = new Image();
image.src = data;
width = image.width;
height = image.height;
}
var files = e.target.files;
var filesArr = Array.prototype.slice.call(files);
filesArr.forEach(function (f) {
if (!f.type.match("image.*")) {
return;
}
var reader = new FileReader();
reader.onloadend = function (e) {
var result = e.target.result;
var html = '<div class="img-wrap"><span class="close">×</span><img src="' + result + '"/>' + f.name + '</div>';
thumbsDiv.innerHTML += html;
readImageDimensions(result);
items.push({
src: result,
w: width,
h: height
});
}
reader.readAsDataURL(f);
});
}
Code for instantiating the gallery:
var openGallery = function () {
var pswpElement = document.querySelectorAll(".pswp")[0];
var options = {
index: 0
};
var gallery = new PhotoSwipe(pswpElement, PhotoSwipeUI_Default, items, options);
gallery.init();
}
The issue was in fact that the image data was loaded asynchronously, and the program tried to read the image dimensions before it was loaded. I used HMR's comment to further research the onload() handler and modified the readImageDimensions() like this:
function readImageDimensions(data) {
var image = new Image();
console.log(data);
image.onload = function () {
width = image.width;
height = image.height;
items.push({
src: data,
w: width,
h: height
});
}
image.src = data;
}
This way, the onload() gets "primed" with reading the width and height, and won't do that until the whole image data is loaded onto the browser cache. The code also pushes the data onto the items[] array and obviously I'll rename the method into something better, like setImageDataForGallery().
I want to export the jpeg image from svg using blob. This working fine in chrome. But, my sample is not working safari browser(MAC).
Can you please tell how to resolve this? wheather blob is support in IOS or not?
while run this sample in ios thrown image load error.
Sample Link: http://jsfiddle.net/kyjs655r/363/
document.getElementById('export').onclick = function () {
var tag = document.getElementById('export');
tag.download = 'Sample' + "." + 'png';
tag.href = getCanvaElement().toDataURL();
}
function getCanvaElement() {
var svgText = document.getElementById("myViewer").outerHTML;
var svg = new Blob([svgText], { type: "image/svg+xml;charset=utf-8" });
var domURL = self.URL || self.webkitURL || self;
var url = domURL.createObjectURL(svg);
var element = document.createElement('canvas');
var ctx = element.getContext("2d");
var image = new Image;
image.onload = function () {
ctx.drawImage(this, 0, 0);
domURL.revokeObjectURL(url);
};
image.onerror = function () {
alert();
};
image.src = url;
return element;
}
We are building an application where the user can upload images, but I need to resize an image before I can upload them to the server. The input for the file is an input[type=file] and we check if the image is valid. If it is valid, we continue with the following request:
Upload.upload({url: url, data: {file: input.x}, headers: {'Authorization': token}});
The input variable is the value of the input field in the HTML. This codes works great when we don't need to resize the image. Unfortunately, this would only be the case in a perfect world. After a while searching for the same problems, I seem to have found the solution using the following function:
var resize = function(size, url, callback) {
var temp = new Image();
temp.onload = function() {
var target = { width: temp.width, height: temp.height, aspect: temp.width / temp.height };
if (temp.width > temp.height) {
size = Math.min(temp.width, size);
target.width = size; target.height = size / target.aspect;
} else {
size = Math.min(temp.height, size);
target.height = size; target.width = size * target.aspect;
}
var canvas = document.createElement('canvas');
canvas.width = target.width; canvas.height = target.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0, temp.width, temp.height, 0, 0, target.width, target.height);
callback(canvas.toDataURL(url.split(',')[0].split(':')[1].split(';')[0]));
}; temp.src = url;
}
This appears to be working great. I need to pass a Base64 string. So I wrapped the upload method inside the following:
var reader = new FileReader();
reader.onload = function(e) {
resize(1000, e.target.result, function(done) {
console.log(done);
Upload.upload({url: url, data: {file: done}, headers: {'Authorization': UserService.getToken()}});
});
}
reader.readAsDataURL(file);
This way I pass a Base64 string containing the image and even this seems to be working like a charm. But the biggest problem is, the server expects a real file and not a Base64 string. So the upload itself fails.
I found the function on Convert Data URI to File then append to FormData which should fix this, but it doesn't. I changed the method to this after adding the method from the link:
var reader = new FileReader();
reader.onload = function(e) {
resize(1000, e.target.result, function(done) {
console.log(done);
Upload.upload({url: url, data: {file: dataURItoBlob(done)}, headers: {'Authorization': UserService.getToken()}});
});
}
reader.readAsDataURL(file);
Does any of you know how I could change the Base64 string back to a file again? I found tons of post explaining how I could show them in a browser, but none solving my problem to upload it as file.
Sorry for the question. But it seems the dataURItoBlob function works fine, but there is was no original filename inside the blob, so I couldn't upload it right away. I changed the resize function so it performs both actions at once and this is the result:
var resize = function(size, url, name, callback) {
var temp = new Image();
temp.onload = function() {
var target = { width: temp.width, height: temp.height, aspect: temp.width / temp.height };
if (temp.width > temp.height) {
size = Math.min(temp.width, size);
target.width = size; target.height = size / target.aspect;
} else {
size = Math.min(temp.height, size);
target.height = size; target.width = size * target.aspect;
}
var canvas = document.createElement('canvas');
canvas.width = target.width; canvas.height = target.height;
var ctx = canvas.getContext('2d');
ctx.drawImage(this, 0, 0, temp.width, temp.height, 0, 0, target.width, target.height);
var type = url.split(',')[0].split(':')[1].split(';')[0];
var data = canvas.toDataURL(type);
//callback(data);
var bytes = (data.split(',')[0].indexOf('base64') >= 0) ? atob(data.split(',')[1]) : unescape(dataURI.split(',')[1]);
var ia = new Uint8Array(bytes.length);
for(var i = 0; i < bytes.length; i++) { ia[i] = bytes.charCodeAt(i); }
var blb = new Blob([ia], {type : type});
blb.name = name;
callback(blb);
}; temp.src = url;
};
To upload the file, I do the following:
var deferred = $q.defer();
var reader = new FileReader();
reader.onload = function(e) {
resize(maxSize, e.target.result, image.name, function(done) {
deferred.resolve(Upload.upload({url: url, data: {file: done}, headers: {'Authorization': token}));
});
}
reader.readAsDataURL(image);
return deferred.promise;
My scenario is:
On clicking a button, import datas on a html into a PDF file.
Since this PDF must have some complicated required style, so my first step is to transfer this page into a image using html2canvas.js and then import this image to a PDF with jsPDF.js
And when the data is too large the PDF must be split to hold all the data,to do this,so I used the codes here: https://github.com/MrRio/jsPDF/pull/397
My problem is: on firefox the splited page on PDF on page 2 or 3...cannot be shown, they are totally blank. but on page 1 it is fine. (this is for firefox)
I tested other browsers they are all fine. pls someone could throw some light on how to fix this?
Here is my plnkr:
http://plnkr.co/edit/ElvAsriK2nssq2U9pgKX?p=preview
function initTemplate(){
datas=getData();
var templateData=_.template($('#tpl').html(), datas);
$('#tplW').html(templateData);
getPDF();
// $('#tplW').append(_.template($('#tpl').html(), datas));
// $('body').html( _.template($('#tpl').html(), datas));
}
function getData(){
var htmlData=$(".MsoNormalTable .inner").find("tr.tablerow");
var datas=[];
$.each(htmlData,function(i,v){
var d=[];
var tds=$(v).find("td");
$.each(tds,function(index,val){
d.push($(val).text());
});
datas.push(d);
});
return datas;
}
function getPDF() {
// initTemplate();
html2canvas($('#tplW')[0], {
onrendered: function(canvas){
canvasToImageSuccess(canvas);
}
});
function canvasToImage (canvas){
var img = new Image();
var dataURL = canvas.toDataURL('image/png');
img.src = dataURL;
return img;
};
function canvasShiftImage (oldCanvas,shiftAmt){
shiftAmt = parseInt(shiftAmt) || 0;
if(!shiftAmt){ return oldCanvas; }
var newCanvas = document.createElement('canvas');
newCanvas.height = oldCanvas.height - shiftAmt;
newCanvas.width = oldCanvas.width;
var ctx = newCanvas.getContext('2d');
var img = canvasToImage(oldCanvas);
ctx.drawImage(img,0, shiftAmt, img.width, img.height, 0, 0, img.width, img.height);
return newCanvas;
};
function canvasToImageSuccess (canvas){
var pdf = new jsPDF('l','px'),
pdfInternals = pdf.internal,
pdfPageSize = pdfInternals.pageSize,
pdfScaleFactor = pdfInternals.scaleFactor,
pdfPageWidth = pdfPageSize.width,
pdfPageHeight = pdfPageSize.height,
totalPdfHeight = 0,
htmlPageHeight = canvas.height,
htmlScaleFactor = canvas.width / (pdfPageWidth * pdfScaleFactor),
safetyNet = 0;
while(totalPdfHeight < htmlPageHeight && safetyNet < 15){
var newCanvas = canvasShiftImage(canvas, totalPdfHeight);
pdf.addImage(newCanvas, 'png', 0, 0, pdfPageWidth, 0, null, 'NONE');
totalPdfHeight += (pdfPageHeight * pdfScaleFactor * htmlScaleFactor);
if(totalPdfHeight < htmlPageHeight){
pdf.addPage();
}
safetyNet++;
}
pdf.save('test.pdf');
};
}
You should use canvas-to-blob and FileSaver.js
and modify this line:
pdf.save('test.pdf');
to this:
var data = pdf.output();
var buffer = new ArrayBuffer(data.length);
var array = new Uint8Array(buffer);
for (var i = 0; i < data.length; i++) {
array[i] = data.charCodeAt(i);
}
var blob = new Blob(
[array],
{type: 'application/pdf', encoding: 'raw'}
);
saveAs(blob, "test.pdf");
You can check it out here.
It worked for me on Mac, Firefox.
I found this solution here.