How to crop image in React Native - javascript

I'm using react-native-camera to take photos. The taken photos are 16/9 ratio but I need them in 4/3.
Thus what I want is to crop the image to for example 1920*1440.
I use ImageEditor from React Native. The code of ImageEditor can be found here.
My code is as follows :
this.camera.capture(target)
.then((data) => {
let cropData = {
offset:{x:0,y:0},
size:{width:1920, height:1440}
};
ImageEditor.cropImage(
data.path,
cropData,
(uri) => {
this.props.captured(this.props.request, {
path: uri,
data: data.data,
longitude: position.coords.longitude,
latitude: position.coords.latitude
}
);
Actions.pop();
},
(error) => {});
})
.catch(err => {
console.error(err)
});
But the code above doesn't work. The saved photo isn't cropped and it is 1440*2560.
Any advice?

It's not entirely clear what happens with your code in captured(), but I think the problem is that you're passing the original data to this.props.captured. My understanding from the docs is that:
If the cropping process is successful, the resultant cropped image will be stored in the ImageStore, and the URI returned in the success callback will point to the image in the store.
So instead of reusing data, you should be reading the cropped image from uri

Related

Crop image to variable in react

I'm creating an app that detects faces and classifies faces' ethnicity using 2 Clarifai APIs. The issue is ethnicity classifier can only do 1 face for 1 photo. My solution is cropping the faces by face detection and then separately classify each face's ethnicity.
Then I got stuck with an idea: I want to crop the face by the coordination provided by the face detection and save the faces to variables, so I can use ethnicity classifier for each face.
I would love to receive some help from you guys. Thank you.
Here is the code of my issue
this.setState({imageURL: this.state.input});
app1.models
.predict(
{
id: 'ethnicity-demographics-recognition',
name: 'appearance-multicultural',
version: 'b2897edbda314615856039fb0c489796',
type: 'visual-classifier',
},
this.state.input
)
.then((response) => console.log('ethnic',response))
.catch((err) => {
console.log("Clarifai Error:", err);
});
app2.models
.predict(
{
id: 'face-detection',
name: 'face-detection',
version: '6dc7e46bc9124c5c8824be4822abe105',
type: 'visual-detector',
}, this.state.input)
.then((response) => {
const regions = response.outputs[0].data.regions;
const box = [];
regions.forEach(region => {
box.push(this.calculateFaceLocation(region))
});
this.displayFaceBox(box);
})
.catch((err) => {
console.log("Clarifai Error:", err);
});
I looked up some solution like HTML canvas and react-image-crop, but I am still unable to save the faces as variables.

Highcharts-React Get Base64 PNG of chart

I'm looking to pass a chart export to a component that specifically requires PNG or JPG- so an SVG will unfortunately not work.
With the help of other SO answers- I was able to get the SVG Base64 using the following code:
let link = "data:image/svg+xml;base64," + btoa(this.lineChartRef.current.CHART.current.chart.getSVG());
Is there a way I can get the PNG base64? Or is there an efficient way within React to convert this SVG base64 to a PNG?
Thanks!!!
Thanks to #ppotaczek for his forwarding of [this SO post][1], I was able to create the following solution for React. Hopefully it will help someone else in the future!
//Start by calling the chart options (using refs) into a variable and JSON stringify
let chartoptions = this.lineChartRef.current.BrokerChart.current.chart.userOptions
chartoptions = JSON.stringify(chartoptions)
//Create a data body with the following parameters
let data = {
options: chartoptions,
filename: 'LineChart',
async: true
}
let url = "https://export.highcharts.com/"
let returnedimageurl = ""
//setState will be called within the Axios return so "This" must
let self = this
axios({
method: 'post',
url: 'https://export.highcharts.com/',
data: data,
})
.then(function (response) {
returnedimageurl= url +response.data
self.setState({
activityChartPng: url
}, self.allowDownload())
})
.catch(function (response) {
//handle error
console.log(response);
});
//The activityChartPvg state can then be passed as props to the React-PDF component
[1]: https://stackoverflow.com/questions/54761784/highcharts-export-multiple-charts-using-jspdf

React get and show attached files in Rails

