Thomas Snape - July/August 2002
This document last updated 08/08/02
The OpenBitmapDC - CloseBitmapDC Methods
The Run Method of the Render Object
The Picture Property of the RenderView Object
External Methods (Using System API)
Add New View to Views Collection Assign to DC:
Download files used for this project
This is a discussion of various methods I have tried to use to create images of TurboCAD drawing views, and save them as image files. For my purposes I am only working with model space views. I classify the views into two general categories; rendered and wireframe (not rendered). In general the methods used can be placed into two groups; built-in methods, and external methods. The built-in methods are those exposed by the TurboCAD SDK that appear to be specifically provided to capture images of drawing views. The external methods are those that do not rely on the TurboCAD SDK, but instead on Windows system API calls. Some of the methods necessarily combine internal and external methods.
The macro accompanying this document (CaptureTests.tcm) contains examples of attempts to use several different methods. Some methods are successful, some are not. Some work with wireframe views, but fail with rendered views. At this time I am only developing this macro in TurboCAD Pro v188.8.131.52d, and I'm only trying to save captured view images as bitmaps.
Many graphics methods in VB and VBA, especially those using API calls, require the use of handles to bitmaps and device contexts (DC's). The Visual Basic PictureBox is a convenient control to use with these methods because it offers image, picture, window handle (hWnd) and DC handle (hDC) properties. VBA does not offer a PictureBox control, and it's Image control and Forms offer only a basic picture property. In order to be able to more easily utilize methods requiring DC's, I created an ActiveX PictureBox control in Visual Basic that can be used in VBA. I identify it as TrsPicture. It doesn't have any special properties or methods, all it does is allow the use of a VB PictureBox control in a VBA macro. The only properties of the PictureBox control I've exposed are the picture, image, hBmp and hDC. You can use TrsPicture freely if it is useful to you. There are more advanced picture controls available from developers if you have a need. A couple that I know of are GT Image and Inspired Creations Enhanced PictureBox.
To run CaptureTests.tcm you will need to have TrsPicture.ocx on your system, and it must be referenced by the macro in the VBA editor. If you are not sure how to do this, or have any difficulty getting it you work, you can download a full installation file for the control from my web site.
The remainder of this document will discuss in some detail each capture method I've tried. I have more or less tried to follow the same steps with each procedure. First, an attempt is made to capture an image of the the drawing active view, and display it on a form. In some cases the form contains an Image control, and in others it contains a TrsPicture control. Then the image is saved to disk as a BMP format bitmap. The macro creates a new directory name "CaptureTests" under the TurboCAD installation directory. The BMP file names start with the name of the procedure that created them, followed by a ten digit number based on the system time when the file was created. This is just to ensure a unique name for each file, and to have some way to tell how and in what sequence the files were created. You will want to remember to go back and delete these files when you are finished because some of them can be pretty large.
As you try the different methods, you will notice that the images produced from the various methods vary in size and view. Some are clipped portions of the full view. Others may be distorted by the bitmap transfer method used. Don't worry about this; the point of these exercises was to succeed in capturing an image. As long was we can obtain a useable image, we can resize it, scale it, etc. as necessary to get the picture we want.
I am hoping that others will take what I have started here and investigate some of these methods further. I will be particularly interested in hearing that someone has been able to successfully use one of the methods that I was not successful with.
Built-In capture methods:
The Drawing object has both SaveAs and SaveCopyAs methods. I've tried both and they seem to work the same when run from code. I use the SaveCopyAs method (Button 1) because of the unsubstantiated belief that if there is a difference between the two methods, it is the safer one to use.
This is a very easy method to use. It works equally well for wireframe and rendered views. And it works for any file format that TurboCAD supports. I think the SaveCopyAs method for capturing the drawing image is satisfactory for most uses.
The use of SaveCopyAs method is a little different than for the other procedures discussed here because the image of the drawing view is saved directly to disk as a bitmap image. If you want to then display the image, or manipulate it in any way you must read it back. This might be a drawback for some applications.
When you use the "Save As" command from the File menu, and specify the "Save as type" as BMP, you can specify some settings in the "BMP File Export" settings dialog. This allows you to choose between saving the current view, or an view of the entire drawing. It also allows you to specify the size in pixels of the saved image. When using the SaveCopyAs method in VBA, we can also specify these same settings, but we must do it by editing the appropriate entries in TurboCAD's INI file; "TCW80.ini". It's not too difficult, it only requires using the WritePrivateProfileString API function. This technique is shown in the macro.
The OpenBitmapDC - CloseBitmapDC Methods:
These methods are described in the TurboCAD SDK documentation "Creating Bitmaps and Metafiles with the View Object". The idea is that the OpenBitmapDC method of the View object will connect the View to a memory DC (Device Context). In this state you could make changes to the View in memory with out changing the View in the drawing. That's beyond the scope of this discussion. What is pertinent to our desire to capture the view image is that when you close the memory DC (using one of three different methods), the image is returned to you in some manner. How the image is returned depends on which Close method you use. When you use the CloseBitmapDC, the handle to a bitmap is returned. The CloseBitmapPictDc method returns a StdPicture object. The CloseBitmapBitsDC methos returns the bitmap bit array information in a SAFEARRAY format.
First of all, I found that all three "CloseBitmap... DC" methods failed when the view is rendered. The error message is "Run-time error '7': Out of memory" . I can only guess that either this is a defect in the program, or that these methods were only intended to be used with wireframe views.
The only method of the three that I was successfully able to use for wireframe views was the OpenBitmapDC - CloseBitmapPictDC pair (Button 3 on the macro CaptureTests menu form). This returned a StdPicture object which can be assigned to the Picture property of a UserForm or an Image control.
The OpenBitmapDC - CloseBitmapDC method (Button 2) returns a handle to a bitmap in memory. This method may work, but perhaps due to my inexperience I was not able to obtain a displayable image.
Same story for the OpenBitmapDC - CloseBitmapBits method (Button 4). The bitmap bit array is returned in a SAFEARRAY. I was able to learn a little about what SAFEARRAY's are, but not enough for me to figure out how to create the structure for a bitmap using the array. I left this procedure "Not Coded" in the macro.
The Run method of the Render Object:
The Render objects represent the three types of rendering that you can perform in TurboCAD (Hidden Line, OpenGL, and Lightworks). You can create an Render object reference, set the properties of the Render, and then render the active view using the Run method of the Render object. Besides initiating the render, the Run method is supposed to return a picture object. The TurboCAD SDK documentation indicates that there is a defect and it does not return the picture. But I had to try it anyway (Button 5). They were right.
The Picture Property of the RenderView Object:
As stated by the TurboCAD SDK documentation, the RenderView object controls the characteristics of a 3D rendering of a drawing view. If a view is not rendered, you can start the render by the BeginRender property of the RenderView object (apparently an alternative to the Render.Run method). One of the properties of the RenderView is the Picture. However, when I try to use the Picture property of a RenderView object in the macro (Button 6), I get an error; "Method 'Picture' of Object 'RenderView' failed."
External System API Methods:
I experimented with the use of Windows system API functions to capture the image from the active view and save the image. The idea is to get a handle to the DC of the active view window, and use either BitBlt or StretchBlt to transfer the window image to another control. The object model shows that there is a DC property of the View object, but in my tests it only returned "0". So I used the view's HWND property with the GetDC API function to obtain the view DC.
In the first of these procedures (Button 8) I transfered the image directly to my PictureBox control. If you then click on the form outside of the PictureBox, the picture image is written to the form, again directly from the view. Notice that any toolbars or dialogs that are on top of the view rectangle will also be included in the captured image. This is may be desirable for some purposes, but probably not for most. Note that when the image is written to the form, a partial image of the form itself maybe be present.
In the second of these procedures (Button 9) I created a memory DC. Then I used BitBlt to copy the active view window image to the memory DC, and then from the DC to my PictureBox control. Again, if you click on the form that appears, the image is written to the form, but this time from the memory DC. The difference is that when the image is written to the form, the image will not contain any part of the form, as in the previous example. This is because the image of the original window is still in memory, and it is not affected by changes that have occurred to the active view since the image was saved.
The third procedure (Button 7) is sort of a cross between what I called the internal and external image capture procedures. In this case, I am again using the OpenBitmapDC, only this time I am using the handle to the DC with BitBlt to transfer the image of the TurboCAD BitmapDC to my PictureBox control. My original thought was that I might be able to capture an image of a rendered view this way, by using the OpenBitmapDC on a wireframe view, running the render on the view in the DC, using BitBlt to transfer the image, then undoing the render and closing the DC. I could not get this to work though. All I was able to do with this idea was to again capture the image of a wireframe view.
Add New View to Views Collection Assign to DC:
The last method I tried (Button 10) is to create a new view of the model by using the Views.Add method. Only instead of adding the view as a new window in the drawing, it is assigned to a DC of an object. In this case, the object is a TrsPicture PictureBox in a form. I did a couple of different things with this procedure. When you first run the procedure, you are presented with an empty picture. You have to click the "Add View" button on the form to create the new view and assign it to the PictueBox. There is a check box to indicate if you want to adjust the camera location and other settings to mimic those of the active drawing view. If you uncheck the box, you get the default World Plan view. Next, you can click the "Render" button to render the view in the PictureBox. Clicking the "Save to file" button saves the current picture of the PictureBox to disk as a bitmap. You can save the picture of either the wireframe or rendered views. (Note that the name that the file is saved as is set before the form is loaded, so successive clicks of the the "Save to file" button will overwrite previous saves. To avoid this, close the form each time and restart by clicking button 10 from the main menu form).
Files used in this project:
All of the procedures described above are contained in this macro: CaptureTests.tcm (63 KB zipped)
The macro contains two code modules, and six forms. The macro must contain a reference to TrsPicture.ocx, which may show up in the References list as "PictureForm".
Code module "modMain" contains the procedures that display the macros menu form ("frmMenu"), and the procedures that are run when the corresponding buttons are clicked on frmMenu. Note that many of the procedures show an optional parameter named "dummy". This is not used in the code at all. The only purpose of the "dummy" parameter is to avoid having TurboCAD display all the procedure names in the macro toolbar.
The code module "modAPI" contains all the system API function declarations used in the procedures, as well as a few type definitions.
Form "frmMenu" just contains the buttons that are used to run the various procedures. The rest of the forms are used by the various procedures.
CaptureTests.tcm needs my ActiveX PictureBox control in order to work. If you want, you can download just the ActiveX control TrsPicture.ocx (5 KB zipped) and register it yourself on your system. Or, you can download the complete setup file (1.4 MB), that will handle the installation and registration for you.