Using compressorjs with React Native expo - javascript

I'm trying to using the amazing compressorjs library in my React native expo project.
Currently, I have this:
import Compressor from 'compressorjs';
export const uploadPicture = async (uri, path) => {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.onerror = function (e) {
console.log(e);
reject(new TypeError("Network request failed"));
};
xhr.responseType = "blob";
xhr.open("GET", uri, true);
xhr.send(null);
});
new Compressor(blob, { //<--- Problem
quality: 0.6,
maxWidth: 512,
maxHeight: 512,
success(result) {
console.log(result)
},
error(err) {
console.log(err.message)
}
})
blob.close();
//firebase stuff to upload after...
}
I'm assuming this doesn't work because compressorjs only allows File and Blob types and I'm inserting a Promise instead. But I have no clue what to do instead.
If anyone can point me into the right direction, that would be amazing!
Thanks.

Consider using the fetch API response.blob method to get the image blob from the URI as opposed to using Ajax XMLHttpRequest
Like this -
Getting the blob via the URI
let blob = await fetch(uri).then(r => r.blob());
You can also take it a step further by getting the actual file from the blob, like this:
Getting the image file from the blob
let file = await fetch(url)
.then((r) => r.blob())
.then((blobFile) => new File([blobFile], "fileName", { type: "image/png" }));
Your finished code should look something like:
import Compressor from "compressorjs";
export const uploadPicture = async (uri, path) => {
let blob = await fetch(uri).then(r => r.blob());
new Compressor(blob, {
...
});
};
OR this
import Compressor from "compressorjs";
export const uploadPicture = async (uri, path) => {
let file = await fetch(url)
.then((r) => r.blob())
.then((blobFile) =>
new File(
[blobFile],
"fileName",
{ type: "image/png" })
);
new Compressor(file, {
...
});
};
Disclaimer
Please note that there's no guarantee that this suggestion will definitely solve your problem but it's DEFINITELY worth a shot.
Cheers.

Related

Convert fetch to axios

I did a 'get' with fetch but I want to do it with axios, could someone help me convert this code to axios?
detail: detail: I made the request to get an image, and I use the blob to be able to show this image to the user, and I would like to do that with axios as well.
Code:
const image = (url) =>
fetch(url)
.then((response) => {
return response.blob();
})
.then(
(blob) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
})
);
const image = async (url) =>
await axios.get(url)
.then(response => {
// can access blog directly from response...
}
Read more about axios here
Here: I am assuming this is a get request?
const image = async (url) => {
return await axios.get(url)
.then((response) => {
return response.blob();
})
.then(
(blob) =>
new Promise((resolve, reject) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.onerror = reject;
reader.readAsDataURL(blob);
})
);
}

How to retrieve image from firebase in react native expo?

I am new to React Native and still learning by doing. I have uploaded images in firebase which I want to show on the second screen. Although, I keep getting errors like
can't find variable: profileImageUrl
I am trying to retrieve the image on the next page.
Here is the code for uploading to firebase:
const uploadImage = async () => {
const blob = await new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
xhr.onload = function () {
resolve(xhr.response);
};
xhr.oneerror = function () {
reject(new TypeError('Network request failed'));
};
xhr.responseType = 'blob';
xhr.open('GET', image, true);
xhr.send(null);
});
const ref = firebase.storage().ref().child('/ankit/');
const snapshot = ref.put(blob);
snapshot.on(
firebase.storage.TaskEvent.STATE_CHANGED,
() => {
setUploading(true);
},
(error) => {
setUploading(false);
console.log(error);
blob.close();
},
() => {
snapshot.snapshot.ref.getDownloadURL().then((url) => {
setUploading(false);
console.log('downlaod url', url);
return url;
});
}
);
};
And here is the code for retrieving:
const [Image, setImage] = useState(false);
let imageRef = firebase.storage().ref('/ankit/');
imageRef
.getDownloadURL()
.then((url) => {
setImage({ profileimageUrl: 'url' });
})
.catch((e) => console.log('getting downloadURL of image error => ', e));
return (
<View>
<Image source={this.state.profileImageUrl}></Image>
</View>
)
You should refactor the code that shows the image. You are using the new hooks state to store the state but try to use it in the html with the syntax of the old react state syntax. This is how it should be:
const [image, setImage] = useState(false);
useEffect(() => {
let imageRef = firebase.storage().ref('/ankit/');
imageRef
.getDownloadURL()
.then((url) => {
setImage(url);
})
.catch((e) => console.log('getting downloadURL of image error => ', e));
},[])
return (
<View>
<Image src={image}></Image>
</View>
);