seems a simple problem but, i don't know why this is causing a little stress, anyway.
here is situation:
after get the attachments on the Post.show in rails
async getAttachments() {
// this.setState({showProgress: true})
let auth_token = window.localStorage.getItem("auth_token");
let post_id = this.props.match.params.id;
fetch(`/posts/${post_id}/attachments`, {
method: "GET",
headers: {
Accept: "application/json",
"Content-Type": "application/json",
Access: auth_token
}
})
.then(response => response.json())
.then(json => {
this.setState({
attachments: json.attachments,
image: json.attachments.image,
thumb: json.attachments.image.thumb,
url: json.attachments.thumb.url
});
})
.catch(error => {
console.error(error);
});
}
i decide to render it as usual
with {this.state.attachments}
but did not rendered.
so i tried to map and then i tried
var attachments = this.state.attachments.map(a => {
return (
<div key={a.id}>
<img source={a.thumb} />
<img source={a.url}>{a.url}</img>
</div>
);
});
the thing is ever rails carrierwave attachment/files. create a object inside the array and many people still have doubt how to grab and render these files.
The HTML image tag uses an attribute named src, not source. That's your problem.
Aside: Consider this snippet of your code:
this.setState({
attachments: json.attachments, // OK, keep
image: json.attachments.image, // bad path into the object
thumb: json.attachments.image.thumb, // bad path into the object
url: json.attachments.thumb.url // bad path into the object
});
The three lines starting with image, thumb, and attachment should be deleted.
The result of using the code without deleting those lines will be that your state looks like:
{
attachments: <an array of attachments>, // correct, wanted, should keep
image: undefined,
thumb: undefined,
url: undefined
}
This is because json.attachments is an array so it does not have any data at the paths you are calling. By "path into the object" I merely mean a sequence of keys to call in sequence of dot notation.

Getting geolocation and Sending an Ajax Request in componentDidMount()

I'm trying to call a weather API with coordinates recieved from the user's computer using navigator.geolocation.getCurrentPosition()
My problem is I'm having trouble figuring out the right way to do this given everything is running asyncronously. Then, I thought I came up with a decent work-around using componentDidMount(), but unfortunately it didn't work.
Here's my codepen (sans API key)
And here's the code:
state = {
data: "Please wait while you're weather is loading...",
}
componentDidMount() {
this.state.hasOwnProperty('uri') ?
fetch(this.state.uri).then((res) => res.json())
.then((data) => this.setState({
data: {
tempString: data.current_observation.temperature_string,
realTemp: data.current_observation.feelslike_string,
skyImg: data.current_observation.icon_url.substring(0, 4) + 's' + data.current_observation.icon_url.substring(4),
location: data.current_observation.display_location.full,
temp_f: data.current_observation.temp_f,
}
}))
.catch((err) => console.log(err.message))
: navigator.geolocation.getCurrentPosition((pos) => {
this.setState({
uri: "https://api.wunderground.com/api/{API GOES HERE}/conditions/q/" + pos.coords.latitude.toString() + "," + pos.coords.longitude.toString() + ".json"
})
console.log(this.state.uri)
})
}
My understanding of how everything is running is as follows:
Initial component renders
componentDidMount() is called and takes a look at the if statement
can't find the URI property, so starts the getCurrentPosition() call, setting state with the new URI property (to my knowledge, this.setState should trigger a re-render, and then...)
componentDidMount() runs again, but this time finds the URI property
for some unknown reason, fetch() isn't running
Though I'm not sure, my best guess is although there is now URI property, by time the new componentDidMount() runs, the program is still in the process of figuring out what to set it as. But I might be completely wrong. I could've also created an infinite loop where componentDidMount() never sees a URI property and continuously re-renders.
As #brub said: componentDidMount doesn't run more than once, no matter how much the ui is updated. I ended up using componentDidUpdate as a solution. Here's the code now:
state = {
data: "Please wait while you're weather is loading...",
}
componentDidMount() {
navigator.geolocation.getCurrentPosition((pos) => {
this.setState({
uri: "https://api.wunderground.com/api/{API GOES HERE}/conditions/q/" + pos.coords.latitude.toString() + "," + pos.coords.longitude.toString() + ".json"
})
})
}
componentDidUpdate() {
fetch(this.state.uri).then((res) => res.json())
.then((data) => this.setState({
data: {
tempString: data.current_observation.temperature_string,
realTemp: data.current_observation.feelslike_string,
skyImg: data.current_observation.icon_url.substring(0, 4) + 's' + data.current_observation.icon_url.substring(4),
location: data.current_observation.display_location.full,
temp_f: data.current_observation.temp_f,
}
}))
.catch((err) => console.log(err.message))
}

