none
problem sizing image to fit screen

    Question

  • Having many thousands of pictures, I made a screen saver with the functionality I want. If the LAN path goes away it reconnects later, bad pics can be deleted, rotated and saved, etc. Sometimes the pics don't size correctly and expand off the screen. If someone can look at the code below and say why it doesn't always work I'd appreciate it. The problem may be reuse of the same picturebox. What I might do is have a dedicated picture box with autosize left on, use that to obtain raw image size, then reload again into the picture box that will be displayed. Thanks

      Private Function loadimage(ByVal pic As PictureBox, ByVal lab As Label, ByVal fname$) As Boolean
        With pic
          .SuspendLayout()
          .SizeMode = PictureBoxSizeMode.AutoSize
          Try
            .Load(fname)
          Catch ex As Exception
            load_fail_count += 1
            If load_fail_count >= 3 Then
              Timer3.Interval = 60000
              Timer3.Start()
            End If
            .ResumeLayout()
            Return False
          End Try
          Dim hdiff As Integer = .Height - Height, wdiff As Integer = .Width - Width
          If hdiff > 0 Or wdiff > 0 Then
            .SizeMode = PictureBoxSizeMode.StretchImage
            If hdiff > wdiff Then
              Dim ratio# = .Width / .Height
              .Height = Height
              .Width = ratio * Height
            Else
              Dim ratio# = .Height / .Width
              .Width = Width
              .Height = ratio * Width
            End If
          End If
          If .Height = Height Then .Top = 0 Else .Top = Int((Height - .Height + 1) * Rnd())
          If .Width = Width Then Left = 0 Else .Left = Int((Width - .Width + 1) * Rnd())
          .ResumeLayout()
          lab.Text = fname
          lab.Top = .Top
          lab.Left = .Left
        End With
        Return True
      End Function
    

    • Edited by dmcdivitt Wednesday, October 27, 2010 4:30 PM typo
    Wednesday, October 27, 2010 4:27 PM

Answers

  • You have to take the resolution into account when determining whether the image will fit properly on your screen. I usually work with absolute sizes because I work with displays and printers. With .NET, you have all of the information available that you need, and you can use whatever unit works best for you.

    Probably, the images that do not work are not the same resolution as your display. If the resolution is, for example 72DPI....you do not want to make that the same logical width and height as the display because it will still not fit because it has stated that it is for output to a device that has 72DPI, and your display probably has 96DPI.

    This is why I work in absolute units. That way, my images are the same size when they are printed as they are when they are displayed. You divide the width and height by the DPI to get the absolute size...for example...

    1024 pixels / 96DPI = 10.667 inches                        1024 pixels / 72DPI = 14.222 inches

    768 pixels / 96DPI   =   8.0 inches                              768 pixels / 72DPI = 10.667 inches

    Now, if you want to retain the image's aspect ratio, you will need to use a Graphics object to 'resample' the image for the display's resolution. For that you will need to set the Graphic's InterpolationMode so that you don't trash the image in the process. The 72DPI image on the right would need to be shrunk, or have its resolution changed.

    • Edited by jinzai Wednesday, October 27, 2010 8:51 PM oops
    • Marked as answer by Chao KuoModerator Monday, November 08, 2010 9:48 AM
    Wednesday, October 27, 2010 8:50 PM
  • This last modification does the trick. The original problem stemmed from trying to load a picturebox then change display properties afterward. It doesn't really work well. The problem with using a bitmap is that it doesn't provide rendered size. If a hidden picturebox with autosize set is used for analysis and left alone, the size of the control provides the ratio required for a rendering perspective.  Whatever's loaded into the picturebox doesn't matter and doesn't have to be addressed with regard to raw resolution.

    code removed, see post at end
    • Marked as answer by Chao KuoModerator Monday, November 08, 2010 9:48 AM
    • Edited by dmcdivitt Monday, November 08, 2010 2:28 PM replaced code
    Wednesday, October 27, 2010 11:12 PM
  • Hi dmcdivitt,

    If you have images with different aspect ratios, you can either stretch the images, in which case some will not look right.

    The alternative is you will either see black bars top and bottom of a PictureBox or to the left and right sides of a PictureBox.

    If you could then zoom in you are going to lose part of your image ( top and bottom ) or from the left and right.

    Unfortunately this is unavoidable, in a similar way to watching some movies on a widescreen television, you will either;

    1. See black bars OR
    2. Lose part of your image.

    I say this is unavoidable if you think of it logically.

    Try zooming in on any image. For example you can never zoom to fit a 6 X 4 inch photograph image to completely

    cover a 7 X 5 inch photo sheet of paper without losing some of the image otherwise the image would look distorted.

    6 X 4 = 3.0 : 2 ratio

    7 X 5 = 2.8 : 2 ratio

    I hope this illustrates the problem of images with different ratios to you.

     



    Regards,

    John

    www.johnaoliver.com
    Wednesday, October 27, 2010 11:47 PM

