Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Grabbing offscreen image

Status
Not open for further replies.

spelltwister

Programmer
May 12, 2005
36
0
0
US
Hello everyone!

I do have a question however. My application creates about ... 1000 objects, cuts the up into the shapes of countries, infantry, calvary, ships, etc, but obviously this can only be viewed in my application. I was wondering if there is a way to take what's being display and turn it into a gif or jpg. The display is ... 3240x2385.

Two issues came up:
1. It only took the visible screen. The image i need is 3280x2860, which sits inside of form1, inside panel1 and i grabbed them both, but neither was the right size.

2. Is there a way to boost the quality? Right now the text is barely readable.

If you need more information, please let me know. I'm not sure if I got my question across fully.

Mike

The code for the screen capture is:

Imports System
Imports System.Runtime.InteropServices
Imports System.Drawing
Imports System.Drawing.Imaging


Namespace ScreenShot
'/ Provides functions to capture the entire screen, or a particular window, and save it to a file.
Public Class ScreenCapture
'/ Creates an Image object containing a screen shot of the entire desktop
Public Function CaptureScreen() As Image
Return CaptureWindow(User32.GetDesktopWindow())
End Function 'CaptureScreen
'/ Creates an Image object containing a screen shot of a specific window
Public Function CaptureWindow(ByVal handle As IntPtr) As Image
Dim SRCCOPY As Integer = &HCC0020
' get te hDC of the target window
Dim hdcSrc As IntPtr = User32.GetWindowDC(handle)
' get the size
Dim windowRect As New User32.RECT
User32.GetWindowRect(handle, windowRect)
Dim width As Integer = windowRect.right - windowRect.left
Dim height As Integer = windowRect.bottom - windowRect.top
' create a device context we can copy to
Dim hdcDest As IntPtr = GDI32.CreateCompatibleDC(hdcSrc)
' create a bitmap we can copy it to,
' using GetDeviceCaps to get the width/height
Dim hBitmap As IntPtr = GDI32.CreateCompatibleBitmap(hdcSrc, width, height)
' select the bitmap object
Dim hOld As IntPtr = GDI32.SelectObject(hdcDest, hBitmap)
' bitblt over
GDI32.BitBlt(hdcDest, 0, 0, width, height, hdcSrc, 0, 0, SRCCOPY)
' restore selection
GDI32.SelectObject(hdcDest, hOld)
' clean up
GDI32.DeleteDC(hdcDest)
User32.ReleaseDC(handle, hdcSrc)

' get a .NET image object for it
Dim img As Image = Image.FromHbitmap(hBitmap)
' free up the Bitmap object
GDI32.DeleteObject(hBitmap)

Return img
End Function 'CaptureWindow
'/ Captures a screen shot of a specific window, and saves it to a file
Public Sub CaptureWindowToFile(ByVal handle As IntPtr, ByVal filename As String, ByVal format As ImageFormat)
Dim img As Image = CaptureWindow(handle)
img.Save(filename, format)
End Sub 'CaptureWindowToFile
'/ Captures a screen shot of the entire desktop, and saves it to a file
Public Sub CaptureScreenToFile(ByVal filename As String, ByVal format As ImageFormat)
Dim img As Image = CaptureScreen()
img.Save(filename, format)
End Sub 'CaptureScreenToFile
Public Function CaptureDeskTopRectangle(ByVal CapRect As Rectangle, ByVal CapRectWidth As Integer, ByVal CapRectHeight As Integer) As Bitmap
'/ Returns BitMap of the region of the desktop, similar to CaptureWindow, but can be used to
'/ create a snapshot of the desktop when no handle is present, by passing in a rectangle
'/ Grabs snapshot of entire desktop, then crops it using the passed in rectangle's coordinates
Dim scap As New ScreenShot.ScreenCapture
Dim bmpImage As New Bitmap(scap.CaptureScreen)
Dim bmpCrop As New Bitmap(CapRectWidth, CapRectHeight, bmpImage.PixelFormat)
Dim recCrop As New Rectangle(CapRect.X, CapRect.Y, CapRectWidth, CapRectHeight)
Dim gphCrop As Graphics = Graphics.FromImage(bmpCrop)
Dim recDest As New Rectangle(0, 0, CapRectWidth, CapRectHeight)
gphCrop.DrawImage(bmpImage, recDest, recCrop.X, recCrop.Y, recCrop.Width, _
recCrop.Height, GraphicsUnit.Pixel)
Return bmpCrop
End Function
'/ Helper class containing Gdi32 API functions
Private Class GDI32
Public SRCCOPY As Integer = &HCC0020
' BitBlt dwRop parameter
Declare Function BitBlt Lib "gdi32.dll" ( _
ByVal hDestDC As IntPtr, _
ByVal x As Int32, _
ByVal y As Int32, _
ByVal nWidth As Int32, _
ByVal nHeight As Int32, _
ByVal hSrcDC As IntPtr, _
ByVal xSrc As Int32, _
ByVal ySrc As Int32, _
ByVal dwRop As Int32) As Int32

