Upload resized image with Javascript / AngularJS - javascript

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;

Related

Blob export not working in safari

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;
}

Choose an image in browser, resize it and send it to server with JS, and let PHP save it on server

I'm working on this classical feature: choose a file in the browser ("Browse"), let JavaScript resize it (max width / height = 500 pixels) and upload it to server, and then let PHP save it to disk.
Here is what I currently have (based on this other question)
$("#fileupload").change(function(event) {
var file = event.target.files[0];
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
var canvas = document.createElement('canvas'), max_size = 500, width = image.width, height = image.height;
if (width > height) { if (width > max_size) { height *= max_size / width; width = max_size; } }
else { if (height > max_size) { width *= max_size / height; height = max_size; } }
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
var dataUrl = canvas.toDataURL('image/jpeg');
var resizedImage = dataURLToBlob(dataUrl);
$.ajax({type: "POST", url: "index.php", success: function(data, status) { }, data: { content: resizedImage, filename: ?? }});
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(file);
}
var dataURLToBlob = function(dataURL) {
var BASE64_MARKER = ';base64,';
if (dataURL.indexOf(BASE64_MARKER) == -1) { var parts = dataURL.split(','); var contentType = parts[0].split(':')[1]; var raw = parts[1]; return new Blob([raw], {type: contentType}); }
var parts = dataURL.split(BASE64_MARKER);
var contentType = parts[0].split(':')[1];
var raw = window.atob(parts[1]);
var rawLength = raw.length;
var uInt8Array = new Uint8Array(rawLength);
for (var i = 0; i < rawLength; ++i) { uInt8Array[i] = raw.charCodeAt(i); }
return new Blob([uInt8Array], {type: contentType});
}
<input id="fileupload" type="file">
The PHP part would be:
<?php
if (isset($_POST['content'])) file_put_contents($_POST['filename'], $_POST['content']);
?>
This currently doesn't work, how should I do the AJAX part to make it work (how to send the data + filename)? Should a FormData be used, if so why and how?
You need to use $_FILES array to retrieve the image info:
if (is_uploaded_file($_FILES['new_img']['tmp_name'])) {
$newimg = $_FILES['new_img']['name'];
move_uploaded_file($_FILES['new_img']['tmp_name'], "../images/{$newimg}");
}
file_put_contents is a function to write files. When you upload a file it is stored in a temp dir, so you can check with is_uploaded_file that it is uploaded with the $_FILES['new_img']['tmp_name'].
You can use it's original name with $_FILES['new_img']['name'] or rename it to prevent injections. Then you have to move the image to it's final location with move_uploaded_file.
I almost forgot the form:
<form action="yourpage.php" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="new_img" id="new_img">
<input type="submit" value="Upload Image" name="submit">
</form>

canvas.toDataURL() returns same dataURL

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.

Converted image should have some small url instead of BaseCode

Right now i am uploading image into canvas and after uploaded image, canvas converted into image by toDataURl. If i am converting canvas into image by toDataURL then i am getting base code(Base Code will be big). I want some small url instead of BaseCode.
var canvas = new fabric.Canvas('canvas');
document.getElementById('file').addEventListener("change", function (e) {
var file = e.target.files[0];
var reader = new FileReader();
reader.onload = function (f) {
var data = f.target.result;
var img = document.createElement('img');
img.src = data;
img.onload = function () {
if (img.width < 300 || img.height < 300)
{
alert("upload image should be greater");
canvas.getActiveObject().remove();
}
};
fabric.Image.fromURL(data, function (img) {
var oImg = img.set({left: 50, top: 100,width:100, height:100, angle: 00}).scale(0.9);
canvas.add(oImg).renderAll();
var a = canvas.setActiveObject(oImg);
var dataURL = canvas.toDataURL({format: 'png', quality: 0.8});
console.log("aaaaaaaaaaa" + dataURL);
// console.log("Canvas Image " + dataURL);
// document.getElementById('txt').href = dataURL;
});
};
reader.readAsDataURL(file);
});
document.querySelector('#txt').onclick = function (e) {
e.preventDefault();
canvas.deactivateAll().renderAll();
document.querySelector('#preview').src = canvas.toDataURL();
var b= canvas.toDataURL();
console.log(b);
}
canvas{
border: 1px solid black;
}
<script src="https://rawgit.com/kangax/fabric.js/master/dist/fabric.min.js"></script>
<input type="file" id="file">
<canvas id="canvas" width="400" height="400"></canvas>
Click Me!!
<br />
<img id="preview" />
JSFiddle: https://jsfiddle.net/varunPes/8gt6d7op/23/
The devil is in the details - nowhere in the question do you even suggest you want to send the image somewhere - the code below is limited to the client - you can only use the short form url on the client, and as mentioned in a comment, only for a session (restart browser, url is useless), or until revokeObjectURL is called
You can - if the browser supports it, use a Blob, it's URL is short
// converts a dataURI to a Blob
function dataUriToBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
var arrayBuffer = new ArrayBuffer(byteString.length);
var _ia = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteString.length; i++) {
_ia[i] = byteString.charCodeAt(i);
}
var dataView = new DataView(arrayBuffer);
var blob = new Blob([dataView], { type: mimeString });
return blob;
}
// cross browser cruft
var get_URL = function () {
return window.URL || window.webkitURL || window;
};
// ... your code, which eventually does this
var b = canvas.toDataURL();
// get an URL from the Blob
var blob = dataUriToBlob(b);
var url = get_URL().createObjectURL(blob);
console.log(url);
//
// ... when finished with the object URL
URL.revokeObjectURL(url);
If you want to avoid send dataURL, you can convert it into DataForm using this function:
function dataURItoBlob(dataURI) {
// convert base64/URLEncoded data component to raw binary data held in a string
var byteString;
if (dataURI.split(',')[0].indexOf('base64') >= 0)
byteString = atob(dataURI.split(',')[1]);
else
byteString = unescape(dataURI.split(',')[1]);
// separate out the mime component
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
// write the bytes of the string to a typed array
var ia = new Uint8Array(byteString.length);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
return new Blob([ia], {type:mimeString});
}
Then, call it:
var dataURL = canvas.toDataURL('image/jpeg', 0.5);
var blob = dataURItoBlob(dataURL);
var fd = new FormData(document.forms[0]);
fd.append("canvasImage", blob);
Finally, send this form (regular or ajax).
Source answer

Import long html into split PDF

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.

Categories