How to send Blob image to NodeJs using Angular2? - node.js

I am having problems trying to upload a photo from my frontend.
I have an input file where I can select a file from my computer.
What I want It is send that photo to my backend and store it as a Blob.
First I try to get the file and save as Blob:
foto: Blob;
setFoto(event){
this.foto = event.target.files[0];
}
But I don't know if this It is correct.
Second I send "this.foto" to the server using HTTP post and save in my db as blob. I think that my problem is that i am not sending the correct information about the photo.
In resume, what I want is send an image that I select from my computer to the server but I am having problems getting the correct information of the photo.
Solution founded
First, here is my input:
<input type="file" (change)="setFoto($event)">
Second, here is the method that you call when you select a photo.
setFoto(event) {
const foto = new Blob([event.target.files[0]]);
var reader = new FileReader();
reader.readAsDataURL(foto);
reader.onloadend = () => {
this.foto = reader.result;
}
}
this.foto is a string.
Then when i click on update button i send the new photo as url and save it in my db (Mysql) as TEXT.
updateApuesta() {
this.userService.updateBet(this.url, {
id: this.userService.getIdbet(),
coste: this.coste,
beneficio: this.beneficio,
foto: this.foto
}).subscribe(this.success.bind(this), this.error);
}
When I try to get the photo from my server I use this. I call my http get service and get the photo.
First, the new image is a
image: SafeResourceUrl;
and I assign the dat that I got from my server.
this.image = this.sanitizer.bypassSecurityTrustResourceUrl(data.foto);
You have to import:
import { DomSanitizer, SafeResourceUrl } from '#angular/platform-browser';
and pass it to your constructor:
constructor(private sanitizer:DomSanitizer ) { }
So finally, you got your image in this.image that is a SafeResourceUrl type. To load it in a you have to do this:
<img [src]="bet.foto"/>
where in your case bet.foto will be yout this.image that you have to pass to the template.

this.userService.updateBet(
this.url,{foto:this.foto}).subscr‌​ibe(this.success.bin‌​d(this), this.error);
and the service is:
updateBet(url, body) {
return this.httpRequest.put(url, body, this.options);
}
put(url, body, options) {
return this.http.put(url, body, this.setOptions(options))
.map(this.extractData)
.catch((error: any) => Observable.throw(error.json().error || 'Server error')); //Show errors if any
}
But what i said, i think i am not sending the correct info about the photo.

Related

My response is not an url, How can I display an image which is not url using base64 and response does not contain bodyBytes?

My api is get() and the response contains data like this
The above image which you can see is my image which I want to display it on web using reactjs. ANd I dont know how can this be done.
The get api returns data, config, headers, request, status,statusText
I want the data above which I some weird format, my image to be displayed. I dont know how to do it. Need help
Update:
action
export const getFileImage = (payload) => async dispatch => {
try {
console.log("Payload--->",payload);
let response = await axios.get('/api/movies/' + payload.movieId + '/document/' + payload.genre.toLowerCase().toString());
console.log("Response----->",response);
} catch (error) {
console.log("error");
}
}
Output of response:
OK, you asked for an example and I wrote this answer...
You can use base64 format to show Images in your React component:
render(){
{this.state.image ? <img src={`data:image/png;base64,${this.state.image}`}/>: ''}
}
I think it would be better to ask backend developer or API provider to convert output for web and your requirements in React JS.

How to display image files stored in mongoDB when an action is performed

I m building a form which accepts file as input (attchment) and display current attachments of a specific user.
As part of this, i am getting attachment data once my component is loaded.
base64,255,216,255,224,0,16,74,70,73,70,0,1,1,1,0,96,0,96,0,0,255,219,0,67,0,5,4,4,4,4,3,5,4,4,4,6,5,5,6,8,13,8,8,7,7,8,16,11,12,9,13,19,16,20,19,18,16,18,18,20,23,29,25,20,22,28,22,18,18,26,35,26,28,30,31,33,33,33,20,25,36,39,36,32,38,29,32,33,32,255,219,0
Data is getting displayed in the form above.
However same data is displyed as below format in my database.
attachments
:
Binary('/9j/4AAQSkZJRgABAQEAYABgAAD/2wBDAAUEBAQEAwUEBAQGBQUGCA0ICAcHCBALDAkNExAUExIQEhIUFx0ZFBYcFhISGiMaHB4f...', 0)
I am able to display data in base64 format in client console.
How can i convert in to link, when clicked the image is viewed?
Route:
app.get(
apiConfig.config.apiVersion + "/get/attachments",
bugController.getAttachmentsById
);
Controller:
let getAttachmentsById = async (req, res) => {
let tracker = await bugModel.findById(req.query.id);
await tracker.populate("attachments").execPopulate();
res.set("Content-type", "image/jpg");
let apiResponse = response.generate(false, null, 200, tracker.attachments);
res.send(apiResponse);
};
Client component:
public getAttachments() {
this.Http.getAttachments().subscribe((response) => {
this.bufferAttach =
'data:image/jpg;base64,' + response['data'][0]['attachments']['data'];
this.base64attach = this.bufferAttach.toString('base64');
console.log('ttchedDAta');
console.log(this.base64attach);
});
}
I found out that we cannot directly store images in DB, instead i have stored images in my DB using Multer and store the link in my DB. That would be more appropriate.

