Can't create an img element based on a Blob - html

I am trying to create a img element based on an image that I am getting as an ArrayBuffer(which I then convert to a Blob). Here is what I've tried so far
private onProfilePictureChanged = (event: any) => {
if (event.target.files && event.target.files[0]) {
const reader: FileReader = new FileReader();
reader.onload = (e: any) => {
this.setState({
profilePicture: new Blob([e.target.response], {
type: "image/jpeg"
}),
profilePictureURL: URL.createObjectURL(new Blob([e.target.response], {
type: "image/jpeg"
}))
}, () => console.log(this.state))
}
reader.readAsArrayBuffer(event.target.files[0]);
}
}
The image takes it's src from the state. After converting the ArrayBufer to Blob then to URL I am getting this url blob:file:///00756259-cff1-4459-9b05-fe8cfbc1b361 . But the image isn't displayed, only it's alt. I also get no error in the console, so I am not sure what the problem might be.
Any suggestion? Thanks in advance!

Related

Node.js converting stream of downloaded pdf file to base64 string results in error

In my application I'm downloading previously stored images and pdf documents from amazon s3:
public async downloadFile(file: string): Promise<DownloadedFileType> {
const data = await this.#s3.send(
new GetObjectCommand({
Bucket: process.env.AWS_BUCKET_NAME,
Key: file,
}),
);
return { stream: data.Body, name: file };
}
Problem happens when I try to convert obtained stream in to base64 image (to send it as a "preview" to my front end):
private getBase64FromStream(
stream: Readable,
fileType: string,
): Promise<string> {
return new Promise((resolve, reject) => {
const data: Uint8Array[] = [];
function onData(chunk: Uint8Array): void {
data.push(chunk);
}
stream.on('data', onData);
stream.once('end', () => {
const result = Buffer.concat(data).toString('base64');
const mimeType =
fileType === 'pdf' ? 'application/pdf' : `image/${fileType}`;
resolve(`data:${mimeType}; base64, ${result}`);
stream.off('data', onData);
});
stream.once('error', reject);
});
}
It works fine for images (jpeg, png, etc.), but doesn't work for pdf documents. Rendering such base64 on my frontend results in error:
export function PreviewComponent({
src,
}: IProps): JSX.Element {
const classes = useStyles();
const { dispatch } = useContext(AppContext);
const onImageClick = () => {
dispatch(openImageModalAction(src));
};
const onError = (e: unknown) => {
console.log(e);
};
return (
<img
className={classes.imageWrapper}
src={src}
alt="preview"
onClick={onImageClick}
onError={onError}
/>
);
}
With error being React's SyntheticBaseEvent:
type: "error"
_reactName: "onError"
I have no clue what I'm doing wrong. I know you can convert pdf files to base64. Any help will be greatly appreciated.
You are using an <img> tag for displaying your PDF, but it happens that PDF are not images, so the img tag will NOT support it.
MDN confirms that PDF is not on the list of supported formats for the img tag:
https://developer.mozilla.org/en-US/docs/Web/HTML/Element/img
Try using an embed or iframe tags instead as indicated here:
How to display PDF file in HTML?
See an example for react here:
https://stackblitz.com/edit/react-ts-pgvu9y?file=index.tsx
class App extends Component<AppProps, AppState> {
constructor(props) {
super(props);
this.state = {
name: 'React'
};
}
render() {
return (
<div>
Displaying a PDF file with React<br/>
embed tag works<br/>
<embed src="https://www.inkwelleditorial.com/pdfSample.pdf" width="800px" height="400px" />
img tag does not work<br/>
<img src="https://www.inkwelleditorial.com/pdfSample.pdf" width="800px" height="400px" />
</div>
);
}
}

Ionic 4 : Recording Audio and Send to Server (File has been corrupted)

