0

Is it possible to reference a React App that is running on another server using <img src="https://www.react_app.com">

The idea is that the React App returns an image string (or similar) like this: data:image/png;base64,iVBORw0KGgoAAAANSUhEUgA ... So that it can be read in a <img src=""> tag? The main question is what React code simply sends back a request with the string so that it can be read in src=""?

Also is there a timeout for how long an <img src=""> attempts to fetch an image?

React component imports

import React, { useCallback, useEffect, useState, useRef } from 'react'
import classNames from 'classnames'
import { fabric } from 'fabric'
import fabricConfig from './fabricConfig'
import FileUploader from './components/FileUploader'
import ColorPicker from './components/ColorPicker'
import Checkbox from './components/Checkbox'
import Button from './components/Button'
import getRatio from './utils/getRatio'
import getInitialCanvasSize from './utils/getInitialCanvasSize'
import getImageFromURL from './utils/getImageFromURL'
import resizeCanvas from './utils/resizeCanvas'
import removeSelectedElements from './utils/removeSelectedElements'
import getCanvasObjectFilterRGB from './utils/getCanvasObjectFilterRGB'
import setAttributes from './utils/setAttributes'
import { Z, Y, DELETE } from './utils/constants'

Fetch image from URL and automatically make changes to it on load

const imageUrl = "www.something.com/image"

if (imageUrl) {
      new Promise(resolve => fabric.loadSVGFromURL(imageUrl, (objects, options) => {
        const group = new fabric.Group(objects)
        resolve(getRatio(group, canvas))
      }))
      .then(({ ratio, width, height }) => {
        fabric.loadSVGFromURL(imageUrl, (objects, options) => {
          try {
            objects.forEach(obj => {
              setAttributes(obj, {
                left: (obj.left * ratio) + ((canvas.width / 2) - ((width * ratio) / 2)),
                top: (obj.top * ratio) + ((canvas.height / 2) - ((height * ratio) / 2)),
              })
              obj.scale(ratio)
              // MAKE EDITS TO THE SVG OBJECT HERE
              canvas.add(obj)
            })
            canvas.renderAll()

            // HERE I AM TRYING TO SAVE THE CANVAS STATE AND SEND IT BACK TO THE THIRD PARTY WEBSITE USING GET PARAMETERS
            var canvasImg = ''
            if(urlParams.get("export") === "png"){
              canvasImg = canvas.toDataURL("image/png")
            } else if (urlParams.get("export") === "pdf") {
              canvasImg = canvas.toDataURL("image/pdf")
            } else {
              onCanvasModified(canvas)
            }
          } catch(err) {
            console.log('Could not retrieve that image')
          }
        })
      })
Alien13
  • 558
  • 3
  • 8
  • 30
  • 2
    you can fetch an image, however, React is essentially a front-end framework, when you build the project, it just compiles into regular HTML, CSS, and JS. It doesn't really "listens to" and "serve" (you've mentioned sends back, which is the same thing) requests. you can't fetch an image from React. but you can use node.js or any other server-side language to do so. – Aniket Kariya Apr 23 '21 at 16:53
  • How do I transfer an image that is created in a React app to node so that it, in turn, can serve that image? – Alien13 Apr 24 '21 at 09:27
  • so you're using fabric.js to work with images. then I assume you know about saving images with `canvas.toDataURL()`. Now, instead of downloading the image, you can store the return value inside a variable and send the image data to the node server using POST request using fetch/axios. – Aniket Kariya Apr 24 '21 at 10:16
  • Yes that is right I am using canvas.toDataURL() in my component to generate the image. I am storing the return value in a variable that I have named `canvasImg` just like this: `canvasImg = canvas.toDataURL("image/png")` how do I proceed from here and send the image to a node server? And how do I proceed from sending the image to the node server to serving it to the third party webpage, through the `` tag? – Alien13 Apr 24 '21 at 10:32
  • can you update the question with a bit of a code so that I can set up a react project on my side the same as yours and make necessary changes to give you an example? there are multiple libraries for fabric -- fabric-webapp, fabric-client, etc and docs doesn't really contain any "installation & getting started" guide... – Aniket Kariya Apr 24 '21 at 10:42
  • Sure, good idea. – Alien13 Apr 24 '21 at 10:47
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/231542/discussion-between-aniket-kariya-and-alien13). – Aniket Kariya Apr 24 '21 at 10:49

