locked
Dwg thumbnail in PictureBox [VB.NET 2010] RRS feed

  • Question

  • Hi forum,

    I'm creating a project retrieving data from a Access database and I want to show a thumbnail preview of my files in a PictureBox.

    I generate the path to the dwg file to show by composing a string.

    Based on the given dwg file (read string generated), I want to display a thumbnail image in a picturebox in my form.

    I did find several ways to do it on the Net (using Shell API, external ocx files with dedicated controls, loading Autocad dlls, etc) , but I don't seem to get any of them to work. :(

     

    Following the links of some of the solutions proposed on the Net

     

    http://social.msdn.microsoft.com/Forums/en-US/vblanguage/thread/af1cd802-c357-435b-8e5a-a8fcacd1c9d7/

    http://www.vbaccelerator.com/home/net/code/libraries/shell_projects/Thumbnail_Extraction/article.asp

    http://social.msdn.microsoft.com/forums/en-US/netfxbcl/thread/1428326d-7950-42b4-ad94-8e962124043e/

    http://www.theswamp.org/index.php?topic=30985.0

     

    I read more carefully these two options:

    http://msdn.microsoft.com/en-us/library/8t23aykb%28v=VS.100%29.aspx

    http://forums.autodesk.com/t5/NET/Save-preview-to-file/td-p/1351977

     

    I guess the first one is the easier way to accomplish the task, but I don't know if a method similar to the following exists for dwg files to extract the thumbnail.

    myBitmap.GetThumbnailImage(40, 40, myCallback, IntPtr.Zero) 

    I tried to import several dlls in order to try all the solutions above but I'm afraid I'm overcomplicating the task.

     

    I ask for the forum guys to enlighten me on this topic..it's driving me nuts..

    thank you in advance for your support

    P.


    pp _______________ VB Express 2010
    Tuesday, April 12, 2011 9:52 PM

