I'm working on react native App using expo API, the App basically takes a picture then the App crop it using ImageEditor.cropImage, finally copy the picture from cache to another location. the code:
takePicture = async function() {
if (this.camera) {
this.camera.takePictureAsync().then(async (data) => {
cropdata = {
offset:{x:0, y:0},
size:{width:100, height:100},
};
await ImageEditor.cropImage(
data.uri,
cropdata,
async (uri) => {
FileSystem.moveAsync({
from: uri,
to: `${FileSystem.documentDirectory}photos/Photo_${this.state.photoId}.jpg`,
}).then(() => {
this.setState({
photoId: this.state.photoId + 1,
});
Vibration.vibrate();
});
},
(error) => {
console.log(error);
}
);
});
}
};
But the following error is shown:
[Unhandled promise rejection: Error: Location
'file:///data/user/0/host.exp.exponent/cache/ReactNative_cropped_image_574763720.jpg'
isn't movable.]
any idea?
Expo’s FileSystem module can copy/move/etc. files that are previously saved in the app’s scope (for example via ImagePicker or using Asset.loadAsync). ImagerEditor is a core React Native functionality and it saves your image to a file that is outside Expo’s scope, thus FileSystem cannot perform actions on this file. more on this can be found here:
https://forums.expo.io/t/where-does-camera-takepictureasync-save-photos/6475/7
so instead of using ImageEditor.cropImage() one should use expo ImageManipulator.
Related
I'm having issues uploading video files to cloudinary in my react app, deployed in netlify. In my App I have a react page with a form that sends the data to my API. My API handles the HTTP requests to my netlify functions (using Axios), and then with the serverless function I call the cloudinary node API to store the video file. The problem happens when I'm passing the data from my API to the serverless function, I'm getting "Error: Stream body too big", because the video exceeds the payload limit of netlify functions (6mb). Do I have to compress the file? It's okay to do it like this (frontend page -> api.js -> serverless function)? Thanks for all the help you guys provide everyday, it helped me a lot!
Files that I have and the error:
page.jsx
const formHandler = async (formValues) => {
try {
...
const res = await addExercise(formValues);
...
} catch (error) {
console.log("error ", error);
}
};
api.js
import { instance } from "./instance";
...
export const addExercise = async (data) => {
try {
const reader = new FileReader();
reader.readAsDataURL(data.exerciseVideo[0]);
reader.onloadend = async () => {
const cloudVideo = reader.result;
const cloudinaryResponse = await instance.post("upload-exerciseVideo", { cloudVideo });
...
}
} catch (error) {
console.log("error", error);
}
};
serverless function (upload-exerciseVideo.js)
import cloudinary from '../src/config/cloudinary';
export const handler = async (event, context) => {
try {
const data = JSON.parse(event.body);
const { cloudVideo } = data;
const cloudinaryRequest = await cloudinary.uploader
.upload(cloudVideo, {
resource_type: "video",
upload_preset: "z9qxfc6q"
});
...
} catch (error) {
console.log('error', error)
return {
statusCode: 400,
body: JSON.stringify(error)
}
}
}
Error:
Netlify Serverless functions are built on top of AWS Lambda functions so there is a hard limit to the size of the file and the amount of time it takes to run the code in the file. You didn't mention the size of your video, but the video does take longer to upload, and even if you are within the 1GB size limit, you may be exceeding the 10-second processing limit. Your video likely already has been compressed, so compression is not a viable option, and decompressing it in the serverless function would probably exceed the time limit. https://www.netlify.com/blog/intro-to-serverless-function.
If you're uploading a large file, like a video, from front-end code, consider using the Upload Widget with an unsigned preset. Here's a link to a code sandbox showing how to create and use the upload widget in React: https://codesandbox.io/s/cld-uw-uymkb. You will need to add your Cloudinary cloudname and an unsigned preset to make this work. You'll find instructions for creating unsigned presets here: https://cloudinary.com/documentation/upload_presets
Context
I am using Dropbox and PDFJs library inside a Google Cloud Function
What I'm doing
Inside my functions folder i run
npm i --save pdfjs-dist
Then I download a pdf content from dropbox (this works)
exports.readAProgram = functions.https.onRequest(async(req, res) => {
var dbx = new Dropbox.Dropbox({ accessToken: ACCESS_TOKEN });
dbx.filesDownload({ path: "/full/path/20220702.pdf" })
.then(function(response) {
console.log('response', response)
res.json(response.result.fileBinary);
})
.catch(function(error) {
// console.error(error);
res.json({"error-1": error})
});
});
I got this
Formatted is this
Note
I do not known what exactly is a fileBinary because
in the official doc (https://www.dropbox.com/developers/documentation/http/documentation#files-download) I cannot see the fileBinary
in the official example of a download they are using a diffent method (https://github.com/dropbox/dropbox-sdk-js/blob/main/examples/javascript/download/index.html)
Next step: pass data to PDF.js.getDocument
I'm looking at the sourcecode, because obviously official api doc is useless.
See here: https://github.com/mozilla/pdf.js/blob/master/src/display/api.js#L232
The getDocument function accepts
string|URL|TypedArray|PDFDataRangeTransport|DocumentInitParameters
Question
How can I convert my Dropbox fileBinary structure into something accettable from PDFJS.getDocument ?
I tried
dbx.filesDownload({ path: "/full/path/20220702.pdf" })
.then(function(response) {
var loadingTask = PDFJS.getDocument(response.result.fileBinary)
.then(function(pdf) {
console.log ("OK !!!!")
res.json(response.result.fileBinary);
})
.catch(function (error) {
console.log ("error)
res.json({"error_2": error})
});
But I got this on console
> C:\laragon\www\test-pdf-dropbox\functions\node_modules\pdfjs-dist\build\pdf.js:2240
> data: structuredClone(obj, transfers)
> ^
>
> ReferenceError: structuredClone is not defined
> at LoopbackPort.postMessage (C:\laragon\www\test-pdf-dropbox\functions\node_modules\pdfjs-dist\build\pdf.js:2240:13)
> at MessageHandler.sendWithPromise (C:\laragon\www\test-pdf-dropbox\functions\node_modules\pdfjs-dist\build\pdf.js:8555:19)
> at _fetchDocument (C:\laragon\www\test-pdf-dropbox\functions\node_modules\pdfjs-dist\build\pdf.js:1356:48)
> at C:\laragon\www\test-pdf-dropbox\functions\node_modules\pdfjs-dist\build\pdf.js:1302:29
> at processTicksAndRejections (node:internal/process/task_queues:96:5)
i solved
First: use legacy dist of PDFJS
instead of using
const PDFJS = require("pdfjs-dist");
I do now
const PDFJS = require("pdfjs-dist/legacy/build/pdf.js");
the npm package is the same, pdfjs-dist
Then: using PDFJS in this way
var pdf = PDFJS.getDocument(new Uint8Array(response.result.fileBinary)).promise
.then(function(pdf) {
console.log ("Letto il PDF !!!!", pdf)
res.json({done: true})
})
Note
fileBinary can be passed to PDFJS using new Uint8Array
i appended .promise before of .then
I am making a project where I want to use darta from yahooFinance.
I have found this project https://www.npmjs.com/package/yahoo-finance.
I have also used the basic sapper template.
Basically what I am trying is to retrive data from YF and show them on the FE.
I gave this piece of code:
<script>
import yahooFinance from 'yahoo-finance';
let response;
async function searchStock (){
yahooFinance.historical({
symbol: 'AAPL',
from: '2020-01-01',
to: '2020-12-31',
}, function (err, quotes) {
console.log(quotes)
});
}
</script>
But everytime I try to compile I get:
Unexpected token (Note that you need #rollup/plugin-json to import JSON files)
1: {
2: "version": "2020d",
^
3: "zones": [
4: "Africa/Abidjan|LMT GMT|g.8 0|01|-2ldXH.Q|48e5",
So I gave tried to import it thus way var yahooFinance = require('yahoo-finance');
But then I get Uncaught (in promise) ReferenceError: require is not defined in to the console.
You won't be able to use the yahoo-finance package on the front end, since it uses Node APIs. Since you're using Sapper, you can use the package in a server route and fetch it from the client.
Create the file yahoo.json.js and place it in src/routes. Then copy + paste the following into it. This will call the historical method from yahoo-finance and return the result as JSON.
import yahooFinance from 'yahoo-finance';
export async function get(req, res, next) {
const response = await new Promise((resolve, reject) => {
yahooFinance.historical({
symbol: 'AAPL',
from: '2020-01-01',
to: '2020-12-31',
}, function (err, quotes) {
if (err) reject(err);
resolve(quotes);
});
})
res.setHeader('Content-Type', 'application/json');
res.end(JSON.stringify(response));
}
You can then call this server route from within a Svelte component. This uses the Sapper preload method to fetch the data before the page renders.
<script context="module">
export async function preload() {
const res = await this.fetch('/yahoo.json');
const data = await res.json();
return {data};
}
</script>
<script>
export let data;
</script>
{JSON.stringify(data)}
You will likely want to enhance the server route to add request parameters and better error handling, but this shows you how to get it working.
I'm trying to make a scanner in React Native that takes an image file, scans it and returns data that contains in barcode. I'm using a BarCodeScanner extension from Expo SDK.
It throws an error when I'm trying to use it.
Error looks like:
An exception was thrown while calling `ExpoBarCodeScannerModule.scanFromURLAsync` with arguments `(
1,
(
"org.iso.QRCode"
)
)`: -[__NSCFNumber length]: unrecognized selector sent to instance 0xe17787ebcc27c1d0
- node_modules/react-native/Libraries/BatchedBridge/NativeModules.js:104:55 in <unknown>
- node_modules/react-native/Libraries/BatchedBridge/MessageQueue.js:414:4 in __invokeCallback
- ... 4 more stack frames from framework internals
My code where I'm trying to use extension method:
file = require('./assets/image.jpg');
componentDidMount(){
BarCodeScanner.scanFromURLAsync(this. file).then(data => {
console.log(data)
}).catch(err => {
console.log(err)
})
}
Do you have any thoughts what does it mean?
A bit too late, but for anyone with simmilar problem. You can use expo ImagePicker package to select image. It will return array of objects. One of the parameters of the object is URI of the image that can be used as an input to BarCodeScanner.scanFromURLAsync method.
const pickImage = async () => {
let result = await ImagePicker.launchImageLibraryAsync({
allowsEditing: false,
quality: 1,
});
if (!result.canceled) {
let decodedBarcodeImage = await BarCodeScanner.scanFromURLAsync(result.assets[0].uri);
// Handle result data
console.log(decodedBarcodeImage);
} else {
// Handle canceled result
console.log('You did not select any image.');
}
};
I'm currently using the expo camera in my application on iOS.
The app crashes when I try to save the image like this.
takePicture = async function() {
this.camera.takePictureAsync().then(data => {
FileSystem.moveAsync({
from: data,
to: `${FileSystem.documentDirectory}photos/Photo_${this.state
.photoId}.jpg`,
}).then(() => {
this.setState({
photoId: this.state.photoId + 1,
});
Vibration.vibrate();
}).catch((err) => {
console.log("Error : " + err);
});
}).catch(error => {
console.log(error);
});
Vibration.vibrate();
console.log("Taking pic");
}
In addition the Vibration.vibrate() doesn't actually vibrate the phone. I receive an error earlier in the execution here:
componentDidMount() {
FileSystem.makeDirectoryAsync(
FileSystem.documentDirectory + 'photos'
).catch(e => {
console.log(e, 'Directory exists');
});
}
The error just says
[Error: Directory 'file:///var/mobile/Containers/Data/Application/X/Documents/ExponentExperienceData/X/photos' could not be created.]
Is there anyone else who has experienced the same issue? If anyone is able to let me know how to add the vibration too this would be fantastic. I've added it in the top of the file as:
import {
StyleSheet,
Text,
View,
TouchableOpacity,
Slider,
Image,
Picker,
Button,
ScrollView,
Vibration,
} from 'react-native';
EDIT: I've solved the issue with saving to the cameraroll. The issue with the vibration still stands.
Thanks
For the first problem you describe, although you solved it via a workaround by saving it to cameraroll, I would suggest you post the edited code to keep the question correctly up to date.
FileSystem Issue
Addressing the FileSystem error issue, the original code should work as it is, but you could check:
If the expo app has appropriate file access permissions (should be automatic via the expo library, but try updating the expo app). Documentation on FileSystem can be found here: https://docs.expo.io/versions/latest/sdk/filesystem.html
You may need to create the intermediate directories (i.e. photos):
like this:
async componentDidMount() {
try {
await FileSystem.makeDirectoryAsync(
`${FileSystem.documentDirectory}photos`,
{
intermediates: true, // creates intermediate directories
}
)
} catch (e) {
console.log(e)
}
}
Vibration Issue
The vibration problem is probably caused by a bug in react-native as described here: https://github.com/facebook/react-native/issues/8955#issuecomment-353373616
As a workaround you could vibrate before setting the state i.e:
takePicture = async function() {
if (this.camera) {
const picture = await this.camera.takePictureAsync();
const pictureFile = await FileSystem.moveAsync(
{
from: picture.uri,
to: `${
FileSystem.documentDirectory
}photos/Photo_${this.state.photoId}.jpg`
}
).catch(err => console.error(err));
Vibration.vibrate();
console.log("Pic taken", this.state.photoId);
return this.setState({
photoId: this.state.photoId + 1
});
}
};