File upload blocking with bigger files

Intro
What I'm trying to achieve is a simple file upload with a progress indication with redux-saga and react). I'm having problems getting this indication because the file upload seems the be blocking - which it shouldn't be.
Expected behaviour
before the file upload starts a re render is triggered and the spinner is shown and the window is not blocked.
Current behaviour
What I have at the moment is a component with a table that show a file per row. A optimistic row gets added with a spinner as the content when the users uploads a file. As soon as the file is uploaded the optimistic row will be replaced by a real row with the file's name etc. When I'm uploading a file around 50MB the window gets blocked and shortly before the file is uploaded (around 0.5s before) the spinner appears and then the file is already uploaded and the spinner disappears again.
side notes
If you replace the file upload with new Promise(res => setTimeout(res, 5000)) it all works fine => it seems like there is a problem with the xhr / fetch.
I've implemented the same using XHR, promises and an onProgress callback to make sure the problem is not fetch.
the implementation looks very close to: https://gist.github.com/robinfehr/2f4018259bf026a468cc31100fed5c9f
Also with this implementation I've experienced the same issue - blocking until almost the end of the upload.
If I put log statements into the render function of the component to see if it's getting re rendered before the file is uploaded, I see (as soon as the block stops and the file is uploaded) that the log statements in the render function are actually correctly triggered with a timestamp before the file upload was done.
In this implementation I'm using the same reducer: optimistic event as well as the real event that reverts the optimistic event, they go trough the same reducer (named fileReducer here).
using a second reducer and concatination instead of the optimistic revert logic helps to displaying the spinner earlier but does not help with the blocking. It therefore seems like the middleware also gets blocked by the blocking call.
saga: (postData uses fetch)
function* createDocument(partnerId, { payload, meta }) {
const siteId = getSiteIdFromRoute();
const {
mediaGroupId,
customArticleId,
logicalComponentId,
type,
name,
documentSrc,
meta: metaFromFrontEnd
} = payload;
const commonEventId = uuid();
const hans = {
optimistic: true
};
const payloadBasic = {
id: commonEventId,
version: 0,
aggregate: {
id: uuid(),
name: 'document'
},
context: {
name: 'contentManagement'
},
payload: {
name,
type,
links: {
partnerId,
siteId,
logicalComponentId,
customArticleId,
mediaGroupId
}
}
};
// creates the optimistic (fake) row with a spinner in the file list component - action marked as optimistic which will be reverted.
yield put(actions.denormalizeEvent({
...payloadBasic,
name: 'documentCreated',
optimistic: true,
payload: {
...payloadBasic.payload,
uploading: true
}
}));
yield fork(executeDocumentUpload, type, siteId, partnerId, documentSrc, payloadBasic);
}
function* executeDocumentUpload(type, siteId, partnerId, documentSrc, payloadBasic) {
const req = yield call(uploadDocument, type, siteId, partnerId, documentSrc);
const body = yield req.json();
const { meta: metaFromFileUpload, id } = body.response;
// removes the optimistic (fake) row from the file list component and and adds the real row with more file information (optimistic event gets reverted in middleware)
yield put(actions.sendCommandSuccess({
...payloadBasic,
name: 'createDocument',
payload: {
...payloadBasic.payload,
meta: metaFromFileUpload
}
}));
}
function uploadDocument(type, siteId, partnerId, documentSrc) {
let url;
if (type === 'site' || type === 'mediaGroup' || type === 'logicalComponent') {
url = `/file/site/${siteId}/document`;
} else if (type === 'customArticle') {
url = `/file/partner/${partnerId}/document`;
}
return postData(url, documentSrc);
}
The problem was that I did send the file as a base64 encode string and set up the request with the wrong content-type.
'Content-Type': 'text/plain;charset=UTF-8'
putting the file into a FormData object and send the request without the mentioned content-type lead to a non-blocking request.

Categories

Resources