Can a React app return an image string that can be read into the SRC attribute of a <img> tag? - html

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')
}
})
})

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:
Save PDF:
Flow Diagram

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

Related

How to perform playwright testing framework in NUXT?

Currently I want to perform end-to-end testing for my nuxt project. However , it keep stuck on the rendering side of NUXT project as shown in the image .
Previously , i was able to access the website with the same code. After i restart my computer , i cant access the website anymore and it stuck in the rendering side of NUXT project. Can anyone help me with this ?
browser.spec.ts
import { resolve, join } from 'path'
import { test, expect } from '#playwright/test'
const ROOT_PATH = resolve(__dirname, '..', 'screenshots')
test('testing', async ({ page, baseURL }) => {
// Nuxt app is running and route '/' is showing.
await page.goto(baseURL + '/')
// await expect(page.locator('h2').locator('text= meow')).toBeVisible()
// Step 1 - Ensure It is in home page after login
await page.screenshot({ path: join(ROOT_PATH, 'meow.png')})
})

Problem with Firebase Image Resize extension [duplicate]

I am following a tutorial to resize images via Cloud Functions on upload and am experiencing two major issues which I can't figure out:
1) If a PNG is uploaded, it generates the correctly sized thumbnails, but the preview of them won't load in Firestorage (Loading spinner shows indefinitely). It only shows the image after I click on "Generate new access token" (none of the generated thumbnails have an access token initially).
2) If a JPEG or any other format is uploaded, the MIME type shows as "application/octet-stream". I'm not sure how to extract the extension correctly to put into the filename of the newly generated thumbnails?
export const generateThumbs = functions.storage
.object()
.onFinalize(async object => {
const bucket = gcs.bucket(object.bucket);
const filePath = object.name;
const fileName = filePath.split('/').pop();
const bucketDir = dirname(filePath);
const workingDir = join(tmpdir(), 'thumbs');
const tmpFilePath = join(workingDir, 'source.png');
if (fileName.includes('thumb#') || !object.contentType.includes('image')) {
console.log('exiting function');
return false;
}
// 1. Ensure thumbnail dir exists
await fs.ensureDir(workingDir);
// 2. Download Source File
await bucket.file(filePath).download({
destination: tmpFilePath
});
// 3. Resize the images and define an array of upload promises
const sizes = [64, 128, 256];
const uploadPromises = sizes.map(async size => {
const thumbName = `thumb#${size}_${fileName}`;
const thumbPath = join(workingDir, thumbName);
// Resize source image
await sharp(tmpFilePath)
.resize(size, size)
.toFile(thumbPath);
// Upload to GCS
return bucket.upload(thumbPath, {
destination: join(bucketDir, thumbName)
});
});
// 4. Run the upload operations
await Promise.all(uploadPromises);
// 5. Cleanup remove the tmp/thumbs from the filesystem
return fs.remove(workingDir);
});
Would greatly appreciate any feedback!
I just had the same problem, for unknown reason Firebase's Resize Images on purposely remove the download token from the resized image
to disable deleting Download Access Tokens
goto https://console.cloud.google.com
select Cloud Functions from the left
select ext-storage-resize-images-generateResizedImage
Click EDIT
from Inline Editor goto file FUNCTIONS/LIB/INDEX.JS
Add // before this line (delete metadata.metadata.firebaseStorageDownloadTokens;)
Comment the same line from this file too FUNCTIONS/SRC/INDEX.TS
Press DEPLOY and wait until it finish
note: both original and resized will have the same Token.
I just started using the extension myself. I noticed that I can't access the image preview from the firebase console until I click on "create access token"
I guess that you have to create this token programatically before the image is available.
I hope it helps
November 2020
In connection to #Somebody answer, I can't seem to find ext-storage-resize-images-generateResizedImage in GCP Cloud Functions
The better way to do it, is to reuse the original file's firebaseStorageDownloadTokens
this is how I did mine
functions
.storage
.object()
.onFinalize((object) => {
// some image optimization code here
// get the original file access token
const downloadtoken = object.metadata?.firebaseStorageDownloadTokens;
return bucket.upload(tempLocalFile, {
destination: file,
metadata: {
metadata: {
optimized: true, // other custom flags
firebaseStorageDownloadTokens: downloadtoken, // access token
}
});
});

How would you create a downloadable pdf in a client side app?

One of our requirements for an admin tool is to create a form that can be filled and translated to a downloadable pdf file. (A terms and condition with blank input fields to be exact).
I did some googling and tried creating a form in html and css and converted it into a canvas using the html2canvas package. Then I used the jspdf package to convert it into a pdf file. The problem is that I cannot get it to fit and resize accordingly to an a4 format with correct margins. I'm sure I can get to a somewhat working solution if I spend some time on it.
However, my real question is how would you guys solution this? Is there a 3rd party app/service that does this exact thing? Or would you do all this in the server side? Our current app is using angular 7 with firebase as our backend.
Cheers!
I was able to use the npm package pdfmake to create a dynamic pdf based on user information the user provided while interacting with my form. (I was using React) It opened the pdf in a new tab and the user is able to save the pdf. In another application (still React),
I used the same package to create a receipt so you can customize the size of the "page". We created the pdf and used the getBase64() method and sent the pdf as an email attachement.
My service function:
getEvidenceFile(id: number, getFileContent: boolean) {
return this.http.get(environment.baseUrl + ‘upload’ + ‘/’ + id , {responseType: ‘blob’ as ‘json’})
.map(res => res);
}
My component function called from the selected item of a FileDownload…
FileDownload(event: any) {
// const blob = await this.callService.getEvidenceFile(event.target.value, true);
// const url = window.URL.createObjectURL(blob);
this.callService.getEvidenceFile(event.target.value, true).subscribe(data => {
var binaryData = [];
binaryData.push(data);
var downloadLink = document.createElement(‘a’);
downloadLink.href = window.URL.createObjectURL(new Blob(binaryData));
document.body.appendChild(downloadLink);
downloadLink.click();
});
}

Passing JSON Config into multiple instances of the same bundled React Application

I have several instances of a react-slick carousel. Each of them requires a different set of config options.
Currently, I have the carousel component bundled up via webpack and then deployed to multiple locations. Unfortunately, this means that the bundle is slightly different in each case, as the config file changes the overall bundle! What's the right approach for this solution?
I feel like I can think of the following solutions:
1) Load the config file asynchronously. Seems like a lazy solution, because making an extra round trip is overkill.
2) Try to use require.ensure to split out the config file into it's own chunk.
What's the right approach for this solution?
Thanks!
To reply for point 1, I've managed to accomplish runtime loading of config this way:
import xhr from 'xhr'
class Config {
load_external_config = (cb) => {
xhr.get("config.json", {
sync: true,
timeout: 3000
},(error, response, body)=>{
if(response.statusCode==200) {
try{
const conf = JSON.parse(body);
for(var i in conf) {
this[i] = conf[i];
}
}catch(e){
/* Manage error */
}
} else {
/* Manage error */
}
})
}
}
export let config = new Config();
The class above has two basic functions, on the one hand it is a "singleton", so every time you import it in each file of your project, the istance remain the same and will not be duplicated. On the other hand, through a XHR package it loads (synchronously) an external json file and puts every config voice in its instance as a first level attribute. Later, you will be able to do this:
import { config } from './config'
config.load_external_config();
config.MY_VAR
For point 2 I would like to see some examples, and I will remain tuned to this post for someone more skilled than me.

