inserting remote image onto windows form in vb.net? - vb.net

anyone have experience doing this?

What do you mean with remote? If you mean an image residing on a web server you can do like this:
Dim client As New System.Net.WebClient()
Dim stream As New System.IO.MemoryStream()
Dim data As Byte() = client.DownloadData("http://somewebsite/someimage.jpg")
client.Dispose()
stream.Write(data, 0, data.Length)
pictureBox.Image = Image.FromStream(stream)
Update
Marcs comment about rewinding the stream sparked my curiosity, so I looked into it, and thought I would add it here for completeness.
After writing the data to the stream, the stream's position will be pointing at the end of the stream and before reading from the stream, you would normally need to set the position to the beginning of the stream (stream.Position = 0). As it turns out, Image.FromStream will do this internally, and restore the stream position after loading the image.

Related

bitmap image printing using axiohm usbcomm dll

I am using an Axiohm thermal printer for printing POS receipt(USBCOMM.dll for communication). Currently, i am able to print the required details along with an image(.bmp file). Now i need to use a new image instead of the existing image. The new image contains barcode.
When i try printing the new image, all i get is some garbage values. Below is the code that i use. Same code works with old image but not with the new image. Is there any format for image that i need to follow.
Dim filepath As String = AppDomain.CurrentDomain.BaseDirectory + "Resources\PrinterDlls\unnamed.bmp"
Using fs = New FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read)
Dim inpt As Byte() = New Byte(fs.Length) {}
inpt(0) = &H1F
fs.Read(inpt, 1, CInt(fs.Length))
Dim ok As Boolean = Usb_WritePort(True, inpt, inpt.Length, written, IntPtr.Zero)
If Not ok OrElse written <> inpt.Length Then
Throw New Exception("USB write failed")
End If
End Using
Well, this is embarrassing that i am answering my own question. I searched for sometime to resolve and raised the question. Soon after, i came across this video in youtube that explain the bitmap image to create for thermal printing
https://www.youtube.com/watch?v=LdB33eWLjgU
Basically, you need to ensure 3 things while creating the image:
1. 8-bit
2. Greyscale
3. Save as .bmp
And the new image will work like a charm while printing. Also ensure the width is less than the paper width.

How do you delete a file generated via webapi after returning the file as response?

I'm creating a file on the fly on a WebAPI call, and sending that file back to the client.
I think I'm misunderstanding flush/close on a FileStream:
Dim path As String = tempFolder & "\" & fileName
Dim result As New HttpResponseMessage(HttpStatusCode.OK)
Dim stream As New FileStream(path, FileMode.Open)
With result
.Content = New StreamContent(stream)
.Content.Headers.ContentDisposition = New Headers.ContentDispositionHeaderValue("attachment")
.Content.Headers.ContentDisposition.FileName = fileName
.Content.Headers.ContentType = New Headers.MediaTypeHeaderValue("application/octet-stream")
.Content.Headers.ContentLength = stream.Length
End With
'stream.Flush()
'stream.Close()
'Directory.Delete(tempFolder, True)
Return result
You can see where I've commented things out above.
Questions:
Does the stream flush/close itself?
How can I delete the tempFolder after returning the result?
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
Update:
I went ahead with accepted answer, and found it to be quite simple:
Dim ReturnStream As MemoryStream = New MemoryStream()
Dim WriteStream As StreamWriter = New StreamWriter(ReturnStream)
With WriteStream
.WriteLine("...")
End With
WriteStream.Flush()
WriteStream.Close()
Dim byteArray As Byte() = ReturnStream.ToArray()
ReturnStream.Flush()
ReturnStream.Close()
Then I was able to stream the content as bytearraycontent:
With result
.Content = New ByteArrayContent(byteArray)
...
End With
On top of all this, it would be great to know how to generate the file and send it to the user without writing it to the file system first. I'm confident this is possible, but I'm not sure how. I'd love to be able to understand how to do this, and solve my current problem.
To do the same thing without writing a file to disk, you might look into the MemoryStream class. As you'd guess, it streams data from memory like the FileStream does from a file. The two main steps would be:
Take your object in memory and instead of writing it to a file, you'd serialize it into a MemoryStream using a BinaryFormatter or other method (see that topic on another StackOverflow Q here: How to convert an object to a byte array in C#).
Pass the MemoryStream to the StreamContent method, exactly the same way you're passing the FileStream now.

