Author Topic: Preview Image Code Objects  (Read 2922 times)

0 Members and 1 Guest are viewing this topic.

frostrap

  • Guest
Preview Image Code Objects
« on: February 27, 2009, 11:41:03 AM »
Below is a function that returns a bitmap for a dwg file referenced by it's directory path. I modified the portions that involve graphics from a post that I found on another site, but the rest of the database transaction code is mine.

The code returns a bitmap that I set as an picturebox's image. The code is run about 20 times in rapid succession to populate 20 seperate pictureboxes from path's that are stored in a listbox.

Are all of the objects in this code being disposed properly? Do I need to dispose the graphics and database objects manually (or any other objects)?

After the code is run a number of times, AutoCAD will crash with an unhandled exception. When the code is being run successfully, I am getting poor performance (the form that the code is returning info to lags a lot).

Any ideas?

Thanks,

Joe

Code: [Select]
      
        ''' <summary>
        ''' Returns a bitmap to be assigned as a pictrebox's image
        ''' </summary>
        ''' <param name="DWGPath">The path of the drawing file (must be a *.dwg file)</param>
        ''' <param name="PictureBoxWidth">The width of the picturebox being used</param>
        ''' <param name="PictureBoxHeight">The height of the picturebox being used</param>
        ''' <returns>A bitmap image that matches the size of the picturebox</returns>
        ''' <remarks></remarks>
        Public Function DrawThumbnail(ByVal DWGPath As String, ByVal PictureBoxWidth As Single, ByVal PictureBoxHeight As String) As Bitmap
            Dim mytransman As DatabaseServices.TransactionManager
            Dim myTrans As DatabaseServices.Transaction
            Dim myDB As New DatabaseServices.Database
            Try
                myDB.ReadDwgFile(DWGPath, IO.FileShare.Read, True, "")
                mytransman = myDB.TransactionManager
                myTrans = mytransman.StartTransaction
                ' Set the scale factor.
                Dim WidthScale As Single = PictureBoxWidth / myDB.ThumbnailBitmap.Width()
                Dim HeightScale As Single = PictureBoxHeight / myDB.ThumbnailBitmap.Height()
                Dim theScale As Single = WidthScale
                If WidthScale > HeightScale Then
                    theScale = HeightScale
                End If
                ' Get the source bitmap.
                Dim bm_source As New Bitmap(myDB.ThumbnailBitmap)

                ' Make a bitmap for the result.
                Dim bm_dest As New Bitmap( _
                    CInt(bm_source.Width * theScale), _
                    CInt(bm_source.Height * theScale))

                ' Make a Graphics object for the result Bitmap.
                Dim gr_dest As Graphics = Graphics.FromImage(bm_dest)

                ' Copy the source image into the destination bitmap.
                gr_dest.DrawImage(bm_source, 0, 0, _
                    bm_dest.Width + 1, _
                    bm_dest.Height + 1)

                ' Display the result.
                Return bm_dest
                myTrans.Commit()
            Catch ex As Exception
                MsgBox(ex.Message & ControlChars.CrLf & ex.StackTrace)

            Finally
                myTrans.Dispose()
            End Try
        End Function

Glenn R

  • Guest
Re: Preview Image Code Objects
« Reply #1 on: February 27, 2009, 12:35:17 PM »
At a quick glance, I don't see where your database (myDb) is being disposed - it should really be destroyed on every iteration of the loop.

frostrap

  • Guest
Re: Preview Image Code Objects
« Reply #2 on: February 27, 2009, 01:39:20 PM »
I added myDB.dispose and then hammered on the function some more. I still ended up with an unhandled exception. There must be a leak somewhere. Perhaps the leak is somewhere else in the code?

Do you think it could be crashing because the function is being called so rapidly?

Code: [Select]
            Catch ex As Exception
                MsgBox(ex.Message & ControlChars.CrLf & ex.StackTrace)
                Return Nothing

            Finally
                myTrans.Dispose()
                myDB.Dispose()
            End Try

frostrap

  • Guest
Re: Preview Image Code Objects
« Reply #3 on: February 27, 2009, 11:26:24 PM »
Thanks for your help.

I ended up disposing the bitmap and graphics objects as I read that they (especially graphics) can make calls from unmanaged code. Not knowing exactly what they're doing, I went ahead and disposed them

I used perfmon to watch the autocad process while debugging, and it does look like garbage collection is working, at least to some extent.

Looking at the stack trace from when the program does crash, I think the problem might actually be how I am opening dwg files to get their thumbs. I'm going to read up on the arx documentation to get some more insite on that process.

Thanks for your help.

Joe


Glenn R

  • Guest
Re: Preview Image Code Objects
« Reply #4 on: February 28, 2009, 02:06:45 PM »
I don't do VB, but I think the problem lies here:

Code: [Select]
Dim myDB As New DatabaseServices.Database

