Author Topic: Getting thumbnails from Autocad DWG files  (Read 5065 times)

0 Members and 1 Guest are viewing this topic.

jerrywilson

  • Guest
Getting thumbnails from Autocad DWG files
« on: October 30, 2013, 05:53:33 AM »
I have a Access database that is used by design engineers to manage their AutoCad revisions. The database uses an activex control to display a thumbnail of the AutoCad drawing, but it is not compatible with the new 2013 DWG format which uses .png instead of .bmp thumbnails.

As far as I can tell the activex control is not being manitained and so I need to find an another way to display the old and new DWG thumnails.

I found some very excellent .NET VB code originally posted by Keith, here on this forum, that works with both old and new DWG formats.

The problem I have is integrating .Net VB with VBa and the Access database.

I am attempting to package the .Net VB code into a .dll which I hope I will be able to use from Access VBa, but I'm having problems with it. I can't seem to access the GetBitmap function when I package the code as a .dll

I've compiled it to register for COM interop and made the assembly COM-visible. 

I'm a bit of a newby when it comes to .NET VB and I'm not entirely sure that my plan will work, but I thought it worth a go. If anyone can offer some advice on this it would be much appreciated.

Code: [Select]
Imports System.Drawing
Imports System.IO
    Public Class ThumbnailImage
        ' 2011 Copyright (C) jgr=&jgr, via http://www.theswamp.org
        ' 2012 (me): Added code to read PNG Thumbnails from DWG (2013 file format)
    Public Class Thumbnail
        Private Sub New()
        End Sub
        Public Function GetBitmap(ByVal fileName As String) As Bitmap
            Using fs As New FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
                Using br As New BinaryReader(fs)
                    fs.Seek(&HD, SeekOrigin.Begin)
                    fs.Seek(&H14 + br.ReadInt32(), SeekOrigin.Begin)
                    Dim bytCnt As Byte = br.ReadByte()
                    If bytCnt <= 1 Then
                        Return Nothing
                    End If
                    Dim imageHeaderStart As Integer
                    Dim imageHeaderSize As Integer
                    Dim imageCode As Byte
                    For i As Short = 1 To bytCnt
                        imageCode = br.ReadByte()
                        imageHeaderStart = br.ReadInt32()
                        imageHeaderSize = br.ReadInt32()
                        If imageCode = 2 Then ' BMP Preview (2012 file format)
                            ' BITMAPINFOHEADER (40 bytes)
                            br.ReadBytes(&HE)
                            'biSize, biWidth, biHeight, biPlanes
                            Dim biBitCount As UShort = br.ReadUInt16()
                            br.ReadBytes(4)
                            'biCompression
                            Dim biSizeImage As UInteger = br.ReadUInt32()
                            'br.ReadBytes(0x10); //biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant
                            '-----------------------------------------------------
                            fs.Seek(imageHeaderStart, SeekOrigin.Begin)
                            Dim bitmapBuffer As Byte() = br.ReadBytes(imageHeaderSize)
                            Dim colorTableSize As UInteger = CUInt(Math.Truncate(If((biBitCount < 9), 4 * Math.Pow(2, biBitCount), 0)))
                            Using ms As New MemoryStream()
                                Using bw As New BinaryWriter(ms)
                                    bw.Write(CUShort(&H4D42))
                                    bw.Write(54UI + colorTableSize + biSizeImage)
                                    bw.Write(New UShort())
                                    bw.Write(New UShort())
                                    bw.Write(54UI + colorTableSize)
                                    bw.Write(bitmapBuffer)
                                    Return New Bitmap(ms)
                                End Using
                            End Using
                        ElseIf imageCode = 6 Then ' PNG Preview (2013 file format)
                            fs.Seek(imageHeaderStart, SeekOrigin.Begin)
                            Using ms As New MemoryStream
                                fs.CopyTo(ms, imageHeaderStart)
                                Dim img = Image.FromStream(ms)
                                Return img
                            End Using
                        ElseIf imageCode = 3 Then
                            Return Nothing
                        End If
                    Next
                End Using
            End Using
            Return Nothing
        End Function
    End Class
End Class


Bert

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #1 on: October 30, 2013, 06:37:12 AM »
I trust you where able to reference your .dll in the Access-Vba ?

Can you show us how you instantiate and use this Class in Vba ?

jerrywilson

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #2 on: October 30, 2013, 06:54:38 AM »
Yes, ThumbnailLib (as I've called the dll) appears in VBA  Tools > References.

In the Object browser "Thumbnail" appears (the public class name) but GetBitmap does not appear in the  Members of "Thumbnail" as I would expect.

(Other classes listed in the object browser have their methods listed in Members of ...)

The VBa code I've been playing with is along the lines of:

Private Sub Detail_Click()
 Dim cMyDLL As ThumbnailImage
 Set cMyDLL = New ThumbnailImage
 Dim file1 As String
      Dim image1 As Image
      Me![ImageFrame].Image = cMyDLL.GetBitmap(file1) 
End Sub

Bert

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #3 on: October 30, 2013, 07:00:43 AM »
Is it not so that the Class Thumbnail holds the GetBitmap method, not the Class ThumbnailImage ?

jerrywilson

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #4 on: October 30, 2013, 07:11:48 AM »
Both appear in the object browser, but yes, class Thumbnail holds the GetBitmap method.

The VBa is just something I've been playing with to try to access the .dll, I've tried both "Thumbnail" and "ThumbnailImage".     

Bert

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #5 on: October 30, 2013, 08:36:35 AM »
Are you using Visual Studio ?
Access is going to communicate with your library using COM. For Access to use a COM library there need to be appropriate entries in the registry. Visual Studio can generate those entries by :
1) On the ‘Application’ tab click the ‘Assembly Information…’ button. In the resulting dialog check the ‘Make assembly COM-visible’ checkbox. Click ‘OK’.
2) On the ‘Build’ tab check the ‘Register for COM interop’ checkbox (towards the bottom: you may need to scroll down).