Writing to FileStream works, MemoryStream copied to FileStream doesn't

I have some code that used a FileStream, StreamWriter and XmlDocument to produce Excel-compatible output files. Very useful!
However I now have a need to make copies of the file, and I'd like to do that in-memory. So I took my original FileStream code and changed the FileStream to a MemoryStream, and then wrapped that in this function:
'----------------------------------------------------------------------------------
Friend Sub Save(Optional ByVal SaveCalculatedResults As Boolean = True)
Dim MStream As MemoryStream
Dim FStream As FileStream
Dim Bytes As Byte()
'make the stream containing the XML
MStream = ToXLSL(SaveCalculatedResults)
If MStream.Length = 0 Then Return
'then read that data into a byte buffer
ReDim Bytes(CInt(MStream.Length))
MStream.Read(Bytes, 0, CInt(MStream.Length))
'and then write it to "us"
FStream = New FileStream("C:\OUTFILE.XLSX", FileMode.Create)
FStream.Write(Bytes, 0, CInt(MStream.Length))
FStream.Flush()
End Sub
This creates a file in the correct location, it has the exact same length as it did before, but opening it in Excel causes an error about the file format being invalid.
Can anyone see any obvious problems in that code? Perhaps I am writing the bytes backwards? Is this possibly a text encoding problem? 32/64 problem?
p.s. I tried using CopyTo, but that doesn't seem to work in VB?
It requires guessing what ToXLSL() does but the behavior gives a strong hint: the MemoryStream's Position is located at the end of the stream. So the Read() call doesn't actually read anything. Verify by checking its return value.
Just get rid of Bytes() entirely, it is very wasteful to duplicate the data like this. You don't need it, the MemoryStream already gives you access to the data:
Using FStream = New FileStream("C:\OUTFILE.XLSX", FileMode.Create)
FStream.Write(MStream.GetBuffer(), 0, CInt(MStream.Length))
End Using
Do note that the Using statement is not optional. And that you cannot write to C:\

Saving a base 64 encoded image in MongoDB GridFS

I have a web service that takes the content of a canvas tag and saves it into a MongoDB GridFS store.
The code below works, however it requires saving the image to disk before sending it to MongoDB.
Using postBody As Stream = Request.InputStream
' Get the body of the HTTP POST (the data:image/png)
postBody.Seek(0, SeekOrigin.Begin)
Dim imageData As String = New StreamReader(postBody).ReadToEnd
Dim base64Data = Regex.Match(imageData, "data:image/(?<type>.+?),(?<data>.+)").Groups("data").Value
Dim data As Byte() = Convert.FromBase64String(base64Data)
Using stream = New MemoryStream(data, 0, data.Length)
Dim img As System.Drawing.Image = System.Drawing.Image.FromStream(stream)
Dim directory = Server.MapPath("~/App_Data/temp/")
Dim file = String.Concat(directory, id, ".png")
img.Save(file, System.Drawing.Imaging.ImageFormat.Png)
Using fs = New FileStream(file, FileMode.Open)
db.GridFS.Upload(fs, id & ".png")
End Using
End Using
End Using
Is there a better way, perhaps without the need to persist it to disk before uploading to MongoDB?
As suggested in the comments, just use the Stream as an argument to Upload instead of writing out to file.
And also note that you do not have to convert to base64 in order to send the file via GridFS (or a plain mongo field for that matter). The input can be binary, unless of course you always want your data base64 encoded for your convenience.

how to prevent the Image.FromFile() method to lock the file

