Home > other >  How do I display a byte array image from a backend that uses AWS S3, in a React component?
How do I display a byte array image from a backend that uses AWS S3, in a React component?

Time:01-05

I am trying to display an image stored in AWS from the SpringBoot API backend, using React. The response I get from the server when doing the fetch below is:

  ‰PNG


IHDRäX³N•jsRGB®ÎégAMA±üa    pHYs.#.#x¥?vf/IDATx^íÝ|]wyÿqï!Ë–eÙ–myÊ#vlg'„=É2«u M¡@hšBÛ?´Ð2úé eh˜„$$…ã@2IÂÊ"‹loËS–lI–,K¶¼þÏ÷ÜóK99’îÒ½çJŸ÷ëõ¼î¹º×¶|ÇyÎo=¿A²18¼Pš.³—:Ôjñ‹Ô!(¤W-Ž„ñ’~ 4
    o@‘H2   @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !$d€„@H2  @B HÈ$  € !
§øc‹±žõãÿø篿þz­Ô=}……ª|Ž÷
}6´ÌŠ®lèJ®J²ÝuMk‰Œê%Ÿe1`¨e|ùå—?tå•W~;üÑ@¡Õײ(½÷qŸ   }VþÈ"Ÿ»oÀ€¦¥1O[Ät5QKu‘U[yÀùú׿^}Ægì¾è¢‹ž²ä<PæüÜ"îó¡PkZKÚ€DãÊI6ßâÇÚÊO“{|JÄ?³ÐæÚB3rœ;v,mmm×ÑÑqô·¾õ­ºFW3çµ|MŸ%f}6|
etc

I thought that I had to convert it into a blob as below but the image is not appearing on the profile.

Profile.js:

const GET_SINGLE_USER_URL = 'http://localhost:8080/users/get-user-by-username'
const USER_IMG_URL = 'http://localhost:8080/image-files/'
class Profile extends Component {

    constructor(props) {
        super(props);
        this.state = {user: '', token: '', img: ''};
    }


    componentDidMount() {
        const imgUrl = USER_IMG_URL   localStorage.getItem("username");
        const payload = {
            "username": localStorage.getItem("username"),
            "password": localStorage.getItem("password")
        };
        fetch(GET_SINGLE_USER_URL, {
            method: 'POST',
            headers: {
                "Accept": "application/json",
                "Content-Type": "application/json",
                "Authorization": localStorage.getItem("token")
            },
            body: JSON.stringify(payload)
        })
            .then(response => response.json())
            .then(data => this.setState({user: data}));

        fetch(imgUrl, {
            method: 'GET',
            headers: {
                "Authorization": localStorage.getItem("token")
            }
        })
            .then(r => r.arrayBuffer())
            .then(buffer => { 
                const blob = new Blob([buffer]);
                this.state.img = URL.createObjectURL(blob);
            });

    }
    render() {
        const {user, img, isLoading} = this.state;

        if (isLoading) {
            return <p>Loading...</p>;
        }

        return (
            <div className="outer-div-container">
            <div>
                <AppNavbar/>
                <Container fluid>
                    <div id="flexbox-container">
                    <div className="card-container" id="profile-card-container">
                    <Card className="profile-card">
                        <CardImg src={img} />
                        <CardText className="profile-data">{user.name}</CardText>
                        <CardText className="profile-data">{user.username}</CardText>
                        <CardText className="profile-data">{user.location}</CardText>
                    </Card>
                    </div>
                    </div>
                </Container>
            </div>
            </div>

I am unsure how to convert the byte array into a displayable image in the React component.

Any help would be greatly appreciated, thanks.

I also tried:

async getImage() {
        const imgUrl = USER_IMG_URL   localStorage.getItem("username");
        fetch(imgUrl,{
            method: 'GET',
            headers: {
                "Authorization": localStorage.getItem("token")
            }
        })
            .then(response => response.json())
            .then(data => {
                console.log(data)
                this.setState({
                    image: "data:image/png;base64,"   data
                })
            })
        console.log(this.state.image) // *1
    }

And now it says unexpected JSON input on the 'PNG' line of response.

Also, when I upload a jpeg instead I get 'ÿØÿàJFIFHHÿÛ'

CodePudding user response:

This approach downloads the image, gets the byte array, converts it to a Blob and stuffs the binary data into a magic url you can use for the image source.

const IMAGE_URL = "https://placekitten.com/200/300";

const fetchImage = async (url) => {
  try {
    const response = await fetch(url);
    const imageBytes = await response.arrayBuffer();
    var blob = new Blob([imageBytes], { type: "image/jpeg" });
    var imageUrl = URL.createObjectURL(blob);
    return imageUrl;
  } catch (error) {
    console.log("ERROR:", error);
  }
};

(async () => {
  const imageSrc = await fetchImage(IMAGE_URL);
  console.log(imageSrc);
  document.getElementById("kittenImage").src = imageSrc;
})();

document.getElementById("app").innerHTML = `
<h1>Kitty!</h1>
<image id='kittenImage'>
`;
<!DOCTYPE html>
<html>

<head>
    <title>Parcel Sandbox</title>
    <meta charset="UTF-8" />
</head>

<body>
    <div id="app"></div>

    <script src="src/index.js">
    </script>
</body>

</html>

CodePudding user response:

You can embed the image response as a data URL in the src attribute of an img tag.

Convert an ArrayBuffer to a data URL:

export function toDataURL(img:ArrayBuffer, contentType:string) {
    const image = btoa(
        new Uint8Array(img)
            .reduce((data, byte) => data   String.fromCharCode(byte), '')
    );
    return `data:${contentType};base64,${image}`;
}
  •  Tags:  
  • Related