Tech Off Thread

8 posts

Programming - VB.Net: Thumbnail Directory View

Back to Forum: Tech Off
  • User profile image
    gmiley

    Here is the basics of what I have and what I need to know.

    So far I have a TreeView navigation section and a ListView that I am attempting to use as an image thumbnail viewer.

    I have it successfully pulling the image contents of the directory and displaying them using Image.GetThumbnailImage().

    The problem I am having however, is that the ListView has no way to adjust aspect for each item. I am assuming that I would need to overlay the aspect ratio maintained thumbnail on a fixed size image then pull that new image in as the display image.

    My question is then, how would I go about doing this? Does anyone have a section of code I could get the idea from or something?

    Thanks

  • User profile image
    Bryn Waibel

    This is the algorithm we use to get a scaled images' size, while preserving its aspect. If we want an image that's inside say a 16x16 box, we'd pass in:

    Size newSize = GetAspect( image.Size, new Size( 16, 16 ) );

    If the image is 30x40, the newsize will come back as 12x16.


    /// <summary>
    /// Get's the largest size which will fit inside newSize, 
    /// while preserving the aspect ration of currentSize
    /// </summary>
    /// <param name="currentSize">The size whose aspect must 
    /// be preserved</param>
    /// <param name="newSize">The maximum bounds of the result. 
    /// negative numbers represent unbounded dimension
    /// convenient for creating fixed width or fixed height 
    /// images with a scaling second dimension</param>
    /// <returns>the appropriate size</returns>
    public static Size GetAspect( Size currentSize, Size newSize )
    {
       if( newSize.Width < 0 && newSize.Height < 0 )
       {
          // Well, not quite unbounded 
          return currentSize;
       }
       float aspect = (float)currentSize.Width / (float)currentSize.Height;
       if( ( (float)newSize.Width / aspect > (float)newSize.Height && 
          newSize.Height >= 0 ) || 
          newSize.Width < 0 )
       {
          newSize.Width = (int)Math.Round( (float)newSize.Height * aspect );
       }
       else
       {
          newSize.Height = (int)Math.Round( (float)newSize.Width / aspect );
       }
       return new Size( NewWidth, NewHeight );
    }
    
    
    Hope this helps.

    PS... The interpolation used in GetThumbnailImage isn't exactly stellar. We draw the image onto a graphics object using InterpolationMode.HighQualityBiCubic.

    PPS... I know people have complained about the resizing that we do, but actually it's a CSS problem, the CSS is stretching the image by about 4 pixels and it looks like crap, I'll fix that sometime soon.

    -Bryn

  • User profile image
    gmiley

    actually this is more of what I was looking for, I can handle the aspect ratio but I was wondering how I could impliment it onto a single sized template image to keep images proportioned when added to a ListView (keep in mind this is just my rough hash out of what I'm working on. I poked around with intellisense untill I figured it out, still need to clean it all up):

    Private Function MakePreviewIcon(ByRef myBGImg As Drawing.Image, ByRef myFGImg As Drawing.Image) As Drawing.Image

    Dim sizeFG As New Size(myFGImg.Width, myFGImg.Height)

    Dim sizeBG As New Size(myBGImg.Width, myBGImg.Height)

    Dim myRectangle As New Drawing.Rectangle( _

    Math.Round(CDbl((sizeBG.Width - sizeFG.Width) / 2), 0), _

    Math.Round(CDbl((sizeBG.Height - sizeFG.Height) / 2), 0), _

    sizeFG.Width, sizeFG.Height)

    Dim myGraphic As Drawing.Graphics = Graphics.FromImage(myBGImg)

    myGraphic.SetClip(myRectangle)

    myGraphic.DrawImage(myFGImg, 0, 0)

    Dim myReturnImg As Image = DirectCast(myBGImg.Clone(), Image)

    myGraphic.DrawImage(myReturnImg, 0, 0)

    Return myReturnImg

    End Function

  • User profile image
    MonkeyMon

    Here's some code i use in an asp.net app i wrote:


     Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Dim connstr As String = Application("ConnectionString").ToString
            Dim cnn As New SqlConnection(connstr)
            Dim cmd As New SqlCommand("select * from t_ezImages where ID=" & Request.QueryString("id"), cnn)
            cnn.Open()
            Dim dr As SqlDataReader = cmd.ExecuteReader()
          
            dr.Read()
           Dim strImageType = dr.GetValue(11)
          
            Dim bindata() As Byte = dr.GetValue(6)
            Dim Thumbnailbindata() As Byte = resizeImage(bindata)


            Response.BinaryWrite(Thumbnailbindata)
           


        End Sub

       
        '*******************************************************
        Public Function resizeImage(ByVal pic() As Byte) As Byte()
            ' Const THUMBNAIL_IMAGE_PATH As String = "C:\Thumbnails\Test.jpg"
            Const maxWidth As Integer = 100
            Const maxHeight As Integer = 100
            Dim inp As New IntPtr
            Dim imgHeight, imgWidth As Double

            Try
                Dim image As System.Drawing.Image = System.Drawing.Image.FromStream(New MemoryStream(pic))
                Dim bm = New Bitmap(image)

                Dim imgHres, imgVres As Single

                'Added this for testing - usually 96 dpi for every picture
                imgHres = bm.horizontalresolution
                imgVres = bm.verticalresolution

                imgHeight = bm.Height
                imgWidth = bm.Width


                If imgWidth > maxWidth Or imgHeight > maxHeight Then
                    'Determine what dimension is off by more
                    Dim deltaWidth As Double = imgWidth - maxWidth
                    Dim deltaHeight As Double = imgHeight - maxHeight
                    Dim scaleFactor As Double

                    If deltaHeight > deltaWidth Then
                        'Scale by the height
                        scaleFactor = maxHeight / imgHeight
                    Else
                        'Scale by the Width
                        scaleFactor = maxWidth / imgWidth
                    End If

                    imgWidth *= scaleFactor
                    imgHeight *= scaleFactor
                End If

                Dim w As Integer = Convert.ToInt32(imgWidth)
                Dim h As Integer = Convert.ToInt32(imgHeight)

                Dim imgbmp As System.Drawing.Image = bm.GetThumbnailImage(w, h, Nothing, inp)
                Dim ms As New MemoryStream
                imgbmp.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg)
                Dim b(ms.Length - 1) As Byte
                ms.Position = 0
                ms.Read(b, 0, ms.Length)
                Return b


                'bitmap.Save(THUMBNAIL_IMAGE_PATH, Imaging.ImageFormat.Jpeg)

     

            Catch ex As Exception

            End Try
        End Function 'resizeImage

  • User profile image
    Bryn Waibel

    Ahh, I see, so I'm guessing that myBGImg is a white square or something and you're drawing the images in the center of the square to keep their center's all aligned. Sorry, i misread the question, we actually have some routines that will work for that as well. We use the source and destination features of DrawImage to place images correctly into a box, but that code isn't used anywhere, so i'll leave you to your business, looks like you've made progress.

    Why are you drawing the result back into the original background image again at the end there?

    Another thing you might want to try is creating a graphics object from an empty (new) image whose size is defined by myBGImg. Then draw the background and the foreground into the new image. This way you won't have to re-initialize your background image every time. I think the way you're doing it here will pollute the original background.

  • User profile image
    gmiley

    Yah I've cleaned it up considerably since I forst figured out what I needed to do.

    Right now I am pulling in a black-line bordered image for myBGImg.

    Here is the code for what I am doing, the myFGImg and myBGImg are being passed in ByVal so it doesn't cause any problems with the source images.

    Dim myRectangle As Drawing.RectangleF = myFGImg.GetBounds(GraphicsUnit.Pixel)

    myRectangle.Y = Math.Round((myBGImg.Height - myRectangle.Height) / 2)

    myRectangle.X = Math.Round((myBGImg.Width - myRectangle.Width) / 2)

    Dim myGraphic As Drawing.Graphics = Graphics.FromImage(myBGImg)

    myGraphic.SetClip(myRectangle)

    myGraphic.DrawImage(myFGImg, myRectangle)

    Return myBGImg.Clone()

  • User profile image
    MonkeyMon

    Be careful with objects in .NET passing ByVal.  Many objects are passed ByRef even with the ByVal declaration since a pointer only is passed. In several examples from MS, they actually populate datasets passed in ByVal in Sub Procedures.....took me a while to figure out what was going on cause I'd prefer to always use a function if i'm grabbing data if possible.

  • User profile image
    kashifmemon

    hi

    im student of Bsc in final year and my final year is Thumb Recognition System so i will search campare the algorithm of thumb and i using tool VB.net backand SQL Server so help me

Comments closed

Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation, please create a new thread in our Forums, or Contact Us and let us know.