-
Mar 5th, 2021, 06:52 AM
#1
Thread Starter
Lively Member
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.
-
Mar 5th, 2021, 07:11 AM
#2
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:
<Extension()>
Public Function ResizeKeepAspect(ByVal img As Image, ByVal width As Integer) As Image
Dim srcWidth As Integer = img.Width
Dim srcHeight As Integer = img.Height
Dim height As Integer
Dim nPercentW As Double = 0
nPercentW = width / srcWidth
height = CInt(srcHeight * nPercentW)
Dim resImage = New Bitmap(width, height)
Using gr = Graphics.FromImage(resImage)
gr.SmoothingMode = SmoothingMode.HighQuality
gr.InterpolationMode = InterpolationMode.HighQualityBicubic
gr.PixelOffsetMode = PixelOffsetMode.HighQuality
gr.DrawImage(img, New Rectangle(0, 0, width, height))
End Using
Return resImage
End Function
Use like:
VB.NET Code:
Dim img = Image.FromFile(fileName)
...
...
Dim avatar = img.ResizeKeepAspect(240)
...
...
-
Mar 5th, 2021, 08:56 AM
#3
Thread Starter
Lively Member
Re: Changing an Image Size
Originally Posted by peterst
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
.
-
Mar 5th, 2021, 09:04 AM
#4
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.
-
Mar 5th, 2021, 09:26 AM
#5
Thread Starter
Lively Member
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 ...
-
Mar 5th, 2021, 09:37 AM
#6
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.
-
Mar 5th, 2021, 09:40 AM
#7
Re: Changing an Image Size
Code used for conversion:
VB.NET Code:
Private Sub ConvertImages(srcDir As String, destDir As String)
Directory.CreateDirectory(destDir)
For Each imgFile In Directory.GetFiles(srcDir, "*.jpg")
Using img = Image.FromFile(imgFile)
Using resized = img.ResizeKeepAspect(300)
Dim destFile = Path.Combine(destDir, Path.GetFileNameWithoutExtension(imgFile) & ".png")
resized.Save(destFile, ImageFormat.Png)
End Using
End Using
Next
For Each subdir In Directory.GetDirectories(srcDir)
Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
ConvertImages(subdir, newDest)
Next
End Sub
Memory usage (still working):
-
Mar 5th, 2021, 09:45 AM
#8
Thread Starter
Lively Member
Re: Changing an Image Size
Originally Posted by peterst
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
-
Mar 5th, 2021, 09:56 AM
#9
Re: Changing an Image Size
Got the Out of memory error but quickly tested with resizing removed:
VB.NET Code:
Private Sub ConvertImages(srcDir As String, destDir As String)
Directory.CreateDirectory(destDir)
For Each imgFile In Directory.GetFiles(srcDir, "*.jpg")
Using img = Image.FromFile(imgFile)
End Using
Next
For Each subdir In Directory.GetDirectories(srcDir)
Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
ConvertImages(subdir, newDest)
Next
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).
-
Mar 5th, 2021, 10:04 AM
#10
Thread Starter
Lively Member
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 ... !
-
Mar 5th, 2021, 10:10 AM
#11
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.
-
Mar 5th, 2021, 10:14 AM
#12
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.
-
Mar 5th, 2021, 10:16 AM
#13
Thread Starter
Lively Member
Re: Changing an Image Size
Originally Posted by peterst
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
-
Mar 5th, 2021, 10:43 AM
#14
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).
-
Mar 5th, 2021, 11:02 AM
#15
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:
Private Sub ConvertImagesMT(srcDir As String, destDir As String)
Directory.CreateDirectory(destDir)
Parallel.ForEach(Directory.GetFiles(srcDir, "*.jpg"),
Sub(imgFile)
Try
Using img = Image.FromFile(imgFile)
Using resized = img.ResizeKeepAspect(300)
Dim destFile = Path.Combine(destDir, Path.GetFileNameWithoutExtension(imgFile) & ".png")
resized.Save(destFile, ImageFormat.Png)
End Using
End Using
Catch ex As Exception
Debug.Print(imgFile)
End Try
End Sub)
For Each subdir In Directory.GetDirectories(srcDir)
Dim newDest = Path.Combine(destDir, Path.GetFileName(subdir))
ConvertImagesMT(subdir, newDest)
Next
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.
-
Mar 6th, 2021, 04:00 AM
#16
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.
-
Mar 6th, 2021, 09:29 AM
#17
Thread Starter
Lively Member
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
-
Forum Rules
|
Click Here to Expand Forum to Full Width
|