problem sizing image to fit screen
-
Wednesday, October 27, 2010 4:27 PM
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
All Replies
-
Wednesday, October 27, 2010 7:50 PM
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 8: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 9:10 PM
Jinzai,
That's excellent!!!!
Renee
-
Wednesday, October 27, 2010 9:22 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 10:02 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:26 PM
I'd appreciate any help. Thanks! I'm already in Illinois :)
-
Wednesday, October 27, 2010 11:12 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:47 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;
- See black bars OR
- 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- Marked As Answer by Chao KuoModerator Monday, November 08, 2010 9:48 AM
-
Thursday, October 28, 2010 2:15 AM
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.
-
Monday, November 08, 2010 2:25 PM
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
-
Tuesday, November 09, 2010 3:10 AM
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 2:32 PM
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.

