Improving performance when working on Images with ASP.NET in VB - vb.net

I am trying to speed up various aspects of my website.
The site is a shopping site various search pages which are slow. There are several potential reasons for this, one being working with images.
The other night I created a function which generates a thumbnail for my Facebook OG tags. The function writes a square image to the server 400px x 400px created by tiling the first few (up to 14) product images generated by a search query.
Running this script in total isolation on a test.aspx file gives me reasonable load time, but nothing I can do can speed it up, even when I don't return anything in the browser, just doing this process is taking about 3 seconds, which obviously expanded across the whole live site slows things down.
The entire code is:
Function mergeImgs(idList, imgList, head, fileName) As String
Try
Dim maxRows = HttpContext.Current.Request.QueryString("r")
Dim imgDim = 400
Dim Image3 As New Bitmap(imgDim, imgDim)
Dim g As Graphics = Graphics.FromImage(Image3)
Dim i = 0
Dim left = 0
Dim rows = 0
For Each item In idList
Dim img = Common.getImageUrl(idList(i), imgList(i), "server", "-tb")
i += 1
If img <> "/Images/awaiting.png" Then
Dim imageData As System.Drawing.Image = System.Drawing.Image.FromFile(img)
Dim aspect As Double = imageData.Width / imageData.Height ' determine aspect and decide how to display image
Dim Image1
Dim fixedHeight = imgDim / maxRows
Dim objGraphic As System.Drawing.Image = System.Drawing.Image.FromFile(img)
Dim aspectRatio = objGraphic.Height / objGraphic.Width
Dim reduction = fixedHeight / objGraphic.Height
Dim newwidth = objGraphic.Width * reduction
Image1 = New Bitmap(objGraphic, objGraphic.Width * reduction, fixedHeight)
g.DrawImage(Image1, New Point(left, fixedHeight * rows))
If left >= imgDim Then
rows += 1
left = 0
ElseIf left < imgDim Then
left += newwidth
ElseIf left < imgDim AndAlso rows = maxRows Then
Exit For
End If
End If
Next
Image3.Save(HttpContext.Current.Server.MapPath("/" & fileName), System.Drawing.Imaging.ImageFormat.Jpeg)
Return rootUrl & fileName
g.Dispose()
g = Nothing
Catch ex As Exception
Return ("<P>" & ex.ToString)
End Try
End Function
There's an external function getImageUrl which is simply a series of logic which writes out a directory structure based on the item ID, this is fast so I doubt holding it up at all.
Variables passed into the function are:
idList = a generic List(of String) ' a list of item IDs
imgList = a generic List(of String) ' a list of image names (image names only stored in DB)
head = the Page.Header ' not actually needed in this prototype, but aimed to allow this to write the OG tag to the Page Header
fileName = simply the name to give the generated image file
I can't help thinking that the section from
Dim imageData As System.Drawing.Image = System.Drawing.Image.FromFile(img)
onwards could potentially be sped up. What this does is work out the aspect ratio of the images loaded, then recalculate the size so they're all the same height so that the tile can be neatly populated in tidy rows.
Dim img = Common.getImageUrl(idList(i), imgList(i), "server", "-tb")
This line loads a thumbnail version ("-tb" in last variable) of the images concerned, so all images being dealt with are approx 50x50px so very small to load and determine the aspect ratios from
There are 4 versions of each image stored on my server, in 4 different sizes for fast display on the website, having messed around with the different images loaded here, it seems to make little difference to the script load time.
Is there anything faster than System.Drawing.Image.FromFile(img) that I can use to load in the images and determine the width and height of it?
There are a couple of other situations on my website where I am required to determine the dimensions of an image and then do something with it and all seem a bit slow.
Any advice most welcome!
Just for info, here's an example of an image generated by the above code
http://www.hgtrs.com/recents.jpg
This is generated from the products returned by this page (which might load slowly!):
http://www.hgtrs.com/search.aspx?Type=recents
I should state the my test.aspx file also includes a call to a database, having tested the query used directly, I get a query time of 0.18 seconds, I dont know how this time expands into a real application. I have optimised this query and the tables (it uses one nested query and a join) as much as I know how.

Related

Random images on buttons