2 Answers2

1

What you want is a CDN, which serves image assets via a GET request (the img src accepts a string which it uses to fetch (GET) content). In short, a CDN serves the application with assets -- be it images, javascript, CSS or HTML. A React application is designed to update content in place via manipulating a virtual DOM; therefore, expecting it to serve assets across domains is anti-pattern. Instead, you would use a custom server (like express) or a web server (like nginx) to serve static assets.

As a simple example, imgur.com would the React application, while i.imgur.com would be their CDN to serve images like this and s.imgur.com would be their CDN to serve CSS/JS assets like this.

This answer goes into more detail how to do it; HOWEVER, this is only one of many, many ways on how accomplish the above, but the concept is still the same: Making a request to retrieve an image via an img src string.

I hesitate to provide full example code since I have no idea what stack you're working with and what your knowledge/comfort-level is regarding backend services. As such, if you want practice consuming a request that serves images on the frontend, then I'd recommend you start with this API service.


Example

Here's one of many ways to do it: Example Repo

To run the example...

1.) Clone the repo: git clone git@github.com:mattcarlotta/save-canvas-example.git

2.) Install dependencies: yarn or npm i

3.) Run yarn dev or npm dev

4.) Click one of the buttons to either save an image as PNG or as a PDF

The example includes quite a bit of notes, but to provide a brief:

  • User clicks button. File Ref
  • Depending on the clicked button, the canvas is converted to a Blob, which is then converted to a File. File Ref
  • This file is then sent (via POST) to an image microservice running at http://localhost:4000 listening for requests to /upload-file. File Ref
  • The microservice sees the request and directs to our middleware functions. File Ref
  • Then it directs it to the /upload-file controller. File Ref
  • The controller determines if the file upload was valid (in the middleware), if not it throws an error. File Ref
  • When valid, the file details are generated from req.file (this comes from our multer middleware function), a directory is created and a file is saved to that directory. File Ref
  • A filepath is then sent back to the client. File Ref
  • Client receives filepath from image microservice and sets it to state. File Ref
  • Client then renders a shareable link, a link to view the file, and a preview. File Ref

Results

Save PNG: enter image description here

Save PDF: enter image description here


Flow Diagram enter image description here

