Sends the image as HTML and draws it on the canvas.
-
This program loads an image saved as a binary from a file and tries to draw the image on an html5 canvas through QWebEngineView.
QImage m_pBkgndImage; #include <QWebEngineScript> bool CBackground::onDraw() { // m_pBkgndImage is QImage if(!m_pBkgndImage->isNull()){ if (m_pBkgndImage->colorSpace().isValid()){ m_pBkgndImage->convertToColorSpace(QColorSpace::SRgb); } QPoint point(0,0); point.rx() = m_bkgndHeader.Left; point.ry() = m_bkgndHeader.Top; QWebEngineView view; QString htmlPath = QFileInfo(__FILE__).dir().absolutePath() + "/canvas.html"; view.load(QUrl::fromLocalFile(htmlPath)); QWebChannel channel; QVariant imageVariant = QVariant::fromValue(*m_pBkgndImage); qDebug() << m_pBkgndImage->size() << " b3"; // output correct value imageObject = new QObject(); imageObject->setProperty("imageData", imageVariant); channel.registerObject("imageObject", imageObject); int imageSizeInBytes = m_pBkgndImage->bytesPerLine() * m_pBkgndImage->height(); QByteArray imageDataArray(reinterpret_cast<const char*>(m_pBkgndImage->bits()), imageSizeInBytes); //view.page()->setWebChannel(&channel); qDebug() << "b4: " << imageDataArray.size(); // output correct value QString jsCode = QString("drawCanvas('%1');").arg(QString(imageDataArray.toBase64())); view.page()->runJavaScript(jsCode); delete imageObject; if(!m_pBkgndImage->isNull()){ delete m_pBkgndImage; m_pBkgndImage = nullptr; } return true; } else { QMessageBox::information(nullptr, "Drawing Image", "Failed 412"); return false; } return false; } /* canvas.js */ function drawCanvas(imageData) { var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height); console.error("length "+imageData.length); // js: Uncaught TypeError: Cannot read properties of undefined (reading 'length') console.error("Image Data Length: " + (imageData ? imageData.length : "Undefined")); // output "undefined" var img = new Image(); img.src = "data:image/webp;base64," + imageData; img.onerror = function(){ console.error("Image failed to load"); // output image failed to load }; img.onload = function() { console.error("onload"); context.drawImage(img, 0, 0); console.error("width: "+img.width); console.error("height: "+img.height); }; }
results is
console.error("length "+imageData.length); js: Uncaught TypeError: Cannot read properties of undefined (reading 'length')
As you can see, a problem arises. Naturally, the canvas is simply filled with yellow. But no image is drawn.
context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height);
It appears to be a problem with the image data the program sent to js. How do I solve this?
Thanks for reading. -
This program loads an image saved as a binary from a file and tries to draw the image on an html5 canvas through QWebEngineView.
QImage m_pBkgndImage; #include <QWebEngineScript> bool CBackground::onDraw() { // m_pBkgndImage is QImage if(!m_pBkgndImage->isNull()){ if (m_pBkgndImage->colorSpace().isValid()){ m_pBkgndImage->convertToColorSpace(QColorSpace::SRgb); } QPoint point(0,0); point.rx() = m_bkgndHeader.Left; point.ry() = m_bkgndHeader.Top; QWebEngineView view; QString htmlPath = QFileInfo(__FILE__).dir().absolutePath() + "/canvas.html"; view.load(QUrl::fromLocalFile(htmlPath)); QWebChannel channel; QVariant imageVariant = QVariant::fromValue(*m_pBkgndImage); qDebug() << m_pBkgndImage->size() << " b3"; // output correct value imageObject = new QObject(); imageObject->setProperty("imageData", imageVariant); channel.registerObject("imageObject", imageObject); int imageSizeInBytes = m_pBkgndImage->bytesPerLine() * m_pBkgndImage->height(); QByteArray imageDataArray(reinterpret_cast<const char*>(m_pBkgndImage->bits()), imageSizeInBytes); //view.page()->setWebChannel(&channel); qDebug() << "b4: " << imageDataArray.size(); // output correct value QString jsCode = QString("drawCanvas('%1');").arg(QString(imageDataArray.toBase64())); view.page()->runJavaScript(jsCode); delete imageObject; if(!m_pBkgndImage->isNull()){ delete m_pBkgndImage; m_pBkgndImage = nullptr; } return true; } else { QMessageBox::information(nullptr, "Drawing Image", "Failed 412"); return false; } return false; } /* canvas.js */ function drawCanvas(imageData) { var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height); console.error("length "+imageData.length); // js: Uncaught TypeError: Cannot read properties of undefined (reading 'length') console.error("Image Data Length: " + (imageData ? imageData.length : "Undefined")); // output "undefined" var img = new Image(); img.src = "data:image/webp;base64," + imageData; img.onerror = function(){ console.error("Image failed to load"); // output image failed to load }; img.onload = function() { console.error("onload"); context.drawImage(img, 0, 0); console.error("width: "+img.width); console.error("height: "+img.height); }; }
results is
console.error("length "+imageData.length); js: Uncaught TypeError: Cannot read properties of undefined (reading 'length')
As you can see, a problem arises. Naturally, the canvas is simply filled with yellow. But no image is drawn.
context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height);
It appears to be a problem with the image data the program sent to js. How do I solve this?
Thanks for reading.@MyNameIsQt
I am unsure precisely why you get that error message from JS when trying to executedrawCanvas(imageData)
viaQString("drawCanvas('%1');").arg(QString(imageDataArray.toBase64()))
. Start by passing e.g. literal string"'hello'"
instead and see if that arrives? Just maybe your base 64 string of a whole image is a very long string being passed and that causes a problem?? I don't know.Meanwhile, perhaps I am missing something, but you create a local
QWebEngineView
object inonDraw()
. That will be destroyed on exit from this function. I don't know what you are trying to do here. -
@MyNameIsQt
I am unsure precisely why you get that error message from JS when trying to executedrawCanvas(imageData)
viaQString("drawCanvas('%1');").arg(QString(imageDataArray.toBase64()))
. Start by passing e.g. literal string"'hello'"
instead and see if that arrives? Just maybe your base 64 string of a whole image is a very long string being passed and that causes a problem?? I don't know.Meanwhile, perhaps I am missing something, but you create a local
QWebEngineView
object inonDraw()
. That will be destroyed on exit from this function. I don't know what you are trying to do here.// cpp QString jsCode = QString("drawCanvas('%1');").arg("Hello"); view.page()->runJavaScript(jsCode); // js function drawCanvas(text) { console.error("text "+text); // undefined var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height); context.font="48px serif"; context.fillText(text, 10, 50); // nothing
The problem seems to occur when sending data from cpp to js.
thanks. -
// cpp QString jsCode = QString("drawCanvas('%1');").arg("Hello"); view.page()->runJavaScript(jsCode); // js function drawCanvas(text) { console.error("text "+text); // undefined var canvas = document.getElementById("myCanvas"); var context = canvas.getContext("2d"); context.fillStyle = "yellow"; context.fillRect(0, 0, canvas.width, canvas.height); context.font="48px serif"; context.fillText(text, 10, 50); // nothing
The problem seems to occur when sending data from cpp to js.
thanks.@MyNameIsQt
Hmm, I don't know why. Try sending, say, just a number (42
) this way instead of a string. Does that get through, so it's some string issue, or is every attempt to pass any argument unsuccessful?And although you, I & the rest of the world know that
QString("drawCanvas('%1');").arg("Hello")
really should be fine, since you are testing why don't you just test withQString jsCode = "drawCanvas(42);"
so as to be 100,000% sure? -
@MyNameIsQt
Hmm, I don't know why. Try sending, say, just a number (42
) this way instead of a string. Does that get through, so it's some string issue, or is every attempt to pass any argument unsuccessful?And although you, I & the rest of the world know that
QString("drawCanvas('%1');").arg("Hello")
really should be fine, since you are testing why don't you just test withQString jsCode = "drawCanvas(42);"
so as to be 100,000% sure?@JonB
I just tried your suggestion. And it still shows the same result. I'm thinking about other ways to pass arguments to js to see this problem more accurately. -
@JonB
I just tried your suggestion. And it still shows the same result. I'm thinking about other ways to pass arguments to js to see this problem more accurately.@MyNameIsQt
I really don't know why this. It's not as though it cannot find thefunction drawCanvas()
function definition (e.g. not loaded yet), as you get into that and the error message indicates it cannot see thetext
parameter. I am not a regular JS dev, but I did doQWebEnginePage::runJavaScript()
in the past under Ubuntu and I remember it working fine.I have no idea whether the following could be in any way related. I still do not understand how you have a
QWebEngineView
as a local variable, waiting to go out of scope. And normally you don't call anything (e.g.runJavaScript()
) to do anything until you know the page has finished loading. There is a void QWebEnginePage::loadFinished(bool ok) signal and/or window or documentonload()
in JS. You might try whether it's any different in any of these (presumably after changing the scope/lifetime of yourQWebEngineView view;
object).