Good evening made the following code, create an array of buttons and panels, now how do I insert random images to those buttons, can you help me please.
Public Sub crearBotonesPaneles(ByVal creaBoton(,) As Button, ByVal creaPanel As Panel)
Dim puntoLocacion As Point
puntoLocacion.X = 20
puntoLocacion.Y = 40
For filas As Integer = 0 To 1
For columnas As Integer = 0 To 3
If IsNothing(creaBoton(filas, columnas)) Then
creaBoton(filas, columnas) = New Button
creaBoton(filas, columnas).Location = puntoLocacion
creaBoton(filas, columnas).Width = 50
creaBoton(filas, columnas).Height = 50
creaPanel.Controls.Add(creaBoton(filas, columnas))
puntoLocacion.X = puntoLocacion.X + 50
End If
Next
puntoLocacion.X = 20
puntoLocacion.Y = puntoLocacion.Y + 50
Next
End Sub
Doing something random ALWAYS means generating one or more random numbers in an appropriate range and then using them in an appropriate manner. The way you determine the range is application-specific and the manner in which you use the number(s) is application-specific. In your case, you might get the paths of all the image files in a folder, use random numbers to order those paths randomly and then use the paths one by one to get the images from the files. E.g.
Private rng As New Random 'Random number generator
Private imagePaths As Queue(Of String)
Private Sub LoadImagePaths()
'Create a new queue of file paths sorted based on a random number mapped to each one.
imagePaths = New Queue(Of String)(Directory.EnumerateFiles(My.Computer.FileSystem.SpecialDirectories.MyPictures,
"*.jpg").
OrderBy(Function(s) rng.NextDouble()))
End Sub
Private Function GetNextImage() As Image
'Load the image paths is there is no queue or the current queue is empty.
If imagePaths?.Any() = False Then
LoadImagePaths()
End If
'Create an image from the next file in the queue.
Return Image.FromFile(imagePaths.Dequeue())
End Function
Based on that code, you just call GetNextImage each time you need a random image. There will be no repeats until the entire list is exhausted.

Notification When Screen is Flashing VB.Net

I would like a notification to be triggered when part the screen starts to flash. This notification can be a msgbox for now, but I will eventually evolve it into an audible sound.
The purpose of this is we have a dashboard that displays various cells throughout the company. When a cell needs assistance, its spot on the dashboard starts to flash. The cells are displayed in horizontally stackedboxes like this;
Cell 1
Cell 2
Cell 3
Ect...
I would like to build an application that scans the screen, lets say every second, and gets each cells pixel intensity.
The notification will be triggered if/when the cells pixel intensity changes each scan for three consecutive scans in a row (ie. the cell must be flashing).
I am hoping that you guys can help me find a way to scan the screen an return a regions average pixel intensity to which I can then replicate and do the comparison to find out if it is flashing.
Thank you in advance, I am using VB.Net.
I was able to accomplish what I was asking by using this:
Private Sub AvgColors(ByVal InBitmap As Bitmap)
Dim btPixels(InBitmap.Height * InBitmap.Width * 3 - 1) As Byte
Dim hPixels As GCHandle = GCHandle.Alloc(btPixels, GCHandleType.Pinned)
Dim bmp24Bpp As New Bitmap(InBitmap.Width, InBitmap.Height, InBitmap.Width * 3,
Imaging.PixelFormat.Format24bppRgb, hPixels.AddrOfPinnedObject)
Using gr As Graphics = Graphics.FromImage(bmp24Bpp)
gr.DrawImageUnscaledAndClipped(InBitmap, New Rectangle(0, 0,
bmp24Bpp.Width, bmp24Bpp.Height))
End Using
Dim sumRed As Int32
Dim sumGreen As Int32
Dim sumBlue As Int32
For i = 0 To btPixels.Length - 1 Step 3
sumRed += btPixels(i)
sumGreen += btPixels(i + 1)
sumBlue += btPixels(i + 2)
Next
hPixels.Free()
Dim avgRed As Byte = CByte(sumRed / (btPixels.Length / 3))
Dim avgGreen As Byte = CByte(sumGreen / (btPixels.Length / 3))
Dim avgBlue As Byte = CByte(sumBlue / (btPixels.Length / 3))
MsgBox(avgRed & vbCrLf & avgGreen & vbCrLf & avgBlue)
End Sub
Private Function Screenshot() As Bitmap
Dim b As Bitmap = New Bitmap(Screen.PrimaryScreen.Bounds.Width, Screen.PrimaryScreen.Bounds.Height)
Using g As Graphics = Graphics.FromImage(b)
g.CopyFromScreen(0, 0, 0, 0, b.Size, CopyPixelOperation.SourceCopy)
g.Save()
End Using
Return b
End Function
and from here I can just adjust the range of bitmap to what I need, add a timer to tick every second, and keep a variable to compare average RGB's to.
Most of the code found from here:
http://www.vbforums.com/showthread.php?776021-RESOLVED-Getting-Average-RGB-Color-Value-of-Entire-Screen

Put images side by side

