Download file using Javascript from a bytearray - javascript

I have a button in my asp net app that when pressed I am calling a rest service that returns a bytearray.
This bytearray is actually a file that I need to start downloading in the browser when the button is pressed. How can I achieve this?
I am thinking along the lines of writing the bytearray to the response and setting the headers.
Is this thinking correct and does someone have some code samples?
---------Update on 3/25----------------
Thanks Justin but not yet what I need. Please look at this link it will return a file for download. What I need to do is have an event client side that will get this file for download without redirecting to this page. It has to be downloaded from my page and not this link.
http://ops.epo.org/3.0/rest-services/published-data/images/US/5000001/PA/firstpage.pdf?Range=1
If you check it out with Fiddler, you will see how the pdf is received as binary.

You can set the responseType as arraybuffer and access it that way. There is even a way to stream the data using onprogress events. JavaScript has come a long way.
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something with each byte in the array
}
}
};
oReq.send(null);
https://developer.mozilla.org/en-US/docs/DOM/XMLHttpRequest/Sending_and_Receiving_Binary_Data
If you mean that the webservice isn't returning binary data, and instead is JSON data like: [0,1,3,4] then that is a different issue.

As far as i know, the closest thing you can do with javascript is an ajax request that has the server parse the data as text

Related

How to post blob and string with XMLHttpRequest javascript and PHP [duplicate]

