compress image on upload in angular - html

I wanted to upload images to products, and users. So im converting the image to base64 string and sending it. But when the selected image is large, the image is not getting uploaded as the base64 string is too large.
Here is the code:
Html
<input type="file" (change)="onFileSelected($event)">
<button type="submit" title="upload" (click)="uploadImage()"></button>
TS File
onFileSelected(event){
var files = event.target.files;
var file = files[0];
if (files && file) {
var reader = new FileReader();
reader.onload =this._handleReaderLoaded.bind(this);
reader.readAsBinaryString(file);
}
}
_handleReaderLoaded(readerEvt) {
var binaryString = readerEvt.target.result;
this.base64textString= btoa(binaryString);
console.log(btoa(binaryString));
}
Im just accepting the images on selection. So, is there any way to comress the image after selection or a way to reduce the base64 string so the image gets uploaded.
Thanks!! in advance.

In Angular you can upload image wihtout converting it into base64. Check this...
import { ViewChild } from '#angular/core';
export class yourComponent {
#ViewChild('fileInput') fileInput;
.
.
.
}
uploadImage(){
let fileBrowser = this.fileInput.nativeElement;
if (fileBrowser.files && fileBrowser.files[0]) {
console.log(fileBrowser.files[0]);
const formData = new FormData();
formData.append("userId", this.userId ); //appending userId in formData
formData.append("image", fileBrowser.files[0]); //appending image in formData
this.apiService.UploadImageMethod(formData)
.subscribe(
response=>{
console.log(response);
if(response.status == 'success'){
console.log(response);
}
},
err => {
this.imageErrorMsg = <any>err.message;
console.log(this.imageErrorMsg);
}
);
}
}
HTML:
<input type="file" id="fileInput" (click)="hideErrorMsg()" accept="image/*" #fileInput>
In API, you can get image data this way. (Php)
UploadImageMethod(){
$fileName = request()->image->getClientOriginalExtension();
$ext = strtolower(request()->image->getClientOriginalExtension());
}
Good Luck!!!

Related

How to check if uploaded file is a JSON file?

I am taking a file input from a user and I want to check if the selected file is a JSON file. How can I do that?
<input type = "file" onChange = {checkJSON}/>
Also how do I retrieve data from the JSON file.
If JSON.parse throws an error, its most likely invalid, therefore you can check if its valid by getting the data into a string and then trying to parse it.
try {
const json = JSON.parse(jsonStr);
} catch (e) {
console.log('invalid json');
}
You can check if file extension is json and be sure that selected file is valid JSON in that way:
function Validate() {
fileName = document.querySelector('#myfile').value;
extension = fileName.split('.').pop();
if (extension != "json")
{
alert("Sorry, " + fileName + " is invalid, allowed extension is json!");
return false;
}
var file = document.getElementById('myfile').files[0];
var reader = new FileReader();
reader.readAsText(file, 'UTF-8');
reader.onload = function(evt) {
var jsondata = evt.target.result;
try {
const json = JSON.parse(jsondata);
document.getElementById('jsondata').innerHTML = jsondata;
} catch (e) {
alert("Sorry, " + fileName + " is not valid JSON file!");
return false;
}
}
return true;
};
Html content:
<script src="script2.js"></script>
File: <input type="file" id="myfile" onchange="Validate()"/><br /><br />
<div id="jsondata"></div>
You can play with my little working live demo on ReplIt (both cases - onsubmit and onchange demos)

Weird behaviour with React Hooks and FileReader

I'm new to React Hooks and honestly I'm not sure if this problem is related to Hooks or if I'm just doing something generally wrong.
I want to build a image uploader comonent that uses the HTML5 FileReader in order to show users the uploaded images before actually POSTing them.
Below is what I have so far.
Basically <div id="from-effect"></div> is currently my way of checking whether the images could be rendered.
I first wanted to fill this <div> without side effects (like <div>I have {files.length} files</div>) but this didn't react to changes at all.
The solution below with useEffect is reacting to changes.
However, if you try uploading a few images you will notice that quite often it's showing wrong results.
function FileUploader(props) {
const [files, setFiles] = useState([]);
const loadImageContent = (name, newFiles) => {
return (e) => {
newFiles.push({ name: name, src: e.target.result });
};
}
const handleUpload = async (e) => {
const newFiles = [];
for (const file of e.target.files) {
const reader = new FileReader();
reader.onload = loadImageContent(file.name, newFiles);
await reader.readAsDataURL(file);
}
setFiles(newFiles);
}
useEffect(() => {
console.log('in use Effect, files:', files);
const prevCont = document.getElementById("from-effect");
prevCont.innerHTML = `I have ${files.length} files`;
});
return <div>
<input
type="file" name="fileUploader" id="fileUploader"
accept="image/*" multiple="multiple"
onChange={handleUpload}
/>
<div id="from-effect"></div>
</div>;
}
What am I doing wrong?
Or even better, how can I implement this without side effects?
I am not sure I follow your ultimate goal, or what you mean when you say you want to show users the uploaded images before POSTing them - do you want to POST automatically, or do you want the user to click an "upload/save/POST" button or something?
Here is an example of how to display images:
Edit: made things a little more clear, added "save" button which shows an alert that contains data you could possibly use to POST back to your server. Also, added a method to "JSONify" the file metadata, since the way we are uploading files does not let us natively convert [object File] into JSON.
const { useState } = React;
function FileUploader(props) {
const [files, setFiles] = useState([]);
const getFileMetadata = file => {
/**
* The way we are handling uploads does not allow us to
* turn the uploaded [object File] into JSON.
*
* Therefore, we have to write our own "toJSON()" method.
*/
return {
lastModified: file.lastModified,
name: file.name,
size: file.size,
type: file.type,
webkitRelativePath: file.webkitRelativePath
}
}
const handleUpload = e => {
let newstate = [];
for (let i = 0; i < e.target.files.length; i++) {
let file = e.target.files[i];
let metadata = getFileMetadata(file);
let url = URL.createObjectURL(file);
newstate = [...newstate, { url, metadata }];
}
setFiles(newstate);
};
const handleSave = () => {
alert(`POST Files Here..\n\n ${JSON.stringify(files,null,2)}`);
}
return (
<div>
<input type="file" accept="image/*" multiple onChange={handleUpload} />
<div>
<button onClick={handleSave} disabled={!(files && files.length > 0)}>
Save Image(s)
</button>
</div>
{files.map(f => {
return (
<div>
<img src={f.url} height="100" width="100" />
</div>
);
})}
</div>
);
}
ReactDOM.render(<FileUploader />, document.body);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.9.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.6/umd/react-dom.production.min.js"></script>