How can one upload an image to a KeystoneJS GraphQL endpoint?

I'm using TinyMCE in a custom field for the KeystoneJS AdminUI, which is a React app. I'd like to upload images from the React front to the KeystoneJS GraphQL back. I can upload the images using a REST endpoint I added to the Keystone server -- passing TinyMCE an images_upload_handler callback -- but I'd like to take advantage of Keystone's already-built GraphQL endpoint for an Image list/type I've created.
I first tried to use the approach detailed in this article, using axios to upload the image
const getGQL = (theFile) => {
const query = gql`
mutation upload($file: Upload!) {
createImage(file: $file) {
id
file {
path
filename
}
}
}
`;
// The operation contains the mutation itself as "query"
// and the variables that are associated with the arguments
// The file variable is null because we can only pass text
// in operation variables
const operation = {
query,
variables: {
file: null
}
};
// This map is used to associate the file saved in the body
// of the request under "0" with the operation variable "variables.file"
const map = {
'0': ['variables.file']
};
// This is the body of the request
// the FormData constructor builds a multipart/form-data request body
// Here we add the operation, map, and file to upload
const body = new FormData();
body.append('operations', JSON.stringify(operation));
body.append('map', JSON.stringify(map));
body.append('0', theFile);
// Create the options of our POST request
const opts = {
method: 'post',
url: 'http://localhost:4545/admin/api',
body
};
// #ts-ignore
return axios(opts);
};
but I'm not sure what to pass as theFile -- TinyMCE's images_upload_handler, from which I need to call the image upload, accepts a blobInfo object which contains functions to give me
The file name doesn't work, neither does the blob -- both give me server errors 500 -- the error message isn't more specific.
I would prefer to use a GraphQL client to upload the image -- another SO article suggests using apollo-upload-client. However, I'm operating within the KeystoneJS environment, and Apollo-upload-client says
Apollo Client can only have 1 “terminating” Apollo Link that sends the
GraphQL requests; if one such as apollo-link-http is already setup,
remove it.
I believe Keystone has already set up Apollo-link-http (it comes up multiple times on search), so I don't think I can use Apollo-upload-client.
The UploadLink is just a drop-in replacement for HttpLink. There's no reason you shouldn't be able to use it. There's a demo KeystoneJS app here that shows the Apollo Client configuration, including using createUploadLink.
Actual usage of the mutation with the Upload scalar is shown here.
Looking at the source code, you should be able to use a custom image handler and call blob on the provided blobInfo object. Something like this:
tinymce.init({
images_upload_handler: async function (blobInfo, success, failure) {
const image = blobInfo.blob()
try {
await apolloClient.mutate(
gql` mutation($image: Upload!) { ... } `,
{
variables: { image }
}
)
success()
} catch (e) {
failure(e)
}
}
})
I used to have the same problem and solved it with Apollo upload link. Now when the app got into the production phase I realized that Apollo client took 1/3rd of the gzipped built files and I created minimal graphql client just for keystone use with automatic image upload. The package is available in npm: https://www.npmjs.com/package/#sylchi/keystone-graphql-client
Usage example that will upload github logo to user profile if there is an user with avatar field set as file:
import { mutate } from '#sylchi/keystone-graphql-client'
const getFile = () => fetch('https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png',
{
mode: "cors",
cache: "no-cache"
})
.then(response => response.blob())
.then(blob => {
return new File([blob], "file.png", { type: "image/png" })
});
getFile().then(file => {
const options = {
mutation: `
mutation($id: ID!, $data: UserUpdateInput!){
updateUser(id: $id, data: $data){
id
}
}
`,
variables: {
id: "5f5a7f712a64d9db72b30602", //replace with user id
data: {
avatar: file
}
}
}
mutate(options).then(result => console.log(result));
});
The whole package is just 50loc with 1 dependency :)
The easies way for me was to use graphql-request. The advantage is that you don't need to set manually any header prop and it uses the variables you need from the images_upload_handler as de docs describe.
I did it this way:
const { request, gql} = require('graphql-request')
const query = gql`
mutation IMAGE ($file: Upload!) {
createImage (data:
file: $file,
}) {
id
file {
publicUrl
}
}
}
`
images_upload_handler = (blobInfo, success) => {
// ^ ^ varibles you get from tinymce
const variables = {
file: blobInfo.blob()
}
request(GRAPHQL_API_URL, query, variables)
.then( data => {
console.log(data)
success(data.createImage.fileRemote.publicUrl)
})
}
For Keystone 5 editorConfig would stripe out functions, so I clone the field and set the function in the views/Field.js file.
Good luck ( ^_^)/*

Internal server error om Azure when writing file from buffer to filesystem

Context
I am working on a Proof of Concept for an accounting bot. Part of the solution is the processing of receipts. User makes picture of receipt, bot asks some questions about it and stores it in the accounting solution.
Approach
I am using the BotFramework nodejs example 15.handling attachments that loads the attachment into an arraybuffer and stores it on the local filesystem. Ready to be picked up and send to the accounting software's api.
async function handleReceipts(attachments) {
const attachment = attachments[0];
const url = attachment.contentUrl;
const localFileName = path.join(__dirname, attachment.name);
try {
const response = await axios.get(url, { responseType: 'arraybuffer' });
if (response.headers['content-type'] === 'application/json') {
response.data = JSON.parse(response.data, (key, value) => {
return value && value.type === 'Buffer' ? Buffer.from(value.data) : value;
});
}
fs.writeFile(localFileName, response.data, (fsError) => {
if (fsError) {
throw fsError;
}
});
} catch (error) {
console.error(error);
return undefined;
}
return (`success`);
}
Running locally it all works like a charm (also thanks to mdrichardson - MSFT). Stored on Azure, I get
There was an error sending this message to your bot: HTTP status code InternalServerError
I narrowed the problem down to the second part of the code. The part that write to the local filesystem (fs.writefile). Small files and big files result in the same error on Azure.fs.writefile seams unable to find the file
What is happpening according to stream logs:
Attachment uploaded by user is saved on Azure
{ contentType: 'image/png',contentUrl:
'https://webchat.botframework.com/attachments//0000004/0/25753007.png?t=< a very long string>',name: 'fromClient::25753007.png' }
localFilename (the destination of the attachment) resolves into
localFileName: D:\home\site\wwwroot\dialogs\fromClient::25753007.png
Axios loads the attachment into an arraybuffer. Its response:
response.headers.content-type: image/png
This is interesting because locally it is 'application/octet-stream'
fs throws an error:
fsError: Error: ENOENT: no such file or directory, open 'D:\home\site\wwwroot\dialogs\fromClient::25753007.png
Some assistance really appreciated.
Removing ::fromClient prefix from attachment.name solved it. As #Sandeep mentioned in the comments, the special characters where probably the issue. Not sure what its purpose is. Will mention it in the Botframework sample library github repository.
[update] team will fix this. Was caused by directline service.

File downloaded by Angular 4 Application from Spring Rest Service is corrupt

We have a Post rest service written in Spring. The response of this service is a json which includes a few string parameters and a byte array. The byte array can be for any type of file.
This service is to be consumed by and Angular application written in Angular 4.
On the Angular page, we want to download this file on click of a button. The below code, hits the rest service, gets the correct response data, but the file that it downloads is corrupt.
I have taken a jpg file for sample and while trying to open the downloaded file, i get an error "We can't open this file". We have verified that the byte array, received in the response, is intact.
bmsService.service.ts
viewDocument(inputdata: String) {
console.log(inputdata);
this.HEADERS.append('Content-Type', 'application/json');
return this.http.post(
VIEW_DOCUMENT_URL,
inputdata,
{headers:this.HEADERS}
).map((res: Response) => res.json());
}
app.component.ts
openViewPopUp(docId: String) {
let attachmentRequest = new AttachmentRequest();
attachmentRequest.docId = docId;
this.bmsService.viewDocument(JSON.stringify(attachmentRequest)).subscribe(
response => {
console.log(response);
let contentType = 'application/octet-stream';
let blob = new Blob([response.fileBytes], { type: contentType });
let link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download="Case5_Evidence.jpg";
link.click();
},
err => {
console.log(err);
});
}
openViewPopUp() method is invoked on click of the button. The browser being used is IE11.

Resources