Multiple image resize with FileReader before php upload - javascript

I have a fine working multi-upload script in php (and a bit javascript).
The problem is, that users takes pictures directly from camera and so the image size is to large and mobile bandwith is small.
So i searched a solution to resize the image client-side and found some posts related FileReader and canvas.
My problem is how to upload the "result" of filereader with my php upload script.
That is what i have:
HTML:
<input id="fileupload" type="file" name="images[]" multiple/>
Javascript to dynamic add upload fields and preview uploads:
var abc = 0;
$(document).ready(function() {
$('#add-file-field').click(function() {
$("#newrow").append("<div class='col-sm-4'><div id='newrow' class='card'><div class='card-body'><input id='fileupload' type='file' name='images[]' multiple/></div></div></div>");
});
$('body').on('change', '#fileupload', function(){
if (this.files && this.files[0]) {
abc += 1;
var z = abc - 1;
var x = $(this).parent().find('#previewimg' + z).remove();
$(this).before("<div id='abcd"+ abc +"' class='card-img-top abcd'><img id='previewimg" + abc + "' src='' style='width:100%; height:100%;'/></div>");
var reader = new FileReader();
reader.onload = imageIsLoaded;
reader.readAsDataURL(this.files[0]);
$(this).hide();
$("#abcd"+ abc).append($("<img/>", {id: 'delete', src: 'x.png', alt: 'delete'}).click(function() {
$(this).parent().parent().parent().remove();
}));
}
});
//To preview image
function imageIsLoaded(e) {
$('#previewimg' + abc).attr('src', e.target.result);
};
$('#upload').click(function(e) {
var name = $(":file").val();
if (!name)
{
alert("First Image Must Be Selected");
e.preventDefault();
}
});
});
And the Php script:
$lastpositionid = $_SESSION['lastpositionid'];
$query = "INSERT INTO media (posid,orderid,name,image,created,tag,type) VALUES('$lastpositionid',$position->order_id,?,?,'$date','Vorher',?)";
$stmt = $con->prepare($query);
if(isset($_FILES['images'])){
$countfiles = count($_FILES['images']['name']);
$target_directory = "../uploads/". $position->order_id;
$file_upload_error_messages="";
for($i=0;$i<$countfiles;$i++){
if(!is_dir($target_directory)){
mkdir($target_directory, 0777, true);
}
$filename = $_FILES['images']['name'][$i];
$shafilename = sha1_file($_FILES['images']['tmp_name'][$i]) . "-" . date('d-m-Y-H-i-s') . "-" . basename($_FILES["images"]["name"][$i]);
$media->image = $filename[$i];
$file_size = $_FILES['images']['size'][$i];
$ext = end((explode(".", $filename)));
$valid_ext = array('jpg','JPG','jpeg','JPEG','png','PNG','gif','GIF','mov','MOV','mp4','MP4');
if(!empty($_FILES["images"]["tmp_name"][$i])){
if($file_size > 104857600){
$file_upload_error_messages.= "<div class=\"alert alert-danger alert-dismissable\">";
$file_upload_error_messages.= "</div>";
}
if(in_array($ext, $valid_ext)){
}
else{
$file_upload_error_messages.= "<div class=\"alert alert-danger alert-dismissable\">";
$file_upload_error_messages.= "</div>";
}
if(!empty($file_upload_error_messages)){
$file_upload_error_messages.= "<div class=\"alert alert-danger alert-dismissable\">";
$file_upload_error_messages.= "</div>";
}
if(empty($file_upload_error_messages)){
if(move_uploaded_file($_FILES['images']['tmp_name'][$i],$target_directory."/".$shafilename)){
echo "<div class=\"alert alert-success alert-dismissable\">";
echo "<button type=\"button\" class=\"close\" data-dismiss=\"alert\" aria-hidden=\"true\">×</button>";
echo "</div>";
// Execute query
$stmt->execute(array($shafilename,'uploads/'.$position->order_id.'/'.$shafilename,$ext));
}
}
}
}
print_r($file_upload_error_messages);
}
Now i think i could use this script (or similar i found here):
function handleFiles()
{
var filesToUpload = document.getElementById('fileupload').files;
var file = filesToUpload[0];
// Create an image
var img = document.createElement("img");
// Create a file reader
var reader = new FileReader();
// Set the image once loaded into file reader
reader.onload = function(e)
{
img.src = e.target.result;
var canvas = document.createElement("canvas");
//var canvas = $("<canvas>", {"id":"testing"})[0];
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0);
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var width = img.width;
var height = img.height;
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;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/png");
document.getElementById('image').src = dataurl;
}
// Load files into file reader
reader.readAsDataURL(file);
}
The script of FileReader is clear to me except the part how to upload it again with php. Btw i´m more familiar with php than js and another problem is how to integrate this functionality in my existing script ...
I have no external upload script, it is all in the same php file.
Thanks.

