I am trying to use jspdf and html2canvas for my project. It works great but if the page is large in size, it takes time to process after clicking the button to download the pdf. I would like to add a spinner as soon as the user clicks on the render PDF button. Though I have set the state for the loading property to true in react, the value is not rendered/displayed but it is displayed right before the pdf is downloaded.
Any thoughts ?
Code
printDocument() {
const input = document.getElementById('container');
this.setState({
isDownloading: true
});
html2canvas(input)
.then((canvas) => {
const imgData = canvas.toDataURL('image/png');
const pdf = new pdfConverter("p", "mm", "a4");
var width = pdf.internal.pageSize.width;
var height = pdf.internal.pageSize.height;
pdf.addImage(imgData, 'JPEG', 0, 0,width,height);
pdf.save("download.pdf");
this.setState({
isDownloading: false
})
})
;
}
Related
I met an issue at Ant Design <Upload /> component. When I upload an image it sends two Img typed requests at the Network console. First contains my orginal image (tested at 650x650 image size), second contains transformed image to 200x200. And here is my question: Why image is rescaled to lower resolution and how can I prevent that? I want to upload orignal images with transparency if that is required.
In my case Upload component is used to upload single image. Component is placed on modal component that is why I prepared dummyRequest.
const UploadImage = ({
defaultValue,
maxFilesAmount,
}: IUploadImageProps<any>): JSX.Element => {
const [fileList, setFileList] = useState<IUploadFile<any>[]>(
defaultValue ?? []
)
const onChange = useCallback(
(info: IUploadChangeParam<IUploadFile<unknown>>): void => {
setFileList(info.fileList)
},
[setFileList]
)
const onPreview = useCallback(async (file: IUploadFile): Promise<void> => {
let src: string | undefined = file?.url ?? file?.thumbUrl ?? ''
if (!_.isNull(src)) {
src = await convertImportImageToBase64(src)
}
const image: HTMLImageElement = new Image()
const imgWindow: Window | null = window.open(src)
image.src = src
imgWindow?.document.write(image.outerHTML)
}, [])
const dummyRequest = useCallback(({ onSuccess }: IUploadRequestOption) => {
setTimeout(() => {
//#ts-ignore
onSuccess('ok')
}, 0)
}, [])
const beforeUpload = useCallback((): false => {
//Required to ignore Ant Desing default converting uploaded image
//For example that removes transparency from png files
return false
}, [])
return (
<Upload
accept={'.jpg, .jpeg, .png'}
listType={'picture-card'}
beforeUpload={beforeUpload}
fileList={fileList}
onChange={onChange}
onPreview={onPreview}
customRequest={dummyRequest}
>
{_.size(fileList) < (maxFilesAmount ?? 1) && 'Upload'}
</Upload>
)
}
At the start I had also a problem with losing transparency at .png images. Image still was defined as png but transparent background got a white color. Used beforeUpload fix that, I not sure why but okej :).
What can I do more to fix this issue? Thanks in advance.
So basically I have a field where the user can choose an image to upload, how do I make it so that when the user chooses the image, it displays that image on the screen.
Example, the user uploads the plant2.jpeg , how do i display that image on that same screen. My code is as follows:
import FileBase64 from 'react-file-base64'
//State to handle plant Files
const [plantFile , setPlantFile] = useState(null)
//Handle the input onDone for FileBase64
const handleFiles = (files) => {
setPlantFile(files)
}
<FileBase64
multiple = {false}
onDone = {handleFiles}
/>
The FileBase64 returns an object like below:
{
base64: "data:image/jpeg;base64,/9j/2wCEAAMCAgMCAgMDAwMEAw",
name: "plant2.jpeg",
type: "images/jpeg"
}
Is there a way I can display that image? Anyway I can make that happen?
I am using antd's Upload component, its task is to just upload the image and then I grab that image and send it to the API to store it. But I keep getting upload failed message tooltip as I am not using any action prop that they provide. Even their own website has this problem as I'm trying to upload something and it shows failed message but it has been actually uploaded. antd's Upload
I am using useState to save the file const [uploadedImage, setUploadedImage] = useState();
My fileProps looks like this:
const fileProps = {
name: 'file',
multiple: false,
onChange(info) {
if (info.file.status !== 'uploading') {
let reader = new FileReader();
reader.onload = (e) => {
setData({
...data,
image: new File([e.target.result], info.file.name),
});
setIsFileUploaded(true);
}
reader.readAsDataURL(info.file.originFileObj);
setUploadedImage(info.file.originFileObj);
}
},
};
I then pass it to the Upload Component:
<Upload {...fileProps}>
<Button icon={<UploadOutlined />}>Upload Image</Button>
</Upload>
Why does it keep showing Upload error Tooltip even though it is successfully uploading and I can store it? how can I remove this tooltip? I know there is a way to hide the list entirely by using: showUploadList: false but I want to show the uploaded file as sometimes during big uploads I don't have any sort of confirmation if the file is uploading or uploaded.
I have also created codesandbox for it: https://codesandbox.io/s/bold-bash-g3qkj
If you just want to save the file to the state, and not send it automatically to the server, you must set the property beforeUpload.
const fileProps = {
name: "file",
multiple: false,
beforeUpload: () => {
return false;
},
onChange(info) {
if (info.file.status !== "uploading") {
let reader = new FileReader();
reader.readAsDataURL(info.file);
setUploadedImage(info.file);
}
}
};
I use html2canvas vs jsPDF in my Reactjs project and I had a required that's export a DOM node to PDF file. When I exported, HTML and CSS was keeped just SVG can't. I dont know why. Have another package on client can help me? Thank for your attetion.
Here is my code to export
const filename = 'TyVan.pdf';
html2canvas(document.querySelector('#buivanty'),{scale: quality}).then(canvas => {
let pdf = new jsPDF('l', 'mm', 'a4', true)
pdf.addImage(canvas.toDataURL('image/png', 1.0), 'png', 10, 10, 180, 150);
pdf.save(filename);
})
I was able to resolve it by doing post processing using onClone option
const options = {
scale: 1,
foreignObjectRendering: true,
onclone: (element) => {
const svgElements: any[] = element.body.getElementsByTagName('svg');
Array.from(svgElements).forEach((svgElement) => {
const bBox: any = svgElement.getBBox();
svgElement.setAttribute('width', bBox.width);
svgElement.setAttribute('height', bBox.height);
});
},
};
html2canvas(<HTMLScriptElement>document.querySelector('.main-container'), options).then(canvas => {
this.clipImage = canvas.toDataURL('image/png');
});
I have a list of images of different sizes.
images = ['https://example.com/1.jpg','https://example.com/2.jpg', ... ]
I want to get an array of their height before rendering them. I will then only render the images which should be in viewport based on scrollHeight. e.g using React Infinte
I can do this easily outside react component
let imgHeights = images.map(imgUrl => {
var img = new Image()
img.src = imgUrl
return img.height;
})
but new image() does not work in react since it depends on DOM.
My React component render method looks like this.
var ImageList = (images) => {
let buildImageList = images.map(imgUrl => {
return <img src= {imgUrl}></img>
})
let imgHeights = images.map(imgUrl => {
let img = new Image()
img.src = imgUrl
return img.height //this doesn't work
})
return (
<Infinte elemetHeight = {imgHeights} onInfiniteLoad ={buildImageList} />
)
}
How can I get The Image height? Should I use ReactDOM to render images in a temporary div?
Images are downloaded asynchronously while the javascript continues to execute, so you need to wait for them to load in order to record their heights. You could wait on their onload event and do something like
let imgHeights = {};
images.forEach(imgUrl => {
let img = new Image();
img.src = imgUrl;
img.onload = () => imgHeights[imgUrl] = img.height;
})
That just gets you started; you still have to figure out how to render them as they become ready.