Results 1 to 17 of 17

Thread: Changing an Image Size

  1. #1

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Changing an Image Size

    Firstly I am still using the 2013 version of vb.net

    I am writing an image processing routine and after 50 or so images it kept running out of memory because Bitmaps are memory hogs and hang around apparently

    Anyway this works and may be useful for others

    Code:
    Public Function ImageSizeChangeLBF(imgSource As Image, intWidth As Integer, intHeight As Integer) As Image 
      ' Written 5th March 2014
    
      Dim memStream As New MemoryStream          ' MUST go outside the Using Statements
    
      ' Make a bitmap for the Destination
      Using bmpDestination As New Bitmap(intWidth, intHeight)
    
        ' Make a Graphics object for the Destination Bitmap.
        Using gphDesination As Graphics = Graphics.FromImage(bmpDestination)
    
          ' Copy the source image into the Destination bitmap with different Dimensions
          gphDesination.DrawImage(imgSource, 0, 0, intWidth + 1, intHeight + 1)
    
          ' Copy to a Memory Stream (CANNOT JUST SET IMAGE = BITMAP AS THIS IS JUST MEMORY AND IT IS RESET BY "END USING")
          bmpDestination.Save(memStream, System.Drawing.Imaging.ImageFormat.Bmp)
    
        End Using
      End Using
    
      '  Return
      ImageSizeChangeLBF = Image.FromStream(memStream)
    
    End Function
    So just do this

    picBox.Image = ImageSizeChangeLBF(picBox.Image, intWidth, intHeight )

    Hope this helps somebody
    Bob

    Ps You need: Imports System.Drawing
    .
    Last edited by wavering; Mar 5th, 2021 at 07:04 AM.

  2. #2
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    I have an extension function that returns the new image with the specified width and keeping the aspect ratio:
    VB.NET Code:
    1. <Extension()>
    2. Public Function ResizeKeepAspect(ByVal img As Image, ByVal width As Integer) As Image
    3.     Dim srcWidth As Integer = img.Width
    4.     Dim srcHeight As Integer = img.Height
    5.     Dim height As Integer
    6.     Dim nPercentW As Double = 0
    7.  
    8.     nPercentW = width / srcWidth
    9.     height = CInt(srcHeight * nPercentW)
    10.  
    11.  
    12.     Dim resImage = New Bitmap(width, height)
    13.  
    14.     Using gr = Graphics.FromImage(resImage)
    15.         gr.SmoothingMode = SmoothingMode.HighQuality
    16.         gr.InterpolationMode = InterpolationMode.HighQualityBicubic
    17.         gr.PixelOffsetMode = PixelOffsetMode.HighQuality
    18.         gr.DrawImage(img, New Rectangle(0, 0, width, height))
    19.  
    20.     End Using
    21.  
    22.     Return resImage
    23. End Function

    Use like:
    VB.NET Code:
    1. Dim img = Image.FromFile(fileName)
    2. ...
    3. ...
    4. Dim avatar = img.ResizeKeepAspect(240)
    5. ...
    6. ...

  3. #3

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    Quote Originally Posted by peterst View Post
    I have an extension function that returns the new image with the specified width and keeping the aspect ratio
    Yes, when I process hundreds of large images in a loop using your version it runs out of memory because the bitmaps pile up

    So you have to use "Using" and then you cannot just return the bitmap as it has been wiped out by "End Using".

    If you just set your image to the bitmap all it does is copy the address so when the bitmap is wiped out your image is wiped out too

    That is why I copy it to a memory stream to preserve it as that creates a separate section in memory (a "deep copy")

    But thanks for this as I have added in your various grpahics modes eg gr.SmoothingMode = SmoothingMode.HighQuality

    I am pretty sure I am right about all this but if I am wrong please accept my humble apologies ...

    Bob
    .

  4. #4
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    I've never used the function for thousands of images - it is only for avatars resizing when user wants to upload. Anyway this shows what happens when copying code from SO (actually translated from C# example from SO if I remember correct) Thanks for the hints. I will update it so no mem leaks for thousands of images - I will test that extensively now.

  5. #5

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    As you will have guessed, I am using this for images from video - hence the thousands of images (just done 9,000 images)

    Incidentally, I give the user the option of preserving aspect ratio or not doing so. It is brilliant for losing weight - you can lose fifty pounds in ten seconds by changing the aspect ratio ...

  6. #6
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    Currently converting an archive with pics from JPG to PNG and also resizing to width=300. No memory leaks: mem usage between 50 and 166MB but more on the lower side as it depends on the source files (DSLR, phones, drone shots, some are already lowered res like 1200 width). More than 4000 files converted, still working, still no mem leaks or any other problem.

  7. #7
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    Code used for conversion:
    VB.NET Code:
    1. Private Sub ConvertImages(srcDir As String, destDir As String)
    2.     Directory.CreateDirectory(destDir)
    3.  
    4.     For Each imgFile In Directory.GetFiles(srcDir, "*.jpg")
    5.         Using img = Image.FromFile(imgFile)
    6.             Using resized = img.ResizeKeepAspect(300)
    7.                 Dim destFile = Path.Combine(destDir, Path.GetFileNameWithoutExtension(imgFile) & ".png")
    8.                 resized.Save(destFile, ImageFormat.Png)
    9.             End Using
    10.         End Using
    11.     Next
    12.  
    13.     For Each subdir In Directory.GetDirectories(srcDir)
    14.         Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
    15.         ConvertImages(subdir, newDest)
    16.     Next
    17. End Sub
    Memory usage (still working):

  8. #8

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    Quote Originally Posted by peterst View Post
    still no mem leaks or any other problem.
    Maybe its because I am using an old version of Vb.net? Anyway, I hope this is a useful discussion for other people - all I can say is I had memory leaks cured by using "using" and a Memory stream

  9. #9
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    Got the Out of memory error but quickly tested with resizing removed:
    VB.NET Code:
    1. Private Sub ConvertImages(srcDir As String, destDir As String)
    2.     Directory.CreateDirectory(destDir)
    3.  
    4.     For Each imgFile In Directory.GetFiles(srcDir, "*.jpg")
    5.         Using img = Image.FromFile(imgFile)
    6.  
    7.         End Using
    8.     Next
    9.  
    10.     For Each subdir In Directory.GetDirectories(srcDir)
    11.         Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
    12.         ConvertImages(subdir, newDest)
    13.     Next
    14. End Sub
    And in 3-4 minutes BOOM - out of memory. So it is not the resize method from Stack Overflow (as many people checked it thousands times).

  10. #10

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    Talking of SO, there is a lot of stuff relating to Bitmaps and memory leaks eg

    https://stackoverflow.com/questions/...ally-disposing

    https://stackoverflow.com/questions/...and-picturebox

    Incidentally using a Static Bitmap appears to work but it sets itself at the largest size so far and refuses to reduce (so you get images inside other images)

    So, I think the consensus is that you need to use "Using" with bitmaps ... !

  11. #11
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    I get the error without any Bitmap - check second example above. No resizing, nothing called so it is only loading image from file. I forgot to check which is the image causing the error so I running again the code and will check the imgFile variable. I am pretty sure it could be bad JPG file.

  12. #12
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    Well, it was just bad image, as I expected. IrfanView (my favorite viewer for years) shows me error "Can't read header" as the file is full of zeros only.

  13. #13

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    Quote Originally Posted by peterst View Post
    I am pretty sure it could be bad JPG file.
    When I use random images I get errors all the time - partly because the image width is best at a multiple of 4 eg "width = 1025" can cause (me) problems because Bitmaps then use padding and if you delve inside the image using a byte array it all gets confusing (to me anyway). So in fact I correct all images to be a multiple of 4

    You can get odd widths when you crop an image

  14. #14
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    By adding try/catch block the conversion procedure completed: 11525 files (81.5GB original size) resized and saved as PNG thumbnails (2.28GB) with 300 pixels width. No crashes, no memory leaks, nothing. Using statement is applied to resized variable so everything is correct. The extension I've shown just works correctly as it must return image (or Bitmap) which is not disposed (and thus unusable for the caller).

  15. #15
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    For those who are interested for doing such multi-folder and thousands of files conversions or similar tasks, the TPL (Task Parallel Library) provides some good features. Here the routine is processing files in single directory in parallel for each statement:

    VB.NET Code:
    1. Private Sub ConvertImagesMT(srcDir As String, destDir As String)
    2.     Directory.CreateDirectory(destDir)
    3.  
    4.     Parallel.ForEach(Directory.GetFiles(srcDir, "*.jpg"),
    5.         Sub(imgFile)
    6.             Try
    7.                 Using img = Image.FromFile(imgFile)
    8.                     Using resized = img.ResizeKeepAspect(300)
    9.                         Dim destFile = Path.Combine(destDir, Path.GetFileNameWithoutExtension(imgFile) & ".png")
    10.                         resized.Save(destFile, ImageFormat.Png)
    11.                     End Using
    12.                 End Using
    13.             Catch ex As Exception
    14.                 Debug.Print(imgFile)
    15.             End Try
    16.         End Sub)
    17.     For Each subdir In Directory.GetDirectories(srcDir)
    18.         Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
    19.         ConvertImagesMT(subdir, newDest)
    20.     Next
    21. End Sub
    The downside is much higher memory usage (hit 3.1GB shown in diagnostic tools, on average between 1GB and 2.4GB) and of course - CPU usage.

  16. #16
    Fanatic Member
    Join Date
    Jun 2019
    Posts
    557

    Re: Changing an Image Size

    Few hours trying are always "better" than one minute reading

    Image.FromFile method raises OutOfMemoryException:

    Exceptions
    OutOfMemoryException
    The file does not have a valid image format.

    -or-

    GDI+ does not support the pixel format of the file.

  17. #17

    Thread Starter
    Lively Member
    Join Date
    May 2011
    Posts
    87

    Re: Changing an Image Size

    You can actually tell how much memory your machine has left by using

    Code:
        lngMemory = CLng(My.Computer.Info.AvailablePhysicalMemory)
    When is use my version of the program it runs fine with no memory loss

    When I use Peterst's version this is what I got (it is a long giving the total available RAM).

    00 Memory available in total = 6273335296
    01 Memory available in total = 6240342016
    02 Memory available in total = 6187552768
    03 Memory available in total = 6134431744
    04 Memory available in total = 6080249856
    05 Memory available in total = 6022045696
    06 Memory available in total = 5968969728
    07 Memory available in total = 5915025408
    08 Memory available in total = 5877121024
    09 Memory available in total = 5823549440
    10 Memory available in total = 5773172736
    11 Memory available in total = 5719351296
    12 Memory available in total = 5664743424
    13 Memory available in total = 5609406464
    14 Memory available in total = 5557661696
    15 Memory available in total = 5510217728
    16 Memory available in total = 5472407552
    17 Memory available in total = 5425143808
    18 Memory available in total = 5382967296
    19 Memory available in total = 5335207936
    20 Memory available in total = 5279494144
    21 Memory available in total = 5226004480
    22 Memory available in total = 5174591488
    23 Memory available in total = 5118885888
    24 Memory available in total = 5062533120
    25 Memory available in total = 5006602240
    26 Memory available in total = 4986376192
    27 Memory available in total = 4932587520
    28 Memory available in total = 4880310272
    29 Memory available in total = 4846444544
    30 Memory available in total = 4798615552
    31 Memory available in total = 4751568896
    32 Memory available in total = 4706897920
    33 Memory available in total = 4661948416
    34 Memory available in total = 4618149888
    35 Memory available in total = 4570312704
    36 Memory available in total = 4518912000
    37 Memory available in total = 4477808640
    38 Memory available in total = 4429479936
    39 Memory available in total = 4384018432
    40 Memory available in total = 4335472640
    41 Memory available in total = 4308938752
    42 Memory available in total = 4277837824
    43 Memory available in total = 4254683136
    44 Memory available in total = 4226215936
    45 Memory available in total = 4196855808
    46 Memory available in total = 4165132288
    47 Memory available in total = 4139171840
    48 Memory available in total = 4123893760
    49 Memory available in total = 4109156352
    50 Memory available in total = 4083625984
    51 Memory available in total = 4067610624
    52 Memory available in total = 4040044544
    53 Memory available in total = 4012244992
    54 Memory available in total = 3978489856
    A first chance exception of type 'System.ArgumentException' occurred in System.Drawing.dll
    The program '[30256] IMAGES.vshost.exe' has exited with code 0 (0x0).

    I rest my case!
    Bob
    .

Tags for this Thread

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width