If you can, declare myDB as a Database, but then inside your try clause, instantiate it using the constructors like so:

Code: [Select]
Dim myDB as Database
...
Try
myDB = new Database (false, true)
...

Look up the constructor for Database to investigate the arguments to the constructor. In essence, if you're reading and ENTIRE dwg file into a new dbase, you do NOT want the constructor to build a 'default drawing' as you're reading an entire drawing file into the object in the first place, also, seeing as you're doing this 'in memory', there won't be a visible 'document' in the graphical editor associated with it...make sense?

frostrap

  • Guest
Re: Preview Image Code Objects
« Reply #5 on: February 28, 2009, 06:42:33 PM »
Very interesting. I see that warning in the documentation. I'm glad you said something, or I probably wouldn't have understood the importance of the warning. That may very well explain why I'm getting memory violation errors.

I admit I don't fully understand the details about what's going on here. The documentation makes it sound as though you are never supposed to set buildDefaultDrawing to true. When would be a proper time to set the that parameter to true? There must be a time, or it wouldn't be an option.

The code is now as follows:

Code: [Select]
        Public Function DrawThumbnail(ByVal DWGPath As String, ByVal PictureBoxWidth As Single, ByVal PictureBoxHeight As String, _
                                      Optional ByVal InvertThumbs As Boolean = False) As Bitmap
            Dim mytransman As DatabaseServices.TransactionManager
            Dim myTrans As DatabaseServices.Transaction
            Dim myDB As DatabaseServices.Database
            Try
                myDB = New Autodesk.AutoCAD.DatabaseServices.Database(False, True)
                myDB.ReadDwgFile(DWGPath, IO.FileShare.ReadWrite, True, "")
                mytransman = myDB.TransactionManager
                myTrans = mytransman.StartTransaction
                ' Set the scale factor.
                Dim WidthScale As Single = PictureBoxWidth / myDB.ThumbnailBitmap.Width()
                Dim HeightScale As Single = PictureBoxHeight / myDB.ThumbnailBitmap.Height()
                Dim theScale As Single = WidthScale
                If WidthScale > HeightScale Then
                    theScale = HeightScale
                End If
                ' Get the source bitmap.
                Dim bm_source As New Bitmap(myDB.ThumbnailBitmap)

                ' Make a bitmap for the result.
                Dim bm_dest As New Bitmap( _
                    CInt(bm_source.Width * theScale), _
                    CInt(bm_source.Height * theScale))

                ' Make a Graphics object for the result Bitmap.
                Dim gr_dest As Graphics = Graphics.FromImage(bm_dest)
                gr_dest.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
                gr_dest.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
                gr_dest.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBilinear


                ' Copy the source image into the destination bitmap.
                gr_dest.DrawImage(bm_source, 0, 0, bm_dest.Width + 1, bm_dest.Height + 1)

                If InvertThumbs Then
                    Dim X As Integer
                    Dim Y As Integer
                    Dim r As Integer
                    Dim g As Integer
                    Dim b As Integer
                    For X = 0 To bm_dest.Width - 1
                        For Y = 0 To bm_dest.Height - 1
                            r = 255 - bm_dest.GetPixel(X, Y).R
                            g = 255 - bm_dest.GetPixel(X, Y).G
                            b = 255 - bm_dest.GetPixel(X, Y).B
                            bm_dest.SetPixel(X, Y, Color.FromArgb(r, g, b))
                        Next Y
                    Next X
                End If


                'Return the result.
                Return bm_dest
                'commit the transaction
                myTrans.Commit()
                'clean up the graphics resources
                bm_dest.Dispose()
                bm_source.Dispose()
                gr_dest.Dispose()
            Catch ex As Exception
                MsgBox(ex.Message & ControlChars.CrLf & ex.StackTrace)
                Return Nothing
            Finally
                myTrans.Dispose()
                myDB.Dispose()
            End Try

Glenn R

  • Guest
Re: Preview Image Code Objects
« Reply #6 on: March 01, 2009, 02:05:38 PM »
Your code might be different, but you don't mention if the errors 'went away'...

Also, in your finally clause, it's generally best to dispose of things in the reverse order of creation...eg. myTrans last, myDB second last (in other words, re your example, swap them around).

frostrap

  • Guest
Re: Preview Image Code Objects
« Reply #7 on: March 03, 2009, 11:08:32 AM »
I think that problem is resolved. I fixed the order in which I was disposing my objects in addition to the other change. I haven't received a fatal error yet.

I am getting a general "Object reference not set to an instance of an object", when I pass a specific dwg into the function, but I think it might be because the dwg file may not have a thumbnail saved. I assume the bitmap variable is getting set to nothing since there is no bitmap to retreive, and when my code tries to modify a null bitmap, it fires off an error.

Anyway, that's my assumption, and I don't think it's related to my original problem.

Thanks Glenn!