Matt Carlotta
  • 18,972
  • 4
  • 39
  • 51
  • Thank you Matt, I am using React to create an app where I am using the Fabric JS library to automatically process an image based on a set of instructions, inside of a Canvas component, the finished image I would like to serve back to the site the user is on. I currently work with a very simple stack. Just to paint the right picture one can imagine that my product looks like the demo under this link, http://fabricjs.com/image-filters. I have a low comfort level with backend services and would appreciate some child-friendly explanations. Thanks! – Alien13 Apr 24 '21 at 09:24
  • Upon request, I have also added the important snippets from my code, related to this question. – Alien13 Apr 24 '21 at 14:00
  • I'll let Aniket help you first. If you still need help, post a github example repo with the just the code relevant to the question (no styles or other components that aren't relevant to reproduce the above). – Matt Carlotta Apr 24 '21 at 15:30
  • Aniket hasn't answered yet, so I created this repo (stripped of all styles and other features) to better describe the problem that I am dealing with https://github.com/MaxHXie/fabricjs-editor-export-image I will also add some more README to make the question more poignant – Alien13 Apr 25 '21 at 09:32
  • Updated answer to include a working example of your code. – Matt Carlotta Apr 25 '21 at 20:28
  • Thanks for this answer Matt, I will have a close look at it soon – Alien13 Apr 28 '21 at 15:11
  • Do you think that the requestor of the image can pass parameters through the URL which serves as instructions on how to modify the response image? For example width=100&height=100 ? Even better if it is possible to apply Fabric JS methods to modify an image, kind of like this? https://stackoverflow.com/questions/13859389/using-fabric-js-to-render-and-manipulate-server-side-canvas-in-node-js – Alien13 Apr 28 '21 at 15:16
  • Yes. The point of the example was to simplify it to button clicks. Nevertheless, you can use query parameters to adjust the image before it gets saved as long as the queries are normalized/sanitized. You wouldn't want the query to crash your application when an invalid query is present. On that note, with a bit of tweaking, you can also pass these queries to the microservice as well and use a more robust image processor like [sharp](https://www.npmjs.com/package/sharp). – Matt Carlotta Apr 28 '21 at 15:27
  • If you want post-processing, then you’ll need to reconfigure the micro service routes to send back processed files. However, that’s beyond the scope of your original question (sending back a string). – Matt Carlotta Apr 28 '21 at 15:32
  • Thank you Matt, this is very interesting, I feel like I need to upgrade my understanding and mind model to gain a better intuition when dealing with backend conundrums, do you happen to know any good material (book or internet)? – Alien13 Apr 29 '21 at 16:19
  • Most of my learning came from trial/error and reverse engineering other projects over many years; however, you may be able to find some courses through [udemy](https://www.udemy.com/courses/development/web-development/). I'd hesitate to recommend any particular course because you'll often find the "Fullstack" course will be heavily focused on the client than on the back-end. – Matt Carlotta Apr 29 '21 at 17:16
  • Added a diagram to the answer. This should make it easier to understand the overall flow. Start from `localhost:3000` and follow the arrows. Once you understand the flow, you can pretty much plug it into any back-end service. – Matt Carlotta Apr 30 '21 at 03:58
  • Oh nice, I will dig my eyes into this momentarily, thank you Matt! – Alien13 Apr 30 '21 at 19:32
1

I've tried to reproduce the project with minimal features. user can add and interact with rectangle and save the image. upon saving it would go to the server and the image data will be stored in a JSON file.

Here's the link to frontend: https://codesandbox.io/s/so-fabric-client-5bjsf

As you have mentioned, there are two different react apps; I've created two routes, /draw where the user can draw the image and /images where I fetch the images. you can consider these two routes as different react projects since the logic remains the same regardless of their origin.

On the backend side, for demonstration purposes and simplicity, I've used a JSON file and sending all the file content in response when the application wants to display the images. It could become problematic once there are hundreds of images or when you want to search them by the user. so consider using a database or any other method.

here's the backend code:

const express = require("express");
const path = require("path");
const fs = require("fs");

const app = express();
const PORT = process.env.PORT || 3000;

app.use(express.static(path.join(__dirname + "/build")));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());

app.post("/save-image", (req, res) => {
    const image = req.body.image
    
    fs.readFile('images.json', function (err, data) {
        if(err) {
            console.log(err)
            res.status(500)
        }
        
        var json = JSON.parse(data)
        json.push({id: json.length, image})
    
        fs.writeFile("images.json", JSON.stringify(json), (err, result) => {
            if(err) console.log(err);
        })
    })

    res.status(200);
})

app.get("/get-images", (req, res) => {
    res.json(JSON.parse(fs.readFileSync("./images.json")))
})

app.listen(PORT, () => {
    console.log(`up and running on port ${PORT}`);
})

images.json is just a file with [] as its content. the code is pretty much self-explainatory, I've uploaded all the code on GitHub as well -- so-fabric-demo and you can check the demo on Heroku

Aniket Kariya
  • 1,471
  • 2
  • 21
  • 26