I would like to record the audio file in mobile application(iOS & Android) and tranfer to server as a formData in ionic 4. I have used the "cordova-plugin-media" to capture the audio using below logics
if (this.platform.is('ios')) {
this.filePaths = this.file.documentsDirectory;
this.fileExtension = '.m4a';
} else if (this.platform.is('android')) {
this.filePaths = this.file.externalDataDirectory;
this.fileExtension = '.3gp';
}
this.fileName = 'recording'+new Date().getHours()+new Date().getMinutes()+new Date().getSeconds()+this.fileExtension;
if(this.filePaths) {
this.file.createFile(this.filePaths,this.fileName,true).then((entry:FileEntry)=> {
this.audio = this.media.create(entry.toInternalURL());
this.audio.startRecord();
});
}
Even I have tried to create the media directly without "File Creation"
I can record and play the audio, but If I am trying to send this file
to server using below logics It won't send properly(corrupted data)
and also web application unable to play .m4a extensions
.
Please correct me If I am doing anything wrong in my code
Upload logic:
let formData:FormData = new FormData();
formData.append('recordID' , feedbackID);
that.file.readAsDataURL(filePath,file.name).then((data)=>{
const audioBlob = new Blob([data], { type: file.type });
formData.append('files', audioBlob, file.name);
that.uploadFormData(formData,feedbackID); //POST Logics -
})
;
I have used the soultion as suggested by Ankush and it works fine.
Used readAsArrayBuffer instead of readAsDataURL.
The .m4a format has supported both ios and android. Also I can
download the the same file from web application.
I am using below code to upload the image to the server. I assume that only a few modifications will be required in this code to transfer media instead of the image file.
private uploadPicture(imagePath: string, apiUrl: string): Observable<ApiResponse<ImageUploadResponseModel>> {
return this.convertFileFromFilePathToBlob(imagePath).pipe(
switchMap(item => this.convertBlobToFormData(item)),
switchMap(formData => this.postImageToServer(formData, apiUrl))
);
}
Rest functions used in above code:
private postImageToServer(formData: FormData, apiUrl: string): Observable<ApiResponse<ImageUploadResponseModel>> {
const requestHeaders = new HttpHeaders({ enctype: 'multipart/form-data' });
return this.http.post<ApiResponse<ImageUploadResponseModel>>(apiUrl, formData, { headers: requestHeaders });
}
private convertBlobToFormData(blob: Blob): Observable<FormData> {
return new Observable<FormData>(subscriber => {
// A Blob() is almost a File() - it's just missing the two properties below which we will add
// tslint:disable-next-line: no-string-literal
blob['lastModifiedDate'] = new Date();
// tslint:disable-next-line: no-string-literal
blob['name'] = 'sample.jpeg';
const formData = new FormData();
formData.append('file', blob as Blob, 'sample.jpeg');
subscriber.next(formData);
subscriber.complete();
});
}
private convertFileFromFilePathToBlob(imagePath: string): Observable<Blob> {
return new Observable<Blob>(subscriber => {
const directoryPath = imagePath.substr(0, imagePath.lastIndexOf('/'));
let fileName = imagePath.split('/').pop();
fileName = fileName.split('?')[0];
this.file.readAsArrayBuffer(directoryPath, fileName).then(fileEntry => {
const imgBlob: any = new Blob([fileEntry], { type: 'image/jpeg' });
imgBlob.name = 'sample.jpeg';
subscriber.next(imgBlob);
subscriber.complete();
}, () => {
subscriber.error('Some error occured while reading image from the filepath.');
});
});
}

Posting a json data to my database with axios (using my backend api)

I have a very strange issue. I've got a backend api to import a json data to my mongodb.
On the screen I have a upload button to upload a file and I used react-dropzone for that. For example think that I have a file like "db.json" and in this file there is a json like as follows
{
"datapointtypes":[
{"id":"Wall plug","features":[{"providesRequires":"provides","id":"Binary switch"},{"providesRequires":"requires","id":"Binary sensor","min":"1","max":"2"}],"parameters":[{"id":"Communication type","type":"Communication type"}],"functions":[{"id":"Electricity"},{"id":"Switch"}]},
{"id":"Door sensor","features":[{"providesRequires":"provides","id":"Binary sensor"}],"parameters":[{"id":"Communication type","type":"Communication type"}],"functions":[{"id":"Door"},{"id":"Sensor"}]}
],
"datatypes":[
{"id":"Communication type","type":"enum","values":[{"id":"Zwave"},{"id":"Zigbee"}]},
{"id":"Zigbee network address","type":"decimal","min":1,"max":65336,"res":1},
{"id":"Serial port","type":"string"}
],
"features":[
{"id":"Zwave receiver","exposedtype":"Zwave command","functions":[{"id":"Communication"}]},
{"id":"Zigbee receiver","exposedtype":"Zigbee command","functions":[{"id":"Communication"}]},
{"id":"Binary switch","exposedtype":"On off state","functions":[{"id":"Actuator"}]},
{"id":"Binary sensor","exposedtype":"On off state","functions":[{"id":"Sensor"}]}
],
"servicetypes":[
{"id":"Room controller","datapointtype":"Room controller","DelayActive":false,"DelayValue":""},
{"id":"Xiaomi door sensor","datapointtype":"Door sensor","parameters":[{"id":"Zigbee network address","type":"Zigbee network address"},{"id":"Zigbee node id","type":"Zigbee node id"}],"parametervalues":[{"id":"Communication type","value":"Zigbee"}]}
],
"systems":[
{"id":"system 2","services":[{"serviceType":"Room controller","id":"servis 1"}],"serviceRelations":[{"serviceName":"servis 1","featureName":"Binary sensor"}],"parametervalues":[{"id":"Delay","paramName":"Delay","serviceType":"Room controller","value":"binary"}]},
{"id":"system 3","services":[{"serviceType":"Room controller","id":"servis 1"}],"serviceRelations":[{"serviceName":"servis 1","featureName":"Binary sensor"}],"katid":"7"}
]
}
The problem is this. If the browser console is open then my code is running succesfully and I can import the json data to my mongodb. But if browser console is closed I'm getting the "SyntaxError: Unexpected end of JSON input" error.
This is the function that I'm using on the import button
class FileUpload extends Component {
state = {
warning: ""
}
uploadFile = (files, rejectedFiles) => {
files.forEach(file => {
const reader = new FileReader();
reader.readAsBinaryString(file);
let fileContent = reader.result;
axios.post('http://localhost:3001/backendUrl', JSON.parse(fileContent),
{
headers: {
"Content-Type": "application/json"
}
})
.then(response => {
this.setState({warning: "Succeed"})
})
.catch(err => {
console.log(err)
});
});
}
render() {
return (
<div>
<Dropzone className="ignore" onDrop={this.uploadFile}>{this.props.children}
</Dropzone>
{this.state.warning ? <label style={{color: 'red'}}>{this.state.warning}</label> : null}
</div>
)
}
}
What is that I am doing something wrong or what causes this?
Can you help me?
Thank you
FileReader reads files asynchronously so you have to use a callback to access the results
I would use readAsText instead of readAsBinaryString in case there are non ascii characters in the JSON
Finally, JSON.parse converts a JSON string to an object(or whatever type it would be). fileContent is already JSON so leave it as is.
const reader = new FileReader();
reader.onlooad = (e) => {
let fileContent = this.result;
axios.post('http://localhost:3001/backendUrl', fileContent,
{
headers: {
"Content-Type": "application/json"
}
})
.then(response => {
this.setState({warning: "Succeed"})
})
.catch(err => {
console.log(err)
});
}
reader.readAsText(file);

