react-native expo save image in cache using Filesystem not working - react-native

App written in React-Native expo.
I have 3 main pages in my app.
first page with a button that will open the second page(which loads the camera to scan a QR)
and the last page(called from the result of the scanned QR in second page) will load a picture from a url.
the picture will always load from the same url, BUT the picture content can change all the time.
i'm managing this using FileSystem to access the cache.
when the camera page loads i'm performing the following steps:
deleting the directory in the cache (if exists)
creating the directory again (now it's empty)
getting the picture from the url and save it in cache directory
After the scan of the QR i'm getting the file uri in the cache and sending it as a parameter to the image page.
Image page shows the correct image in the first time but when i change the image in the url and starting again in the app from the first page, i'm getting the previous image and not the updated one.
If i'm deleting the cache directory and creating it again, how is it possible i'm getting an old image?
hope i was able to explain my self
code when loading the camera page :
const imgDir = FileSystem.cacheDirectory + "AdImage/";
const dirInfo = await FileSystem.getInfoAsync(imgDir);
//check if AdImage directory exists in cache and delete if exists
if (dirInfo.exists)
{
await FileSystem.deleteAsync(imgDir);
}
//create an empty directory (since we delete b4)
await FileSystem.makeDirectoryAsync(imgDir);
const uri =
"https://myWebsite.azurewebsites.net/Images/AdvertiseImg/Image.jpeg?" + randNum;//random number for timestamp
//get the image with the uri and save it in the directory created b4 loop- call image img+compNum
const newImage = await FileSystem.downloadAsync(uri, imgDir + 'img');
once QR code is scanned :
const imgFile = FileSystem.cacheDirectory + "AdImage/img";
const uriToImageFromCacheInfo1 = await FileSystem.getInfoAsync(imgFile);
if (uriToImageFromCacheInfo1.exists) {
navigation.navigate("Image", {
uri: uriToImageFromCacheInfo1.uri //call image page with uri image saved in cache
});
On Image page assign to param that is bound to image
const [uriFromCache, setUriFromCache] = useState(navigation.getParam("uri"));
rendered view with image :
<View style={[{ height: "92%", backgroundColor: "#EE7629" }]}>
<Image source={
uri: uriFromCache,
}
style={{ width: "100%", height: "100%", resizeMode: "stretch" }}
/>
</View>

Related

react-native-vision-camera save a photo with react-native-fs

I am making a function for saving a photo by react-native-vision-camrea.
For that, I am using RNFS from react-native-fs to access the android file path and saving react-native-vision-camera's useRef-Value.
Below is my Code.
function Cam(){
const devices = useCameraDevices()
const device = devices.back
const camera = useRef(null)
const takePhotoOptions = {
qualityPrioritization: 'speed',
flash: 'on'
}
const captureHandler = async()=>{
try{
if (camera.current == null) throw new Error('Camera Ref is Null');
console.log('Photo taking ....');
const data = await camera.current.takePhoto(takePhotoOptions)
await RNFS.moveFile(`/${data.path}`, `${RNFS.ExternalDirectoryPath}/temp.jpg`)
.then(()=>console.log("Image Moved",`${data.path}`,'-- to --',`${RNFS.ExternalDirectoryPath}`))
await RNFS.writeFile(`${RNFS.ExternalDirectoryPath}/temp.jpg`, data, 'ascii')
.then(()=>console.log("Image wrote",`${data.path}`,'-- to --',`${RNFS.ExternalDirectoryPath}`))
}catch(err){
console.log(err)
}
}
return(<>
{device != null&&<>
<Button title='Take a Photo' onPress={()=>captureHandler()}/>
<View style={{ flex: 1 }}>
<Camera
ref={camera}
style={StyleSheet.absoluteFill}
device={device}
photo={true}
isActive={true}
/>
</View>
</>}
</>)
}
I got permission to CAMERA/WRITE_EXTERNAL_STORAGE.
And available to get data.path and RNFS.ExternalDirectoryPath.
But I could not find the file that I took a picture for saving.
I tried to attempt both moveFile/writeFile functions from RNFS.
Below is the log I got
LOG Photo taking...
LOG Image Moved /data/user/0/com.camera/cache/mrousavy6998557498651783260.jpg -- to -- /storage/emulated/0/Android/data/com.camera/files
LOG Image wrote /data/user/0/com.camera/cache/mrousavy6998557498651783260.jpg -- to -- /storage/emulated/0/Android/data/com.camera/files
From react-native-fs documentation for Android:
Android support is currently limited to only the DocumentDirectory. This maps to the app's files directory.
Try to use DocumentDirectory instead of ExternalDirectoryPath

React Native how to use fast image for expo using cache

I uploaded images to firebase storage and fetching it on the display. It's working fine, but I noticed that it reloads every time changing to other page and the speed is quite slow.
So, after googling I found expo-fast-image (because I'm using expo)
https://www.npmjs.com/package/expo-fast-image
so, after installing it, I'm trying to follow or copy the given an example, but I don't know how to use it properly. Below is my code with expo-fast-image.
Does anyone know how to use it properly?
import ExpoFastImage from 'expo-fast-image';
const CustomListItem = ({id, number, data, coffeeBean, description, image, Order}) => {
const user = auth.currentUser;
const name = user.displayName;
const ImageLoad = (image, id) => (
<View>
<ExpoFastImage
uri= {image}
CacheKey={`cache.${id}`}
/>
</View>
)
return (
<ListItem key={id} bottomDivider onPress={() => {Order({id, number, coffeeBean, description, image})}} >
<ExpoFastImage image={image, id}/>
<Avatar rounded source={{CacheKey: `cache.${id}`}} />
<ListItem.Content >
<ListItem.Title style={{ fontWeight: '800'}}>{id}</ListItem.Title>
<ListItem.Subtitle numberOfLines={1} ellipsizeMode='tail'>
Stock: {number}
</ListItem.Subtitle>
</ListItem.Content>
</ListItem>
)
}
export default CustomListItem
If expo-fast-image uses Image from react-native, images are cached and they are downloaded again only when the url changes. So in your situation, you might be giving different urls to the component which propmts it to download again. Make sure the url is always the same. Even if you add some random string like #some-random-value at the end of url which does nothing. It triggers the download action.

Show local image file:///tmp/someimage.jpg

Scenario
I'm contributing for a OSS project that is build on BlazorServerSide and ElectronNET.API Version 9.31.1.
In an Electron window we would like to show images from local storage UI via <img> tag.
What I have tried:
I have tried with:
<img src="file:///home/dani/pictures/someimage.jpg" />
But doesn't work. Image doesn't appear. I have then tried to create electron window with WebSecurity = false, but also doesn't help (images appears as broken on UI):
var browserWindowOptions = new BrowserWindowOptions
{
WebPreferences = new WebPreferences
{
WebSecurity = false,
},
};
Task.Run(async () => await Electron.WindowManager.CreateWindowAsync(
browserWindowOptions,
$"http://localhost:{BridgeSettings.WebPort}/Language/SetCultureByConfig"
));
Finally, as workaround, I'm sending the images as data base64 in img src's attribute, but it looks like a dirty approach.
My Question:
My question is, how can I show on electron window picture files from local storage.
Some irrelevant info:
The open source line where I need assistance.
There are several ways to go about this, so I will try to cover the most relevant use cases. Some of this depends on the context of your project.
Access to local files behave as cross origin requests by default. You could try using the crossorigin=anonymous attribute on your image tag, but doesn't work because your local file system will not be responding with cross origin headers.
Disabling the webSecurity option is a workaround, but is not recommended for security reasons, and will not usually work correctly anyway if your html is not also loaded from the local file system.
Disabling webSecurity will disable the same-origin policy and set allowRunningInsecureContent property to true. In other words, it allows the execution of insecure code from different domains.
https://www.electronjs.org/docs/tutorial/security#5-do-not-disable-websecurity
Here are some methods of working around this issue:
1 - Use the HTML5 File API to load local file resources and provide the ArrayBuffer to ImageData to write the image to a <canvas> .
function loadAsUrl(theFile) {
var reader = new FileReader();
var putCanvas = function(canvas_id) {
return function(loadedEvent) {
var buffer = new Uint8ClampedArray(loadedEvent.target.result);
document.getElementById(canvas_id)
.getContext('2d')
.putImageData(new ImageData(buffer, width, height), 0, 0);
}
}
reader.onload = putCanvas("canvas_id");
reader.readAsArrayBuffer(theFile);
}
1.b - It is also possible to load a file as a data URL. A data URL can be set as source (src) on img elements with JavaScript. Here is a JavaScript function named loadAsUrl() that shows how to load a file as a data URL using the HTML5 file API:
function loadAsUrl(theFile) {
var reader = new FileReader();
reader.onload = function(loadedEvent) {
var image = document.getElementById("theImage");
image.setAttribute("src", loadedEvent.target.result);
}
reader.readAsDataURL(theFile);
}
2 - Use the Node API fs to read the file, and convert it into a base64 encoded data url to embed in the image tag.
Hack - Alternatively you can try loading the image in a BrowserView or <webview>. The former overlays the content of your BrowserWindow while the latter is embedded into the content.
// In the main process.
const { BrowserView, BrowserWindow } = require('electron')
const win = new BrowserWindow({ width: 800, height: 600 })
const view = new BrowserView()
win.setBrowserView(view)
view.setBounds({ x: 0, y: 0, width: 300, height: 300 })
view.webContents.loadURL('file:///home/dani/pictures/someimage.jpg')

Displaying images encoded with base64 in react native

I am new to react native and I am trying to display images encoded with base 64.
<Image source={{uri: `data:image/png;base64,${element.img}`}}
style={{height: 200, width: null, flex: 1}}/>
This is the mongoose scheme where I store my images
img: {
data: Buffer,
contentType: String,
},
And this is how I save them to database (photoData contains img):
this.setState({img:data.base64})
axios.post('uri', photoData, config)
Here is my img data : img data
data is returning back as buffer so using this
data:image/png;base64,${element.img}
is not working. I tried using Buffer.from('','base64').toString('ascii') but still, image is not showing.
Your response is a buffer object you will have to use the below code to convert to base64 Image.
const data = Buffer.from(response, 'binary').toString('base64');
const base64Image = `data:image/png;base64,${data}`;
and then you can use the image normally
<Image source={{uri: base64Image}}/>

how to save the generated QR-code using react-native-qrcode

I am trying to generate QR code, by using this module 'react-native-qrcode', Here I got generated QR code like this, How can I save this QR code.
Can anyone give me suggestions that how to save this generated qr,any help much appreciated
The library you use uses a webview, therefore you have no image you may save. To save the QR code in a conceptional fashion you may store the value provided and put it into the component as you would like to display it. If you need to get the image, you would need to extend the webview javascript part to use the ImageData interface of the canvas. This is IMHO quite tricky and I am not entirely sure if it is even possible to get data back from the web view.
Use rn-qr-generator to generate a QR code. It will return a path or base64 of generated Image. Later you can use CameraRoll module to store the image in CameraRoll (or Gallery on android).
import RNQRGenerator from 'rn-qr-generator';
import CameraRoll from "#react-native-community/cameraroll";
RNQRGenerator.generate({
value: 'your_qr_string_value_here',
height: 100, // height of the output image
width: 100, // width of the output image
base64: false, // default 'false'
backgroundColor: 'black', // default 'white'
color: 'white', // default 'black'
})
.then(response => {
const { uri, width, height, base64 } = response;
this.setState({ imageUri: uri });
CameraRoll.save(uri);
})
.catch(error => console.log('Cannot create QR code', error));
Before calling CameraRoll.save make sure you have permission to save the image. Permission example see here.