react-to-print
react-to-print copied to clipboard
contentWindow of the print Iframe is not loaded.
``First of all, Thanks for your amazing library. I'm currently using react-to-print happily in my project.
But I'm having a problem which is that contentWindow of the print Iframe is not loaded when I try to put some images in my document. Without images, react-to-print works very well.
Below is my screenshot of error message.
I'm using Electron and here is part of my source code with image tags.
const [objectiveUrl, setObjectiveUrl] = useState<string | undefined>(undefined)
useEffect(() => {
const reader = new FileReader()
reader.onload = () => {
setObjectiveUrl(reader.result as string)
}
if (image instanceof Promise) {
image.then((_file) => {
reader.readAsDataURL(_file)
})
} else if (image instanceof File || image instanceof Blob) {
reader.readAsDataURL(image)
}
}, [])
return (
<Column spacing={10}>
<img className="objective_pdf_image" src={objectiveUrl} alt="Objective" />
<div className="objective_pdf_image_title">{title}</div>
</Column>
)
1 or 2 images work well, but if there comes more than 2 or 3 images, webContent doesn't show up.
Hello. I can't say I'm a Electron expert, but from what you're describing it sounds like Electron waits for the resources to load before making the contentWindow
available. We do already wait 500ms for content to load, but it's possible that needs to be longer in your case. If that is the problem, I see two possible solutions:
- detect if we are in an electron env, and if we are, see if there is some electron specific API that can be called to wait for the content to load
- we could allow the end user the ability to pass their own value for the timeout, but that wouldn't result in a good user experience since you wouldn't know what value to pass and instead would just have to make the value huge, resulting a large amounts of lag between the user clicking the print button and something actually happening
Is there an easy way for me to get your code above running in Electron on my machine so I can test it?
Sorry for my late reply, I think 2nd solution looks reasonable because I'm currently using Electron API waiting for the contentWindow
to be loaded like the example below.
ipcMain.on('pdf-printer', (e, _url: string) => {
const viewer = new BrowserView()
viewer.setBounds({ x: 0, y: 0, width: 800, height: 1200 })
viewer.setAutoResize({ width: true, height: true })
viewer.webContents.loadURL(_url).then(() => {
viewer.webContents.printToPDF({}).then((_pdf) => {
viewer.webContents.print({}, (success, failureReason) => {
if (!success) {
console.log(failureReason)
}
console.log('Print started!')
})
})
})
})
I think if it's because of the 500ms time limit you set, could you test in your own environment whether your library can wait loading several images or not?
Currently, I'm using images from AWS S3, so I think react-to-print
needs time to download images from S3.
Can you allow users to set value for timeout?? If they don't, you can set it to 500ms default I think.
Yeah, I'm trying to think of a solution that works well cross-platform, since this isn't really an issue browser users face as the images are already cached by the browser when react-to-print
goes to load them. I'd really like to avoid adding Electron specific API options. Give me through the weekend to see if I can figure out something better, or if we should just use this approach
Thanks for your support.
I think because I'm passing base64 encoded string to src of <image />
, images are not cached so it takes some time.
I should try to find out something better too,, let me know when you find something good.
Thanks!
Good News!
Since I started to pass AWS S3 download url instead of base64 encoded string to <image />
, it works!
It definitely seems that passing base64 encoded string was a problem.
Though the download url from AWS S3 has 5 minutes duration, it works as well after 5 minutes, can't find out why it's working 😅
But I still have a problem when I put local images, I'm currently passing URL.createObjectURL(_image)
I think this is the problem, I should find out how to pass local image path to <image />
.
Interesting, I wonder if the browser caches images from data URLs differently. Could you possible share one of the base64 strings you were using so I can test with it?
In addition, how can I put local images url to <image />
?
I tried to put local image files like this,
setObjectiveUrl(URL.createObjectURL(image))
but it shows up like this,