Prefetch resources for async routes

Is there a way to prefetch or preload async routes? I'm exploring how to do this right now with RR2/3. The basic idea is I code split on every route but I'd like to be able to cache bundles for connected pages in a service worker before visiting that page. So what I'd like to do is have a custom <Link> that every time it's rendered, it tries to cache the resources of the page it's linked to. This would make page transitions considerably faster. What I don't know is if there's a way to emulate navigating to a route so that the resources will be fetched. Is there an API for this or some sort of tricky way to do this someone can think of?
This is what I came up. It's a component that wraps the React Router Link component and in componentDidMount (so only runs on the client not the server) check if in production (no need to run this during development) and if this is a browser that doesn't support Service Workers (this check is specific to my use case). Then manually match against the location and call any async getComponent functions.
import React from 'react'
import Link from 'react-router/lib/Link'
class GatsbyLink extends React.Component {
componentDidMount () {
// Only enable prefetching of Link resources in production and for browsers that
// don't support service workers *cough* Safari/IE *cough*.
if (process.env.NODE_ENV === 'production' && !('serviceWorker' in navigator)) {
const routes = require('my-routes')
const { createMemoryHistory } = require('history')
const matchRoutes = require('react-router/lib/matchRoutes')
const getComponents = require('react-router/lib/getComponents')
const createLocation = createMemoryHistory().createLocation
if (typeof routes !== 'undefined') {
matchRoutes([routes], createLocation(this.props.to), (error, nextState) => {
getComponents(nextState, () => console.log('loaded bundle(s) for ' + this.props.to))
})
}
}
}
render () {
return <Link {...this.props} />
}
}
module.exports = GatsbyLink
You could just do a require.ensure... section in a timeout when the Link is mounted. That should require the code split and load it up async. The timeout will ensure it get's loaded in a separate file.
I would recommend using RR4 for code splitting as I found in RR3 the async required routes get re-included and re-rendered if a child route changes. In my case, I had the componentWillMount of my routes being fired for any child route changes. e.g. Navigating from /agent/step-1 to /agent/step-2 will cause the Component for /agent to be unmounted and re-mounted.