html2canvas not including fetched image in downloaded png - reactjs

I'm trying to use the movie db API to fetch a movie poster and allow the user to put text next to it, then allow them to download that component using html2canvas. The downloaded image works, it has the right colors and text just not the movie. The image fills it's container using a background-image style but I also tried using an img tag but that didn't work either. Here is the download function:
const handleDownload = async () => {
const element = ref.current;
const canvas = await html2canvas(element, {useCORS: true, allowTaint: true});
const data = canvas.toDataURL('image/png');
const link = document.createElement('a');
if (typeof link.download === 'string') {
link.href = data;
link.download = 'image.png';
document.body.appendChild(link);
link.click();
document.body.removeChild(link);
} else {
window.open(data);
}
}
this is the error that I'm getting:
Here is what it's supposed to capture:
Here is what it actually captures:
I tried using background-image style for the container and I also tried using an img tag and it was the same error. I also tried setting useCORS to false which also didn't work.

This solution was thanks to #ChristianUnnerstall
The problem was that it was being blocked by cors. I had to add crossOrigin="anonymous" to the img tag that was rendered from the imdb database:
<img
id="chosen-image"
src={
selectedMovieImg
? `${selectedMovieImg}?not-from-cache-please}`
: ""
}
alt="movie poster"
crossOrigin="anonymous"
/>
I had to add ?not-from-cache-please so cors sees it as a different request and it will be rendered to the dom and selectedMovieImg is a variable that holds the imdb link to the resource!

Related

Firebase Storage not displaying image properly (shows a small box)

EDIT: I've updated the CORS config but its still showing the same error.
I have a Tinymce RTE on my page, and when u drop an image into the editor, I have some functions that upload it to firebase storage, then swaps out the src of the text editor with the url fetched from firebase. It works kinda ok, but its being displayed as a broken link image icon.
When I check the link, its because originally it downloads the image when the link is clicked. I added a metadata property when it uploads it, but now its just showing a tiny box.
Here is the code where the image dropped into the editor is uploaded into firebase storage
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: 'image/jpeg',
};
await uploadBytes(storageRef, file, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message
console.log(error.message);
}
};
Originally, i didnt include the contentType metadata, and it was just uploading as application/octet-stream, which i assume is why it prompts you to save the image.
Image link: https://firebasestorage.googleapis.com/v0/b/cloudnoise-news.appspot.com/o/ref.jpg?alt=media&token=1edc90e7-1668-4a06-92a3-965ce275798b
Currently its displaying this
Somethings i checked through
firebase storage rules is in test mode, so should be able to read and write by anyone.
i tried sticking in different MIME types but it either shows the tiny box, or it shows "undefined"
the files upload successfully and the "swap" in Tinymce editor is also all good.
Any idea why this is happening?
you need to set the metadata tag
const metadata = {
contentType: file.type,
};
This should ensure that the correct content type is set when the image is uploaded to Firebase Storage.
If this does not resolve the issue, you may need to check that the URL returned from getDownloadURL is valid and points to the correct image. You can try opening the URL in a new browser tab to verify that the image is accessible.
I fixed it by adding a blob, I created a blob object with the file data, then i just made it upload the blob object instead of the single file.
const imagesUploadHandler = async (blobInfo, success, failure) => {
try {
const file = blobInfo.blob();
const storageRef = ref(storage, file.name);
const metadata = {
contentType: file.type,
};
// Create a new Blob object with the file data
const blob2 = await new Blob([file], { type: file.type });
// Upload the Blob to Firebase Storage
await uploadBytes(storageRef, blob2, metadata);
const url = await getDownloadURL(storageRef);
console.log(url);
return url;
} catch (error) {
// Call the failure callback with the error message;;
console.log(error.message)
}
};

How to upload image to image column from SharePoint List using REST API(React)