Converting an Image url to base64 in Angular

I am struggling trying to convert a given image url to base64... in my case i have a String with the image's path
var imgUrl = `./assets/logoEmpresas/${empresa.logoUrl}`
how can i convert the given image url in a base64 directly?... i tried this post.
Converting an image to base64 in angular 2
but this post is getting the image from a form... how can i adapt it?
You can use this to get base64 image
async function getBase64ImageFromUrl(imageUrl) {
var res = await fetch(imageUrl);
var blob = await res.blob();
return new Promise((resolve, reject) => {
var reader = new FileReader();
reader.addEventListener("load", function () {
resolve(reader.result);
}, false);
reader.onerror = () => {
return reject(this);
};
reader.readAsDataURL(blob);
})
}
Then call it like this
getBase64ImageFromUrl('your url')
.then(result => testImage.src = result)
.catch(err => console.error(err));
works like charm in pdfMake and angular
You can use this function to create generate a base64 image
toDataURL = async (url) => {
console.log("Downloading image...");
var res = await fetch(url);
var blob = await res.blob();
const result = await new Promise((resolve, reject) => {
var reader = new FileReader();
reader.addEventListener("load", function () {
resolve(reader.result);
}, false);
reader.onerror = () => {
return reject(this);
};
reader.readAsDataURL(blob);
})
return result
};
and then call it like this
imageSrcString = await this.toDataURL(imageSrc)
If we're doing this in Angular, we may as well make use of HttpClient and a Service.
Let's go ahead and add the HttpClientModule into our related Module, we'll need this in order to use HttpClient.
#NgModule({
imports: [HttpClientModule],
...
})
export class AppModule {}
Then let's create a generic Image Service, and then ask Angular to inject the HttpClient into our Service.
#Injectable()
export class ImageService {
constructor(private http: HttpClient) { }
}
Once that's done we can actually create our function in our service
imageUrlToBase64(urL: string) {
return this.http.get(urL, {
observe: 'body',
responseType: 'arraybuffer',
})
.pipe(
take(1),
map((arrayBuffer) =>
btoa(
Array.from(new Uint8Array(arrayBuffer))
.map((b) => String.fromCharCode(b))
.join('')
)
),
)
}
When we use http.get and provide arraybuffer as our response type, Angular interprets the body of our request as an ArrayBuffer. What that means is that we'll now have our image as an array of bytes. All we need to do is then convert our ArrayBuffer to a base64 string. If you'd like to view alternative options, this SO Question has good answers.
// taken from above
map(
btoa(
Array.from(new Uint8Array(arrayBuffer))
.map((b) => String.fromCharCode(b))
.join('')
)
)
Now that the function is done, we can shift to usage:
#Component()
export class AppComponent {
base64Image: string;
constructor(private imageService: ImageService) {
this.imageService.imageUrlToBase64('https://picsum.photos/200/300').subscribe(
base64 => {
this.base64Image = base64
})
}
}
We'll now have access to the image as a base64

How to pipe a readable stream into a URL.createObjectURL without waiting for the whole file?