error in uploading the image from angular to nodejs

My Html file is -
<form method="post" [formGroup]="orderForm" enctype="multipart/form-data" (ngSubmit)="OnSubmit(orderForm.value)" >
<div class="form-group">
<label for="image">Select Branch Image</label>
<input type="file" formControlName="branchImg" (change)="onFileChange($event)" class="form-control-file" id="image">
</div>
</form>
and my .ts file is -
public orderForm: FormGroup;
onFileChange(event) {
const reader = new FileReader();
if (event.target.files && event.target.files.length) {
const [file] = event.target.files;
reader.readAsDataURL(file);
reader.onload = () => {
this.orderForm.patchValue({
branchImg: reader.result
});
};
}
}
ngOnInit() {
this.orderForm = this.formBuilder.group({
branchImg: [null, Validators.required]
});
}
and then submit the form.
I am supposed to get the image address and the upload that address in cloudinary
But when I am consoling the body in my nodejs app
it gives something like this-
branchImg: 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAgAAAQABAAD/7QCEUGhvdG9zaG9wIDMuMAA4QklNBAQAAAAAAGccAigAYkZCTUQwMTAwMGE4MjBkMDAwMD and so on.
I don't think that it is the images address. Can anyone tell me that what is this? and how to get that image's address which I will upload to cloudinary
As the Eric suggest -
my app.js code is
router.post('/branch',(req,res) =>{
const body = req.body;
const base64Data = body.branchImg.replace(/^data:image\/png;base64,/, "");
console.log(base64Data);
fs.writeFile("out.jpg", base64Data, 'base64', function(err,result) {
console.log(result);
});
});
it gives result as undefined
That basically is a base64 encoding of the image data. What you need to do after you get that is write that to a file, and then upload it to cloudinary
//this will write the base64 data as a jpg file to your local disk
require("fs").writeFile("out.jpg", base64Data, 'base64', function(err) {
//after you write it to disk, use the callback space here to upload said file
//to your cloudinary endpoint
});

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

Angular 4 - Upload CSV

I am making an Angular4
I have a button that converts data to a csv file with header.
Now I want to do it the other way around, I want to upload a csv file.
So for testing, I make an object and make a csv file from it, and then I want to click on a button and upload that file and get the same result.
I found an angular module to export csv, but I can't find one that does it the other way around. Can someone help me with that?
This is my code:
test.ts
import { Component, OnInit} from '#angular/core';
import { Angular2Csv } from 'angular2-csv/Angular2-csv';
import {Unit} from "../../../_shared/unit";
#Component({
moduleId: module.id,
templateUrl: 'test.component.html',
styleUrls: ['./test.css']
})
export class TestComponent implements OnInit {
ngOnInit() {}
public export() {
// Unit (id,name,description)
var data = [new Unit(1,"Unit1","This is unit 1!")];
var options = {
fieldSeparator: ';',
quoteStrings: '"',
decimalseparator: ',',
showLabels: true,
useBom: true
};
new Angular2Csv(data, "data", options);
}
public import(){}
}
test.html
<button (click)="export()">Download CSV</button>
<button (click)="import()">Upload CSV</button>
You can achieve the functionality using a custom function, Try this :
private extractData(data) { // Input csv data to the function
let csvData = data;
let allTextLines = csvData.split(/\r\n|\n/);
let headers = allTextLines[0].split(',');
let lines = [];
for ( let i = 0; i < allTextLines.length; i++) {
// split content based on comma
let data = allTextLines[i].split(',');
if (data.length == headers.length) {
let tarr = [];
for ( let j = 0; j < headers.length; j++) {
tarr.push(data[j]);
}
lines.push(tarr);
}
}
console.log(lines); //The data in the form of 2 dimensional array.
}
You can find the detailed post here: http://blog.sodhanalibrary.com/2016/10/read-csv-data-using-angular-2.html#.WWxu9XV97OQ
You can read the file inside the file listener function like this:
function handleFileSelect(evt) {
var files = evt.target.files; // FileList object
var file = files[0];
var reader = new FileReader();
reader.readAsText(file);
reader.onload = function(event){
var csv = event.target.result; // Content of CSV file
this.extractData(csv); //Here you can call the above function.
}
}
Inside html do this:
<input type="file" (change)="handleFileSelect($event)"/>