I have a page that has jquery and the amazon SDK. There is text in an area box that the user can change. I successfully make the request to Amazon. I get back the PCM AudioStream (Int16Array). How do I then convert this stream to a downloadable PCM file? When the file downloads, the file is useless and can't be played. The file does have a size greater than 0, so that makes me believe there is data there.
<script>
AWS.config.region = 'us-east-1';
AWS.config.accessKeyId = 'CANDY';
AWS.config.secretAccessKey = 'CANES';
var polly = new AWS.Polly({apiVersion: '2016-06-10'});
var params = {
OutputFormat: 'pcm',
Text: 'Text from the textbox',
VoiceId: 'Joey',
SampleRate: '16000',
TextType: 'text'
};
polly.synthesizeSpeech(params, function(err, data) {
if (err){
console.log(err, err.stack); // an error occurred
} else {
var stream = new Int16Array(audioStream);
var arrayBuffer = stream.buffer;
var blob = new Blob([arrayBuffer], {type: 'audio/pcm'});
var url = URL.createObjectURL(blob);
.....set href for link to url.......
}
});
</script>
If you are sure the url object is correct (can you download it from a separate browser tab?), I would use JQuery to dynamically change your DOM, as per this answer How to change the href for a hyperlink using jQuery
Related
I have a suitelet that creates a html page. This page has a html element input type file. I am trying to take that file and upload it to the file cabinet. This is not done on a NetSuite form so the file element is not a netsuite file object.
The javascript on the HTML page is as follows
function uploadPhotoToNetSuite(){
var bookingid = $("#txtAddPhotoBookingId").val();
var caseid = $("#txtAddPhotoCaseId").val();
var isCase = caseid != "";
var base64Image = document.getElementById("imageToAdd").src;
var formData = new FormData();
formData.append("operations", 'uploadphoto');
formData.append("bookingid", bookingid);
formData.append("caseid", caseid);
formData.append("image", base64Image);
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (this.readyState == 4) {
var objResponse = JSON.parse(xhr.responseText);
if(!objResponse.uploadphoto.success){
alert(objResponse.uploadphoto.err);
} else {
closeLoading();
}
clearPhotoUpload();
}
};
xhr.open("POST", stAPIURL, true);
loading("Uploading Photo");
xhr.send(formData);
}
Then this matches to a method in my suitelet as follows.
function uploadPhoto(params, recUser){
try{
var imageFolder = 767406;
var thePhoto = params.image;
var filetype = "png";
if(thePhoto.indexOf("image/png") > -1) filetype = "png";
var theFile = file.create({
name: 'test.' + filetype,
fileType: filetype == "jpg" ? file.Type.JPGIMAGE : file.Type.PNGIMAGE,
contents: thePhoto,
description: 'This is a plain text file.',
encoding: file.Encoding.UTF8,
folder: imageFolder,
isOnline: true
});
var id = theFile.save();
} catch(err){
return {
success : false,
err : JSON.stringify(err)
}
}
return {
success : true
}
}
When this is happens I am getting the error UNEXPECTED_ERROR. The variable thePhoto is a base64 string of the image.
UPDATE:
I change the suitelet code to create a text file and the file uploaded perfectly and the base64 string was in the text file. When I took that base64 string and put it through a convertor, the image I uploaded was the result.
With this in mind, I changed the code again to;
var theFile = file.create({
name: 'test.jpg',
fileType: file.Type.JPGIMAGE,
contents: thePhoto,
description: 'This is a plain text file.',
encoding: file.Encoding.UTF8,
folder: imageFolder,
isOnline: true
});
And uploaded a .jpg file. Once again I got the error.
I was experiencing the same issue and finally figured out the resolution. NetSuite does convert Base64 image data to a JPEG file in the file cabinet automatically, but it can only be the raw base64 data. The base64 metadata at the beginning needs to be removed. After several hours of frustration, adding the first two lines to the function below allowed it to save properly as a JPEG file (without the unexpected error).
function saveJPEGFile(fileName, fileContents){
if (fileContents.startsWith('data:image/jpeg;base64'))
fileContents=fileContents.substring('data:image/jpeg;base64,'.length);
log.debug('saving file:',`${fileName} : ${fileContents.length} : ${fileContents}`)
var fileObj = file.create({
name : fileName,
fileType: file.Type.JPGIMAGE,
contents: fileContents,
folder : 1127
});
var fileId = fileObj.save();
}
I am generating a ZipFile with Python 3.7 on Ubuntu 18.04 and serving it with Flask 1.0.2. I know the Flask code works because I can type the endpoint in my browser explicitly and get a valid ZipFile that I can decompress on Windows 10. I am now trying to get my Javascript code to download the ZipFile with a Button Click. The problem is that the resulting file is declared "Corrupt" by Windows and cannot be decompressed. How can I make the Javascript download the file correctly?
The Flask code is shown here:
#app.route("/get_new_training_data", methods=["GET"])
def create_and_serve_training_data_zipfile():
# Define the location of the new training data
newDataLocation = "%s" % (configuration.NEW_TRAINING_DATA_LOCATION)
# Ensure it exists or throw and error
if os.path.isdir(newDataLocation):
print("[%s] Creating new ZipFile for download from: %s" % (os.path.basename(__file__), newDataLocation))
# Create a zipfile in memory and send it back to the user
# The zipfile will contain the training data collected through
# the webbrowser button controls
try:
memoryFile = BytesIO()
with zipfile.ZipFile(memoryFile, 'w', zipfile.ZIP_DEFLATED) as zf:
for root, dirs, files in os.walk(newDataLocation):
for file in files:
print("[%s] Adding file to ZipFile: %s" % (os.path.basename(__file__), file))
zf.write(os.path.join(root, file))
memoryFile.seek(0)
return send_file(memoryFile, mimetype='application/zip', attachment_filename='ImageData.zip', as_attachment=True)
except Exception as err:
newStatus = {"download_image_data": "Failed: Error Could not create Zipfile: %s"%(err)}
print("[%s] Error downloading new Training Data - JSON Response is: %s" % (
os.path.basename(__file__), newStatus))
return jsonify(newStatus), 500
else:
newStatus = {"download_image_data": "Failed: Error Training Data directory does not exist"}
print("[%s] Error downloading new Training Data - JSON Response is: %s" % (os.path.basename(__file__), newStatus))
return jsonify(newStatus), 500
The Javascript code is here:
// Add an on click for the download data button
var downloadTrainingDataButton = document.getElementById("downloadTrainingData");
downloadTrainingDataButton.onclick = function() {
console.log("Downloading New Training Data ...");
// Do a web request to download a zip file of the training data
var logRequestXmlHttp = new XMLHttpRequest();
logRequestXmlHttp.open( "GET", "http://{{host_ip}}/get_new_training_data", true ); // false for synchronous request
logRequestXmlHttp.onload = function(e) {
code = logRequestXmlHttp.response;
if (logRequestXmlHttp.status == 200) {
var blob = new Blob([this.response], {type: "application/zip"});
var url = window.URL.createObjectURL(blob);
var link = document.createElement('a');
document.body.appendChild(link);
link.style = "display: none";
link.href = url;
link.download = "ImageData.zip";
link.click();
setTimeout(() => {
window.URL.revokeObjectURL(url);
link.remove(); } , 100);
console.log("Success downloading zip file");
}
};
logRequestXmlHttp.onerror = function () {
console.log("Error with downloading zip file: " + logRequestXmlHttp.responseText + " Code: " + code);
};
logRequestXmlHttp.send( null );
}
To download files you can use the HTML5 download attribute on an anchor tag to let it know it needs to download a resource instead of navigating to it. This is probably the easiest way to achieve what you want.
For example:
Download Training Data
I have an Ionic application which downloads a file from a Web API. The content of the file can be found in the _body property of the HTTP response.
What I'm trying to do is convert this text into an arrayBuffer so I can save the content into a file.
However, the issue that I'm having is that any file (PDF files in my instance) that have images and/or large in size either don't show up at all or show up as correputed files.
At first I thought this was an issue relating Ionic. So to make sure I tried to simulate this issue and I was able to reproduce it.
Is this snippet you can select a PDF file, then download it. You would find that the downloaded file is corrupted and exactly how my Ionic app displays them.
HTML:
<input type="file" id="file_input" class="foo" />
<div id="output_field" class="foo"></div>
JS:
$(document).ready(function(){
$('#file_input').on('change', function(e){
readFile(this.files[0], function(e) {
//manipulate with result...
$('#output_field').text(e.target.result);
try {
var file = new Blob([e.target.result], { type: 'application/pdf;base64' });
var fileURL = window.URL.createObjectURL(file);
var seconds = new Date().getTime() / 1000;
var fileName = "cert" + parseInt(seconds) + ".pdf";
var a = document.createElement("a");
document.body.appendChild(a);
a.style = "display: none";
a.href = fileURL;
a.download = fileName;
a.click();
}
catch (err){
$('#output_field').text(err);
}
});
});
});
function readFile(file, callback){
var reader = new FileReader();
reader.onload = callback
//reader.readAsArrayBuffer(file);
reader.readAsText(file);
}
https://jsfiddle.net/68qeau3h/3/
Now, when using reader.readAsArrayBuffer(file); everything works as expected, however in my particular case, I used reader.readAsText(file); because this is how the data is retrieve for me, this is text form.
When adding these lines of code to try to convert the string into an arrayBuffer
...
var buf = new ArrayBuffer(e.target.result.length * 2); // 2 bytes for each char
var bufView = new Uint16Array(buf);
for (var i=0, strLen=e.target.result.length; i<strLen; i++) {
bufView[i] = e.target.result.charCodeAt(i);
}
var file = new Blob([buf], { type: 'application/pdf' });
...
This will not work and generate PDF files that the browser can't open.
So to recap, what I'm trying to do is somehow convert the result I get from reader.readAsText(file); to what reader.readAsArrayBuffer(file); produces. Because the files I'm working with, or the data im retrieving from my backend is this text form.
I need to retrieve and then display a pdf file. I have working code that retrieves an image from a database, converts to .pdf, and returns that as JSON. I can display this just fine in chrome by making it into a blob, but because IE refuses to support data URIs, I figure I could generate a temporary pdf file on the server and then link to it like this, as suggested elsewhere on the site:
<iframe style="width: 100%; height: 100%;" frameborder="0" scrolling="no" id="myFrame">
<p>It appears your web browser doesn't support iframes.</p>
</iframe>
And then set the src attribute in .js file:
$('#myFrame').attr('src', 'http://www.example.com/tempPDFname.pdf');
How would I generate this file and make it available on server (C#) so I can set the src attribute?
"GhostScript" may help you. Please check the linkes How to use Ghostscript for converting PDF to Image and https://ghostscriptnet.codeplex.com/
How to return a PDF from a Web API application
[HttpGet]
[Route("documents/{docid}")]
public HttpResponseMessage Display(string docid) {
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.BadRequest);
var documents = reader.GetDocument(docid);
if (documents != null && documents.Length == 1) {
var document = documents[0];
docid = document.docid;
byte[] buffer = new byte[0];
//generate pdf document
MemoryStream memoryStream = new MemoryStream();
MyPDFGenerator.New().PrintToStream(document, memoryStream);
//get buffer
buffer = memoryStream.ToArray();
//content length for use in header
var contentLength = buffer.Length;
//200
//successful
var statuscode = HttpStatusCode.OK;
response = Request.CreateResponse(statuscode);
response.Content = new StreamContent(new MemoryStream(buffer));
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = contentLength;
ContentDispositionHeaderValue contentDisposition = null;
if (ContentDispositionHeaderValue.TryParse("inline; filename=" + document.Name + ".pdf", out contentDisposition)) {
response.Content.Headers.ContentDisposition = contentDisposition;
}
} else {
var statuscode = HttpStatusCode.NotFound;
var message = String.Format("Unable to find resource. Resource \"{0}\" may not exist.", docid);
var responseData = responseDataFactory.CreateWithOnlyMetadata(statuscode, message);
response = Request.CreateResponse((HttpStatusCode)responseData.meta.code, responseData);
}
return response;
}
There's already a solution for writing file JSON online but I want to save json file locally.
I've tried to use this example http://jsfiddle.net/RZBbY/10/
It creates a link to download the file, using this call
a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show();
Is there a way to save the file locally instead of providing a downloadable link?
There are other types of conversion beyond data:application/x-json;base64?
Here's my code:
<!DOCTYPE html>
<head>
<meta charset="utf-8">
<title>jQuery UI Sortable - Default functionality</title>
<link rel="stylesheet" href="http://jqueryui.com/themes/base/jquery.ui.all.css">
<script src="http://jqueryui.com//jquery-1.7.2.js"></script>
<script src="http://jqueryui.com/ui/jquery.ui.core.js"></script>
<script src="http://jqueryui.com/ui/jquery.ui.widget.js"></script>
<script src="http://jqueryui.com/ui/jquery.ui.mouse.js"></script>
<script src="http://jqueryui.com/ui/jquery.ui.sortable.js"></script>
<script src="http://jqueryui.com/ui/jquery.ui.accordion.js"></script>
<link rel="stylesheet" href="http://jqueryui.com/demos/demos.css">
<meta charset="utf-8">
<style>a { font: 12px Arial; color: #ac9095; }</style>
<script type='text/javascript'>
$(document).ready(function() {
var f = $('form'), a = $('a'),
i = $('input'), t = $('textarea');
$('#salva').click(function() {
var o = {}, v = t.val();
a.hide();//nasconde il contenuto
i.each(function() {
o[this.name] = $(this).val(); });
if (v === '') {
t.val("[\n " + JSON.stringify(o) + " \n]")
}
else {
t.val(v.substr(0, v.length - 3));
t.val(t.val() + ",\n " + JSON.stringify(o) + " \n]")
}
});
});
$('#esporta').bind('click', function() {
a.attr('href', 'data:application/x-json;base64,' + btoa(t.val())).show();
});
</script>
</head>
<body>
<form>
<label>Nome</label> <input type="text" name="nome"><br />
<label>Cognome</label> <input type="text" name="cognome">
<button type="button" id="salva">Salva</button>
</form>
<textarea rows="10" cols="60"></textarea><br />
<button type="button" id="esporta">Esporta dati</button>
Scarica Dati
</body>
</html>
Based on http://html5-demos.appspot.com/static/a.download.html:
var fileContent = "My epic novel that I don't want to lose.";
var bb = new Blob([fileContent ], { type: 'text/plain' });
var a = document.createElement('a');
a.download = 'download.txt';
a.href = window.URL.createObjectURL(bb);
a.click();
Modified the original fiddle: http://jsfiddle.net/9av2mfjx/
You should check the download attribute and the window.URL method because the download attribute doesn't seem to like data URI.
This example by Google is pretty much what you are trying to do.
It is not possible to save file locally without involving the local client (browser machine) as I could be a great threat to client machine. You can use link to download that file. If you want to store something like Json data on local machine you can use LocalStorage provided by the browsers, Web Storage
The possible ways to create and save files in Javascript are:
Use a library called FileSaver
saveAs(new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"}));
Create a blob object and offer a “save as”.
var a = document.createElement("a");
a.href = window.URL.createObjectURL(new Blob(["CONTENT"], {type: "text/plain"}));
a.download = "demo.txt";
a.click();
Upload the data, save it on the server.
var data = new FormData();
data.append("upfile", new Blob(["CONTENT"], {type: "text/plain"}));
fetch("SERVER.SCRIPT", { method: "POST", body: data });
Create a writable file stream.
const fileHandle = await window.showSaveFilePicker();
const fileStream = await fileHandle.createWritable();
await fileStream.write(new Blob(["CONTENT"], {type: "text/plain"}));
await fileStream.close();
In NodeJS, simply use the file system module
require("fs").writeFile("demo.txt", "Foo bar!");
<!-- (A) LOAD FILE SAVER -->
<!-- https://cdnjs.com/libraries/FileSaver.js -->
<!-- https://github.com/eligrey/FileSaver.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/2.0.5/FileSaver.min.js"></script>
<script>
// (B) "SAVE AS"
var myFile = new File(["CONTENT"], "demo.txt", {type: "text/plain;charset=utf-8"});
saveAs(myFile);
</script>
// (A) CREATE BLOB OBJECT
var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
// (B) CREATE DOWNLOAD LINK
var url = window.URL.createObjectURL(myBlob);
var anchor = document.createElement("a");
anchor.href = url;
anchor.download = "demo.txt";
// (C) "FORCE DOWNLOAD"
// NOTE: MAY NOT ALWAYS WORK DUE TO BROWSER SECURITY
// BETTER TO LET USERS CLICK ON THEIR OWN
anchor.click();
window.URL.revokeObjectURL(url);
document.removeChild(anchor);
<script>
function blobajax () {
// (A) CREATE BLOB OBJECT
var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
// (B) FORM DATA
var data = new FormData();
data.append("upfile", myBlob);
// (C) AJAX UPLOAD TO SERVER
fetch("3b-upload.php", {
method: "POST",
body: data
})
.then((res) => { return res.text(); })
.then((txt) => { console.log(txt); });
}
</script>
<input type="button" value="Go" onclick="blobajax()"/>
<script>
async function saveFile() {
// (A) CREATE BLOB OBJECT
var myBlob = new Blob(["CONTENT"], {type: "text/plain"});
// (B) FILE HANDLER & FILE STREAM
const fileHandle = await window.showSaveFilePicker({
types: [{
description: "Text file",
accept: {"text/plain": [".txt"]}
}]
});
const fileStream = await fileHandle.createWritable();
// (C) WRITE FILE
await fileStream.write(myBlob);
await fileStream.close();
}
</script>
<input type="button" value="Save File" onclick="saveFile()"/>
// (A) LOAD FILE SYSTEM MODULE
// https://nodejs.org/api/fs.html
const fs = require("fs");
// (B) WRITE TO FILE
fs.writeFile("demo.txt", "CONTENT", "utf8", (error, data) => {
console.log("Write complete");
console.log(error);
console.log(data);
});
/* (C) READ FROM FILE
fs.readFile("demo.txt", "utf8", (error, data) => {
console.log("Read complete");
console.log(error);
console.log(data);
});
*/
It all depends on what you are trying to achieve with "saving locally". Do you want to allow the user to download the file? then <a download> is the way to go. Do you want to save it locally, so you can restore your application state? Then you might want to look into the various options of WebStorage. Specifically localStorage or IndexedDB. The FilesystemAPI allows you to create local virtual file systems you can store arbitrary data in.
While most despise Flash, it is a viable option for providing "save" and "save as" functionality in your html/javascript environment.
I've created a widget called "OpenSave" that provides this functionality available here:
http://www.gieson.com/Library/projects/utilities/opensave/
-mike
So, your real question is: "How can JavaScript save to a local file?"
Take a look at http://www.tiddlywiki.com/
They save their HTML page locally after you have "changed" it internally.
[ UPDATE 2016.01.31 ]
TiddlyWiki original version saved directly. It was quite nice, and saved to a configurable backup directory with the timestamp as part of the backup filename.
TiddlyWiki current version just downloads it as any file download. You need to do your own backup management. :(
[ END OF UPDATE
The trick is, you have to open the page as file:// not as http:// to be able to save locally.
The security on your browser will not let you save to _someone_else's_ local system, only to your own, and even then it isn't trivial.
-Jesse
If you are using FireFox you can use the File HandleAPI
https://developer.mozilla.org/en-US/docs/Web/API/File_Handle_API
I had just tested it out and it works!