I'm trying to upload a jpeg file (2.1Mb) using react-images-upload, however, when I save the received file on backend, it has 7.5 Mb. Could anyone give me suggestions to understand what's wrong?
<ImageUploader
withIcon={true}
buttonText="Choose the Document"
onChange={onDrop}
maxFileSize={5242880}
idealResolution={{ width: 640, height: 480 }}
isMaxResolution={true}
/>
and the handle function:
const onDrop = (documentFiles, documentDataURLs) => {
const document = documentFiles.pop();
document.arrayBuffer().then((arrayBuffer) => {
dispatch(
submitDocument(
[{ name: document.name, bytes: new Uint8Array(arrayBuffer) }],
submitDocumentCallback
)
);
});
};
In the backend, I'm justing saving the bytes using a FileOutputStream.
I looked at the source code for react-images-upload and have to say that it doesn't look like something I'd want to put in production.
I also don't see how you actually make it upload to the server. Your example doesn't include where you specify the server URL.
For uploading files in React, I'd go with something more robust. I'm biased toward react-uploady (since it's my project). So I'd recommend it. But there are other good ones as well (I guess).
For example, with react-uploady, its as simple as:
import React from "react";
import Uploady from "#rpldy/uploady";
import UploadButton from "#rpldy/upload-button";
const MyApp = () => (
<Uploady destination={{url: "https://my-server.com/upload"}}>
<UploadButton/>
</Uploady>
);
Related
It's been 3 days, I am searching for a solution to display my *.docx and *.xlxs file in my angular application. I have an API which is returning the files as blob. Now, I want to use that blob to show the file. I can easily download the file using window.open(blobLink), however, my main task was to view the file. So, I searched and found ngx-doc-viewer and it does not work with the blob link as I currently found and file needed to be publicly accessible. But, my application will run in the local network. So, how can I solve this problem. Here is my *.ts and HTML code below=>
TS
getFile(fileData: File) {
this.tempBlob= null;
this.ProposalService.getFile(fileData).subscribe(
(retFileData: any) => {
this.tempRetFileData = retFileData;
},
(err: Error) => {
},
() => {
const blob = new Blob([this.tempRetFileData], { type: this.contentType });
this.docURL = window.URL.createObjectURL(blob);
}
);
}
HTML
<ngx-doc-viewer [url]="docURL" viewer="google" style="width:100%;height:50vh;"></ngx-doc-viewer>
Note: Any other free Library and solution is acceptable.
For blob type use viewer="mammoth":
<ngx-doc-viewer [url]="docURL" **viewer="mammoth"** style="width:100%;height:50vh;"></ngx-doc-viewer>
To use mammoth, also add:
npm install mammoth --save
and make sure mammoth.browser.min.js is loaded. For the angular/cli you would add the following in angular.json:
"scripts": [
"node_modules/mammoth/mammoth.browser.min.js"
]
Next.js lays out a pretty comprehensive way to get imagery from the /public/ folder (where the app has you store static assets). The pattern is to use fs from Node and do the fetch in getStaticProps.
My attempt:
export async function getStaticProps({ params, preview = false, previewData }) {
const cityData = dataFiltered.find( city => city.citySlug === params.slug )
const cityMapImagePath = path.join(process.cwd(), `/public/static-maps/${cityData.imgPath}`)
const cityMapImageRes = await fs.readFile(cityMapImagePath)
const cityMapImageProcessed = JSON.stringify(cityMapImageRes)
return {
props: {
preview,
cityData: cityData,
cityMapImage: cityMapImageProcessed
},
revalidate: 60,
};
}
This code works, but it returns a pretty weird response when I reference that object in my component:
<img src="{ "type":"Buffer", "data":[255,216,255,224,0,6,75,56,86,87,...] } />
My error has something to do with how I'm processing what fs gives me back. Do I need to encode my jpeg into base64 to get Next to use it? This answer suggests stringifying and then parsing (didn't work for me). Or maybe I need a full blown endpoint to do this? Next isn't very clear on how to get imagery from getStaticProps into the component above it - perhaps you know how?
All data that is returned from the getStaticProps needs to be JSON serializable, so yes, if you want to return image there , you need to base64 encode it (this can be a problem for big images).
The other solution (if the scenario permits it) is not to do it with getStaticProps rather load the image on demand in the front end, by hitting the API after the page has already loaded.
What I ended up doing for the fetch in getStaticProps:
export async function getStaticProps({ params, preview = false, previewData }) {
const cityData = dataFiltered.find( city => city.citySlug === params.slug )
const cityMapImagePath = path.join(process.cwd(), `/public/static-maps/${cityData.imgPath}`)
let cityMapImageRes, cityMapImageProcessed
try {
cityMapImageRes = await fs.readFile(cityMapImagePath)
cityMapImageProcessed = Buffer.from(cityMapImageRes).toString('base64')
} catch {
cityMapImageProcessed = null
}
return {
props: {
preview,
cityData: cityData,
cityMapImage: cityMapImageProcessed
},
revalidate: 60,
};
}
Also make sure up in the component, you are properly encoding your image source as base64 with the data:image/png;base64, prefix. This was a silly mistake that cost me an hour of debugging:
<img src={`data:image/png;base64,${cityMapImage}`} alt='Alt text here' />
Finally, also note that Next.js when used with Vercel will impose a hard, 50MB cap (compressed) on the serverless function used to process your page file request. If you're doing a [slug].js template, all the assets for EVERY page generated will count towards that cap. You'll hit it pretty fast on deploy, so double check yourself.
I'm having some trouble using Filepond for React. Currently, I want to preload a user's profile picture when the page is loaded. I have tried two different approaches but none have worked yet:
First, I try to use the server load option of Filepond like so:
<FilePond
ref={pond}
... other props here
files={[
{
source: this.props.user.id,
options: {
type: 'local'
}
}
]}
server={{
load: (userId, load) => {
fetch(fetchDomain + "/profiles/" + userId)
.then(res => res.blob())
.then(blob => {
console.log('blob is: ', blob)
return load
})
}
}}
/>
I fetch from my express backend which is running on the same domain and returns an s3 image URL. This leads to an infinite loading situation and a picture is never loaded. I kept making small changes to this trying to fix it, but was never able to get it to work. At some point when I was messing with the code it would finish loading, but the image would be gray/unavailable with no error messages.
Another approach I took was simply setting Files to an image URL and this didn't work either. Same result, a greyed out image that I can clear it by clicking the remove item button. I did notice, however, that if that URL was a base64 url it would actually load the image properly.
I've been debugging this for a few hours already. Is there something I am missing here?
I'm not sure if it's relevant, but the setup at the top of my file looks like:
import 'filepond/dist/filepond.min.css';
import CropperEditor from './Cropper';
import FilePondPluginFileValidateType from "filepond-plugin-file-validate-type";
import FilePondPluginImageExifOrientation from "filepond-plugin-image-exif-orientation";
import FilePondPluginImagePreview from "filepond-plugin-image-preview";
import FilePondPluginImageCrop from "filepond-plugin-image-crop";
import FilePondPluginImageResize from "filepond-plugin-image-resize";
import FilePondPluginImageTransform from "filepond-plugin-image-transform";
import FilePondPluginImageEdit from "filepond-plugin-image-edit";
import 'filepond-plugin-image-preview/dist/filepond-plugin-image-preview.css';
const fetchDomain = process.env.NODE_ENV === 'production' ? process.env.REACT_APP_FETCH_DOMAIN_PROD : process.env.REACT_APP_FETCH_DOMAIN_DEV;
// Register the plugins for filepond
registerPlugin(
FilePondPluginFileValidateType,
FilePondPluginImageExifOrientation,
FilePondPluginImagePreview,
FilePondPluginImageCrop,
FilePondPluginImageResize,
FilePondPluginImageTransform,
FilePondPluginImageEdit,
);
const pond = React.createRef();
Here is a picture of what the component looks like when loading after I got rid of all the plugins apart from FilePondPluginImagePreview and use the first method:
It says undefined...
After further reading of the documentation I'm now confused about whether I should be loading or fetching.
I was understanding the load and fetch features of the server object incorrectly. I had to get the image URL before and then use fetch or load within the server object in order to get the file from that URL and then convert it to a blob format. This would also work with an external server endpoint being called within the load feature of the server object as I was trying to do initially, but you'd have to make sure the server returns a file, not a URL. Well, I guess it could return a URL but you'd then have to do another fetch on that URL and then convert it to blob.
The answer to this question is what I did essentially.
File Preview in React FilePond not showing up when setting initial file
I am trying to upload file with Google App script and React.
Google Script:
function uploadArquivoParaDrive(base64Data, nomeArq, idPasta) {
try{
var splitBase = base64Data.split(','),
type = splitBase[0].split(';')[0].replace('data:','');
var byteCharacters = Utilities.base64Decode(splitBase[1]);
var ss = Utilities.newBlob(byteCharacters, type);
ss.setName(nomeArq);
var file = DriveApp.getFolderById(idPasta).createFile(ss);
return file.getName();
}catch(e){
return 'Erro: ' + e.toString();
}
}
I can run this ant it works:
function uploadFile() {
var image = UrlFetchApp.fetch('url to some image').getBlob();
var file = {
title: 'google_logo.png',
mimeType: 'image/png'
};
file = Drive.Files.insert(file, image);
Logger.log('ID: %s, File size (bytes): %s', file.id, file.fileSize);
}
This is React script:
onSubmit = (e) => {
e.preventDefault();
axios.get(url, {...this.state}, {
headers: {
'Content-Type': 'multipart/form-data'
}
}, (response) => {
console.log(response);
})
};
setFile = (event) => {
console.log(event.target.files)
this.setState({file: event.target.files[0]});
};
render() {
return (
<form>
<input type="file" id="file" onChange={this.setFile} />
<button onClick={this.onSubmit}>ADD</button>
</form>
)
}
I am trying with POST, but I am getting 400 response. I know that this can't be GET request, but and with it, I am getting - 200 with no response.
I can insert rows in sheets, but I want to upload files to Google Drive with Google App Scripts.
I know that there is a way to upload files via Google Scripts and React, because, there is a way without React (google.script.run).
Here are two different approaches that are used in mixed mode. It's unacceptable in some contexts.
Let's say softly 'React is a dummy'. This is an add-on that you should always avoid when somewhat comes to something that you depend on, but you cannot change. See what SOLID is.
Below it is always assumed that you are working in a browser. Your web-pages are hosted in the web application of the Google Apps Script.
The first approach. Using XMLHttpRequests
On client side you have to use XMLHttpRequests call from your browser.
On server side you have to use doGet doPost reserved functions. Always transfer data in a clear and simple format. This will save time searching for errors.
Example https://stackoverflow.com/a/11300412/1393023
The second approach. Using Client-side API
On client side you have to use google.script.run call from your browser.
On server side you have to use your functions. Always transfer data in a clear and simple format. This will save time searching for errors.
Example https://stackoverflow.com/a/15790713/1393023
Consequence
Your example has signs of mixing approaches. Unfortunately, it cannot be quickly debugged.
There is no reason that React is causing the problem. If so, then your architecture is incorrect.
If you want to use axios, then you need to consider the first approach.
If you want to use google.script.run then you need to catch onSubmit then you need to call an interface that implement google.script.run. Usually asynchronously, since the last call will still be completed with a callback.
I'm kind of confused with the documentation. I did my research, little resources. Maybe someone can help me out. i'm using a CRNA - create-react-app. i have a button that suppose to upload a file using URI to Google Drive. I already have the initial steps like API key, client id, enable API like Drive api. I manage to make Google Picker work. but no luck with Google Drive upload.
There is a save-to-drive button embedded UI. just copy paste, works in plain HTML. But what i need is to create my own method to execute the upload process. Thank you all.
Please use following steps, I hope it will help:
Add Package yarn add react-google-picker into your project, Package Link here
Get your Google Developer Key, Client Id ready from https://console.developers.google.com
Implement following code:
Note: Do not forget to change 'YOUR_DEVELOPER_KEY_HERE', 'YOUR_CLIENT_ID_HERE' with your keys in following code:
import React, {Component} from 'react';
import GooglePicker from 'react-google-picker';
class MyPage extends Component{
render(){
return (
<GooglePicker clientId={'YOUR_CLIENT_ID_HERE'}
developerKey={'YOUR_DEVELOPER_KEY_HERE'}
scope={['https://www.googleapis.com/auth/drive.readonly']}
onChange={data => console.log('on change:', data)}
onAuthFailed={data => console.log('on auth failed:', data)}
multiselect={true}
navHidden={true}
authImmediate={false}
viewId={'DOCS'}
mimeTypes={['image/png', 'image/jpeg', 'image/jpg']}
createPicker={ (google, oauthToken) => {
const googleViewId = google.picker.ViewId.DOCS;
const uploadView = new google.picker.DocsUploadView();
const docsView = new google.picker.DocsView(googleViewId)
.setIncludeFolders(true)
.setSelectFolderEnabled(true);
const picker = new window.google.picker.PickerBuilder()
.enableFeature(google.picker.Feature.SIMPLE_UPLOAD_ENABLED)
.enableFeature(google.picker.Feature.MULTISELECT_ENABLED)
.addView(docsView)
.addView(uploadView)/*DocsUploadView added*/
.setOAuthToken(oauthToken)
.setDeveloperKey('YOUR_DEVELOPER_KEY_HERE')
.setCallback((data)=>{
if (data.action == google.picker.Action.PICKED) {
var fileId = data.docs[0].id;
alert('The user selected: ' + fileId);
picker();
}
});
picker.build().setVisible(true);
}}>
<span>Click here</span>
<div className="google"></div>
</GooglePicker>
);
}
}
export default MyPage
This is how it looks ;)