How to download blob in input?
Code html:
<img id="image" src="${pageContext.request.contextPath}/image/accaunt/user?${nowDate.time}"/>
<label id="text-add-photo" for="img-input">replace</label>
<input id="img-input" name="file" type="file" style="display: none;"/>
Code JS
const canvas = cropper.getCroppedCanvas();
const fileImage = canvas.toDataURL("image/jpg").replace(/^data:image\/(png|jpg|jpeg);base64,/, "");
$("img-input").val(fileImage);
and it is not work...
After 4 months ago i'm can answer this question.
This can be done by loading the bytes into another input field. Pre-attaching the listener to the old field.
It is my class.
This class works in conjunction with cropper js. When you change the value in the input window opens, which allows you to crop the image. After that, from cropper js we get cropper.getCroppedCanvas (). ToDataURL () and in the field a new field will be assigned a value. This field must be processed on the server side:
class ModalImageLoader {
constructor(data) {
this.data = data;
}
init() {
let MainClass = this;
var parentDiv = $(this.data.parent_div);
if (parentDiv.hasClass("load-modal-image")) {
$(parentDiv).children("#modal-image-fone").remove();
}
parentDiv.addClass("load-modal-image");
var foneModalImage = $('<div>', {id: 'modal-image-fone'});
foneModalImage.addClass('off');
parentDiv.prepend(foneModalImage);
var modalImage = $('<div>', {id: 'modal-image'});
modalImage.addClass('modal');
modalImage.addClass('window');
modalImage.addClass('white');
foneModalImage.append(modalImage);
var wrap = $('<div>', {id: 'wrapper-upt-image'});
modalImage.append(wrap);
var imageCropper = $('<img>', { id: 'img-crop' });
modalImage.append(imageCropper);
var wrapButtons = $('<div>');
wrapButtons.addClass("wrap-buttons");
modalImage.append(wrapButtons);
var buttonCancel = $('<button>');
buttonCancel.addClass('cancel');
buttonCancel.addClass('orange');
buttonCancel.html('назад');
buttonCancel.click(function () { MainClass.cancel(); });
wrapButtons.append(buttonCancel);
var buttonAccept = $('<button>');
buttonAccept.addClass('accept')
buttonAccept.addClass('orange');
buttonAccept.html('далее');
buttonAccept.click(function () { MainClass.saveToDataUrl(); });
wrapButtons.append(buttonAccept);
this.addListenerForInput(this.data.props);
}
show() {
$('.load-modal-image #modal-image-fone').removeClass('off');
}
hide() {
$('.load-modal-image #modal-image-fone').addClass('off');
}
initCrop(props) {
this.data.props = props;
$('#img-crop').attr('src', props.src);
if (props.aspWidth == undefined) props.aspWidth = 1;
if (props.aspHeight == undefined) props.aspHeight = 1;
var image = document.getElementById('img-crop');
var cropper = new Cropper(image, {
aspectRatio: props.aspWidth / props.aspHeight,
movable: false,
zoomable: false,
rotatable: false,
scalable: false
});
this.cropper = cropper;
this.show();
}
open(props) {
this.data.props = props;
this.initCrop(props);
}
close() {
this.cropper.destroy();
$(this.data.props.input).prop('value', null);
this.hide();
}
saveToDataUrl() {
this.setBase64ForImage();
$(this.data.props.input64).val(this.cropper.getCroppedCanvas().toDataURL());
this.close();
}
setBase64ForImage() {
$(this.data.props.img).attr('src', this.cropper.getCroppedCanvas().toDataURL());
}
cancel() {
this.close();
}
addListenerForInput(props) {
var MainClass = this;
this.data.props = props;
$(props.input).change(
function(e){
/*var input = $('#myFile')[0];
var file = input.files[0];*/
var file = e.target.files[0];
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(e){
MainClass.open({
src: e.target.result,
input: props.input,
img: props.img,
imgType: $(props.input)[0].files[0].type,
funSender: props.funSender,
input64: props.input64
});
}
});
}
/**
* #deprecated with create new branch modal-image-loader
*/
static sendBlob(path, method, blob) {
var formData = new FormData();
formData.append('file', blob);
$.ajax({
url: path,
type: method,
enctype: 'multipart/form-data',
processData: false,
contentType: false,
cache: false,
data: formData
});
}
}
This is converter (Java). You can paste this code in setter:
import org.apache.commons.io.IOUtils
import sun.misc.BASE64Decoder
import java.awt.image.BufferedImage
import java.io.ByteArrayInputStream
object ConverterUtils {
fun convertBase64ToImage(base64Text: String): ByteArray {
// tokenize the data
val parts = base64Text.split(",")
val imageString = parts[1]
// create a buffered image
val imageByte: ByteArray
val decoder = BASE64Decoder()
imageByte = decoder.decodeBuffer(imageString)
val bis = ByteArrayInputStream(imageByte)
val bytes = IOUtils.toByteArray(bis)
bis.close()
return bytes
}
}
Related
must be a simple question but I've been struggling for a week with it. I have a super simple jquery based audio capture - what I just want is to save it as a file based on a controller action. The problem is that I can't figure out how to pass blob file to the controller. This is the code I have to capture audio (see below). With image I can just use
document.getElementById("canvas").toDataURL("image/png");
then pass it to controller and save it as image, something like this:
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(imageData);
bw.Write(data);
bw.Close();
}
fs.Close();
}
so ideally I would want something akin to how I save images.
$(function () {
$('body').append(
$('<button/>')
.attr("id", "start")
.html("start")
).append(
$('<button/>')
.attr("id", "stop")
.html("stop")
).append(
$('<div/>').
attr("id", "ul")
)
let log = console.log.bind(console),
ul = $('#ul')[0],
start = $('#start')[0],
stop = $('#stop')[0],
stream,
recorder,
counter = 1,
chunks,
media;
media = {
tag: 'audio',
type: 'audio/ogg',
ext: '.ogg',
gUM: { audio: true }
}
navigator.mediaDevices.getUserMedia(media.gUM).then(_stream => {
stream = _stream;
recorder = new MediaRecorder(stream);
recorder.ondataavailable = e => {
chunks.push(e.data);
if (recorder.state == 'inactive') makeLink();
};
log('got media successfully');
}).catch(log);
start.onclick = e => {
start.disabled = true;
stop.removeAttribute('disabled');
chunks = [];
recorder.start();
}
stop.onclick = e => {
stop.disabled = true;
recorder.stop();
start.removeAttribute('disabled');
}
function makeLink() {
let blob = new Blob(chunks, { type: media.type })
, url = URL.createObjectURL(blob)
, div = document.createElement('div')
, mt = document.createElement(media.tag)
, hf = document.createElement('a')
;
mt.controls = true;
mt.src = url;
hf.href = url;
hf.download = `${counter++}${media.ext}`;
hf.innerHTML = `donwload ${hf.download}`;
div.appendChild(mt);
ul.appendChild(div);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
Much appreciated
So just in case anyone else stumples on it, as expected it was quite simple (not the cleanest code but here you go):
create a new Blob value:
recorder.ondataavailable = e => {
chunks.push(e.data);
superBuffer = new Blob(chunks, { type: 'audio/ogg' });
if (recorder.state == 'inactive') makeLink(); //console.log(e.data)
Then use Ajax to send this to server:
var reader = new window.FileReader();
reader.readAsDataURL(superBuffer);
reader.onloadend = function () {
base64 = reader.result;
base64 = base64.split(',')[1];
$.ajax({
url: 'MyController/Action1',
type: 'POST',
data: {
audioname: "hello",//obviously change to something dynamic
chunks: base64
},
success: function (response) { console.log(response); },
error: function (response) { console.log(response); }
});
Then in the code-behind:
[HttpPost]
public IActionResult Action1(string audioname, string chunks)
{
string fileNameWitPath = Path.Combine(_hostingEnvironment.WebRootPath, "audio", "test.ogg");
using (FileStream fs = new FileStream(fileNameWitPath, FileMode.Create))
{
using (BinaryWriter bw = new BinaryWriter(fs))
{
byte[] data = Convert.FromBase64String(chunks);
bw.Write(data);
bw.Close();
}
fs.Close();
}
return Content(chunks) ;//this is for testing - sends back full chunk on success, would probably just want some confirm all is good message
}
Note this is work in progress obviously with things to fill, but in general works
I have a multi-file input field:
<input type="file" class="image_file" multiple>
I am using FileReader to show previews of images whilst they are being uploaded.
I now also want to show a progress bar on each individual image whilst it is being uploaded. Here is what I have tried:
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
}
};
reader.readAsDataURL(file);
$.ajax({
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = container.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
},
success: function(result) {
if (result.status == true) {
$('.success-message').show();
}
else {
alert('There was an error uploading your file.);
}
}
});
}
});
The issue I am having is on this line in the xhr function:
var progressElem = container.find('progress');
The image preview appears but the AJAX upload isn't working. No errors are shown in the console either. I think because var container was set within the reader.onload function, the xhr function doesn't have access to it.
If I move that var outside of the function, the image upload works but only one image preview and one progress bar is shown.
Does anybody know the correct way to do this?
The problem is that there is a single xhr that is created and deleted when the for loop runs. The previous xhr are destroyed once the code finishes so it will never run.
The way I got round this was to not use jQuery and/or create a new xmlhttprequest for each for loop.
var array = []; //ADDED HERE
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
}
};
reader.readAsDataURL(file);
array[array.Length] = $.ajax({ //ADDED HERE
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = container.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
},
success: function(result) {
if (result.status == true) {
$('.success-message').show();
} else {
alert('There was an error uploading your file.);
}
}
});
}
});
I need to emphasis that I haven't looked through your code completely but hopefully this will steer you in the right direction.
Looking at your question description, I assume:
Image Preview works since you mentioned "The image preview appears"
Image uploads since you mentioned "If I move that var outside of the function, the image upload works..."
Where is the problem then?
The problem is your variable container is not accessible inside xhr() function as you mentioned already.
What is the solution?
There can be many possible solutions for you problem, but I think moving the ajax request block inside reader.onload is better idea since, the variable container will be accessible to child function and it will be called only if vaild file is being uploaded.
$('.image_file').change(function() {
var input = $(this);
var files = this.files;
var total = files.length;
var url = input.attr('data-url');
for (var i = 0; i < total; i++) {
var formData = new FormData();
var file = files[i];
formData.append('image_file', file);
var reader = new FileReader();
reader.onload = function(e) {
var container = $('.photos .photo:not(.active):first');
if (container.length) {
var ajaxFunction = function() {
var myXhr = $.ajaxSettings.xhr();
var progressElem = this.find('progress');
if (myXhr.upload) {
myXhr.upload.addEventListener('progress', function(e) {
if (e.lengthComputable) {
progressElem.attr({
value: e.loaded,
max: e.total
});
}
}, false);
}
return myXhr;
};
container.css('background-image', 'url(' + e.target.result + ')').addClass('active uploading');
$.ajax({
type: 'post',
url: url,
data: formData,
cache: false,
processData: false,
contentType: false,
xhr: ajaxFunction.bind(container),
success: function(result) {
if (result.status == true) {
$('.success-message').show();
} else {
alert('There was an error uploading your file.');
}
}
});
}
};
reader.readAsDataURL(file);
}
});
.photo {
display: none;
height: 200px;
width: 200px;
float: left;
}
.active {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input type="file" class="image_file" multiple data-url="http://httpbin.org/post">
<div class="photos">
<div class="photo">
<progress></progress>
</div>
<div class="photo">
<progress></progress>
</div>
</div>
Updated: used bind() function to pass current value of the variable container to the ajaxFunction()
I am working on reading .csv /xlsx file uploaded using javaScript and get the result as array containing each row . I was able to read the file and get data using FileReader and SheetJs with following code.
// code for the new excel reader
$scope.do_file = function(files)
{
$scope.fileContent = [];
var X = XLSX;
var global_wb;
var f = files[0];
var reader = new FileReader();
reader.onload = function(e)
{
var data = e.target.result;console.log(data);
global_wb = X.read(data, {type: 'array'});
var output = "";
var result = {};
global_wb.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_json(global_wb.Sheets[sheetName], {header:1});
if(roa.length) result[sheetName] = roa;
});
$scope.fileContent = result["Sheet1"];
if(!result["Sheet1"])
{
$scope.fileContent = result["contacts"].filter(function(el) { return typeof el != "object" || Array.isArray(el) || Object.keys(el).length > 0; });
}
};
reader.readAsArrayBuffer(f);
};
For reading most of the files the code works , but when file containing Hebrew text with Windows-1255 encoding i get gibberish data.
Looking in for more options i tried to read the file as text using reader.readAsText and change the encoding as necessary , check the following code:
function is_Hebrew(data)
{
var position = data.search(/[\u0590-\u05FF]/);
return position >= 0;
}
$scope.do_file = function(files)
{
var fullResult = [];
var file =files[0];
var reader = new FileReader();
reader.onload = function(e){
var data = e.target.result;
if(!is_Hebrew(data.toString()))
{
reader.readAsText(file,'ISO-8859-8');
}
};
reader.readAsText(file);
reader.onloadend = function(){
var lines = reader.result.split('\r\n');
console.log(lines);
lines.forEach(element => {
var cell = element.split(',');
fullResult.push(cell);
});
console.log(reader);
};
};
but the above code is not suitable as it does not read the file as each row identifying each cell. if any one of cell contains string with coma separated value (for example if a cell contains a string value such as "25,28,29" ) the array output gives wrong data as it considers each values as each cell.
So i decided to stick with first method but i am not able to change the encoding .Is there a possible way to change encoding in the first code where i have used the readAsArrayBuffer to read the file data ?
After going through lot of possible solutions i found that answer to the above question was to combine the above two methods. The first method for reading the xlsx files and second method for reading csv files. Also i have used an additional javaScript library called papaparse in the second method to solve the problem of reading data in each cell
$scope.is_Hebrew = function($data){
var position = $data.search(/[\u0590-\u05FF]/);
return position >= 0;
}
// code for the new excel reader
$scope.do_file = function(files)
{
var config = {
delimiter: "", // auto-detect
newline: "", // auto-detect
quoteChar: '"',
escapeChar: '"',
header: false,
trimHeader: false,
dynamicTyping: false,
preview: 0,
encoding: "",
worker: false,
comments: false,
step: undefined,
complete: undefined,
error: undefined,
download: false,
skipEmptyLines: false,
chunk: undefined,
fastMode: undefined,
beforeFirstChunk: undefined,
withCredentials: undefined
};
$scope.fileContent = [];
var f = files[0];
var fileExtension = f.name.replace(/^.*\./, '');
if(fileExtension == 'xlsx')
{
var X = XLSX;
var global_wb;
var reader = new FileReader();
reader.onload = function(e)
{
var data = e.target.result;
global_wb = X.read(data, {type: 'array'});
var result = {};
global_wb.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_json(global_wb.Sheets[sheetName], {header:1});
if(roa.length) result[sheetName] = roa;
});
$scope.fileContent = result["Sheet1"];
if(!result["Sheet1"])
{
$scope.fileContent = result["contacts"].filter(function(el) { return typeof el != "object" || Array.isArray(el) || Object.keys(el).length > 0; });
}
};
reader.readAsArrayBuffer(f);
}
else if(fileExtension == 'csv')
{
var reader = new FileReader();
reader.onload = function(e)
{
var data = e.target.result;
console.log(f);
console.log($scope.is_Hebrew(data.toString()));
if(!$scope.is_Hebrew(data.toString()))
{
reader.readAsText(f,'ISO-8859-8');
}
};
reader.readAsText(f);
reader.onloadend = function(e){
var c = Papa.parse(reader.result,[ config])
console.log(c);
$scope.fileContent = c["data"].filter(function(el) { return typeof el != "object" || Array.isArray(el) || Object.keys(el).length > 0; });
};
}
else
{
alert("File Not supported!");
}
$scope.fileContent.push([]);
};
Hey guys am new to jQuery,How can I change this javascript code into jQuery functional code so that I call it whenever I want at any object
LIKE: $("#profile_img").uploader();
Apparently this code works fine, but the problem I have is I have to populate the code every time I need to upload a file in a different file input upload.
var input = document.getElementById("choosen_feeds_image"),
formdata = false;
if (window.FormData) {
formdata = new FormData();
document.getElementById("feeds_upload_btn").style.display = "none";
}
if (input.addEventListener) {
input.addEventListener("change", function (evt) {
var i = 0, len = this.files.length, img, reader, file;
document.getElementById("response").innerHTML = ""
for (; i < len; i++) {
file = this.files[i];
if (!!file.type.match(/image.*/)) {
if (window.FileReader) {
reader = new FileReader();
reader.onloadend = function (e) {
showUploadedItem(e.target.result);
};
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("feeds_image", file);
}
if (formdata) {
$.ajax({
url: "member/feeds_image_upload",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
if (res.length <= 40) {
document.getElementById('feeds_image_response').innerHTML = res;
$("#feeds_image_response").css('display', 'none');
} else {
document.getElementById("response").innerHTML = res;
$("#response").css('display', 'none');
}
}
});
}
} else {
document.getElementById("response").innerHTML = "";
alert("Sorry, You choose unsupported file");
}
}
}), false
};
you can type all inside a function like this
function uploader(){
console.log('myFuntionUploader');
}
and then call the function like this
uploader();
I am trying to add the page_id and page_slug to the loop so that when an image is uploaded the details page id and slug go to.
Normally I would use this: data: { page_id: page_id, page_slug: page_slug }
But formData is there..
(function () {
var input = document.getElementById("images"),
formdata = false;
var page_id = $('#page_id').val();
var page_slug = $('#page_slug').val();
function showUploadedItem (source) {
var list = document.getElementById("image-list"),
li = document.createElement("li"),
img = document.createElement("img");
img.src = source;
li.appendChild(img);
list.appendChild(li);
}
if (window.FormData) {
formdata = new FormData();
document.getElementById("btn").style.display = "none";
}
input.addEventListener("change", function (evt) {
document.getElementById("response").innerHTML = "Uploading . . ."
var i = 0, len = this.files.length, img, reader, file;
for ( ; i < len; i++ ) {
file = this.files[i];
if (!!file.type.match(/image.*/)) {
if ( window.FileReader ) {
reader = new FileReader();
reader.onloadend = function (e) {
showUploadedItem(e.target.result, file.fileName);
};
reader.readAsDataURL(file);
}
if (formdata) {
formdata.append("images[]", file);
}
}
}
if (formdata) {
$.ajax({
url: "admin/pages/upload/",
type: "POST",
data: formdata,
processData: false,
contentType: false,
success: function (res) {
document.getElementById("response").innerHTML = res;
}
});
}
}, false);
}());
I do not think you can manipulate the FormData object directly inside the $.ajax or even $.ajaxSetup functions, so adding two calls to append in the following code block should include the required parameters.
if (window.FormData) {
formdata = new FormData();
formdata.append('page_id', page_id);
formdata.append('page_slug', page_slug);
document.getElementById("btn").style.display = "none";
}
The page_id and page_slug values are unique to so do not need appending in the loop; just once after creating the FormData object.
Please also see Using FormData objects for more examples.