I know it's doable with mediaSource but media source doesn't support all video formats (like fragmented mp4 for example). Which is a problem because my application doesn't have a server that can fix the file. It's a client side application only.
const blob = await ipfs.getBlobFromStream(hash)
const url = URL.createObjectURL(blob)
this.setState({...this.state, videoSrc: url})
const getBlobFromStream = async (hash) => {
return new Promise(async resolve => {
let entireBuffer
const s = await stream(hash)
s.on('data', buffer => {
console.log(buffer)
if (!entireBuffer) {
entireBuffer = buffer
}
else {
entireBuffer = concatTypedArrays(entireBuffer, buffer)
}
})
s.on('end', () => {
const arrayBuffer = typedArrayToArrayBuffer(entireBuffer)
const blob = new Blob(arrayBuffer)
resolve(blob)
})
})
}
this is the code i'm using right now, which basically waits for the entire file and puts it in a single array and then into a blob and then into URL.createObjectURL
You can do it in which you restructure your code:
await ipfs.startBlobStreaming(hash);
this.setState({...this.state, videoComplete: true});
const startBlobStreaming = async (hash) => {
return new Promise(async (resolve) => {
let entireBuffer;
const s = await stream(hash);
s.on('data', buffer => {
if (!entireBuffer) {
entireBuffer = buffer;
} else {
entireBuffer = concatTypedArrays(entireBuffer, buffer);
}
const arrayBuffer = typedArrayToArrayBuffer(entireBuffer);
const blob = new Blob(arrayBuffer);
const url = URL.createObjectURL(blob);
this.setState({...this.state, videoSrc: url});
});
s.on('end', _ => resolve())
});
}
I dont know how intensive the buffers are come into s.on but you could also collect a amount of buffer in a certain time(e.g. 1000ms) and then create the blob url.

how can i download a video mp4 file using node.js?

I want to let users download a video from my AWS S3 bucket. The video format is MP4:
app.get("/download_video", function(req,res) {
filename = "s3.xxx.amazon.com/bucketname/folder/video_example.mp4";
// im stuck on what i can do here
});
There are a lot of examples on how to download images and textfiles online using nodejs, but I can't find anything on videos.
use strict
const Fs = require('fs')
const Path = require('path')
const Listr = require('listr')
const Axios = require('axios')
function one (tasks) {
tasks.run()
.then(process.exit)
.catch(process.exit)
}
if (process.argv) {
const tasks = [{
title: 'Downloading',
task: async (ctx, task) => {
const url = 'https://s3.xxx.amazon.com/bucketname/folder/video_example.mp4"'
const path = Path.resolve(__dirname, 'media', 'video.mp4')
const response = await Axios({
method: 'GET',
url: url,
responseType: 'stream'
})
response.data.pipe(Fs.createWriteStream(path))
return new Promise((resolve, reject) => {
response.data.on('end', () => {
resolve()
})
response.data.on('error', err => {
reject(err)
})
})
}
}]
one(new Listr(tasks))
}
Try this
const fetch = require('node-fetch');
const fs = require('fs');
const response = await fetch(yourUrl);
const buffer = await response.buffer();
fs.writeFile(`./videos/name.mp4`, buffer, () =>
console.log('finished downloading video!'));
Third-party modules are no longer needed as of Node.js v18.
import { createWriteStream } from 'node:fs';
import { Readable } from 'node:stream';
const videoFileUrl = 'https://sveltejs.github.io/assets/caminandes-llamigos.mp4';
const videoFileName = 'video.mp4';
if (typeof (fetch) === 'undefined') throw new Error('Fetch API is not supported.');
const response = await fetch(videoFileUrl);
if (!response.ok) throw new Error('Response is not ok.');
const writeStream = createWriteStream(videoFileName);
// Reference https://stackoverflow.com/a/66629140/12817553
const readable = Readable.fromWeb(response.body);
readable.pipe(writeStream);
await new Promise((resolve, reject) => {
readable.on('end', resolve);
readable.on('error', reject);
});

Categories