I have a problem of uploading image to image column in sharepoint online via pnpjs
I don't know how to convert image and upload to image column in sharepoint list.
I tried lot of ways (by convert image to blob, filedata) nothing works.
Keep in much this is not an attachments for the list..
It's a new column(image) in sharepoint list
reference image click here
Looks like the image is not stored in the list. JSON is stored. So you can just upload image to site assets (that's what sharepoint does when you set the image manually) and then put the json to the field. I would try something like this (assuming you are using pnpjs)
import * as React from "react";
import { sp } from "#pnp/sp/presets/all";
// hello world react component
export const HelloWorld = () => {
const uploadFile = async (evt) => {
const file: File = evt.target.files[0];
// upload to the root folder of site assets in this demo
const assets = await sp.web.lists.ensureSiteAssetsLibrary();
const fileItem = await assets.rootFolder.files.add(file.name, file, true);
// bare minimum; probably you'll want other properties as well
const img = {
"serverRelativeUrl": fileItem.data.ServerRelativeUrl,
};
// create the item, stringify json for image column
await sp.web.lists.getByTitle("YourListWithImageColumn").items.add({
Title: "Hello",
YourImageColumn: JSON.stringify(img)
});
};
return (<div>
<input type='file' onChange={uploadFile} />
</div>);
};
#azarmfa,
The image file in fact did not store in the image field. The field just references its location. You could first upload the image file to a library (by default it will be site asset), then update the item like below:
let list = sp.web.lists.getByTitle("mylinks");
let json = {
"fileName": "Search_Arrow.jpg",
"serverUrl": "https://abc.sharepoint.com",
"serverRelativeUrl": "/sites/s01/Style%20Library/Images/Search_Arrow.jpg"
};
let jsonstr = JSON.stringify(json);
const i = await list.items.getById(3).update({
Title: "My New Tit",
img: jsonstr
});
BR

onClick "save image as" in React

I want to simulate Save Image As when the user clicks on an image.
I read this and this thread but I couldn't find the answer.
I'm using CRA and the image is not on my server. Is there a way where I can achieve this?
Here is a Sandbox:
https://codesandbox.io/s/save-image-as-react-pm3ts?file=/src/App.js
<a
href="https://img.mipon.org/wp-content/uploads/2019/12/14094031/logo-cover-website.png"
download
>
<img
download
alt="Mipon"
style={{ width: "300px" }}
onClick={() => console.log("should trigger save image as")}
src="https://img.mipon.org/wp-content/uploads/2019/12/14094031/logo-cover-website.png"
/>
</a>
The download attribute will not work as intended since Blink engine will block cross-origin <a download>. Checkout Deprecations and removals in Chrome 65.
To avoid what is essentially a user-mediated cross-origin information
leakage, Blink will now ignore the presence of the download attribute
on anchor elements with cross origin attributes. Note that this
applies to HTMLAnchorElement.download as well as to the element
itself.
You may try to draw the image to a canvas element and download its dataURL. But this approach will work only if the requested domain has an Access-Control-Allow-Origin headers that allow shared requests. Images without CORS approval will taint the canvas and you will encounter error Tainted canvases may not be exported download image when you try to use methods like toDataURL(). In that case, you can host the image with services like Cloudinary and the download with canvas approach will work.
Here is a function to download an image using canvas, you may use it in a onclick event handler:
function downloadImage(src) {
const img = new Image();
img.crossOrigin = 'anonymous'; // This tells the browser to request cross-origin access when trying to download the image data.
// ref: https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image#Implementing_the_save_feature
img.src = src;
img.onload = () => {
// create Canvas
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
canvas.width = img.width;
canvas.height = img.height;
ctx.drawImage(img, 0, 0);
// create a tag
const a = document.createElement('a');
a.download = 'download.png';
a.href = canvas.toDataURL('image/png');
a.click();
};
}

How to get a tensor from an image

I have an image and I would like to get the tensor from it.
Some of the images are already on the frontend server be whereas others will be served by the server
To do that, one needs to use fromPixels
In case the image is already displayed in an html page
You can consider doing a querySelector to get the image first and then you can use fromPixels
html
<img id="my-image" src="mydata.jpg">
js
const image = document.querySelector("#my-image")
const t = tf.fromPixels(image)
If the image is not present in the html page, you can use the constructor Image to create it and then pass it as parameter to fromPixels
const im = new Image()
im.onload = () => {
const a = tf.fromPixels(im, 4)
a.print()
console.log(a.shape)
}
im.src = "url-of-the-image"
document.body.appendChild(im)
onload makes sure that the image has finished downloading before converting it to a tensor.
If the image url and the url on which the frontend page is served are different there will be a cross-origin issue when creating the tensor. If the server serves the image with an access control that allows the frontend to retrieve that image, then setting the crossOrigin attribute of the image will solve the issue, otherwise there will nothing that can be done to get the tensor from that image.
const im = new Image()
im.crossOrigin = "anonymous";
im.src = "https://i.imgur.com/lVlPvCB.gif"
document.body.appendChild(im)
im.onload = () => {
const a = tf.fromPixels(im, 4)
a.print()
console.log(a.shape)
}
<html>
<head>
<!-- Load TensorFlow.js -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/tensorflow/0.12.4/tf.js"> </script>
</head>
<body>
</body>
</html>

Save PDF file loaded in iframe

I am trying to save a pdf file that is loaded in an iFrame. There is by default a button in the iFrame to save the file but I want an extra button (outside the iFrame) to save the file.
<iframe id="labelFrame" src="loadedFile.pdf"></iframe>
<button id="savePDF">Download File</button>
In javascript:
$('#savePDF').click(function(){
var save = document.getElementById('labelFrame');
//Save the file by opening the explorer for the user to select the place to save or save the file in a default location, how do I do this?
}
What is the best way to reach this?
I needed an answer to this question as well and found a solution.
When displaying a PDF in an IFrame the browser will render it in an <embed> element and from there we cant use it in javascript as far as i know.
We'll need to use XMLHttpRequest to get the PDF from a server as a Blob object only then we can both display it and save it using javascript.
var iframe = document.getElementById('labelFrame'),
saveBtn = document.getElementById('savePDF'),
pdfUrl = 'loadedFile.pdf';
var xhr = new XMLHttpRequest();
xhr.open("GET", pdfUrl);
xhr.responseType = 'blob'; // <- important (but since IE10)
xhr.onload = function() {
var blobUrl = URL.createObjectURL(xhr.response); // <- used for display + download
iframe.src = blobUrl
saveBtn.onclick = function() {
downloadBlob(blobUrl, 'myFilename.pdf');
}
};
xhr.send();
The xhr.onload function will set to src of the iframe and add the onclick handler to the save button
Here is the downloadBlob() function that i've used in the example
function downloadBlob(blobUrl, filename) {
var a = document.createElement('a');
a.href = blobUrl;
a.target = '_parent';
// Use a.download if available. This increases the likelihood that
// the file is downloaded instead of opened by another PDF plugin.
if ('download' in a) {
a.download = filename;
}
// <a> must be in the document for IE and recent Firefox versions,
// otherwise .click() is ignored.
(document.body || document.documentElement).appendChild(a);
a.click();
a.remove();
}

Resources