How can I convert from user input image to URL in react

I'm taking an image as an input from user using the below code
<input type="file" onChange={this.fileUpload}/>
I want to convert the image into URL.
This is what I used in fileUpload() function
fileUpload = (event) => {
let src = event.target.value.getAsDataURL();
this.setState({
image: src
});
}
Please let me know how to convert image into URL.
You can use the function below as ImageChange function and use the state variable imagePreviewUrl to preview the image.
_handleImageChange(e) {
let reader = new FileReader();
let file = e.target.files[0];
reader.onloadend = () => {
this.setState({
file: file,
imagePreviewUrl: reader.result
});
}
reader.readAsDataURL(file)
}
Add ref to your input tag, so you can access the dom for that element:
<input type="file" ref={this.myFiles} onChange={this.fileUpload}/>
fileUpload=()=>{
// Now get files in the FileList object
const files = this.myFiles.files
// Define what type of file to accept:
const accept = ["image/png"];
if (accept.indexOf(files[0].mediaType) > -1) {
this.setState({
image: files[0].getAsDataURL()
})
}
}
More infos: https://developer.mozilla.org/en-US/docs/Web/API/File/getAsDataURL

How to display image returned in JSON response after uploading

I have a page where you can upload images. Everything works except I don't know how to make the page refresh with the new image which is returned in the json response on success. I cant use location.reload() because it refreshes the whole app and starts off from the home page. I am using angular2/typescript for my frontend
component.ts (The image value is returned on success)
uploadFile(): any {
let file = this.fileInput.nativeElement;
if (file.files && file.files[0]) {
let fileToUpload = file.files[0];
this.getService
.uploadImg(fileToUpload)
.subscribe(
response => {
},
err => {
console.log("ERR", err)
}
},
() => console.log("Success")
);
}
My solution would be to update the src attribute of the img container. This can be done using the setAttribute function. A primitive example is below.
Javascript
uploadFile(): any {
let file = this.fileInput.nativeElement;
if (file.files && file.files[0]) {
let fileToUpload = file.files[0];
this.getService
.uploadImage(fileToUpload, this.id)
.subscribe(
response => {
this.image = response.image;
document.getElementbyId("image-id").setAttribute("src", "data:image/JPG;base64," + pic.pic );
},
err => {
console.log("ERR", err)
}
},
() => console.log("Success")
);
}
HTML
<div *ngIf="pic.pic">
<img id="image-id" [src]="'data:image/JPG;base64,' + pic.pic" />
</div>
Heres how I solved it.
component.ts (The image value is returned on success)
pic: any;
upload: any {
let file = this.fileInput.nativeElement;
if (file.files && file.files[0]) {
let fileToUpload = file.files[0];
this.getService
.uploadImg(fileToUpload)
.subscribe(
response => {
//Assign the response here
this.pic = response.image;
},
err => {
console.log("ERR", err)
}
},
() => console.log("Success")
);
}
The html page
<img [src]="'data:image/JPG;base64,' + pic " />