You can't shrink an image on the client side and the upload it as a file, but you can shrink the image and then get a dataURI of the shurnken image and upload it as a string, then convert it back to an image on the server side.
var maxWidth = 100;
var maxHeight = 100;
document.getElementById("myfile").onchange = function() {
var reader = new FileReader();
reader.onload = function(e) {
var img = new Image();
img.onload = function() {
var cnvs = document.createElement('canvas');
var rectRatio = img.width / img.height;
var boundsRatio = maxWidth / maxHeight;
var w, h;
if (rectRatio > boundsRatio) {
w = maxWidth;
h = img.height * (maxWidth / img.width);
} else {
w = img.width * (maxHeight / img.height);
h = maxHeight;
}
cnvs.width = w;
cnvs.height = h;
var ctx = cnvs.getContext('2d');
ctx.drawImage(img, 0, 0, w, h);
var uri = cnvs.toDataURL();
// Do something here to upload the smaller verion of the datauri
// for now i'm just putting it on the page though
document.body.innerHTML = '<img src="' + uri + '">';
};
img.src = e.target.result;
};
reader.readAsDataURL(this.files[0]);
}
<input type=file id=myfile accept=".png">
Then on the PHP side you can save it as an actual image like this
$data = $_POST['mydatauri'];
$encodedData = str_replace(' ','+',substr($data,strpos($data,",")+1));
$decodedData = base64_decode($encodedData);
file_put_contents("myUploadImage.png", $decodedData);

Related

How to crop an image with jquery?

Can I crop an image without a canvas? And how to crop an image without resizing the image? Like this real picture to be 133px x 133px
Large Image to be Small Image
Large Image To be Small Image
And thiis my code https://jsfiddle.net/w26La1u6/2/
$(document).on('change', '#files', function(event) {
var files = event.target.files; // FileList object
var output = document.getElementById("list");
for (var i = 0, f; f = files[i]; i++) {
if (f.type.match('image.*')) {
if (this.files[0].size < 12097152) {
var reader = new FileReader();
reader.onload = (function(theFile) {
return function(e) {
var span = document.createElement('span');
span.innerHTML = ['<img class="thumbnail" src="', e.target.result,
'" title="', escape(theFile.name), '"/>'
].join('');
output.insertBefore(span, null);
};
})(f);
$('#clear, #list').show();
reader.readAsDataURL(f);
} else {
alert("Image Size is too big. Minimum size is 2MB.");
$(this).val("");
}
}
}
})
But if there is no other way to crop without canvas, tell me how to crop with canvas
EDIT
<input id="uploadImage" type="file" accept="image/*" capture="camera" />
<img id="imgDisplay" src="http://placehold.it/300x200" alt="Not a kitten" />
var Resample = (function (canvas) {
// (C) WebReflection Mit Style License
function Resample(img, width, height, onresample) {
var load = typeof img == "string",
i = load || img;
if (load) {
i = new Image;
// with propers callbacks
i.onload = onload;
i.onerror = onerror;
}
i._onresample = onresample;
i._width = width;
i._height = height;
load ? (i.src = img) : onload.call(img);
}
function onerror() {
throw ("not found: " + this.src);
}
function onload() {
var
img = this,
width = img._width,
height = img._height,
onresample = img._onresample
;
// Altered section - crop prior to resizing
var imgRatio = img.width / img.height;
var desiredRatio = width / height;
var cropWidth, cropHeight;
if (desiredRatio < imgRatio) {
cropHeight = img.height;
cropWidth = img.height * desiredRatio;
} else {
cropWidth = img.width;
cropHeight = img.width / desiredRatio;
}
delete img._onresample;
delete img._width;
delete img._height;
canvas.width = width;
canvas.height = height;
context.drawImage(
// original image
img,
// starting x point
0,
// starting y point
0,
// crop width
cropWidth,
// crop height
cropHeight,
// destination x point
0,
// destination y point
0,
// destination width
width,
// destination height
height
);
onresample(canvas.toDataURL("image/png"));
}
var context = canvas.getContext("2d"),
round = Math.round;
return Resample;
}(
this.document.createElement("canvas"))
);
var newCropWidth = 133;
var newCropHeight = 133;
function loadImage(data) {
document.querySelector('#imgDisplay').src = data;
}
function handleFileSelect(evt) {
if (evt.target.files.length === 1) {
var picFile = evt.target.files[0];
if (picFile.type.match('image.*')) {
var fileTracker = new FileReader;
fileTracker.onload = function() {
Resample(
this.result,
newCropWidth,
newCropHeight,
loadImage
);
}
fileTracker.readAsDataURL(picFile);
}
}
}
document.querySelector('#uploadImage').addEventListener('change', handleFileSelect, false);
There are ways to do it using jQuery UI but you can just utilize a plugin that someone else already made such as Cropper