All replies

  • The left property was missing a period. Fixing that helped. I changed the code to what's pasted below and the resultant image is still sometimes larger than the form. The form is maximized, but for debug I tried not maximizing with elongated shapes. Most of the time the image does what it should within the form, but sometimes it still exceeds the size of the form.

    code removed, see post at end
    • Edited by dmcdivitt Monday, November 08, 2010 2:28 PM replaced code
    Wednesday, October 27, 2010 7:50 PM
  • You have to take the resolution into account when determining whether the image will fit properly on your screen. I usually work with absolute sizes because I work with displays and printers. With .NET, you have all of the information available that you need, and you can use whatever unit works best for you.

    Probably, the images that do not work are not the same resolution as your display. If the resolution is, for example 72DPI....you do not want to make that the same logical width and height as the display because it will still not fit because it has stated that it is for output to a device that has 72DPI, and your display probably has 96DPI.

    This is why I work in absolute units. That way, my images are the same size when they are printed as they are when they are displayed. You divide the width and height by the DPI to get the absolute size...for example...

    1024 pixels / 96DPI = 10.667 inches                        1024 pixels / 72DPI = 14.222 inches

    768 pixels / 96DPI   =   8.0 inches                              768 pixels / 72DPI = 10.667 inches

    Now, if you want to retain the image's aspect ratio, you will need to use a Graphics object to 'resample' the image for the display's resolution. For that you will need to set the Graphic's InterpolationMode so that you don't trash the image in the process. The 72DPI image on the right would need to be shrunk, or have its resolution changed.

    • Edited by jinzai Wednesday, October 27, 2010 8:51 PM oops
    • Marked as answer by Chao KuoModerator Monday, November 08, 2010 9:48 AM
    Wednesday, October 27, 2010 8:50 PM
  • Jinzai,

    That's excellent!!!!

    Renee

    Wednesday, October 27, 2010 9:10 PM
  • If I load into a picturebox and take the width and height of the control, and if autosize was set, aren't variations in the picture encapsulated by that? If I load an image it always loads as it should. Afterward, the height and width of the picturebox represents whatever aspect ratio in terms of the hardware being used to view the picturebox.

    Using a bitmap and getting the height and width off a bitmap may not be the best way to go because height and width is not a rendered height and width like a control on a form.

    I don't care about any image specifics. What I care about is the final shape of the picturebox control. Loading the picturebox with autosize set, produces a control with correct proportions. That control must then be resized to fit within the form. So, autosize is used to find values and stretch is used to render. That's how I did it with VB6. There, two controls must be used, an image control in combination with a picturebox.

    Wednesday, October 27, 2010 9:22 PM
  • Sure, everything except this one little thing that we are discussing now....resolution. VB6 was not written to run on a system with a variable display resolution. (Not talking about screen size here, only dots per inch.) Windows and VB and not  mind readers, and it is always best to err on the side of safety.

    However, it is 5pm in Iowa, and I need to get off break...so I can clock out and go home to Illinois. Your last paragraph seems to be saying that you can live with it. If so, cheers...if not, I would be willing to show you how I would do it...later.

    Wednesday, October 27, 2010 10:02 PM
  • I'd appreciate any help. Thanks! I'm already in Illinois :)

    Wednesday, October 27, 2010 10:26 PM
  • This last modification does the trick. The original problem stemmed from trying to load a picturebox then change display properties afterward. It doesn't really work well. The problem with using a bitmap is that it doesn't provide rendered size. If a hidden picturebox with autosize set is used for analysis and left alone, the size of the control provides the ratio required for a rendering perspective.  Whatever's loaded into the picturebox doesn't matter and doesn't have to be addressed with regard to raw resolution.

    code removed, see post at end
    • Marked as answer by Chao KuoModerator Monday, November 08, 2010 9:48 AM
    • Edited by dmcdivitt Monday, November 08, 2010 2:28 PM replaced code
    Wednesday, October 27, 2010 11:12 PM
  • Hi dmcdivitt,

    If you have images with different aspect ratios, you can either stretch the images, in which case some will not look right.

    The alternative is you will either see black bars top and bottom of a PictureBox or to the left and right sides of a PictureBox.

    If you could then zoom in you are going to lose part of your image ( top and bottom ) or from the left and right.

    Unfortunately this is unavoidable, in a similar way to watching some movies on a widescreen television, you will either;

    1. See black bars OR
    2. Lose part of your image.

    I say this is unavoidable if you think of it logically.

    Try zooming in on any image. For example you can never zoom to fit a 6 X 4 inch photograph image to completely

    cover a 7 X 5 inch photo sheet of paper without losing some of the image otherwise the image would look distorted.

    6 X 4 = 3.0 : 2 ratio

    7 X 5 = 2.8 : 2 ratio

    I hope this illustrates the problem of images with different ratios to you.

     



    Regards,

    John

    www.johnaoliver.com
    Wednesday, October 27, 2010 11:47 PM
  • Thanks John. As I described the point has nothing to do with aspect ratios. For instance a picturebox control can be mounted on a form and when loaded from a file name it displays correctly. It does that because correct rendering is encapsulated in the picturebox control and none of that must be calculated manually. If I want a picture to fit my screen, all I have to do is resize a picturebox, keeping the dimensions the VB engine gave it. Two picturebox controls are necessary for this. One must be loaded with autosize set so the picturebox will automatically configure itself. A second picturebox must be sized, using the ratio of the first, and the same image file loaded there, or the image copied from one to the other. The same picturebox cannot be loaded and resized or reconfigured.

    My screen saver has a black background and pictures appear randomly around the screen. Black bars don't make any difference, but thanks for the wonderful explanation.

    Thursday, October 28, 2010 2:15 AM
  • Pictures were still occasionally bigger than the desktop window on monitors other than 1920x1080. 1920x1080 is so wide, pictures on my test machine always exceeded height before exceeding width, and I didn't see my logic error. The code below does a better test in case someone sees the thread and uses the code.

      Private Function loadimage(ByVal pic As PictureBox, ByVal lab As Label, ByVal filename$, ByVal async As Boolean) As Boolean
        loadinprogress = True
        Try
          If async Then sizer.LoadAsync(filename) Else sizer.Load(filename)
        Catch
          loadimageerror()
          Return False
        End Try
        loadimagefname = filename
        loadimagepic = pic
        loadimagelab = lab
        If Not async Then loadimagecomplete()
        Return True
      End Function
    
      Private Sub loadimagecomplete()
        Dim M As Integer = IIf(domargin, marginsize, 0)
        Dim H As Integer = Height - (M * 2)
        Dim W As Integer = Width - (M * 2)
        With loadimagepic
          Try
            .Image.Dispose()
          Catch
          End Try
          .Image = Nothing
          Dim hdiff As Integer = sizer.Height - H, wdiff As Integer = sizer.Width - W
          If hdiff > 0 Or wdiff > 0 Then
            .SizeMode = PictureBoxSizeMode.Zoom
            Dim hnew As Integer = (sizer.Height / sizer.Width) * W
            Dim wnew As Integer = (sizer.Width / sizer.Height) * H
            If hnew <= H Then
              .Height = hnew
              .Width = W
            Else
              .Width = wnew
              .Height = H
            End If
          Else
            .SizeMode = PictureBoxSizeMode.AutoSize
          End If
          .Image = sizer.Image
          If .Height = H Then .Top = M Else .Top = Int((H - .Height + 1) * Rnd())
          If .Width = W Then .Left = M Else .Left = Int((W - .Width + 1) * Rnd())
          loadimagelab.Text = loadimagefname
          loadimagelab.Top = .Top
          loadimagelab.Left = .Left
          loadimagelab.BringToFront()
        End With
        loadinprogress = False
      End Sub
    
      Private Sub loadimageerror()
        advise("image fail")
        load_fail_count += 1
        If load_fail_count >= 3 Then
          Timer3.Interval = 60000
          Timer3.Start()
        End If
        loadinprogress = False
      End Sub
    
    
    

    Monday, November 08, 2010 2:25 PM
  • Thanks John. As I described the point has nothing to do with aspect ratios. For instance a picturebox control can be mounted on a form and when loaded from a file name it displays correctly. It does that because correct rendering is encapsulated in the picturebox control and none of that must be calculated manually. If I want a picture to fit my screen, all I have to do is resize a picturebox, keeping the dimensions the VB engine gave it. Two picturebox controls are necessary for this. One must be loaded with autosize set so the picturebox will automatically configure itself. A second picturebox must be sized, using the ratio of the first, and the same image file loaded there, or the image copied from one to the other. The same picturebox cannot be loaded and resized or reconfigured.

    My screen saver has a black background and pictures appear randomly around the screen.

    Black bars don't make any difference , but thanks for the wonderful explanation.

     

    Hi again dmcdivitt,

    You could resize the same PictureBox in code.

    Who needs a PictureBox for a screen saver type program anyway?

    In the following code I could have added a PictureBox to the Form in code and docked it or simply made it the same size as the Form.

     

    With a Form or a PictureBox if you set the .BackgroundImageLayout property

    to ImageLayout.Zoom any pictures will be made to fit your screen.  :-D

     

    Anyway, try running this short bit of code on your computer.>>

     

    Public Class Form1
    
      Private WithEvents myTimer As New Timer
      Private myPics() As String
      Private rand As New Random
    
      Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
    
        Me.DoubleBuffered = True
        Me.BackColor = Color.Black
        Me.FormBorderStyle = Windows.Forms.FormBorderStyle.None
        Me.WindowState = FormWindowState.Maximized
        Me.BackgroundImageLayout = ImageLayout.Zoom
        myPics = System.IO.Directory.GetFiles(My.Computer.FileSystem.SpecialDirectories.MyPictures)
        myTimer.Interval = 1000
        myTimer.Start()
    
      End Sub
    
      Private Sub myTimer_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles myTimer.Tick
    
        Dim picNumber As Integer = rand.Next(0, myPics.GetUpperBound(0) + 1)
        Try
          Me.BackgroundImage = Image.FromFile(myPics(picNumber))
        Catch ex As Exception
        End Try
    
      End Sub
    End Class
    




    Regards,

    John

    www.johnaoliver.com
    Tuesday, November 09, 2010 3:10 AM
  • That's a neat idea not using a picturebox. With my screensaver I have several issues to address. Latency across the LAN causes a delay when pictures load. On a fast computer there's a small delay when pics are local, but across the LAN it's more pronounced. So I alternate pictureboxes, having the next already loaded. Also, some pics are much smaller than the screen. I want those to appear in a random position. For others I want what borders there may be to be random. The screen saver has hot keys so if a pic needs to be rotated I can do that and save. If I like the current pic I can copy to the desktop. If I want to see more in that series I can tell it to step through all in the current folder instead of randomly choosing from everything. It goes back 100 pics. If the screen saver stops, when it starts again it resumes where it was before with the same history.

    I reconnected a couple of old laptops to show pics and computers on the high-def TVs show pics. My wife's computer on her desk shows pics. It's fun! People watch when they come over. We'll get tired of it after awhile, but while in the picture mode I wanted the screen saver to do whatever I thought of.

    Tuesday, November 09, 2010 2:32 PM