Low quality thumbnails in listview VB.net - vb.net

I use VB.net
I use ListView to view 50*x thumbnails(.jpg) at the left to the items.
But instead of 32bit high quality thumbnails, ListView lowers them to 8bit or 16bit(not sure).
Here's the code
Private Sub afterprocessed()
ListView1.Items.Clear()
Dim imlTemp As New ImageList
Dim dirFiles() As String = IO.Directory.GetFiles("backend\communicate\thumbnails")
Dim _imgList As New ImageList
Dim imgSize As New Size
imgSize.Width = 50
ListView1.SmallImageList = _imgList
Dim count As Integer = 0
Dim item As New ListViewItem
For Each dirFile As String In dirFiles
Dim imgFilename As String = IO.Path.GetFileNameWithoutExtension(dirFile)
Dim img As New System.Drawing.Bitmap(dirFile)
Dim imgImage As Image = Image.FromFile(dirFile)
'Dim imgHeight As Integer
'imgHeight = imgImage.Height
imgSize.Height = imgImage.Height
_imgList.ImageSize = imgSize
_imgList.Images.Add(img.Clone)
ListView1.Items.Add(imgFilename, count)
count += 1
Next
End Sub
And the quality is noticably low. Compared to original JPG
Any advice? I'd greatly appreciate it :D

You need this.
this.ListView1.SmallImageList.ColorDepth = ColorDepth.Depth32Bit;

I had a similar problem one time and I found out it was being caused by using the ImageList.ImageSize method, which seems to use a poor resizing algorithm. I resolved it by ensuring all the images I used were already the correct size on disk before loading them. But if that's not an option for you it shouldn't be too difficult to resize them before adding them to the ImageList.

Related

Taking a screenshot of only portion of the browser using selenium in VBA | "Selenium VBA"

so this one is about taking a screenshot of only a portion of the browser using Selenium in VBA. I saw there is something like
takescreenshot.hieght
takescreenshot.width
but not sure how to use these sub attributes height and width or if they will work.
Plus I have multiple images to save using different filenames automatically. I tried this but it did not work.
dim bot as chromedriver, img as selenium.image
bot.get "http:// xxxxxxx.....com"
..
..
for a = 1 to 100
set img = bot.takescreenshot(500)
img.Saveas this workbook.path & " :\" & a & ".jpg"
any suggestions please. Thanks in advance
There is unfortunately no built in function to take partial screenshots. However, you might try the following function to get an image of a specific element--please forgive any vb related mistakes I may have made as I rarely use the language.
Public Function CaptureElementScreenShot(ByVal element As HTMLElement, ByVal uniqueName As String) As Image
Dim screenshot As Screenshot = (CType(Me.driver, ITakesScreenshot)).GetScreenshot()
screenshot.SaveAsFile(filename, System.Drawing.Imaging.ImageFormat.Jpeg)
Dim img As Image = Bitmap.FromFile(uniqueName)
Dim rect As Rectangle = New Rectangle()
If element IsNot Nothing Then
Dim width As Integer = element.Size.Width
Dim height As Integer = element.Size.Height
Dim p As Point = element.Location
rect = New Rectangle(p.X, p.Y, width, height)
End If
Dim bmpImage As Bitmap = New Bitmap(img)
Dim croppedImage = bmpImage.Clone(rect, bmpImage.PixelFormat)
Return croppedImage
End Function

how to write image bytes to a text file in .net

Am trying to copy my image value to text file. my code is below.
If fldtype = "System.Byte[]" Then
Dim bits As Byte() = CType(drow(dc), Byte())
Using ms As New MemoryStream(bits)
Dim sw As New StreamWriter(ms)
Dim sr As New StreamReader(ms)
Dim myStr As String = sr.ReadToEnd()
MessageBox.Show(myStr)
fldvalue = fldvalue + "," + myStr
End Using
I find this to be one of the easiest ways to write a Byte[] to a string:
If fldtype = "System.Byte[]" Then
Dim bits As Byte() = CType(drow(dc), Byte())
Dim s As String = Convert.ToBase64String(bits)
End If
Works in reverse, too:
Dim newBytes() As Byte = Convert.FromBase64String(s)
The answer linked in the original comments could prove to be better options. Answering these questions would go a long way:
Why write an image out to text in the first place?
What do you mean to do with it once it's there?
Do you need to be able to retrieve that string and re-form the original image?
Question #3 is especially important because the information you are capturing matters when it comes to image format information. That could be lost, making it difficult to reconstitute the original image 100%.

Visual Basic Check whether two images are the same or different

