Sending resized images through AJAX/AngularJS - javascript

Basically I am trying resize image, then send and save on server. I am using this directive Mischi/angularjs-imageupload-directive mainly for resizing images. However i have no idea how to send this "resized" one. The only return i've got is dataURL for resized image, and i found solution to make blob out of it instead of file. However my server respond with "500 Internal Server Error" and i think its because of Content-Type: application/ocet-stream. I need to send Content-Type: image/*
Heres my script
angular.module('imageuploadDemo', ['imageupload'])
.controller('DemoCtrl', function($scope, $http) {
// Not important stuff, only to clear/fill preview and disable/enable buttons
$scope.clearArr = function() {
$scope.images4 = null;
}
$scope.testowy = function(test) {
console.log(test);
}
// --- Creating BLOB --- //
function dataURLtoBlob(dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while(n--){
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr]);
}
$scope.test;
// --- Here magic goes on --- //
$scope.single = function(image) {
var formData = new FormData();
angular.forEach(image, function(file) {
var blob = dataURLtoBlob(file.resized.dataURL);
formData.append('files[]', blob);
//formData.append('files[]', file.file); <-- This works, but sending non-resized image (raw one)
})
formData.append('id', $scope.test);
console.log('test');
$http.post('myserver/addimg', formData, {
headers: { 'Content-Type': undefined }, //I am not even sure if its working...
transformRequest: angular.identity
}).success(function(result) {
$scope.uploadedImgSrc = result.src;
$scope.sizeInBytes = result.size;
});
};
});
And here is my server site
public function add(Request $request)
{
$id=$request->id;
$files = Input::file('files');
foreach($files as $file) {
$destinationPath = 'galeria';
$filename = $file->getClientOriginalName();
$file->move($destinationPath, $filename);
copy('galeria/'.$filename,'galeria/thumbs/'.$filename);
image::make('galeria/thumbs/'.$filename);
image::make('galeria/thumbs/'.$filename,array(
'width' => 300,
'height' => 300,
))->save('galeria/thumbs/'.$filename);
Images::create(['src'=>$filename,'id_category'=>$id]);
return redirect()->back();
}
return Images::all();
}

Issue in FormData.append()
Parameter: The append() method of the FormData interface appends a new value onto an existing key inside a FormData object, or adds the key if it does not already exist.
It has 3 parameters: FormData.append(name, value, filename)
var formData = new FormData();
// Key pair value
formData.append('username', 'Chris');
formData.append('userpic', myFileInput.files[0], 'chris.jpg');
// Array Notation:
formData.append('userpic[]', myFileInput1.files[0], 'chris1.jpg');
formData.append('userpic[]', myFileInput2.files[0], 'chris2.jpg');
Reference URLs:
https://developer.mozilla.org/en-US/docs/Web/API/FormData/append

Heh, i found an answer on my own. The issue was not sending image name... so everything you have to do is sending blob with name
formData.append('files[]', blob, file.file.name);

Related

JavaScript Blob to FormData with SAPUI5 mobile app