Answers

  • Hi fredpox,

    Welcome to the MSDN Forum.

    Here is a test code of retrieve the BMP data from a DWG file for your reference.

    Imports System.Collections.Generic
    Imports System.ComponentModel
    Imports System.Data
    Imports System.Drawing
    Imports System.Text
    Imports System.Windows.Forms
    Imports System.IO
    
    Partial Public Class Form1
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Dim viewDwg As New ViewDWG()
        PictureBox1.Image = viewDwg.GetDwgImage("d:\s.dwg")
      End Sub
      Private Class ViewDWG
        Private Structure BITMAPFILEHEADER
          Public bfType As Short
          Public bfSize As Integer
          Public bfReserved1 As Short
          Public bfReserved2 As Short
          Public bfOffBits As Integer
        End Structure
        Public Function GetDwgImage(ByVal FileName As String) As Image
          If Not (File.Exists(FileName)) Then
            Throw New FileNotFoundException("the file didn't find")
          End If
          'declare a filestream to read the DWG file
          Dim DwgF As FileStream
          'the position of file description block
          Dim PosSentinel As Integer
          'Binary Reader
          Dim br As BinaryReader
          'the thumbnail farmat
          Dim TypePreview As Integer
          'the thumbnail postion
          Dim PosBMP As Integer
          'the thumbnail size
          Dim LenBMP As Integer
          'the thumbnail depth
          Dim biBitCount As Short
          'BMP file header,because DWG doesn't include the header,we need add it by ourself
          Dim biH As BITMAPFILEHEADER
          'BMP file body in the DWG file
          Dim BMPInfo As Byte()
          'to store the memory stream
          Dim BMPF As New MemoryStream()
          'Binary Writer
          Dim bmpr As New BinaryWriter(BMPF)
          Dim myImg As Image = Nothing
    
          Try
            'DWG file stream
            DwgF = New FileStream(FileName, FileMode.Open, FileAccess.Read)
            br = New BinaryReader(DwgF)
            'read from the thirteenth byte
            DwgF.Seek(13, SeekOrigin.Begin)
            'read the thumbnail description block position
            PosSentinel = br.ReadInt32()
            'read from the thirty-first byte of the thumbnail description block
            DwgF.Seek(PosSentinel + 30, SeekOrigin.Begin)
            'the thirty-first byte represent the thumbnail picture format, 2 means BMP, 3 means WMF
            TypePreview = br.ReadByte()
    
            If TypePreview = 1 Then
            ElseIf TypePreview = 2 OrElse TypePreview = 3 Then
              'the BMP block postion saved by DWG file
              PosBMP = br.ReadInt32()
              'the BMP block size
              LenBMP = br.ReadInt32()
              'move to the BMP block
              DwgF.Seek(PosBMP + 14, SeekOrigin.Begin)
              'read the btye depth
              biBitCount = br.ReadInt16()
              'read all BMP content
              DwgF.Seek(PosBMP, SeekOrigin.Begin)
              'the BMP with no header
              BMPInfo = br.ReadBytes(LenBMP)
              br.Close()
              DwgF.Close()
              biH.bfType = 19778
              'build the header
              If biBitCount < 9 Then
                biH.bfSize = 54 + 4 * CInt(Math.Truncate(Math.Pow(2, biBitCount))) + LenBMP
              Else
                biH.bfSize = 54 + LenBMP
              End If
              'reserved byte
              biH.bfReserved1 = 0
              'reserved byte
              biH.bfReserved2 = 0
              'BMP data offset
              'write BMP header
              biH.bfOffBits = 14 + 40 + 1024
              'file type
              bmpr.Write(biH.bfType)
              'file size
              bmpr.Write(biH.bfSize)
              '0
              bmpr.Write(biH.bfReserved1)
              '0
              bmpr.Write(biH.bfReserved2)
              'offset
              bmpr.Write(biH.bfOffBits)
              'write BMP file
              bmpr.Write(BMPInfo)
              'move the pointer to the beginning
              BMPF.Seek(0, SeekOrigin.Begin)
              'create the BMP file
              myImg = Image.FromStream(BMPF)
              bmpr.Close()
              BMPF.Close()
            End If
            Return myImg
          Catch ex As Exception
            Throw New Exception(ex.Message)
          End Try
        End Function
      End Class
    
    End Class
    

    I hope this will be helpful.

    Best regards,


    Mike Feng [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Thursday, April 14, 2011 11:42 AM
    Moderator
  • Hi Fredpox,

    What do you mean "control the dimensions of the picture I get"? Do you mean "zoom in"? If so, the two links should be helpful to you:

    http://social.msdn.microsoft.com/Forums/en-US/vbide/thread/625f8169-4cfb-4b16-a4ba-9030d0a76e39

    http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/0609b802-b3d4-417e-8a58-4237993589cc

    the both is related to zoom in a picture.

    As you know, each type of file obey a kind of protocol standard, the standard provide the farmat: which byte means size, which byte means data, and so on. in most cases, the protocol standard isn't open. So the code may do not work with the other type of file.

    I hope this will be helpful.

    Best regards


    Mike Feng [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Friday, April 15, 2011 5:38 AM
    Moderator
  • Fred,

    For the purpose you want I use also the GetThumbnailImage, it does not what it suggest, but creates simply a new thumbnail from a bitmap.

    But first you have to create of course an image from a scratch.

    I don't know if you know how to do that as all samples on MSDN show that as a result from the paint event.

    The form2 part of the sample on our website shows how it can be done.

    http://www.vb-tips.com/dbpages.aspx?Search=clock

    And then of course that GetThumbnailImage

    (Don't care it is handling a webpage, your part of the code is the same for a windows form)

     

     

     


    Success
    Cor
    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Friday, April 15, 2011 6:16 AM

All replies

  • I have this example that show how to create on a form a thumbnail of another form.

    In this example form1 creates a second form (I put a browser on it, but it can be anything). and then creates a thumbnail of this form. the thumbnail is painted on the form1.

    In the example, the thumbnail is dynamic, so any change in the second form is reflected in the thumbnail, but if this is not the behaviour you need, you can just move the thumbnail image to a bitmap and it will become a static image.

    Hope this can help you ...

    just paste the code, the form needs no control

     

    Public Class Form1
    
      Private ThumbID As Integer = 0
      Public Sub showThumbNail()
        If ThumbID <> 0 Then
          DwmUnregisterThumbnail(ThumbID)
          ThumbID = 0
        End If
        Dim result As Integer
        Dim hWnd As IntPtr
        hWnd = FindWindow(Nothing, "Form2")
        result = DwmRegisterThumbnail(Me.Handle, hWnd, ThumbID)
        If result = 0 Then
          Dim ThumbSize As New PSIZE
          DwmQueryThumbnailSourceSize(ThumbID, ThumbSize)
    
          Dim rect As New Rectangle(10, 10, 300, 300)
          Dim ThumbPropreties As New DWM_THUMBNAIL_PROPERTIES
          ThumbPropreties.dwflags = DWM_TNP_RECTDESTINATION Or DWM_TNP_VISIBLE Or DWM_TNP_SOURCECLIENTAREAONLY
          ThumbPropreties.fSourceClientAreaOnly = True
          ThumbPropreties.fVisible = True
          ThumbPropreties.opacity = CByte((255 * 100) / 100)
          ThumbPropreties.rcDestination = rect
          result = DwmUpdateThumbnailProperties(ThumbID, ThumbPropreties)
        Else
          MsgBox("Cannot Create the Thumbnail")
        End If
      End Sub
    
      Private Sub Form1_FormClosing(ByVal sender As Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles Me.FormClosing
        DwmUnregisterThumbnail(ThumbID)
      End Sub
    
      Dim F As New Form2
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
        Me.Size = New Size(550, 300)
        Button1.Location = New Point(445, 20)
        F.Show()
      End Sub
    
      '===================WIN 32 REGION ===============================
    
      'A value for the rcDestination member has been specified.
      Const DWM_TNP_RECTDESTINATION As Integer = &H1
      'A value for the rcSource member has been specified.
      Const DWM_TNP_RECTSOURCE As Integer = &H2
      'A value for the opacity member has been specified.
      Const DWM_TNP_OPACITY As Integer = &H4
      'A value for the fVisible member has been specified.
      Const DWM_TNP_VISIBLE As Integer = &H8
      'A value for the fSourceClientAreaOnly member has been specified.
      Const DWM_TNP_SOURCECLIENTAREAONLY As Integer = &H10
    
      Public Structure DWM_THUMBNAIL_PROPERTIES
        Public dwflags As Integer
        Public rcDestination As Rectangle
        Public rcSource As Rectangle
        Public opacity As Byte
        Public fVisible As Boolean
        Public fSourceClientAreaOnly As Boolean
      End Structure
    
      Public Structure PSIZE
        Public X As Integer
        Public Y As Integer
      End Structure
    
      Declare Function DwmRegisterThumbnail Lib "Dwmapi.dll" (ByVal hwndDestination As IntPtr, ByVal hwndSource As IntPtr, ByRef phThumbnailId As Integer) As Integer
      Declare Function DwmUpdateThumbnailProperties Lib "Dwmapi.dll" (ByVal hThumbnailId As Integer, ByVal ptnProperties As DWM_THUMBNAIL_PROPERTIES) As Integer
      Declare Function DwmUnregisterThumbnail Lib "Dwmapi.dll" (ByVal phThumbnailId As Integer) As Integer
      Declare Auto Function FindWindow Lib "User32.dll" (ByVal lpClassName As String, ByVal lpWindowName As String) As IntPtr
      Declare Function DwmQueryThumbnailSourceSize Lib "Dwmapi.dll" (ByVal phThumbnailId As Integer, ByRef pSize As PSIZE) As Integer
    End Class
    
    
    Class Form2 : Inherits Form
      Public WithEvents Wb As New WebBrowser With {.Parent = Me}
      Public Sub New()
        MyBase.New()
        Me.Text = "Form2"
        Me.Size = New Size(800, 500)
        Wb.Dock = DockStyle.Fill
        Wb.Navigate("http://www.altavista.com")
      End Sub
    
      Private Sub Wb_DocumentCompleted(ByVal sender As Object, ByVal e As System.Windows.Forms.WebBrowserDocumentCompletedEventArgs) Handles Wb.DocumentCompleted
        Form1.Focus()
        Form1.showThumbNail()
        Me.Location = Form1.Location + Form1.Size
      End Sub
    
    End Class
    
    Wednesday, April 13, 2011 11:06 AM
  • Hi fredpox,

    Welcome to the MSDN Forum.

    Here is a test code of retrieve the BMP data from a DWG file for your reference.

    Imports System.Collections.Generic
    Imports System.ComponentModel
    Imports System.Data
    Imports System.Drawing
    Imports System.Text
    Imports System.Windows.Forms
    Imports System.IO
    
    Partial Public Class Form1
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles Me.Load
        Dim viewDwg As New ViewDWG()
        PictureBox1.Image = viewDwg.GetDwgImage("d:\s.dwg")
      End Sub
      Private Class ViewDWG
        Private Structure BITMAPFILEHEADER
          Public bfType As Short
          Public bfSize As Integer
          Public bfReserved1 As Short
          Public bfReserved2 As Short
          Public bfOffBits As Integer
        End Structure
        Public Function GetDwgImage(ByVal FileName As String) As Image
          If Not (File.Exists(FileName)) Then
            Throw New FileNotFoundException("the file didn't find")
          End If
          'declare a filestream to read the DWG file
          Dim DwgF As FileStream
          'the position of file description block
          Dim PosSentinel As Integer
          'Binary Reader
          Dim br As BinaryReader
          'the thumbnail farmat
          Dim TypePreview As Integer
          'the thumbnail postion
          Dim PosBMP As Integer
          'the thumbnail size
          Dim LenBMP As Integer
          'the thumbnail depth
          Dim biBitCount As Short
          'BMP file header,because DWG doesn't include the header,we need add it by ourself
          Dim biH As BITMAPFILEHEADER
          'BMP file body in the DWG file
          Dim BMPInfo As Byte()
          'to store the memory stream
          Dim BMPF As New MemoryStream()
          'Binary Writer
          Dim bmpr As New BinaryWriter(BMPF)
          Dim myImg As Image = Nothing
    
          Try
            'DWG file stream
            DwgF = New FileStream(FileName, FileMode.Open, FileAccess.Read)
            br = New BinaryReader(DwgF)
            'read from the thirteenth byte
            DwgF.Seek(13, SeekOrigin.Begin)
            'read the thumbnail description block position
            PosSentinel = br.ReadInt32()
            'read from the thirty-first byte of the thumbnail description block
            DwgF.Seek(PosSentinel + 30, SeekOrigin.Begin)
            'the thirty-first byte represent the thumbnail picture format, 2 means BMP, 3 means WMF
            TypePreview = br.ReadByte()
    
            If TypePreview = 1 Then
            ElseIf TypePreview = 2 OrElse TypePreview = 3 Then
              'the BMP block postion saved by DWG file
              PosBMP = br.ReadInt32()
              'the BMP block size
              LenBMP = br.ReadInt32()
              'move to the BMP block
              DwgF.Seek(PosBMP + 14, SeekOrigin.Begin)
              'read the btye depth
              biBitCount = br.ReadInt16()
              'read all BMP content
              DwgF.Seek(PosBMP, SeekOrigin.Begin)
              'the BMP with no header
              BMPInfo = br.ReadBytes(LenBMP)
              br.Close()
              DwgF.Close()
              biH.bfType = 19778
              'build the header
              If biBitCount < 9 Then
                biH.bfSize = 54 + 4 * CInt(Math.Truncate(Math.Pow(2, biBitCount))) + LenBMP
              Else
                biH.bfSize = 54 + LenBMP
              End If
              'reserved byte
              biH.bfReserved1 = 0
              'reserved byte
              biH.bfReserved2 = 0
              'BMP data offset
              'write BMP header
              biH.bfOffBits = 14 + 40 + 1024
              'file type
              bmpr.Write(biH.bfType)
              'file size
              bmpr.Write(biH.bfSize)
              '0
              bmpr.Write(biH.bfReserved1)
              '0
              bmpr.Write(biH.bfReserved2)
              'offset
              bmpr.Write(biH.bfOffBits)
              'write BMP file
              bmpr.Write(BMPInfo)
              'move the pointer to the beginning
              BMPF.Seek(0, SeekOrigin.Begin)
              'create the BMP file
              myImg = Image.FromStream(BMPF)
              bmpr.Close()
              BMPF.Close()
            End If
            Return myImg
          Catch ex As Exception
            Throw New Exception(ex.Message)
          End Try
        End Function
      End Class
    
    End Class
    

    I hope this will be helpful.

    Best regards,


    Mike Feng [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Thursday, April 14, 2011 11:42 AM
    Moderator
  • Dear Crazypenny, dear Mike,

    thanks for your welcome, I'm a newbie of VB.NET and I'm learning a lot in this forum, thanks to your helpful and friendly advices.

     

    I tried both of yours suggestions and here I summarize my results.

    I thought Crazypenny code was ok until I run it and I got an Access violation exception when executing the Sub showThumbNail(), when assigning the value to result variable.

    Just to give you more details about this, I can see the web page is loading correctly, but then everything freezes and I get that message from VB.NET.

     

    I tested Mike's code and it actually works great!

    I just wanted to ask you if is there a way to control the dimensions of the picture I get (i.e. can I change the image ratio without set my PB to stretch?) and how is it generated.

    My very basic understanding of VB.NET still needs to improved and I'd like to know more about this kind of code you suggested.

    I can see you defined a class (ViewDWG), and a function GetDwgImage(), that you use to get the Image file to assign to the PictureBox.

    I guess the code executed in the function GetDwgImage() is a stream reading command to get informations from the dwg file to extract the thumbnail data  saved therein, but I don't understand how exactly.

    I'm a technical designer and I use Autocad at work every day and I would like to improve my understanding on how dwg files are composed.

    I know a dwg file is a sort of database, in which every entity is stored with properties, but I can't understand how your code works exactly to get to the proper byte in which the informations are stored and if this is possible for any other binary type of files.

    thanks again for your help.

    P.


    pp _______________ VB Express 2010
    Thursday, April 14, 2011 9:00 PM
  • Hi Fredpox,

    What do you mean "control the dimensions of the picture I get"? Do you mean "zoom in"? If so, the two links should be helpful to you:

    http://social.msdn.microsoft.com/Forums/en-US/vbide/thread/625f8169-4cfb-4b16-a4ba-9030d0a76e39

    http://social.msdn.microsoft.com/Forums/en-US/vbgeneral/thread/0609b802-b3d4-417e-8a58-4237993589cc

    the both is related to zoom in a picture.

    As you know, each type of file obey a kind of protocol standard, the standard provide the farmat: which byte means size, which byte means data, and so on. in most cases, the protocol standard isn't open. So the code may do not work with the other type of file.

    I hope this will be helpful.

    Best regards


    Mike Feng [MSFT]
    MSDN Community Support | Feedback to us
    Get or Request Code Sample from Microsoft
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.

    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Friday, April 15, 2011 5:38 AM
    Moderator
  • Fred,

    For the purpose you want I use also the GetThumbnailImage, it does not what it suggest, but creates simply a new thumbnail from a bitmap.

    But first you have to create of course an image from a scratch.

    I don't know if you know how to do that as all samples on MSDN show that as a result from the paint event.

    The form2 part of the sample on our website shows how it can be done.

    http://www.vb-tips.com/dbpages.aspx?Search=clock

    And then of course that GetThumbnailImage

    (Don't care it is handling a webpage, your part of the code is the same for a windows form)

     

     

     


    Success
    Cor
    • Marked as answer by fredpox Tuesday, April 19, 2011 9:31 PM
    Friday, April 15, 2011 6:16 AM
  • Dear Cor, dear Mike,

    sorry for the delay of this answer.

    My question was about the possibility to further zoom in the bitmap retrieved by the dwg file.

    I solved with a little 'trick' by creating two buttons which actions are changing the sizemode property of the PictureBox from Zoom to Center.

    I'll deepen this topic and I'll further try your hints.

     

    Now I'm quite happy with the results and I'll mark your posts as answers.

    The only thing I don't understand is about some generig GDI+ exception error I eventually get as I activate the GetDwgImage function.

    It happens that some of the files I have to handle don't display a thumbnail, it also happens in Explorer, but it's quite simple to solve the problem: I just need to open up the drawing and save it. Next time I browse the file I can see the thumbnail in Explorer.
    This thing works even for my app, but some files, even if the dwg path is ok and the thumbnail displays correctly in explorer, I get the exception above.

    In order to make sure the file path was ok, I created some other buttons that trigger the opening of the file itself, the folder and other files contained therein.

    I'll try to post the code for your reference as I get back to work.

     

    regards,

    P.


    pp _______________ VB Express 2010
    Tuesday, April 19, 2011 9:30 PM
  • Hi all,

    Could you help me change post 2 code from thumbnail view to normal view please?

    regards

    toe

     

    edit:

    After a lot of searching it seems this will not be possible without a 3rd party component unless there is a way of enlarging a thumbnail.


    • Edited by toecutter Tuesday, June 28, 2011 2:50 AM researching
    Monday, June 27, 2011 11:40 PM