Declare Function CreateCompatibleBitmap Lib "gdi32.dll" ( _
ByVal hdc As IntPtr, _
ByVal nWidth As Int32, _
ByVal nHeight As Int32) As IntPtr

Declare Function CreateCompatibleDC Lib "gdi32.dll" ( _
ByVal hdc As IntPtr) As IntPtr

Declare Function DeleteDC Lib "gdi32.dll" ( _
ByVal hdc As IntPtr) As Int32

Declare Function DeleteObject Lib "gdi32.dll" ( _
ByVal hObject As IntPtr) As Int32

Declare Function SelectObject Lib "gdi32.dll" ( _
ByVal hdc As IntPtr, _
ByVal hObject As IntPtr) As IntPtr
End Class 'GDI32
'/ Helper class containing User32 API functions
Public Class User32
<StructLayout(LayoutKind.Sequential)> _
Public Structure RECT
Public left As Integer
Public top As Integer
Public right As Integer
Public bottom As Integer
End Structure 'RECT

Declare Function GetDesktopWindow Lib "user32.dll" () As IntPtr

Declare Function GetWindowDC Lib "user32.dll" ( _
ByVal hwnd As IntPtr) As IntPtr

Declare Function ReleaseDC Lib "user32.dll" ( _
ByVal hwnd As IntPtr, _
ByVal hdc As IntPtr) As Int32

Declare Function GetWindowRect Lib "user32.dll" ( _
ByVal hwnd As IntPtr, _
ByRef lpRect As RECT) As Int32

End Class 'User32
End Class 'ScreenCapture
End Namespace 'ScreenShot


Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
I don't think you need to do a screencapture. You just need to copy the graphics object of the form where I suppose you have drawn your stuff to the graphics objct of an image. Yes it's that simple. ;-)

Christiaan Baes
Belgium

"My new site" - Me
 
Hmm... not sure what you mean. There are over 1000 objects inside panel1 of form1 and I need the image of all of them on top of each other.

Could you get a specific example of saving a graphics object?

Thanks,

Mike

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
What it sounds like you want to do is a double buffer of sorts. Instead of drawing your graphics on the form, you draw all of your graphics to an image object in memory. When the image object is done you then draw the image object to the form. It winds up being significantly more efficient and smoother than trying to update the screen graphics live time.

-Rick

VB.Net Forum forum796 forum855 ASP.NET Forum
[monkey]I believe in killer coding ninja monkeys.[monkey]
 
Well, I hadn't thought of that actually, but there might be a problem still. Several hundred of the "images" are actually picture boxes with regions cut out so that they can later be dragged around and interactive.

Is there a way to take that picture box and draw it to the graphics object without actually figuring a way to redraw the pic box and background image in it?

Thanks

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
Well, this is getting into a bit of theory and would require a good amount of design work but...

You could use an image click map (thread796-1061219) to identify what object the user has clicked on. In the sample in that thread, the only thing that was tracked was the state name, but I'm guessing you are going to need a whole bunch more information, so you'll probrably need a class with information like top, left, image, mousedown image, drag image, mouse up image, selected image, etc... in addition to all of your game related data.