I know there are several threads about this topic, but I was not able to identify the problem in my case.
I have an application, where I upload an image to an endpoint-URL and after processing I'll receive a response. Works fine so far. The file is contained within a formdata object when using FileUploader-Control from SAPUI5.
When switching from file upload to "taking a picture with smartphone-camera", I dont have a file, I have an base64 dataurl (XString) image object.
var oImage = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAABQAA…8ryQAbwUjsV5VUaAX/y+YSPJii2Z9GAAAAABJRU5ErkJggg=="} // some lines are missing > 1 million lines
I thought converting it to blob and appending it to FormData might be the solution, but it does not work at all.
var blob = this.toBlob(oImage)
console.log("Blob", blob); // --> Blob(857809) {size: 857809, type: "image/png"} size: 857809 type: "image/png" __proto__: Blob
var formData = new window.FormData();
formData.append("files", blob, "test.png");
console.log("FormData", formData); // seems empty --> FormData {}__proto__: FormData
Functions (works fine from my perspective)
toBlob: function dataURItoBlob(dataURI) {
var byteString = atob(dataURI.split(',')[1]);
var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]
var ab = new ArrayBuffer(byteString.length);
var ia = new Uint8Array(ab);
for (var i = 0; i < byteString.length; i++) {
ia[i] = byteString.charCodeAt(i);
}
var bb = new Blob([ab], {
"type": mimeString
});
return bb;
},
This is my problem, FormData is empty and my POST-request throws an undefined error (Loading of data failed: TypeError: Cannot read property 'status' of undefined at constructor.eval (...m/resources/sap/ui/core/library-preload.js?eval:2183:566))
//Create JSON Model with URL
var oModel = new sap.ui.model.json.JSONModel();
var sHeaders = {
"content-type": "multipart/form-data; boundary=---011000010111000001101001",
"APIKey": "<<myKey>>"
};
var oData = {
formData
};
oModel.loadData("/my-destination/service", oData, true, "POST", null, false, sHeaders);
oModel.attachRequestCompleted(function (oEvent) {
var oData = oEvent.getSource().oData;
console.log("Final Response XHR: ", oData);
});
Thanks for any hint
The upload collection is a complex standard control that can be used for attachment management. On desktop it opens a file dialog, on mobile it opens the ios or android photo options, which means picking a photo from the camera roll, or taking a new photo.
Fairly basic example, including the upload URL's and other handlers you'll need. More options are available, adjust to suit your needs. In your XML:
<UploadCollection
uploadUrl="{path:'Key',formatter:'.headerUrl'}/Attachments"
items="{Attachments}"
change="onAttachUploadChange"
fileDeleted="onAttachDelete"
uploadEnabled="true"
uploadComplete="onAttachUploadComplete">
<UploadCollectionItem
documentId="{DocID}"
contributor="{CreatedBy}"
fileName="{ComponentName}"
fileSize="{path:'ComponentSize',formatter:'.formatter.parseFloat'}"
mimeType="{MIMEType}"
thumbnailUrl="{parts:[{path:'MIMEType'},{path:'DocID'}],formatter:'.thumbnailURL'}"
uploadedDate="{path:'CreatedAt', formatter:'.formatter.Date'}" url="{path:'DocID',formatter:'.attachmentURL'}" visibleEdit="false"
visibleDelete="true" />
</UploadCollection>
Here's the handlers. Especially the onAttachUploadChange is important. I should mention there's no explicit post. If the uploadUrl is set correctly a post is triggered anyway.
onAttachUploadChange: function(oEvent) {
var csrf = this.getModel().getSecurityToken();
var oUploader = oEvent.getSource();
var fileName = oEvent.getParameter('files')[0].name;
oUploader.removeAllHeaderParameters();
oUploader.insertHeaderParameter(new UploadCollectionParameter({
name: 'x-csrf-token',
value: csrf
}));
oUploader.insertHeaderParameter(new UploadCollectionParameter({
name: 'Slug',
value: fileName
}));
},
onAttachDelete: function(oEvent) {
var id = oEvent.getParameter('documentId');
var oModel = this.getModel();
//set busy indicator maybe?
oModel.remove(`/Attachments('${encodeURIComponent(id)}')`, {
success: (odata, response) => {
//successful removal
//oModel.refresh();
},
error: err => console.log(err)
});
},
onAttachUploadComplete: function(oEvent) {
var mParams = oEvent.getParameter('mParameters');
//handle errors an success in here. Check `mParams`.
}
as for the formatters to determine URLs, that depends on your setup. In the case below, the stream is set up on the current binding contect, in which case this is one way to do it. You'll need the whole uri so including the /sap/opu/... etc bits.
headerUrl: function() {
return this.getModel().sServiceUrl + this.getView().getBindingContext().getPath()
},
URL for attachments is similar, but generally points to an entity of the attachment service itself.
attachmentURL: function(docid) {
return this.getModel().sServiceUrl + "/Attachments('" + docid + "')/$value";
},
You could fancy it up to check if it's an image, in which case you could include the mime type to show a thumbnail.
There might be better ways of doing this, but I've found this fairly flexible...