Asynchronous file uploading working (in fact not working) differently in different browsers

I am testing line by line resizing and uploading files within a form client-side.
There is a button to select a file, javascript throws an alert about image attributes, resizes the image, assigns it to a hidden field and posts the form. I started with a single image and the relevant code is:
HTML
<form action="add2.php" method="post" enctype="multipart/form-data" id="addform">
<input type="file" id="i1_file" onchange="resize('i1_file', 'addform')" />
<input type="hidden" name="uploadfile" id="image1" value="" />
Javascript
function resize(inputid, formid)
{
var inpFiles = document.getElementById(inputid);
var file = inpFiles.files[0];
... Initial file checks here: type, size etc...
var dataurl = null;
// create <img> element
var img = document.createElement("img");
var reader = new FileReader();
var image = document.getElementById('image1');
// document.write("Before image1 :" + image.name + "<br />");
reader.onloadend = function(e) {
img.src = e.target.result;
img.onload = function() {
// Once you have the image preview in an <img> element, you can draw this image in a <canvas> element to pre-process the file.
var canvas = document.createElement("canvas");
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var width = img.width;
var height = img.height;
//document.write("src " + img.src + "<br />");
document.write("width " + img.width + "<br />");
document.write("height " + img.height + "<br />");
if ((width > 1024) && (width > height))
{
var new_width = 1024;
var ratio = new_width / width;
var new_height = Math.round(height * ratio);
}
else if (height > 768)
{
var new_height = 768;
var ratio = new_height / height;
var new_width = Math.round(width * ratio);
}
else
{
var new_width = width;
var new_height = height;
}
document.write("new_height: " + new_height + "<br />");
canvas.width = new_width;
canvas.height = new_height;
var ctx = canvas.getContext('2d');
ctx.drawImage(img,0,0,new_width, new_height);
// save canvas as dataUrl
dataurl = canvas.toDataURL("image/jpeg", 0.8);
document.write("FormData " + formid + "<br />");
//document.write("dataurl: " + dataurl + "<br />");
image.value = dataurl;
//var fd = new FormData(document.getElementById(formid));
document.write("Before FormData " + "<br />");
var fd = new FormData(document.forms["addform"]);
var xhr = new XMLHttpRequest();
document.write("Posting <br />" + xhr.readyState );
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
if (xhr.status === 200) {
// OK
alert('response:'+xhr.responseText);
// here you can use the result (xhr.responseText)
} else {
// not OK
alert('failure!');
}
}
};
xhr.open('POST', 'add2.php', true);
document.write("After Open <br />" + xhr.readyState);
xhr.setRequestHeader("Content-type","multipart/form-data");
document.write("Before Send <br />" );
xhr.send(fd);
console.log(xhr.response);
} //onload
}
reader.readAsDataURL(file);
}
The first browser was Firefox and it hangs after producing this output (i.e. up to xhr.open):
width 4176
height 3120
new_height: 765
FormData addform
Before FormData
Posting
0
Chrome did not redirect at all and stayed on the same page where the form was.
IE10 only output "width 4176" (the very first debugging print).
Can anyone spot what I am doing wrong and why the behaviour is so different in modern browsers?

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>

Can't limit number of files and save it to database, Image uploader Javascript and PHP