I am using following code to put JPG's into a DataGridView's Image cell.
If strFileName.ToLower.EndsWith(".jpg") Then
Dim inImg As Image = Image.FromFile(strFileName)
DataGridView4.Rows.Add()
DataGridView4.Rows(DataGridView4.Rows().Count - 1).Cells(0).Value = inImg
End If
The problem is that I need to save this file from within the program, but i get the message that the file is beeing used by another program.
So i tried to add inImg.Dispose() before the end if, but then the program doesnt display the images anymore in the DataGridView.
How can i add images in the DataGridView without locking them?
thanks
When you use the Image.FromFile(strFileName) method to create the Image, the method locks the file until you release the Image. The exact reason is explained below. And it's why you can't access more than one time to the same image file with this method.
You could instead:
use the Image.FromStream(stream) method.
that you use with a New FileStream or a MemoryStream that you create from the image file.
Here are possible implementation of a custom SafeImageFromFile method that doesn't lock the image file:
Public Shared Function SafeImageFromFile(path As String) As Image
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Dim img = Image.FromStream(fs)
Return img
End using
End Function
Or
Public Shared Function SafeImageFromFile(path As String) As Image
Dim bytes = File.ReadAllBytes(path)
Using ms As New MemoryStream(bytes)
Dim img = Image.FromStream(ms)
Return img
End Using
End Function
Usage
If strFileName.ToLower.EndsWith(".jpg") Then
Dim inImg As Image = SafeImageFromFile(strFileName)
Dim index as integer = DataGridView4.Rows.Add()
DataGridView4.Rows(index).Cells(0).Value = inImg
End If
Important note
Here I create the FileStream or a MemoryStream using a Using statement to make sure the stream is released. It works fine on my system and it seems it work for you too, though MSDN says about Image.FromStream(stream) method:
You must keep the stream open for the lifetime of the Image.
The reason of this sentence is explain here: KB814675 Bitmap and Image constructor dependencies
GDI+, and therefore the System.Drawing namespace, may defer the
decoding of raw image bits until the bits are required by the image.
Additionally, even after the image has been decoded, GDI+ may
determine that it is more efficient to discard the memory for a large
Bitmap and to re-decode later. Therefore, GDI+ must have access to the
source bits for the image for the life of the Bitmap or the Image
object.
To retain access to the source bits, GDI+ locks any source file, and
forces the application to maintain the life of any source stream, for
the life of the Bitmap or the Image object.
So know the code above could generate GDIexceptions because of releasing the stream using Using. It could happen when you save the image from the file or during the image creation. From this thread Loading an image from a stream without keeping the stream open and Hans Passant's comment they fixed several problems with indexed pixel formats in the Vista version of gdiplus.dll., it would happen only on XP.
To avoid this you need to keep the stream open. The methods would be:
Public Shared Function SafeImageFromFile(path As String) As Image
Dim fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Dim img = Image.FromStream(fs)
Return img
End Function
Or
Public Shared Function SafeImageFromFile(path As String) As Image
Dim bytes = File.ReadAllBytes(path)
Dim ms = New MemoryStream(bytes)
Dim img = Image.FromStream(ms)
Return img
End Function
But those last methods have some disadvantage like not releasing the stream (memory issue) and they violate rule CA2000 Dispose objects before losing scope .
The KB article gives some workarounds:
Create a Non-Indexed Image
This approach requires that the new image be in a non-indexed pixel
format (more than 8 bits-per-pixel), even if the original image was in
an indexed format. This workaround uses the Graphics.DrawImage()
method to copy the image to a new Bitmap object:
Construct the original Bitmap from the stream, from the memory, or from the file.
Create a new Bitmap of the same size, with a pixel format of more than 8 bits-per-pixel (BPP).
Use the Graphics.FromImage() method to obtain a Graphics object for the second Bitmap.
Use Graphics.DrawImage() to draw the first Bitmap onto the second Bitmap.
Use Graphics.Dispose() to dispose of the Graphics.
Use Bitmap.Dispose() to dispose of the first Bitmap.
Create an Indexed Image
This workaround creates a Bitmap object in an indexed format:
Construct the original Bitmap from the stream, from the memory, or from the file.
Create a new Bitmap with the same size and pixel format as the first Bitmap.
Use the Bitmap.LockBits() method to lock the whole image for both Bitmap objects in their native pixel format.
Use either the Marshal.Copy function or another memory copying function to copy the image bits from the first Bitmap to the second Bitmap.
Use the Bitmap.UnlockBits() method to unlock both Bitmap objects.
Use Bitmap.Dispose() to dispose of the first Bitmap.
Here is an implementation of Non-Indexed Image creation, based on KB article and this answer https://stackoverflow.com/a/7972963/2387010 Your best bet is creating a pixel-perfect replica of the image -- though YMMV (with certain types of images there may be more than one frame, or you may have to copy palette data as well.) But for most images, this works:
Private Shared Function SafeImageFromFile(path As String) As Bitmap
Dim img As Bitmap = Nothing
Using fs As New FileStream(path, FileMode.Open, FileAccess.Read)
Using b As New Bitmap(fs)
img = New Bitmap(b.Width, b.Height, b.PixelFormat)
Using g As Graphics = Graphics.FromImage(img)
g.DrawImage(b, Point.Empty)
g.Flush()
End Using
End Using
End Using
Return img
End Function
Someone indicated that what is important is that the FileStream is opened in read mode (FileAccess.Read).
True, but it makes more sens if you don't use Using statement and so you don't release the stream, or in multi threads context: FileAccess.Write is inappropriate, and FileAccess.ReadWrite is not required, but open the stream with FileAccess.Read mode won't prevent to have an IO.Exception if another program (or yours in multi threads context) has opened the file with another mode than FileAccess.Read.
If you want to be able to display the image and at the same time be able to save data to the file, Since you don't lock the file with those methods, you should be able to save the image (delete/overwrite the previous file) using the Image.Save method.
# Chris: Opening approximately 100 large (3400x2200) images with your final code, I was receiving an invalid argument crash on [img = new bitmap(...], I have seen this before opening an image of zero size, but that was not the case here. I added fs.dispose and successfully opened thousands of images of the same size of the same set as the first test without issue. I'm interested in your comments on this.
Private Function SafeImageFromFile(FilePath As String) As Image
Dim img As Bitmap = Nothing
Using fs As New FileStream(FilePath, FileMode.Open, FileAccess.Read)
Using b As New Bitmap(fs)
img = New Bitmap(b.Width, b.Height, b.PixelFormat)
Using g As Graphics = Graphics.FromImage(img)
g.DrawImage(b, Point.Empty)
g.Flush()
End Using
End Using
fs.Dispose()
End Using
Return img
End Function
This works without issue, ran 4189 images 3400x2200 through it (twice) without issue, this moves the filestream outside of the function and re-uses it. Im closing the file to release the write lock. Im pointing a picturebox at this image in a loop for my test.
Private fsIMG As FileStream
Private Function SafeImageFromFile(FilePath As String) As Image
'Ref: http://stackoverflow.com/questions/18250848/how-to-prevent-the-image-fromfile-method-to-lock-the-file
Dim img As Bitmap = Nothing
fsIMG = New FileStream(FilePath, FileMode.Open, FileAccess.Read)
Using b As New Bitmap(fsIMG)
img = New Bitmap(b.Width, b.Height, b.PixelFormat)
Using g As Graphics = Graphics.FromImage(img)
g.DrawImage(b, Point.Empty)
g.Flush()
End Using
End Using
fsIMG.Close()
Return img
End Function
After searching the internet for long time I found out I can use this code without any error.
Private fsIMG As FileStream
Private Function SafeImageFromFile(FilePath As String) As Image
'Ref: http://stackoverflow.com/questions/18250848/how-to-prevent-the-image-fromfile-method-to-lock-the-file
Dim img As Bitmap = Nothing
fsIMG = New FileStream(FilePath, FileMode.Open, FileAccess.Read)
Using b As New Bitmap(fsIMG)
img = New Bitmap(b.Width, b.Height, b.PixelFormat)
Using g As Graphics = Graphics.FromImage(img)
g.DrawImage(b, Point.Empty)
g.Flush()
End Using
End Using
fsIMG.Close()
Return img
End Function
I encountered the same situation and used this code:
' Create memory stream from file
Dim ms As New MemoryStream()
' Open image file
Using fs As New FileStream(.FileName, FileMode.Open, FileAccess.Read)
' Save to memory stream
fs.CopyTo(ms)
End Using
' Create image from the file's copy in memory
Dim img = Image.FromStream(ms)
I didn't dispose the memory stream because it allows to save the image later using exactly the same encoding as the original file, using this code:
img.Save(someOtherStream, img.RawFormat)