MemoryStream to HttpResponseMessage

I have generated a Pdf on the server, and need to return it as a response to my web client, so that I get a 'Save As' dialog.
The pdf is generated, and saved to a Memory stream... which is then returned to my method which will return the HttpResponseMessage.
The is the method:
[Route("GeneratePdf"), HttpPost]
public HttpResponseMessage GeneratePdf(PlateTemplateExtendedDto data)
{
var doc = GeneratePdf(DataForThePdf);
//using (var file = File.OpenWrite("c:\\temp\\test.pdf"))
// doc.CopyTo(file); // no need for manual stream copy and buffers
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
byte[] buffer = new byte[0];
//get buffer
buffer = doc.GetBuffer();
//content length for use in header
var contentLength = buffer.Length;
response.Headers.AcceptRanges.Add("bytes");
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(doc);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("render");
response.Content.Headers.ContentDisposition.FileName = "yes.pdf";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = doc.Length;
return response;
}
However, the document renders as a blank file, and although it has a file size, and properties of the document I created (pdf information if File Properties is all right, as well as page width and height), the document displays as blank.
If I un-comment the code that is commented out, to save locally, the file is perfect. File size is 228,889 bytes. However, when I let it go to my web page and save it, it's 405,153 bytes and the filename is 'undefined'.
If I breakpoint, I see these results:
On the front end script, I handle the downloaded object like this:
$.post("/api/PlateTemplate/GeneratePdf", data).done(function (data, status, headers) {
// headers = headers();
var filename = headers['x-filename'];
var contentType = headers['content-type'];
//Create a url to the blob
var blob = new Blob([data], { type: contentType });
var url = window.URL.createObjectURL(blob);
var linkElement = document.createElement('a');
linkElement.setAttribute('href', url);
linkElement.setAttribute("download", filename);
//Force a download
var clickEvent = new MouseEvent("click", {
"view": window,
"bubbles": true,
"cancelable": false
});
linkElement.dispatchEvent(clickEvent);
});
I'm unsure where the file is being corrupted. What am I doing wrong?
Edit: Using the following code as suggested:
$.post("/api/PlateTemplate/GeneratePdf", data).done(function (data, status, headers) {
alert(data.length);
var xhr = new XMLHttpRequest();
$("#pdfviewer").attr("src", URL.createObjectURL(new Blob([data], {
type: "application/pdf"
})))
.Net code:
var doc = GeneratePdf(pdfParams);
HttpResponseMessage response = Request.CreateResponse(HttpStatusCode.OK);
byte[] buffer = new byte[0];
//get buffer
buffer = doc.ToArray();
//content length for use in header
var contentLength = buffer.Length;
response.Headers.AcceptRanges.Add("bytes");
response.StatusCode = HttpStatusCode.OK;
response.Content = new StreamContent(doc);
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("render");
response.Content.Headers.ContentDisposition.FileName = "yes.pdf";
response.Content.Headers.ContentType = new MediaTypeHeaderValue("application/pdf");
response.Content.Headers.ContentLength = doc.Length;
return response;
It seems I am losing data.
The alert is the length of the 'data.length' in my javascript, after I get data back from the call.
The file properties is the original pdf file info.
File sends from api, size is 227,564, which matches the byte size on disk if I save it. So it SEEMS the sending is OK. But on the javascript size, when I read in the file, it's 424946, when I do: var file = new Blob([data], { type: 'application/pdf' }); (Where data is the response from the server).
The ContentLength setting looks somewhat suspicious (not consequent):
//content length for use in header
var contentLength = buffer.Length;
response.Content.Headers.ContentLength = doc.Length;
I 'fixed' this by using base64 encoded string from the .Net controller to the javascript web api call result, and then allowed the browser to convert it into binary by specifying the type ('application/pdf').

Reduce size of image when converted to Base64

I am using the File reader in JavaScript,i need to Post my image to WebApi and convert it into byte Array and save it in server,Its working fine,Now my problem is base64 string increasing the size of image, Let say if i upload image of 30Kb, it is storing has 389Kb in server,How i can save in same size or reduce size of image need help
//File Reader
function OnFileEditImageEntry(file) {
var reader = new FileReader();
reader.onloadend = function (evt) {
var ImageBase64 = evt.target.result;
return ImageBase64 ;
};
reader.readAsDataURL(file);
}
//WEB API//
public IHttpActionResult UpdateUserDetails(ImageModel model)
{
try
{
if (model.ImageBase64 != "")
{
var PicDataUrl = "";
string ftpurl = "ftp://xxx.xxxxx.xxxx/";
var username = "xxx";
var password = "xxxxx";
string UploadDirectory = "xxxx/xx";
string FileName =model.ImageFileName;
String uploadUrl = String.Format("{0}{1}/{2}", ftpurl, UploadDirectory,FileName);
FtpWebRequest req = (FtpWebRequest)FtpWebRequest.Create(uploadUrl);
req.Proxy = null;
req.Method = WebRequestMethods.Ftp.UploadFile;
req.Credentials = new NetworkCredential(username, password);
req.EnableSsl = false;
req.UseBinary = true;
req.UsePassive = true;
byte[] data =Convert.FromBase64String(model.ImageBase64);
req.ContentLength = data.Length;
Stream stream = req.GetRequestStream();
stream.Write(data, 0, data.Length);
stream.Close();
}
}
}
Send the raw binary instead of increasing the size ~30% with base64/FileReader
with fetch
// sends the raw binary
fetch('http://example.com/upload', {method: 'post', body: file})
// Append the blob/file to a FormData and send it
var fd = new FormData()
fd.append('file', file, file.name)
fetch('http://example.com/upload', {method: 'post', body: fd})
With XHR
// xhr = new ...
// xhr.open(...)
xhr.send(file) // or
xhr.send(fd) // send the FormData
Normally when uploading files, try to avoid sending a json as many developers tends to to wrong. Binary data in json is equal to bad practice (and larger size) eg:
$.post(url, {
name: '',
data: base64
})
Use the FormData#append as much as possible or if you feel like it:
fd.append('json', json)

Convert Byte array to Base64 string in Angularjs

I am getting byte array in service response and that image would be shown in an image field of my html page. Any idea how can i implement this. I tried to find out solution for this over stack overflow but not able to get valid solution. Please help. My code is:
this.getPrescription = function(pres_id) {
var deff = $q.defer();
$http({
method: "GET",
url: "www.abc.com/api/&prescriptionOnly=false&page=1",
headers: {
'Authorization': 'Bearer ' + localStorage.getItem("chemist_access_token"),
'Content-Type': 'application/json'
},
responseType: 'arraybuffer'
}).then(function(objS) {
console.log("getPrescription:\n" + JSON.stringify(objS))
deff.resolve(objS);
}, function(objE) {
errorHandler.serverErrorhandler(objE);
deff.reject(objE);
});
return deff.promise;
};
and in my controller I am calling like:
$scope.getPrescription = function(id) {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop: false
});
serverRepo.prescriptionGet(id).then(function(objS) {
console.log("orderByCustomer:\n" + JSON.stringify(objS));
$scope.picdata=$window.URL.createObjectURL(new Blob([objS.data], {type: 'image/png'}));
$ionicLoading.hide();
console.log("getOrderByNew_success_loadMore:\n" +$scope.picdata);
}, function(objE) {
$ionicLoading.hide();
});
}
and when I check my console it showing:
getOrderByNew_success_loadMore:
blob:file:///0aa86d9f-61a1-4049-b18c-7bf81e05909f
Use this filter to convert byte array to base64
app.filter('bytetobase', function () {
return function (buffer) {
var binary = '';
var bytes = new Uint8Array(buffer);
var len = bytes.byteLength;
for (var i = 0; i < len; i++) {
binary += String.fromCharCode(bytes[i]);
}
return window.btoa(binary);
};
});
to bind it as image use
<img ng-src="data:image/JPEG;base64,{{picture | bytetobase}}" alt="..." width="100" height="100">
Or if you need to assign it a variable use
var image = $filter('bytetobase')($scope.picture );
If you need to display and image from byte array you can create an object using Blob and get it's URL to pass into the image tag source. The last parameter in Blob constructor contains information about blob type, so you should set correct type during blob creation.
$http.get(url, {responseType: 'arraybuffer'})
.then(function(response) {
return $window.URL.createObjectURL(new Blob([response.data], {type: 'image/png'}));
});
And when you don't plan to work with your object any longer (e.g. after image has been loaded in appropriate img tag)
Update
Alternative solution with base64
$scope.getPrescription = function(id) {
$ionicLoading.show({
template: '<ion-spinner icon="spiral"></ion-spinner>',
noBackdrop: false
});
serverRepo.prescriptionGet(id).then(function(objS) {
console.log("orderByCustomer:\n" + JSON.stringify(objS));
// Creating file reader
var reader = new window.FileReader();
// Creating blob from server's data
var data = new Blob([objS.data], {type: 'image/jpeg'});
// Starting reading data
reader.readAsDataURL(data);
// When all data was read
reader.onloadend = function() {
// Setting source of the image
$scope.picdata = reader.result;
// Forcing digest loop
$scope.$apply();
}
$ionicLoading.hide();
console.log("getOrderByNew_success_loadMore:\n" +$scope.picdata);
}, function(objE) {
$ionicLoading.hide();
});
}