first of all Im really new with Javascript and lets tell you what i need.
I have this code to make an image uploader to resize it on client-side and works perfect, made by Joel Vardy. But I need to limint the number of images to upload by 10. I can't figured it out how to do it... also i can't find a way to host the image links on the Database via php
The HTML
<head>
<title>Upload Photos</title>
<link rel="stylesheet" href="./style.css" />
<head>
<body>
<h1>Upload Photos</h1>
<form>
<input type="file" accept="image/*" multiple />
<div class="photos">
</div>
</form>
<script src="./upload.js"></script>
</body>
The JS
document.querySelector('form input[type=file]').addEventListener('change', function(event){
var files = event.target.files;
// Iterate through files
for (var i = 0; i < files.length; i++) {
// Ensure it's an image
if (files[i].type.match(/image.*/)) {
// Load image
var reader = new FileReader();
reader.onload = function (readerEvent) {
var image = new Image();
image.onload = function (imageEvent) {
// Add elemnt to page
var imageElement = document.createElement('div');
imageElement.classList.add('uploading');
imageElement.innerHTML = '<span class="progress"><span></span></span>';
var progressElement = imageElement.querySelector('span.progress span');
progressElement.style.width = 0;
document.querySelector('form div.photos').appendChild(imageElement);
// Resize image
var canvas = document.createElement('canvas'),
max_size = 1200,
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);
// Upload image
var xhr = new XMLHttpRequest();
if (xhr.upload) {
// Update progress
xhr.upload.addEventListener('progress', function(event) {
var percent = parseInt(event.loaded / event.total * 100);
progressElement.style.width = percent+'%';
}, false);
// File uploaded / failed
xhr.onreadystatechange = function(event) {
if (xhr.readyState == 4) {
if (xhr.status == 200) {
imageElement.classList.remove('uploading');
imageElement.classList.add('uploaded');
imageElement.style.backgroundImage = 'url('+xhr.responseText+')';
console.log('Image uploaded: '+xhr.responseText);
} else {
imageElement.parentNode.removeChild(imageElement);
}
}
}
// Start upload
xhr.open('post', 'process.php', true);
xhr.send(canvas.toDataURL('image/jpeg'));
}
}
image.src = readerEvent.target.result;
}
reader.readAsDataURL(files[i]);
}
}
// Clear files
event.target.value = '';
});
The PHP
$filename = md5(mt_rand()).'.jpg';
$data = file_get_contents('php://input');
$image = file_get_contents('data://'.substr($data, 5));
if ( ! file_put_contents('images/'.$filename, $image)) {
header('HTTP/1.1 503 Service Unavailable');
exit();
}
unset($data);
unset($image);
echo './images/'.$filename;
Any help will be appreciated, Thank you!
To limit the script to only work with max 10 files, do something like this:
for (var i = 0; i < files.length; i++) {
if (i < 11){
}
}
for the database, read about mysql and learn it.

Javascript file resizing generating bad base64 string

I've been trying to resize images client side (using HTML5) before upload. It resizes it and sends through a base64 string, but it seems to be broken. The base64 string has spaces and line breaks and weird things, even if I take them out, it seems to still be broken.
This is my HTML:
<div class="form-group">
<canvas id="canvas"></canvas>
<label for="fileToUpload">Select Files to Upload</label>
<input type="file" id="FileUpload1" name="FileUpload1" />
<output id="filesInfo"></output>
</div>
And of course my javascript:
<script type="text/javascript">
if (window.File && window.FileReader && window.FileList && window.Blob) {
document.getElementById('FileUpload1').onchange = function () {
var files = document.getElementById('FileUpload1').files;
for (var i = 0; i < files.length; i++) {
resizeAndUpload(files[i]);
}
};
} else {
alert('The File APIs are not fully supported in this browser.');
}
function resizeAndUpload(file) {
var reader = new FileReader();
reader.onloadend = function () {
var tempImg = new Image();
tempImg.src = reader.result;
tempImg.onload = function () {
var MAX_WIDTH = 400;
var MAX_HEIGHT = 300;
var tempW = tempImg.width;
var tempH = tempImg.height;
if (tempW > tempH) {
if (tempW > MAX_WIDTH) {
tempH *= MAX_WIDTH / tempW;
tempW = MAX_WIDTH;
}
} else {
if (tempH > MAX_HEIGHT) {
tempW *= MAX_HEIGHT / tempH;
tempH = MAX_HEIGHT;
}
}
var canvas = document.getElementById('canvas');
canvas.width = tempW;
canvas.height = tempH;
var ctx = canvas.getContext("2d");
ctx.drawImage(this, 0, 0, tempW, tempH);
var dataURL = canvas.toDataURL("image/jpeg");
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function (ev) {
document.getElementById('filesInfo').innerHTML = 'Done!';
};
xhr.open('POST', 'Upload', true);
xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
alert(dataURL);
var data = 'image=' + dataURL;
xhr.send(data);
}
}
reader.readAsDataURL(file);
}
</script>
The dataURL variable, that's what contains the bad base64 string.
Here is your problem:
Base 64 encoded string includes characters like / and + , which as you can imagine have special significance if the request content type is said to be application/x-www-form-urlencoded. So, with your current code, + sign gets decoded as a space, and combinations like \n get interpreted as control characters such as line feed, new line etc.
All you have to do is encode dataURL to make sure it is safe for use as a parameter value. This is as simple as using the encodeURIComponent method.
i.e. var data = 'image=' + encodeURIComponent(dataURL);
Hope this helps.

Categories