So I have a program which downloads images online and then stores them in files. But if two images have the same name, I have a piece of code which changes the file name to add a 1 to the end so that there are no errors. However, I was thinking it would be better to first check whether or not the images are the same before renaming them. And I am no way near good enough at VB as of yet to make my own image comparison code, so I looked on google and found this code but the thing is the code says that 2 identical images are different so? If anyone could have a look at the problem I would be hugely grateful.
Edit: Just for some further clarity I am comparing an image I already have stored in my folder with an image from the internet.
Re-Edit: I have found out that I have not correctly loaded one of the image variables if anybody knows what I need to change this would help? As I made the image variables the same to test and it worked fine.
Dim image1 As Bitmap = New System.Drawing.Bitmap(New IO.MemoryStream(New System.Net.WebClient().DownloadData(picture)))
Dim image2 As Bitmap = CType(Image.FromFile(path + "\" + uname + ".png", True), Bitmap)
Dim a As Boolean = AreSameImage(image1, image2)
If a Then
MsgBox("Identical image")
Else
MsgBox("Different images")
End If
Public Function AreSameImage(ByVal I1 As Image, ByVal I2 As Image) As Boolean
Dim BM1 As Bitmap = I1
Dim BM2 As Bitmap = I2
For X = 0 To BM1.Width - 1
For y = 0 To BM2.Height - 1
If BM1.GetPixel(X, y) <> BM2.GetPixel(X, y) Then
Return False
End If
Next
Next
Return True
End Function
Just out of curiosity if anyone knows how I could make it so that it checks the image against all the files in a certain folder - this would be really helpful. Thanks again!
Try to load your picture like this
Dim req As WebRequest = WebRequest.Create("http://www.google.co.il/Picture.jpg")
Dim stream As Stream = req.GetResponse().GetResponseStream()
Dim img As Image = Image.FromStream(stream)
Dim image1 As Bitmap = New Bitmap(img)
Is the path for Image2 correct?

Loading Picture Stored in Access Database into Program VB.NET

I have an Access Database linked with a VB project through a data source. In the database on one of the tables, I have an OLE Object field. I have saved pictures in .BMP format and .JPG format in this field. The problem I am encountering is loading this image into my application. This is what I would like to be able to do:
ButtonMeal1.BackgroundImage = IPOSDBDataSet.Meals.Rows(0).Item(5)
Where Item(5) is the column of the row where the image is stored.
Is there another way of doing this. Do I have to load the picture into the program by storing it as a variable, and then using that to change the background image of the button. There are no clear answers on the internet regarding my issue. Please help!
EDIT 1:
After doing some more research, I found some code and adjusted it to try fix my problem.
Dim ImageByteArray As Byte() = CType(IPOSDBDataSet.Meals.Rows(0).Item(5), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(ImageByteArray)
Dim MyImage As Image = Drawing.Image.FromStream(ImageMemoryStream)
PictureBox1.Image = MyImage
However, I receive the error "Parameter is Not Valid" with the 3rd line of the code. Would anyone be able to tell me how I could adjust my code to fix this issue, or tell me if I am doing something completely wrong?
EDIT 2:
I keep on changing the code around, but the error is always "Parameter is not valid.". What parameter is not valid?
EDIT 3:
No matter what I change it to, the error still persists. What is this parameter that is causing all my issues?
Dim ImageByteArray As Byte() = CType(IPOSDBDataSet.Meals.Rows(0).Item(5), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(ImageByteArray)
Dim ImageStream As Stream = ImageMemoryStream
Dim MyImage As Image = Drawing.Image.FromStream(ImageStream)
PictureBox1.Image = MyImage
EDIT 4:
Can anyone please help? I really need to be able to implement this into my program. Is there any other possible way of storing images in an access database, and importing them into my vb.net program?
Credit goes to TnTinMan from CodeProject for the answer. Hopefully this helps someone else:
Dim ImageByteArray As Byte() = CType(DataSet.Table.Rows(RowNo).Item(ItemNo), Byte())
Dim ImageMemoryStream As MemoryStream = New IO.MemoryStream(GetImageBytesFromOLEField(ImageByteArray))
Dim MyImage As Image = Drawing.Image.FromStream(ImageMemoryStream)
Friend Shared Function GetImageBytesFromOLEField(ByVal oleFieldBytes() As Byte) As Byte()
Dim BITMAP_ID_BLOCK As String = "BM"
Dim JPG_ID_BLOCK As String = ChrW(&HFF).ToString() & ChrW(&HD8).ToString() & ChrW(&HFF).ToString()
Dim PNG_ID_BLOCK As String = ChrW(&H89).ToString() & "PNG" & vbCrLf & ChrW(&H1A).ToString() & vbLf
Dim GIF_ID_BLOCK As String = "GIF8"
Dim TIFF_ID_BLOCK As String = "II*" & ChrW(&H0).ToString()
Dim imageBytes() As Byte
' Get a UTF7 Encoded string version
Dim u7 As System.Text.Encoding = System.Text.Encoding.UTF7
Dim strTemp As String = u7.GetString(oleFieldBytes)
Dim st2 As String = System.Text.Encoding.UTF8.GetString(oleFieldBytes)
' Get the first 300 characters from the string
Dim strVTemp As String = strTemp.Substring(0, 300)
' Search for the block
Dim iPos As Integer = -1
If strVTemp.IndexOf(BITMAP_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(BITMAP_ID_BLOCK)
ElseIf strVTemp.IndexOf(JPG_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(JPG_ID_BLOCK)
ElseIf strVTemp.IndexOf(PNG_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(PNG_ID_BLOCK)
ElseIf strVTemp.IndexOf(GIF_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(GIF_ID_BLOCK)
ElseIf strVTemp.IndexOf(TIFF_ID_BLOCK) <> -1 Then
iPos = strVTemp.IndexOf(TIFF_ID_BLOCK)
Else
Throw New Exception("Unable to determine header size for the OLE Object")
End If
' From the position above get the new image
If iPos = -1 Then
Throw New Exception("Unable to determine header size for the OLE Object")
End If
imageBytes = New Byte(CInt(oleFieldBytes.LongLength - iPos - 1)) {}
Array.ConstrainedCopy(oleFieldBytes, iPos, imageBytes, 0, oleFieldBytes.Length - iPos)
Return imageBytes
End Function
There isn't really such a thing as an 'image' stored in an Access table, only a binary stream. Therefore, the left hand side of your expression doesn't know that the right hand side is providing an image. You would have to stream the binary stream into a stream in VB.NET, then use System.Graphics methods to make it into a BMP or PNG or whatever. You could assign that object to the button.
still show error: index and length must refer to a location within the string.Parameter name: len

linq submitchanges runs out of memory

I have a database with about 180,000 records. I'm trying to attach a pdf file to each of those records. Each pdf is about 250 kb in size. However, after about a minute my program starts taking about about a GB of memory and I have to stop it. I tried doing it so the reference to each linq object is removed once it's updated but that doesn't seem to help. How can I make it clear the reference?
Thanks for your help
Private Sub uploadPDFs(ByVal args() As String)
Dim indexFiles = (From indexFile In dataContext.IndexFiles
Where indexFile.PDFContent = Nothing
Order By indexFile.PDFFolder).ToList
Dim currentDirectory As IO.DirectoryInfo
Dim currentFile As IO.FileInfo
Dim tempIndexFile As IndexFile
While indexFiles.Count > 0
tempIndexFile = indexFiles(0)
indexFiles = indexFiles.Skip(1).ToList
currentDirectory = 'I set the directory that I need
currentFile = 'I get the file that I need
writePDF(currentDirectory, currentFile, tempIndexFile)
End While
End Sub
Private Sub writePDF(ByVal directory As IO.DirectoryInfo, ByVal file As IO.FileInfo, ByVal indexFile As IndexFile)
Dim bytes() As Byte
bytes = getFileStream(file)
indexFile.PDFContent = bytes
dataContext.SubmitChanges()
counter += 1
If counter Mod 10 = 0 Then Console.WriteLine(" saved file " & file.Name & " at " & directory.Name)
End Sub
Private Function getFileStream(ByVal fileInfo As IO.FileInfo) As Byte()
Dim fileStream = fileInfo.OpenRead()
Dim bytesLength As Long = fileStream.Length
Dim bytes(bytesLength) As Byte
fileStream.Read(bytes, 0, bytesLength)
fileStream.Close()
Return bytes
End Function
I suggest you perform this in batches, using Take (before the call to ToList) to process a particular number of items at a time. Read (say) 10, set the PDFContent on all of them, call SubmitChanges, and then start again. (I'm not sure offhand whether you should start with a new DataContext at that point, but it might be cleanest to do so.)
As an aside, your code to read the contents of a file is broken in at least a couple of ways - but it would be simpler just to use File.ReadAllBytes in the first place.
Also, your way of handling the list gradually shrinking is really inefficient - after fetching 180,000 records, you're then building a new list with 179,999 records, then another with 179,998 records etc.
Does the DataContext have ObjectTrackingEnabled set to true (the default value)? If so, then it will try to keep a record of essentially all the data it touches, thus preventing the garbage collector from being able to collect any of it.
If so, you should be able to fix the situation by periodically disposing the DataContext and creating a new one, or turning object tracking off.
OK. To use the smallest amount of memory we have to update the datacontext in blocks. I've put a sample code below. Might have sytax errors since I'm using notepad to type it in.
Dim DB as YourDataContext = new YourDataContext
Dim BlockSize as integer = 25
Dim AllItems = DB.Items.Where(function(i) i.PDFfile.HasValue=False)
Dim count = 0
Dim tmpDB as YourDataContext = new YourDataContext
While (count < AllITems.Count)
Dim _item = tmpDB.Items.Single(function(i) i.recordID=AllItems.Item(count).recordID)
_item.PDF = GetPDF()
Count +=1
if count mod BlockSize = 0 or count = AllItems.Count then
tmpDB.SubmitChanges()
tmpDB = new YourDataContext
GC.Collect()
end if
End While
To Further optimise the speed you can get the recordID's into an array from allitems as an anonymous type, and set DelayLoading on for that PDF field.