When the user clicks on the image (the displayed image is the one from your double buffer), you check the mouse position for the pixel color on the click map. Find the corelating object in your collection of 'game pieces'. Use the top x,y coordinates from the object and the mouse position to determine your off-set (so that the game piece doesn't jump when you click on it). Also on the click you'll want to change that objects 'state' flag to 'mouse down'.

In the double buffer system you'll want to paint the background, then cycle through all of the 'game pieces' and draw their images based on the state and their image properties.

Once the double buffer is done rendering, you bitblt the image from memory to the form.

It'll take a lot of work, but the performance should be significantly better then a huge number of picture boxes.

-Rick

VB.Net Forum forum796 forum855 ASP.NET Forum
[monkey]I believe in killer coding ninja monkeys.[monkey]
 
so, you're saying that the image that i create will stay in memory the entire time and when I click it'll look at what piece is where the click is and allow it to move through moving the image in memory?

I'm not sure how that would work though because the image is not square and when they click it might be not on the image.

I'm not worried about the performance right now, we're in testing and just trying to get a functional game going. The only performace lag is when you scroll a long distance it takes about 2 seconds to repaint the screen.

Also, I'm just looking to get the game to take a picture of the turn when it starts and upload that static image to the server for out-of-game viewing.

Could you rephrase this: "then cycle through all of the 'game pieces' and draw their images based on the state and their image properties." I'm not sure what you mean. How do I add the .image to the image that's there already?

IE, the map is named map and has an image property already. I then create a new bitmap and copy the image from the map. Then I draw a bunch of things and fill in different regions. How to I add the image of the infantry picturebox to that new bitmap?

Thanks,

Mike

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
With the image click map, would it be able to handle the drag and drop that I was talking about in the other post?

Thanks

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
Like I said, it would take a good amount of work, trial and error, and playing arround (I have to admit, the idea has me somewhat excited, but I have nada for time to work on such a toy).

Yes, you could click and drag.

Let's assume you have a background image (a map of sorts). And let's assum you have 2 different army icons (icons as in an image that represents something, not a .ico file). Each of the army icons would be associated with a 'Game Piece' object. The Game Piece would hold information about the location of the piece, it's z-order (for having objects on top of eachother) and the image to use.

In your double buffer you would first bitblt your map to a fresh bitmap object. Then you would loop through all of the game pieces (your two armies) ordered by the z-order value. For each game piece you would bitblt it's associated image onto that bitmap that you bitblted your background to. Using the game piece's position information to determine where it needs to be bitblted.

Once you are done going through all of the game pieces you would bitblt the appropriate part of the bitmap to the form. You would probrably actually save the image to a property on the form, then in the form's paint method use bitblt to paint the form with that image. That way you could move the double buffer into it's own thread and avoid bogging the gui while updaing graphics.

At the same time that you are maintaining the double buffer to bitblt to the screen you need to maintain another bitmap in memory (the click map). This bitmap will just flat color shapes on it. You would have a bitmap that is the exact shape of each user interactable object in a unique solid color. When the user clicks on the form, you check the position of their cursor on the click map. You can use the color of the pixel at the location of the click (on the click map, not the form) to determine what object they clicked on.

Once you know which game piece the user has clicked on you can change the picture associated with that piece to have a halo or highlight or what ever.

-Rick

VB.Net Forum forum796 forum855 ASP.NET Forum
[monkey]I believe in killer coding ninja monkeys.[monkey]
 
Wowzers,

That really is going to be a bit of work, lol. Might be too much work for this particular game actually, but maybe for one of the others we have on the production run :-/.

As far as that goes, I'm thinking this project will have to wait. I'm hoping that there is still a way to do what I had described though, I have the game done in that respect except for filling in the background images of the map countries... :-/.

Thanks,

Mike

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
Whoops, it seems that I replied thinking this was a different post and I can't figure out how to edit the above...

Anyway, here's the response I would have given ;-D.

Thanks for that, I'm probably going to use this just for grabbing the image out of memory and I'll work on the drag and drop part of that for a larger project. This game is a 2 player game that will make us... very little in comparison to the larger games.

I may have missed it, but in response to a previous post, how do you draw a picture box to a bitmap image and maintain the region/backgroud_image/location?

Thanks,

Mike

Online multiplayer strategy games huh? Try, 1483online.com where the games are FREE and the community drives enhancements to the game. ;-D
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top