I've seen many partial answers to this here and elsewhere, but I am very much a novice coder and am hoping for a thorough solution. I have been able to set up recording audio from a laptop mic in Chrome Canary (v. 29.x) and can, using recorder.js, relatively easily set up recording a .wav file and saving that locally, a la:
http://webaudiodemos.appspot.com/AudioRecorder/index.html
But I need to be able to save the file onto a Linux server I have running. It's the actual sending of the blob recorded data to the server and saving it out as a .wav file that's catching me up. I don't have the requisite PHP and/or AJAX knowledge about how to save the blob to a URL and to deal, as I have been given to understand, with binaries on Linux that make saving that .wav file challenging indeed. I'd greatly welcome any pointers in the right direction.
Client side JavaScript function to upload the WAV blob:
function upload(blob) {
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",blob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
PHP file upload_wav.php:
<?php
// get the temporary name that PHP gave to the uploaded file
$tmp_filename=$_FILES["that_random_filename.wav"]["tmp_name"];
// rename the temporary file (because PHP deletes the file as soon as it's done with it)
rename($tmp_filename,"/tmp/uploaded_audio.wav");
?>
after which you can play the file /tmp/uploaded_audio.wav.
But remember! /tmp/uploaded_audio.wav was created by the user www-data, and (by PHP default) is not readable by the user. To automate adding the appropriate permissions, append the line
chmod("/tmp/uploaded_audio.wav",0755);
to the end of the PHP (before the PHP end tag ?>).
Hope this helps.
Easiest way, if you just want to hack that code, is go in to recorderWorker.js, and hack the exportWAV() function to something like this:
function exportWAV(type){
var bufferL = mergeBuffers(recBuffersL, recLength);
var bufferR = mergeBuffers(recBuffersR, recLength);
var interleaved = interleave(bufferL, bufferR);
var dataview = encodeWAV(interleaved);
var audioBlob = new Blob([dataview], { type: type });
var xhr=new XMLHttpRequest();
xhr.onload=function(e) {
if(this.readyState === 4) {
console.log("Server returned: ",e.target.responseText);
}
};
var fd=new FormData();
fd.append("that_random_filename.wav",audioBlob);
xhr.open("POST","<url>",true);
xhr.send(fd);
}
Then that method will save to server from inside the worker thread, rather than pushing it back to the main thread. (The complex Worker-based mechanism in RecorderJS is because a large encode should be done off-thread.)
Really, ideally, you'd just use a MediaRecorder today, and let it do the encoding, but that's a whole 'nother ball of wax.

Upload an image to server using chrome extensions

I am doing a chrome extension capable of getting from a webpage an image, and after I got it, I'm trying to upload it to an intranet server automatically without user iteration.
I am doing this right now.
This is on Content_script.js
...
x = $(frame1).contents().find("#image");
chrome.extension.sendRequest(x[0].src);
...
This is on background.js
chrome.extension.onRequest.addListener(function(links) {
chrome.downloads.download( { url: links ,
conflictAction: "overwrite",
filename: "get_image.jpg" },
function(DescargaId) {
var formData = new FormData();
formData.append("doc", Blob, "~/Downloads/get_image.jpg");
var request = new XMLHttpRequest();
request.open("POST", "http://192.168.0.30/app_get_pictures/upload_img.php");
request.setRequestHeader("Content-Type", "multipart/form-data");
request.send(formData);
} );
This on upload_img.php
...
$uploaddir = $_SERVER['DOCUMENT_ROOT'].'/app_get_pictures/images/';
$uploadfile = $uploaddir . basename($_FILES['doc']['name']);
move_uploaded_file($_FILES['doc']['tmp_name'], $uploadfile);
...
With this, I already download the image successfully to the local machine, but can't upload the image to the server.
It is possible to do this, or even if I can upload the image to the server directly without download it first to the local machine.
Note: I don't have any tag form on a popup page in the extension solution, and I don't have a popup page neither, because as I already said, I don't need any iteration from the user.
Thanks for your help!
Thanks to https://stackoverflow.com/users/934239/xan I resolved this problem using his advise, here is the resulting working code.
...
// With this I can download or get content image into var blob
var xhr = new XMLHttpRequest();
var kima = $(frame1).contents().find("#image");
xhr.open('GET',kima[0].src,true);
xhr.responseType = 'blob';
xhr.onload = function(e) {
if (this.status == 200) {
var blob = new Blob([this.response], {type: 'image/png'});
send_image(blob);
}
};
xhr.send();
....
// After the image is loaded into var blob, it can be send
// to the server side
function send_image(x){
var formData = new FormData();
formData.append("doc", x);
var request = new XMLHttpRequest();
request.open("POST", "http://192.168.0.30/app_get_image/upload_img.php");
request.send(formData);
}
All this code into the content_script of the chrome extension. Also the code of the background using API download isn't needed anymore.
Hope this could works for anybody else.
Thanks again.
Besides the fact that the callback of downloads.download does NOT indicate that the file is already downloaded (only that the download is queued)..
formData.append("doc", Blob, "~/Downloads/get_image.jpg");
What do you think this code does? Documentation, for reference.
The second parameter is supposed to hold the data of the file; the third parameter is just the file name for the purposes of naming anonymous data (e.g. in a Blob)
Instead, you pass the Blob object itself; not an instance of Blob with the data.
In fact, with this architecture, you won't be able to upload the file, since at no point does chrome.downloads API give you access to the file's contents, and you can't just access a file on a disk by filename (which is what I think you thought this code would do).
To actually access the data, you need to request it yourself with XHR (or Fetch API if you want to be "modern"). Then, you get the response object which you can request to be a Blob. Then, you can both upload the blob and invoke chrome.downloads together with createObjectURL to "download" it from your extension's memory.

How to load a PDF into a blob so it can be uploaded?

I'm working on a testing framework that needs to pass files to the drop listener of a PLUpload instance. I need to create blob objects to pass inside a Data Transfer Object of the sort generated on a Drag / Drop event. I have it working fine for text files and image files. I would like to add support for PDF's, but it seems that I can't get the encoding right after retrieving the response. The response is coming back as text because I'm using Sahi to retrieve it in order to avoid Cross-Domain issues.
In short: the string I'm receiving is UTF-8 encoded and therefore the content looks like you opened a PDF with a text editor. I am wondering how to convert this back into the necessary format to create a blob, so that after the document gets uploaded everything looks okay.
What steps do I need to go through to convert the UTF-8 string into the proper blob object? (Yes, I am aware I could submit an XHR request and change the responseType property and (maybe) get closer, however due to complications with the way Sahi operates I'm not going to explain here why I would prefer not to go this route).
Also, I'm not familiar enough but I have a hunch maybe I lose data by retrieving it as a string? If that's the case I'll find another approach.
The existing code and the most recent approach I have tried is here:
var data = '%PDF-1.7%����115 0 obj<</Linearized 1/L ...'
var arr = [];
var utf8 = unescape(encodeURIComponent(data));
for (var i = 0; i < utf8.length; i++) {
arr.push(utf8.charCodeAt(i));
}
var file = new Blob(arr, {type: 'application/pdf'});
It looks like you were close. I just did this for a site which needed to read a PDF from another website and drop it into a fileuploader plugin. Here is what worked for me:
var url = "http://some-websites.com/Pdf/";
//You may not need this part if you have the PDF data locally already
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function () {
if (this.readyState == 4 && this.status == 200) {
//console.log(this.response, typeof this.response);
//now convert your Blob from the response into a File and give it a name
var fileOfBlob = new File([this.response], 'your_file.pdf');
// Now do something with the File
// for filuploader (blueimp), just use the add method
$('#fileupload').fileupload('add', {
files: [ fileOfBlob ],
fileInput: $(this)
});
}
}
xhr.open('GET', url);
xhr.responseType = 'blob';
xhr.send();
I found help on the XHR as blob here. Then this SO answer helped me with naming the File. You might be able to use the Blob by itself, but you won't be able to give it a name unless its passed into a File.

Javascript on Firefox: Accessing binary data from html object possible?

On an html page I have an <object> that hosts a pdf.
I would need to access the binary data of the pdf via Javascript, but I cannot figure out how
to accomplish that. I get access to the object element itself but cannot think of a method for getting the data in it.
Is it possible at all?
You can not get the binary from an object tag, but you can make an AJAX request to the server and get it as ArrayBuffer by using the new responseType attribute:
var http = new XMLHttpRequest();
http.open("get", "somefile.pdf", true);
http.responseType = "arraybuffer";
http.onload = function(e)
{
if(http.response)
{
// http.response contains the file
}
};
http.send(null);
Note that this method only works in newer browsers and is obviously restricted by the Same-Origin-Policy.

Ajax Binary Response

Hi I'm wondering if there's anyway to stream a binary response in AJAX? This would be an ultimate solution otherwise I would need to realize the binary image to a file then stream that file to the user with a different URL.
new Ajax.Request('/viewImage?id=123', {
// request returns a binary image inputstream
onSuccess: function(transport) {
// text example
// alert(transport.responseText)
// QUESTION: is there a streaming binary response?
$('imgElem').src = transport.responseBinary;
},
onFailure: function(transport) {
// handle failure
}
});
It might not be possible to stream binary data, but you can use Ajax to retrieve binary data.
This is possible using one of two methods: Javascript Typed Arrays or an XMLHttpResponse overrideMimeType hack. Have a read of a good article on MDN – these examples are taken from there: Sending and Receiving Binary Data
The Typed Array method looks like this:
var oReq = new XMLHttpRequest();
oReq.open("GET", "/myfile.png", true);
oReq.responseType = "arraybuffer";
oReq.onload = function (oEvent) {
var arrayBuffer = oReq.response; // Note: not oReq.responseText
if (arrayBuffer) {
var byteArray = new Uint8Array(arrayBuffer);
for (var i = 0; i < byteArray.byteLength; i++) {
// do something with each byte in the array
}
}
};
oReq.send(null);
Typed Arrays are not supported in IE < 10, Firefox < 4, Chrome < 7, Safari < 5.1 and Opera < 11.6, and mobile support is shaky but improving.
The second method uses an XMLHttpRequest method called overrideMimeType to allow the binary data to be passed through unmodified.
var req = new XMLHttpRequest();
req.open('GET', '/myfile.png', false);
// XHR binary charset opt by Marcus Granado 2006 [http://mgran.blogspot.com]
req.overrideMimeType('text\/plain; charset=x-user-defined');
req.send(null);
if (req.status != 200) return '';
// do stuff with req.responseText;
You get an unparsed binary string, upon which you can use var byte = filestream.charCodeAt(x) & 0xff; to retrieve a specific byte.
This is an extension to Tom Ashworth's response (which helped to put me on the right track with the issue I was facing). This allows you to just get the filestream (FileStreamResult if you are using asp.net mvc) and set it to the img src, which is cool.
var oReq = new XMLHttpRequest();
oReq.open("post", '/somelocation/getmypic', true );
oReq.responseType = "blob";
oReq.onload = function ( oEvent )
{
var blob = oReq.response;
var imgSrc = URL.createObjectURL( blob );
var $img = $( '<img/>', {
"alt": "test image",
"src": imgSrc
} ).appendTo( $( '#bb_theImageContainer' ) );
window.URL.revokeObjectURL( imgSrc );
};
oReq.send( null );
The basic idea is that the data is returned untampered with, it is placed in a blob and then a url is created to that object in memory. See here and here. Note supported browsers.
What you can do, if you are trying to generate an image on the fly, is to just do:
<img src="http://myurl/myfile.php?id=3" />
then you can send the data with the appropriate mimetype.
If you really want to send an image, then you may want to look at the HTML5 canvas tag, but I am not certain how excanvas would work with this, for being cross-platform.
You could write to the canvas, but it would be more efficient to just use the img tag.
When you call your service, you should ask for a dataType: 'binary' response. Then, you can use saveAs(FileSaver.js) to trigger the download or createObjectURL to open in new window.
But, $.ajax doesn't let you download binary content out of the box, it will try to decode your binary from UTF-8 and corrupt it. Either use a jQuery plugin to solve this problem jquery.binarytransport.js
exemplo:
$.ajax({
type: "POST",
url: $("form#data").attr("action"),
data: formData,
dataType: 'binary', //--> using jquery.binarytransport.js
success: function (response) {
// Default response type is blob
saveAs(response, "test.pdf"); //--> using FileSaver.js
let fileURL = URL.createObjectURL(blob);
window.open(fileURL); // open file in new window
}
});
Good look! :)
You can send any response you want, being it plain text, HTML, an image... whatever! It's up to you how to handle it when you receive it.
But... you cannot assign a binary image to the <IMG> src attribute. You'd better just return the URL to the image and assign that instead - well, to be honest, there are some encodings to embed images in the SRC, but they are not cross-browser so you'll want to stay away from them.
I managed to get download of binary file without corrupted data working using jQuery ajax by adding:
xhrFields: {responseType: 'blob'}

Categories

Resources