Solved Canvas issue
-
Hi! In my main.qml I have Window as a root entity and nested Canvas in it (I decided that a Form will be an extra element in my app). At certain point of development it became necessary to set a background color for my Canvas (white color), but Canvas doesn't have a property for this, so I set "white" to the color property of a parent - Window entity. However, when I got access to a pixel array through getImageData() and looked through it I saw that RGBA color of each pixel on the clean Canvas was "(0,0,0,255)"(black) instead of "(255,255,255,255)"(white). Is it a bug? Or I did something wrong?
-
Your Canvas is a child of something indeed, but it has it's own paint methods.
If you're trying to paint a JPG image for instance, each and every pixel will be painted according to your image, and JPG does not have transparency, so the white background you defined will always be replaced by the JPG value.
So, maybe you are not doing anything wrong, but have the wrong kind of picture? (JPG instead of PNG)
-
@peteritv I used default settings of Canvas in terms of image type. My task was only to implement drawing with a mouse on the white Canvas and to code white pixels as 0 and colored pixels as 1 for the needs of my core logic class. And when I wrote a "for" cycle to iterate over all pixels on the Canvas, it revealed that the background pixels are black in the data array, though Canvas per se was displayed as white. Sort of magic....
-
Maybe I spoke before I knew what was really going on...
It might help if you post the sceleton of your application, so we can see the context.
-
@peteritv Here you can see entire main.qml:
import QtQuick 2.7 import QtQuick.Window 2.2 import QtQuick.Controls 2.0 Window { id: "window" visible: true width: 640 height: 480 maximumHeight: height maximumWidth: width minimumHeight: height minimumWidth: width color: "white" title: "Однослойный перцептрон" Component.onCompleted: { setX(Screen.width/2 - width/2) setY(Screen.height/2 - height/2) neuro.loadWeights() } property int xpos property int ypos property bool hold property bool clearCanvas:false Canvas { id:canvas anchors.top: parent.top width: 640 height: 410 onPaint: { var ctx = getContext('2d') if(clearCanvas) { ctx.fillStyle = "white" ctx.fillRect(0,0,width,height) clearCanvas=false } else { ctx.lineCap = "round" ctx.lineWidth = 30 ctx.strokeStyle = 'blue' ctx.beginPath() ctx.moveTo(xpos,ypos) xpos = area.mouseX ypos = area.mouseY ctx.lineTo(xpos, ypos) ctx.stroke() } } MouseArea { id:area anchors.fill: parent acceptedButtons: Qt.LeftButton | Qt.RightButton onPressed: { if(mouse.buttons & Qt.LeftButton) { hold=true xpos = mouseX ypos = mouseY } } onPositionChanged: { if(hold & (mouse.buttons & Qt.LeftButton)) { canvas.requestPaint() } } onReleased: { hold = false } onClicked: { infoArea.visible = false } } } Button { id:recognize anchors.bottom: parent.bottom anchors.horizontalCenter: parent.horizontalCenter height: 50 width: 300 anchors.bottomMargin: 8 text:"Распознать" onClicked: { var image = canvas.getContext('2d').getImageData(0,0,canvas.width,canvas.height) var norm_px = [] for(var i = 0, n=image.data.length; i<n; i+=4) { if(image.data[i]===0 && image.data[i+1]===0 && image.data[i+2]===255 && image.data[i+3]===255) { norm_px.push(1) } else { norm_px.push(0) } } neuro.signal = norm_px neuro.calculate() if (neuro.exitSignal===1) { recognitionState.text="\u03F4" recognitionState.color="green" } else if (neuro.exitSignal===2) { recognitionState.text="\u03A8" recognitionState.color="green" } else { recognitionState.text="\u2205" recognitionState.color="red" } infoArea.visible = true exitInfo.text = "\u03F4: "+ neuro.exitTheta.toFixed(5) + " " + "\u03A8: " + neuro.exitPsi.toFixed(5); canvas.requestPaint() clearCanvas=true } } Rectangle { visible: false id: "infoArea" anchors.horizontalCenter: canvas.horizontalCenter anchors.verticalCenter: canvas.verticalCenter width: 200 height: 200 color: "white" border.color: "black" border.width: 3 radius: 10 Text { anchors.horizontalCenter: parent.horizontalCenter anchors.verticalCenter: parent.verticalCenter id:recognitionState text:"\u03F4" font.family: "Helvetica" font.pointSize: 100 color: "green" } MouseArea { id: "hoverArea" anchors.fill: parent hoverEnabled: true ToolTip { id:"exitInfo" visible: hoverArea.containsMouse } } } }
Only the color of mouse traces is defined correctly, unlike the background and it's strange.
P.S. Sorry for my English, it is my second language, I will try to be more clear if you don't understand something in my posts.
-
After reading some docs, I am sure you are not telling something.
You want to draw on something that is white, correct?
So your canvas must be a child of something that is white.For instance:
Rectangle { color: white; Canvas { ... } }Is that the case here?
-
@peteritv Yes, you are correct. In my case I set Canvas as a child of a white Window, but Context2D shows me, suddenly, that the canvas is the child of the black Window. Though it is displayed as white.
-
OK, I just run your example, and it seems to work.
I have a white background on which I can draw.
When I draw I see the traces of my mouse with a big "point" size.
Draw color is blue.Everything seems to work.
Now, since I don't have your "Neuro" file, THAT may be your problem...
-
We have a synchronisation issue here to :)
So when you run your program, you are drawing on a black thing?
-
Where/How do you use Context2D?
-
Ahhhh! I understand now! (I think)
You think that what ever background you choose, it will be part of your canvas?
That is NOT the case!The canvas just is a container for some points being drawn!
For instance, you can take the canvas, and put it on something else like a red Rectangle.
It will still have the same points, but now on a red background.In other words, the canvas does NOT hold any information at all about the background. It just knows about some pixels.
-
So in your case, you need to fill your Canvas with white pixels itself.
So with ur ctx functions, draw a white rectangle first, which will be the base of your canvas for drawing on.
-
So, instead of making your parent white:
Within your canvas, draw a white rectangle on start,
and then start drawing on that -
But that explaines why you see "black" instead of "white" on your Context2D
I am assuming you are just interested in the points, and not the background, for further processing.
So forget about the canvas background, ok? -
@peteritv Huge thanks, I finnally got what's going on! A visible background of working application is just a result of visual compositing the Canvas with it's parent and these two does not share any properties between each other. Thanks a lot again, I think it is very important to know such nuances.