jerrywilson

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #6 on: October 30, 2013, 09:07:18 AM »
Yes, I built the dll in Visual Studio and made the assembly COM visible and registered for COM interop.

Keith™

  • Villiage Idiot
  • Seagull
  • Posts: 16899
  • Superior Stupidity at its best
Re: Getting thumbnails from Autocad DWG files
« Reply #7 on: October 30, 2013, 10:19:48 AM »
Using a .net assembly in the manner you talk about may need to be registered differently.

Try registering the dll with regasm.exe (it is located in the .net framework folder for the version of .net you are using in the build. i.e. .net V2 is located at C:\windows\microsoft.net\Framework\v2.0.50727\regasm.exe.

You can find the reference to regasm.exe here

If this isn't the problem, try cleaning the project and rebuilding from scratch.
Proud provider of opinion and arrogance since November 22, 2003 at 09:35:31 am
CadJockey Militia Field Marshal

Find me on https://parler.com @kblackie

jerrywilson

  • Guest
Re: Getting thumbnails from Autocad DWG files
« Reply #8 on: October 30, 2013, 11:16:49 AM »
I have registered it using regasm and created a type library (tbl) file using the regasm /tbl option.

I'll rebuild from scratch again and see if that helps.

In the mean time, would you expect the GetBitMap method to be accessible in my previous code.

I have changed the the Class types from the original code in an attempt to make the GetBitMap method visible. Originally it was like this:

Code: [Select]
' 2011 Copyright (C) jgr=&jgr, via http://www.theswamp.org
' 2012 (me): Added code to read PNG Thumbnails from DWG (2013 file format)
Friend NotInheritable Class ThumbnailReader
  Private Sub New()
  End Sub
  Friend Shared Function GetBitmap(fileName As String) As Bitmap
    Using fs As New FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)
      Using br As New BinaryReader(fs)
        fs.Seek(&HD, SeekOrigin.Begin)
        fs.Seek(&H14 + br.ReadInt32(), SeekOrigin.Begin)
        Dim bytCnt As Byte = br.ReadByte()
        If bytCnt <= 1 Then
          Return Nothing
        End If
        Dim imageHeaderStart As Integer
        Dim imageHeaderSize As Integer
        Dim imageCode As Byte
        For i As Short = 1 To bytCnt
          imageCode = br.ReadByte()
          imageHeaderStart = br.ReadInt32()
          imageHeaderSize = br.ReadInt32()
          If imageCode = 2 Then ' BMP Preview (2012 file format)
            ' BITMAPINFOHEADER (40 bytes)
            br.ReadBytes(&HE)
            'biSize, biWidth, biHeight, biPlanes
            Dim biBitCount As UShort = br.ReadUInt16()
            br.ReadBytes(4)
            'biCompression
            Dim biSizeImage As UInteger = br.ReadUInt32()
            'br.ReadBytes(0x10); //biXPelsPerMeter, biYPelsPerMeter, biClrUsed, biClrImportant
            '-----------------------------------------------------
            fs.Seek(imageHeaderStart, SeekOrigin.Begin)
            Dim bitmapBuffer As Byte() = br.ReadBytes(imageHeaderSize)
            Dim colorTableSize As UInteger = CUInt(Math.Truncate(If((biBitCount < 9), 4 * Math.Pow(2, biBitCount), 0)))
            Using ms As New MemoryStream()
              Using bw As New BinaryWriter(ms)
                bw.Write(CUShort(&H4D42))
                bw.Write(54UI + colorTableSize + biSizeImage)
                bw.Write(New UShort())
                bw.Write(New UShort())
                bw.Write(54UI + colorTableSize)
                bw.Write(bitmapBuffer)
                Return New Bitmap(ms)
              End Using
            End Using
          ElseIf imageCode = 6 Then ' PNG Preview (2013 file format)
            fs.Seek(imageHeaderStart, SeekOrigin.Begin)
            Using ms As New MemoryStream
              fs.CopyTo(ms, imageHeaderStart)
              Dim img = Image.FromStream(ms)
              Return img
            End Using
          ElseIf imageCode = 3 Then
            Return Nothing
          End If
        Next
      End Using
    End Using
    Return Nothing
  End Function
End Class

But I thought the "Friend NotInheritable Class" type for ThumbnailReader, and the "Friend Shared Function" type for GetBitMap might have been causing some of the compliation problems I was having with it.