How do I combine two images in VB.net to create one big image. They are both 1920x1080 jpegs and I'd like it to come out in a 3840x1080 jpeg.
Like this: I get these images in:
image 1
And get this out: image 1 side by side with image 2
I found it. The code is pretty easy, basically two images in one image out.
Dim ImageOne As System.Drawing.Image = Image.FromFile("img1")
Dim ImageTwo As System.Drawing.Image = System.Drawing.Image.FromFile("img2")
'replace path of image two with Image2.ImageUrl
Dim NewImageHeight As Integer = If(ImageOne.Height > ImageTwo.Height, ImageOne.Height, ImageTwo.Height)
'To calculate height of new image
Dim NewImageWidth As Integer = ImageOne.Width + ImageTwo.Width
' width of new image
Dim NewImageBmp As New Bitmap(NewImageWidth, NewImageHeight, Imaging.PixelFormat.Format32bppArgb)
' you can change the bpp as per your requirment. Size of image directly propotionate to bpp of image
Dim NewImageGrx As Graphics = System.Drawing.Graphics.FromImage(NewImageBmp)
NewImageGrx.DrawImageUnscaled(ImageOne, 0, 0)
'draw first image at coordinate 0,0
NewImageGrx.DrawImageUnscaled(ImageTwo, ImageOne.Width, 0)
'draw second image at coordinate image1.width,0
Dim CombineImage As String = Guid.NewGuid().ToString() + ".jpg"
NewImageBmp.Save("output file", ImageFormat.Jpeg)
' saving combined image. You can specify the ImageFormat as per your requirment.
'disposing objects after use
ImageOne.Dispose()
ImageTwo.Dispose()
NewImageBmp.Dispose()
NewImageGrx.Dispose()

One picture box shown many times in the same form

My Goal is to create a maze in VS using VB.net, I currently have managed to make a random Generator that makes the "maze" and shows the location of the last wall made.
Horizontalwalls = Randomizer.Next(60, 91) 'Makes 60 - 90 Horizontal Walls
VirticalWalls = Randomizer.Next(60, 91) 'Makes 60 -90 Vertical Walls
Dim HLoops = 0 'counter for Horizontal walls
Dim VLoops = 0
lbxHorizontal.Items.Clear() 'empties the list box i have which stores the walls location
lbxvertical.Items.Clear()
Do While HLoops < (Horizontalwalls)
HLoops += 1 'adds to the counter
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
lbxHorizontal.Items.Insert(0, Randomizer.Next(0, 10))
'Attempt at making visable walls
pbxhorizontalwall.Top = (lbxHorizontal.Items.Item(0) * GridSize - 2) 'This and next line puts the wall in desired location
pbxhorizontalwall.Left = (lbxHorizontal.Items.Item(1) * GridSize - 2)
Loop
however the only way i know to make all the walls visible is to make 90 horizontal wall pictures, go though naming them all, then GLaaa... there must be a easier way to copy the same image over the screen at the desired location.
At the moment, all i really want to know is the line of code that will copy the image (and maybe a way to mass clear them all when the maze is reset) and then i'll work out how to get it into place...
You first create the list of images with:
Dim imageList As New List(Of Bitmap)
imageList.Add("image to add") 'do it for all the images you have
Then create a bitmap:
Dim bitmapWall as Bitmap = New Bitmap(widthOfbitmap, heightofbitmap, Drawing.Imaging.PixelFormat.Format24bppRgb)
Draw the list of images to the bimap:
Dim objGraphics As Graphics = Graphics.FromImage(bitmapWall)
For i = 0 To imageList.Count
objGraphics.DrawImage(imageList(i), x, y, imageList(i).Width, imageList(i).Height)
Next
objGraphics.Dispose()
x,y is the coordinates of where your images are drawn (you should change them for every iteration)
Lastly:
Me.BackgroundImage = bitmapWall
Me.Invalidate()
Dont forget to dispose the list and the bitmap in the end.
valter

Is there a better way to count the lines in a text file?

Below is what I've been using. While it does work, my program locks up when trying to count a rather large file, say 10,000 or more lines. Smaller files run in no time.
Is there a better or should I say faster way to count the lines in a text file?
Here's what I'm currently using:
Dim selectedItems = (From i In ListBox1.SelectedItems).ToArray()
For Each selectedItem In selectedItems
ListBox2.Items.Add(selectedItem)
ListBox1.Items.Remove(selectedItem)
Dim FileQty = selectedItem.ToString
'reads the data file and returns the qty
Dim intLines As Integer = 0
'Dim sr As New IO.StreamReader(OpenFileDialog1.FileName)
Dim sr As New IO.StreamReader(TextBox1_Path.Text + "\" + FileQty)
Do While sr.Peek() >= 0
TextBox1.Text += sr.ReadLine() & ControlChars.CrLf
intLines += 1
Loop
ListBox6.Items.Add(intLines)
Next
Imports System.IO.File 'At the beginning of the file
Dim lineCount = File.ReadAllLines("file.txt").Length
See this question.
Even if you make your iteration as efficient as can be, if you hand it a large enough file you're going to make the application freeze while it performs the work.
If you want to avoid the locking, you could spawn a new thread and perform the work asynchronously. If you're using .NET 4.0 you can use the Task class to make this very easy.
TextBox2.Text = File.ReadAllLines(scannerfilePath).Length.ToString()