I created a react app for a tutorial and it writes text over an uploaded image. The user after image upload types in Top Box
and Bottom Box
but when I try to save the image after the user has typed text, no text shows up. Can anyone please help as I want the image to be downloaded with text.
The files are Header.js
with code:
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import CardMedia from '@material-ui/core/CardMedia';
import { withStyles } from '@material-ui/core/styles';
import CardActionArea from '@material-ui/core/CardActionArea';
import { Card, CardContent } from "@material-ui/core";
import IconButton from '@material-ui/core/IconButton';
import PhotoCamera from '@material-ui/icons/PhotoCamera';
const styles = theme => ({
media: {
display: 'flex',
height: 400,
objectFit: 'contain',
alignItems: 'center',
},
})
class Header extends Component {
render() {
const {classes} = this.props;
return(
<Card >
<CardContent >
<div style={{position:'relative'}}>
<CardMedia
component="img"
image = {this.props.imageIn}
/>
<div style={{position: 'absolute', color: 'white', top: '5%', left: '50%', transform:'translateX(-50%)'}}>
{this.props.topText}
</div>
<div style={{position: 'absolute', color: 'white', bottom: '5%', left: '50%', transform:'translateX(-50%)'}}>
{this.props.bottomText}
</div>
</div>
</CardContent>
</Card>
);
}
}
export default withStyles(styles)(Header)
and App.js
as:
import React, {Component} from 'react';
import logo from './logo.svg';
import './App.css';
import CardMedia from '@material-ui/core/CardMedia';
import { withStyles } from '@material-ui/core/styles';
import CardActionArea from '@material-ui/core/CardActionArea';
import { Card, CardContent } from "@material-ui/core";
import Header from './Header';
import Grid from '@material-ui/core/Grid';
import TextField from '@material-ui/core/TextField';
import IconButton from '@material-ui/core/IconButton';
import PhotoCamera from '@material-ui/icons/PhotoCamera';
const styles = (theme) => ({
input: {
display: 'none'
}
});
class App extends Component{
state = {
topText: '',
bottomText: '',
randomImg: "http://i.imgflip.com/1bij.jpg",
allImages: [],
images: []
}
handleChange = (event) => {
const {name, value} = event.target
this.setState({ [name]: value })
}
handleCapture = ({ target }) => {
const fileReader = new FileReader();
const name = target.accept.includes('image') ? 'images' : 'videos';
fileReader.readAsDataURL(target.files[0]);
fileReader.onload = (e) => {
this.setState((prevState) => ({
[name]: [...prevState[name], e.target.result]
}));
};
};
render() {
return(
<div>
<input
accept="image/*"
style={{display: 'none'}}
id="icon-button-photo"
onChange={this.handleCapture}
type="file"
/>
<label htmlFor="icon-button-photo">
<IconButton color="primary" component="span">
<PhotoCamera />
</IconButton>
</label>
<Grid container justify="left" spacing={8}>
<Grid item xs={12} sm={6}>
<TextField
id="standard-name"
label="Top Text"
name = "topText"
value={this.state.topText}
onChange={this.handleChange}
margin="normal"
variant="filled"
/>
</Grid>
<Grid item xs={12} sm={6}>
<TextField
id="standard-name"
label="Bottom Text"
name = "bottomText"
value={this.state.bottomText}
onChange={this.handleChange}
margin="normal"
variant="filled"
/>
</Grid>
<Header topText = {this.state.topText} bottomText = {this.state.bottomText} imageIn = {this.state.images}/>
</Grid>
</div>
)
}
}
export default App
In your code the texts are distinct elements (childs of the div
's in below code):
<CardMedia
component="img"
image = {this.props.imageIn}
/>
<div style={{position: 'absolute', color: 'white', top: '5%', left: '50%', transform:'translateX(-50%)'}}>
{this.props.topText}
</div>
<div style={{position: 'absolute', color: 'white', bottom: '5%', left: '50%', transform:'translateX(-50%)'}}>
{this.props.bottomText}
</div>
</div>
Rather you may try to incorporate the text into image like:
const canvas = this.refs.canvas;
const ctx = canvas.getContext("2d");
const img = this.refs.image;
img.onload = () => {
ctx.drawImage(img, 0, 0);
ctx.font = "40px Courier";
ctx.fillText(this.props.text, 210, 75); // THIS IS THE PLACE TEXT IS EMBEDDED INTO THE PICTURE
};
In this code sandbox link, https://codesandbox.io/s/blazing-sun-e2bgf , you can find a simple class named Canvas
which uses above method so that when the file is saved you can see the text.
One catch here, the example I provided is free from material UI. You are using CardMedia
class which takes the image and shows it. But in the example I provided, the method is generic. So you can place the image seperately in the card.
Credit: https://blog.cloudboost.io/using-html5-canvas-with-react-ff7d93f5dc76
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With