Is there a way to convert a file to byte in angular js?

I am trying to upload a file (bytes) to server. is there a way to convert this from ui side, i am using angular js?
Api i am using is done with ASP.new and the my sql table has fields:
FileName (string) and File (Collection of Byte).
Here is what i have tried so far
$scope.upload = function(){
var file = $scope.myFile;
var fileName=file.name;
Upload.uploadFile((file), uploadUrl,fileName);
};
App.service('fileUpload', ['$http', function ($http) {
this.uploadFile = function(File, uploadUrl,fileName){
var fd = new FormData();
console.log(File); //returns {}
fd.append('File', new Uint8Array(File));
var data ={
FileName : fileName,
};
fd.append("FileName", JSON.stringify(data.FileName));
$http.post(uploadUrl, fd, {
transformRequest: angular.identity,
headers: {'Content-Type': 'application/json'}
})
}
}]);
Not sure if this will suit your needs, but I'm assuming you just need a file uploaded using Angular. I ran into problems doing this myself until I found a little directive called ng-file-upload. Pretty simple to use and include and even provides fallbacks for older browsers.
Hope that helps :)
I agree, ng-file-upload is great. I'm also similarly posting my file to a database with base64 string as my "file_content" of my json object. With the resulting FileList* object from ng-file-upload (or a normal <input type="file"/>), I use the FileReader* object to read the file as a DataUrl (FileReader has a few other readAs methods too).
Note: I also use LoDash* (_.last and _.split).
uploadFile() {
var reader = new FileReader();
reader.onload = (event) => {
var data = {
file_id: 1,
//strip off the first part ("data:[mime/type];base64,") and just save base64 string
file_content: _.last(_.split(event.target.result, ','));,
file_name: this.file.name,
mime_type: this.file.type
}
/*... POST ...*/
};
//this.file is my model for ng-file-upload
reader.readAsDataURL(this.file);
}
http://jsfiddle.net/eliseosoto/JHQnk/
Then to download the file later, I use FileSaver.js* saveAs:
downloadFile(fileFromDB) {
var convertDataURIToBinary = () => {
var raw = window.atob(fileFromDB.file_content);
var rawLength = raw.length;
var array = new Uint8Array(new ArrayBuffer(rawLength));
for (var i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}
var bin_array = convertDataURIToBinary();
saveAs(new Blob([bin_array], { type: fileFromDB.mime_type }), fileFromDB.file_name);
}
*sorry, my reputation isn't high enough to post links to all these, but you could google them and it should be the first result

Categories

Resources