[RESOLVED] Get the image generated by Graphics into a bitmap
Inside PictureBox1_Paint I used PaintEventArgs parameter to draw some graphics and make transformations (rotation/scale).
All changes are visible in the picturebox. Now I want to extract the image/bitmap updated, I mean, a bitmap with all that transformations I did, how to do it? The image in the picturebox is always Nothing.
VB Code:
Private Sub PictureBox1_Paint(ByVal sender As System.Object, _
ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.Clear(PictureBox1.BackColor)
RotateImage(e) 'Another sub
ZoomImage(e) 'Another sub
e.Graphics.DrawImage(MyBitmap, -PosX, -PosY) 'My bitmap drawn with transformation
End Sub
There I send MyBitmap to be drawn by e.Graphics, but it's not 'transformed', it's just used to draw, How can I get the transfomed bitmap?
Re: From graphics created with PaintEventArgs to real image
from the look of your code (without seeing the other routines source code)
it looks like your modified image is in the MyBitmap variable when you are at this line of code, correct?
VB Code:
e.Graphics.DrawImage(MyBitmap, -PosX, -PosY) 'My bitmap drawn with transformation
so you can just use that bitmap object. Unless I am missing something.
Also, the reason the image in the picturebox is nothing, is because you are drawing the image directly to the DC of the picturebox, which is different than assigning an image property to it.
Re: From graphics created with PaintEventArgs to real image
Nope, the MyBitmap is never updated, e.Graphics has all the transformations, anything you send to it will be drawn using that transformations, a line, a rectanlge, or a bitmap, but the bitmap is never updated, it's never transformed, it's just used to draw, but the transformations are not reflected in the bitmap.
Quote:
Also, the reason the image in the picturebox is nothing, is because you are drawing the image directly to the DC of the picturebox, which is different than assigning an image property to it.
Ok, then, is there any way to create a bitmap from that DC?
Re: From graphics created with PaintEventArgs to real image
Bump.
I just need to extract that transformed bitmap from there. The transformation is visible (rotation/scale), but I just can't find the way to extract that new image generated by System.Drawing.Graphics into a new bitmap.
At least, anybody here knows how to get the DC of a picturebox?? This way, maybe I could use BitBlt or StrechBlt to get that image.
Re: Get the image generated by Graphics into a bitmap
I think you can get the hdc like this
VB Code:
Dim hdc As IntPtr = e.Graphics.GetHdc()
But there has to be a better way to do what you want to do...
Re: Get the image generated by Graphics into a bitmap
Ok, then, that would be FromDc parameter for BitBlt, now I need DestDc, but VB.net Pictureboxes and bitmaps don't have hDC, like in VB6, at least i can't find it. Maybe I could use CreateCompatibleDC API but, I just can't believe that this stuff is not native in VB.net, weird.
Re: Get the image generated by Graphics into a bitmap
OK, I think I figured it out.
VB Code:
Dim bm As New Bitmap(PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height)
Dim g As Graphics = Graphics.FromImage(bm)
' Draw your stuff here
RotateImage(g) 'Another sub
ZoomImage(g) 'Another sub
'now you have a bitmap you can use
PictureBox1.Image = bm
PictureBox2.Image = bm
1 Attachment(s)
Re: Get the image generated by Graphics into a bitmap
That should work, but for some reason, in this case, it doesn't.
My project is attached.
Re: Get the image generated by Graphics into a bitmap
This exercise has forced me to learn a lot about the graphics object and graphics transformations.
The way I handle this problem is to create a module-level graphics object which will handle all of our drawing. We can at any time access the contents of the grapics object through it's associated bitmap. We need two module-level bitmaps: one to hold the original picture which we will continually redraw to the graphics object; and the other to store the pixel data of the graphics object.
At the Module level
VB Code:
[FONT=Courier New] [COLOR=#0000FF]Private[/COLOR] OrigBitMap [COLOR=#0000FF]As[/COLOR] Bitmap
[COLOR=#0000FF]Private[/COLOR] bm [COLOR=#0000FF]As[/COLOR] Bitmap
[COLOR=#0000FF]Private[/COLOR] g [COLOR=#0000FF]As[/COLOR] Graphics[/FONT]
In the form
VB Code:
[FONT=Courier New] [COLOR=#007A00]'OrigBitMap will hold our original picture
[/COLOR] OrigBitMap = [COLOR=#0000FF]New[/COLOR] Bitmap(lAppPath & "[COLOR=#7A0000]\Tiger.bmp[/COLOR]")
PictureBox1.Width = CInt(OrigBitMap.Width * 2)
PictureBox1.Height = CInt(OrigBitMap.Height * 2)
PosX = CType((PictureBox1.ClientSize.Width - OrigBitMap.Width) / 2, [COLOR=#0000FF]Single[/COLOR])
PosY = CType((PictureBox1.ClientSize.Height - OrigBitMap.Height) / 2, [COLOR=#0000FF]Single[/COLOR])
[COLOR=#007A00]'associate a bitmap (bm) with the drawing surface (g)
[/COLOR] [COLOR=#007A00]'make it the same size as our picturebox
[/COLOR] bm = [COLOR=#0000FF]New[/COLOR] Bitmap(PictureBox1.ClientSize.Width, PictureBox1.ClientSize.Height)
g = Graphics.FromImage(bm)
[COLOR=#007A00]'our 1st transformation puts the image in the middle
[/COLOR] g.TranslateTransform(PosX, PosY, MatrixOrder.Append)
g.DrawImage(OrigBitMap, 0, 0)
[COLOR=#007A00]'show the image in the picturebox
[/COLOR] PictureBox1.Image = bm[/FONT]
Note that all the transformations are cumulative. This means that if we want to rotate by a certain amount, we have to know how much we've rotated already. Same goes for scaling. Here are the new functions for rotation and scaling.
VB Code:
[FONT=Courier New] [COLOR=#0000FF]Public[/COLOR] [COLOR=#0000FF]Sub[/COLOR] RotateImage([COLOR=#0000FF]ByVal[/COLOR] Gr [COLOR=#0000FF]As[/COLOR] Graphics, [COLOR=#0000FF]ByVal[/COLOR] mRotAngle [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR])
[COLOR=#0000FF]Static[/COLOR] OldAngle [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR] = 0
[COLOR=#007A00]'move center of image to origin before rotating
[/COLOR] Gr.TranslateTransform(-CSng(PictureBox1.ClientSize.Width / 2), _
-CSng(PictureBox1.ClientSize.Height / 2), MatrixOrder.Append)
[COLOR=#007A00]'rotate image by the additional amount
[/COLOR] Gr.RotateTransform(mRotAngle - OldAngle, MatrixOrder.Append)
[COLOR=#007A00]'move image center back to picbox center
[/COLOR] Gr.TranslateTransform(CSng(PictureBox1.ClientSize.Width / 2), _
CSng(PictureBox1.ClientSize.Height / 2), MatrixOrder.Append)
[COLOR=#007A00]'clear old drawing
[/COLOR] Gr.Clear(PictureBox1.BackColor)
[COLOR=#007A00]'draw new image
[/COLOR] Gr.DrawImage(OrigBitMap, 0, 0)
[COLOR=#007A00]'save current rotation angle
[/COLOR] OldAngle = mRotAngle
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]Sub
[/COLOR]
[COLOR=#0000FF]Public[/COLOR] [COLOR=#0000FF]Sub[/COLOR] ZoomImage([COLOR=#0000FF]ByVal[/COLOR] Gr [COLOR=#0000FF]As[/COLOR] Graphics, [COLOR=#0000FF]ByVal[/COLOR] scalex [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR] = 1, [COLOR=#0000FF]ByVal[/COLOR] scaley [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR] = 1)
[COLOR=#007A00]'move center of image to origin before scaling
[/COLOR] Gr.TranslateTransform(-CSng(PictureBox1.ClientSize.Width / 2), _
-CSng(PictureBox1.ClientSize.Height / 2), MatrixOrder.Append)
[COLOR=#007A00]'scale image by new factor
[/COLOR] Gr.ScaleTransform(scalex, scaley, MatrixOrder.Append)
[COLOR=#007A00]'move image center back to picbox center
[/COLOR] Gr.TranslateTransform(CSng(PictureBox1.ClientSize.Width / 2), _
CSng(PictureBox1.ClientSize.Height / 2), MatrixOrder.Append)
[COLOR=#007A00]'clear old drawing
[/COLOR] Gr.Clear(PictureBox1.BackColor)
[COLOR=#007A00]'draw new image
[/COLOR] Gr.DrawImage(OrigBitMap, 0, 0)
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]Sub[/COLOR][/FONT]
And these are called from the trackbars like so
VB Code:
[FONT=Courier New] [COLOR=#0000FF]Private[/COLOR] [COLOR=#0000FF]Sub[/COLOR] TrackRotation_Scroll([COLOR=#0000FF]ByVal[/COLOR] sender [COLOR=#0000FF]As[/COLOR] System.Object, _
[COLOR=#0000FF]ByVal[/COLOR] e [COLOR=#0000FF]As[/COLOR] System.EventArgs) [COLOR=#0000FF]Handles[/COLOR] TrackRotation.Scroll
[COLOR=#007A00]'perform a rotation transformation on the graphics object
[/COLOR] RotateImage(g, TrackRotation.Value)
[COLOR=#007A00]'show the results
[/COLOR] PictureBox1.Image = bm
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]Sub
[/COLOR]
[COLOR=#0000FF]Private[/COLOR] [COLOR=#0000FF]Sub[/COLOR] TrackZoom_Scroll([COLOR=#0000FF]ByVal[/COLOR] sender [COLOR=#0000FF]As[/COLOR] System.Object, _
[COLOR=#0000FF]ByVal[/COLOR] e [COLOR=#0000FF]As[/COLOR] System.EventArgs) [COLOR=#0000FF]Handles[/COLOR] TrackZoom.Scroll
[COLOR=#0000FF]Static[/COLOR] oldScaleX [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR] = 1
[COLOR=#0000FF]Static[/COLOR] oldScaleY [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single[/COLOR] = 1
[COLOR=#0000FF]Dim[/COLOR] ScaleX [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single
[/COLOR] [COLOR=#0000FF]Dim[/COLOR] ScaleY [COLOR=#0000FF]As[/COLOR] [COLOR=#0000FF]Single
[/COLOR] [COLOR=#007A00]'Since all the transformations are cumulative,
[/COLOR] [COLOR=#007A00]'we have to keep track of the previous scaling factors
[/COLOR] [COLOR=#007A00]'differences in scaling are ratios
[/COLOR] [COLOR=#0000FF]If[/COLOR] ChkZoomX.Checked [COLOR=#0000FF]Then
[/COLOR] ScaleX = CType(TrackZoom.Value / 100 / oldScaleX, [COLOR=#0000FF]Single[/COLOR])
oldScaleX = CSng(TrackZoom.Value / 100)
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]If
[/COLOR] [COLOR=#0000FF]If[/COLOR] ChkZoomY.Checked [COLOR=#0000FF]Then
[/COLOR] ScaleY = CType(TrackZoom.Value / 100 / oldScaleY, [COLOR=#0000FF]Single[/COLOR])
oldScaleY = CSng(TrackZoom.Value / 100)
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]If
[/COLOR] [COLOR=#007A00]'scale the graphics object and display results
[/COLOR] ZoomImage(g, Scalex, Scaley)
PictureBox1.Image = bm
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]Sub[/COLOR][/FONT]
Notice that in the TrackZoom Scroll we have to form the ratio of the previous zoom position to the new zoom position to get the new zoom factor. In the case rotation it is easier since rotation is additive.
Finally, if you want to access the current image simply access the associated bitmap.
VB Code:
[FONT=Courier New] [COLOR=#0000FF]Private[/COLOR] [COLOR=#0000FF]Sub[/COLOR] Button2_Click([COLOR=#0000FF]ByVal[/COLOR] sender [COLOR=#0000FF]As[/COLOR] System.Object, [COLOR=#0000FF]ByVal[/COLOR] e [COLOR=#0000FF]As[/COLOR] System.EventArgs) [COLOR=#0000FF]_
Handles[/COLOR] Button2.Click
[COLOR=#007A00]'How to save transformed image to file here?
[/COLOR] PictureBox2.Image = bm
[COLOR=#0000FF]End[/COLOR] [COLOR=#0000FF]Sub[/COLOR][/FONT]
Re: Get the image generated by Graphics into a bitmap
Moeur, thank you from the heart man, that works perfectly ;)
As you said, transformations are cumulative that was not the case in my old code, I was using the Paint event of the picturebox sending always the original bitmap, it was transformed but temporary, and there was not way to save it. Now i see how transformations work. Thank you again! :thumb: