Preserve Exif/Image Properties - vb.net

In a web app, users can upload images, which save on the server. It creates thumbnails of the image on the back end with the following code, but all exif data of the image is lost.
I want to preserve the exif data from the original image all throughout the process, and have it included in the final stream. I can read the exif properties from the image, but can't get it to preserve when saving.
To clarify, I am not trying to read, parse, or do anything specific to the metadata itself, I just want to preserve it exactly as it was in the original image during image processing.
Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs)
'prepare image
Dim imgFullSize As System.Drawing.Image
'attempt to get the image
Dim sInputURL As String = HttpUtility.UrlDecode(Request.QueryString("IptFl"))
If InStr(sInputURL, "http://") > 0 Or InStr(sInputURL, "https://") Then
'from web url
Dim imgWebRequest As System.Net.WebRequest
Dim imgWebResponse As System.Net.WebResponse
imgWebRequest = System.Net.WebRequest.Create(sInputURL)
imgWebResponse = imgWebRequest.GetResponse()
imgFullSize = System.Drawing.Image.FromStream(imgWebResponse.GetResponseStream())
Else
'from file
imgFullSize = System.Drawing.Image.FromFile(Server.MapPath(sInputURL))
End If
' Dim props As PropertyItem() = imgFullSize.PropertyItems
' For Each prop As PropertyItem In props
' Response.Write(prop.Id.ToString() & "<br />")
' Next
'determine type
Dim sFileExtension As String = "png"
If Left(Right(sInputURL, 4), 1) = "." Then sFileExtension = Right(sInputURL, 3) 'for jpg, gif, etc
If Left(Right(sInputURL, 5), 1) = "." Then sFileExtension = Right(sInputURL, 4) 'for tiff, jpeg, etc
Dim jpgEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Jpeg)
Dim gifEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Gif)
Dim pngEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Png)
'set the quality
Dim myEncoder As System.Drawing.Imaging.Encoder = System.Drawing.Imaging.Encoder.Quality
Dim myEncoderParams As New EncoderParameters(1)
Dim myEncoderQuality As New EncoderParameter(myEncoder, CType(100L, Int32))
myEncoderParams.Param(0) = myEncoderQuality
'save img to memory stream
Dim ms As New MemoryStream()
Select Case sFileExtension
Case "jpg" : imgFullSize.Save(ms, jpgEncoder, myEncoderParams)
Case "png", "gif" : imgFullSize.Save(ms, pngEncoder, myEncoderParams)
Case Else : imgFullSize.Save(ms, pngEncoder, myEncoderParams)
End Select
'output the memory stream
Response.ContentType = "image/" & sFileExtension
ms.WriteTo(Response.OutputStream)
'---> when I save the above image and look at the exif, it doesn't exist
End Sub
Private Function GetEncoder(ByVal format As ImageFormat) As ImageCodecInfo
Dim codecs As ImageCodecInfo() = ImageCodecInfo.GetImageDecoders()
Dim codec As ImageCodecInfo
For Each codec In codecs
If codec.FormatID = format.Guid Then Return codec
Next codec
Return Nothing
End Function

So this did the trick. Basically I had to loop through the source image properties, and for each, set the property in the new image.
'retrieve relative path to image
Dim sSrc As String = HttpUtility.UrlDecode(Request.QueryString("IptFl"))
'prepare image
Dim oImg As System.Drawing.Image
'attempt to get the image, either from web or local file
If InStr(sSrc, "http://") > 0 Or InStr(sSrc, "https://") Then
Dim oRequest As System.Net.WebRequest = System.Net.WebRequest.Create(sSrc)
Dim oResponse As System.Net.WebResponse = oRequest.GetResponse()
oImg = System.Drawing.Image.FromStream(oResponse.GetResponseStream())
oResponse.Close()
Else
oImg = System.Drawing.Image.FromFile(Server.MapPath(sSrc))
End If
'discard if image file not found
If oImg Is Nothing Then Response.End()
Dim sFileExt As String = Split(sSrc, ".")(UBound(Split(sSrc, ".")))
Dim oCanvas As System.Drawing.Bitmap = New System.Drawing.Bitmap(oImg.Width, oImg.Height, System.Drawing.Imaging.PixelFormat.Format16bppRgb555)
For Each pi As PropertyItem In oImg.PropertyItems
oCanvas.SetPropertyItem(pi)
Next
Dim oGraphic As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(oCanvas)
oGraphic.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.Default
oGraphic.DrawImage(oImg, 0, 0, oImg.Width, oImg.Height)
Dim oStream As System.IO.MemoryStream = New System.IO.MemoryStream()
oCanvas.Save(oStream, System.Drawing.Imaging.ImageFormat.Jpeg)
Response.ContentType = "image/" & sFileExt
'output the memory stream
oStream.WriteTo(Response.OutputStream)
Response.End()

Related

Crop image and save it in database using vb.net

I'm following a tutorial on Image Cropping with resizing using vb.net . Everything works well, But instead of saving it
on the hard disk. I want to save it on my database(SQLServer).
This is the code of saving on a disk
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles cropSaveBtn.Click
Dim tempFileName As String
Dim svdlg As New SaveFileDialog()
svdlg.Filter = "JPEG files (*.jpg)|*.jpg|All files (*.*)|*.*"
svdlg.FilterIndex = 1
svdlg.RestoreDirectory = True
If svdlg.ShowDialog() = Windows.Forms.DialogResult.OK Then
tempFileName = svdlg.FileName 'check the file exist else save the cropped image
Try
Dim img As Image = PreviewPictureBox.Image
SavePhoto(img, tempFileName, 225)
Catch exc As Exception
MsgBox("Error on Saving: " & exc.Message)
End Try
End If
End Sub
Public Function SavePhoto(ByVal src As Image, ByVal dest As String, ByVal w As Integer) As Boolean
Try
Dim imgTmp As System.Drawing.Image
Dim imgFoto As System.Drawing.Bitmap
imgTmp = src
imgFoto = New System.Drawing.Bitmap(w, 225)
Dim recDest As New Rectangle(0, 0, w, imgFoto.Height)
Dim gphCrop As Graphics = Graphics.FromImage(imgFoto)
gphCrop.SmoothingMode = SmoothingMode.HighQuality
gphCrop.CompositingQuality = CompositingQuality.HighQuality
gphCrop.InterpolationMode = InterpolationMode.High
gphCrop.DrawImage(imgTmp, recDest, 0, 0, imgTmp.Width, imgTmp.Height, GraphicsUnit.Pixel)
Dim myEncoder As System.Drawing.Imaging.Encoder
Dim myEncoderParameter As System.Drawing.Imaging.EncoderParameter
Dim myEncoderParameters As System.Drawing.Imaging.EncoderParameters
Dim arrayICI() As System.Drawing.Imaging.ImageCodecInfo = System.Drawing.Imaging.ImageCodecInfo.GetImageEncoders()
Dim jpegICI As System.Drawing.Imaging.ImageCodecInfo = Nothing
Dim x As Integer = 0
For x = 0 To arrayICI.Length - 1
If (arrayICI(x).FormatDescription.Equals("JPEG")) Then
jpegICI = arrayICI(x)
Exit For
End If
Next
myEncoder = System.Drawing.Imaging.Encoder.Quality
myEncoderParameters = New System.Drawing.Imaging.EncoderParameters(1)
myEncoderParameter = New System.Drawing.Imaging.EncoderParameter(myEncoder, 60L)
myEncoderParameters.Param(0) = myEncoderParameter
imgFoto.Save(dest, jpegICI, myEncoderParameters)
imgFoto.Dispose()
imgTmp.Dispose()
Catch ex As Exception
End Try
End Function
I want it to save the picture to SQL Server 2008 (Image data type) together with my two data just like this
Using cmd As New SqlClient.SqlCommand("dbo.uspAdd", cn)
cmd.CommandType = CommandType.StoredProcedure
cmd.Parameters.Add("#firstname", SqlDbType.VarChar, 100).Value = txtName.Text
cmd.Parameters.Add("#lastName", SqlDbType.VarChar, 100).Value = txtSurname.Text
'add insert picture code here
cmd.ExecuteNonQuery()
MsgBox("Save Record New record Successfully")
End Using
And now i'm stuck for almost 8 hours finding ways on how to fix this.Can anyone help me to solve this. Any help would be very much appreciated.
I would suggest converting the image to Base64 and then storing it as a string.
Then when you want to get the image back you need to convert it back from Base64 to an image.
You can convert an image to Base64 using this code:
Public Function ConvertImageToBase64(ByRef img As Image, ByVal format As System.Drawing.Imaging.ImageFormat) As String
Dim ImgStream As MemoryStream = New MemoryStream()
img.Save(ImgStream, format)
ImgStream.Close()
Dim ByteArray() As Byte = ImgStream.ToArray()
ImgStream.Dispose()
Return Convert.ToBase64String(ByteArray)
End Function
(http://www.dailycoding.com/posts/convert_image_to_base64_string_and_base64_string_to_image.aspx)
And to convert it back to an image you can use this code:
Public Function ConvertBase64ToImage(ByVal base64 As String) As Image
Dim img As System.Drawing.Image
Dim MS As System.IO.MemoryStream = New System.IO.MemoryStream
Dim b64 As String = base64.Replace(" ", "+")
Dim b() As Byte
b = Convert.FromBase64String(b64)
MS = New System.IO.MemoryStream(b)
img = System.Drawing.Image.FromStream(MS)
Return img
End Function
(http://snipplr.com/view/27514/vbnet-base64-to-image/)
Now you can basically add the image as a string, like this:
Dim Base64Bitmap As String = ConvertImageToBase64(img, System.Drawing.Imaging.ImageFormat.Png)
cmd.Parameters.Add("#Image", SqlDbType.VarChar, Base64Bitmap.Length).Value = Base64Bitmap

image in the SQL_database in vb.net

I have a problem to record the image in the SQL_database in vb.net.Enter as a file without a problem but I can not write in SQL.ABCreateNewBarcode is a PictureBox. I have a problem to take BackgroundImage from PictureBox to save in SQL. I save BackgroundImage in BarcodeImg folder but I can not save in SQl
Private Sub btnSaveBarcode_Click(sender As Object, e As EventArgs) Handles btnSaveBarcode.Click
'Create Image Object
Dim ABCreateNewBarcode As Object
ABCreateNewBarcode = CreateObject("BARCODE.BarcodeCtrl.1")
ABCreateNewBarcode.Text = txtNewBarcode.Text
ABCreateNewBarcode.typename = "Code128"
DirBarcodeImg = Application.StartupPath & "\barcodeimg"
'Save Image
If txtNewBarcode.Text = "" Then
MsgBox("Click the Create Button to create a New Barcode")
ElseIf Directory.Exists(DirBarcodeImg) = False Then
Call Directory.CreateDirectory(DirBarcodeImg)
Else
ABCreateNewBarcode.SaveAsBySize(DirBarcodeImg & "\" & txtInsertPartName.Text & ".png", 300, 130)
Dim ImageToSave As Image = ABCreateNewBarcode.BackgroundImage
Dim ms As New MemoryStream
ImageToSave.Save(ms, ImageToSave.RawFormat)
Dim buffer As Byte() = MS.GetBuffer()
'Add SQL Parameters
SQL.AddParam("#name", txtInsertPartName.Text)
SQL.AddParam("#image", buffer)
'Run Imsert Command
SQL.ExecQuery("INSERT INTRO information (PartName,BarcodeImg) " &
"VALUES (#name,#image) ")
End If
End Sub
After chaging you request "INTO" instead of "INTRO" try this line:
SQL.Parameters.AddWithValue("#image", txtInsertPartName.Text).SqlDbType = SqlDbType.Image
and replace :
Dim ms As New MemoryStream
ImageToSave.Save(ms, ImageToSave.RawFormat)
Dim buffer As Byte() = MS.GetBuffer()
by this:
Dim fs As FileStream
fs = New FileStream(imagename, FileMode.Open, FileAccess.Read)
'a byte array to read the image
Dim picbyte As Byte() = New Byte(fs.Length - 1) {}
fs.Read(picbyte, 0, System.Convert.ToInt32(fs.Length))
fs.Close()
'open the database using odp.net and insert the data
Dim buffer As Byte() =picbyte

Resize and Compress image to byte array without saving the new image

The image is first resized, compressed and then saved on disk as "Preview.jpg" and then it is opened to convert into byte array. The code works fine but I cannot figure out how to do it without saving the image on disk.
Here is the code:
Public Function GetThumb_Preview(ByVal sourceImg As String) As Byte()
Dim jgpEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Jpeg)
Dim myEncoder As System.Drawing.Imaging.Encoder = System.Drawing.Imaging.Encoder.Quality
Dim myEncoderParameters As New EncoderParameters(1)
Dim myEncoderParameter As New EncoderParameter(myEncoder, 50&)
myEncoderParameters.Param(0) = myEncoderParameter
Dim myBitmap As New Bitmap(sourceImg)
Dim oWidth As Integer = myBitmap.Width
Dim oHeight As Integer = myBitmap.Height
Dim aspectRatio As Double = oHeight / oWidth
Dim thumbWidthDouble As Double = 200
Dim thumbHeightDouble As Double = Math.Round(thumbWidthDouble * aspectRatio)
Dim thumbWidth As Integer = CInt(thumbWidthDouble)
Dim thumbHeight As Integer = CInt(thumbHeightDouble)
Dim myThumb As New Bitmap(myBitmap, thumbWidth, thumbHeight)
Dim targetPreviewPath As String = "E:\Preview.jpg"
myThumb.Save(targetPreviewPath, jgpEncoder, myEncoderParameters)
Dim myImage As Image = Image.FromFile(targetPreviewPath)
Dim imgByteArray As Byte() = Nothing
'Image to byte[]
Dim imgMemoryStream As MemoryStream = New MemoryStream()
myImage.Save(imgMemoryStream, System.Drawing.Imaging.ImageFormat.Jpeg)
imgByteArray = imgMemoryStream.GetBuffer()
Return imgByteArray
End Function
That is a lot of variables to do so little. You also have a number of objects not being disposed. It will also return a valid Byte array only when the resulting byte data is less than the buffer size. It works in this case because you are resizing to 200x and reducing quality.
I didnt test if I collapsed all those variables correctly, but should be very close. More important is disposing things you create, and getting the all the Bytes for the return:
Dim jgpEncoder As ImageCodecInfo = GetEncoder(ImageFormat.Jpeg)
Dim myEncoder As System.Drawing.Imaging.Encoder =
System.Drawing.Imaging.Encoder.Quality
Dim myEncoderParameters As New EncoderParameters(1)
Dim myEncoderParameter As New EncoderParameter(myEncoder, 50&)
myEncoderParameters.Param(0) = myEncoderParameter
Dim imgByteArray As Byte()
Using myBitmap As New Bitmap(sourceImg) ' i guess this is from file
Dim aspectRatio As Double = myBitmap.Height / myBitmap.Width
' USING for disposable objects
Using myThumb As New Bitmap(myBitmap, 200,
CInt(Math.Round(200 * aspectRatio))),
ms As New MemoryStream
' encode image to memstream
myThumb.Save(ms, jgpEncoder, myEncoderParameters)
' rewind and get ALL bytes for the new image
ms.Position = 0
imgByteArray = ms.ToArray
End Using
End Using ' dispose
Return imgByteArray
You could save it to a stream and load it from there
Using Str As New MemoryStream
myThumb.Save(Str, jgpEncoder, myEncoderParameters)
myImage = Image.FromStream(Str)
End Using

streamwriter in windows store app - write text to file in VB

Does anybody have VB code to emulate Streamwriter for Windows Store?
I know it's been replaced by StorageFolder class but there is no VB sample in MSDN and I can't seem to translate properly from c# examples. Any help would be appreciated. I am just trying to write text (CSV) to a file and save it to the documents folder. In the code below windows store want a stream instead of strPath when I try dim-ing a streamwriter. (been playing with pickerdialog too, but that might be the next hurdle).
Dim strpath As String = Windows.Storage.Pickers.PickerLocationId.DocumentsLibrary & "\" & strFileName
'Build String for file*******************
Dim swExport As StreamWriter = New StreamWriter(strpath)
swExport.Flush()
For x = 0 To intCount - 1
strLine = "WriteSomeText"
swExport.WriteLine(strLine)
Next x
Possibly the simplest approach would be to use a MemoryStream if you like StreamWriter, so something like:
Dim sessionData As New MemoryStream()
' TODO: stage data in sessionData
Dim swExport As StreamWriter = New StreamWriter(sessionData)
swExport.Flush()
For x = 0 To intCount - 1
strLine = "WriteSomeText"
swExport.WriteLine(strLine)
Next x
Dim file As StorageFile = await ApplicationData.Current.RoamingFolder.CreateFileAsync("towns.json", CreationCollisionOption.ReplaceExisting)
Using (fileStream As Stream = await file.OpenStreamForWriteAsync())
sessionData.Seek(0, SeekOrigin.Begin)
await sessionData.CopyToAsync(fileStream)
await fileStream.FlushAsync()
End Using
I was making it too difficult. To write to a file I just needed to use storagefolder and storagefile. I have also included the FileSavePicker in the code (note that filetypechoices is mandatory)
Private Async Function btnExport_Click(sender As Object, e As RoutedEventArgs) As Task
'Calls Filepicker to determine location
'Calls Sqlite to select ALL
'Creates CSV file to be saved at location chosen
'save to file
Dim intCount As Integer = "5"
Dim x As Integer
Dim strLine As String 'hold each line for export file
'Create FileName based on date
Dim strDate As String = Date.Today.ToString("MMddyyyy")
Dim strFileName As String = "Export" & strDate & ".csv"
' Configure save file dialog box
Dim dlgPicker As New Windows.Storage.Pickers.FileSavePicker
'add types for picker (manditory field)
Dim types = New List(Of String)
types.Add(".csv")
types.Add(".txt")
'set picker parameters
dlgPicker.SuggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.Downloads
dlgPicker.SuggestedFileName = strFileName '"Document" '
dlgPicker.FileTypeChoices.Add("CSV/TXT", types) 'manditory
dlgPicker.DefaultFileExtension = ".csv" 'Filter files by extension
dlgPicker.CommitButtonText = "Save"
' Show save file dialog box
Dim SaveCSV = Await dlgPicker.PickSaveFileAsync()
'************************get data************
Dim sbExport As Text.StringBuilder = New Text.StringBuilder
sbExport.AppendLine(strHeader)
For x = 0 To intCount - 1
strLine = "Get the text you want to write here"
sbExport.AppendLine(strLine)
Next x
'************************************
'write data to file
Await FileIO.WriteTextAsync(SaveCSV, sbExport.ToString)
Dim mb As MessageDialog = New MessageDialog("Done")
Await mb.ShowAsync()
End Function

Pdf to Tiff file covert in vb.net using PdfSharp.dll

i am using Pdfsharp.dll to convert tiff image to pdf file in vb.net, and it is successfull when i run in my machine, when i use it from other machine, which shows the Error like "Raw string contains invalid character with a value > 255.", please any one help me to fix error,
i using the PdfSharp.dll library and the following code
Dim objDoc As PdfDocument
Dim objPdfPage As PdfPage
Dim objTiffImg As Image
Dim objXImg As XImage
Dim iPageCount As Integer
Dim objXgr As XGraphics
Dim sPdfFile As String = Nothing
Dim objDir As DirectoryInfo
Dim objFile As FileInfo()
Dim objFileInfo As FileInfo
Try
objTiffImageSpliter = New TiffImageSplitter()
objDoc = New PdfDocument
iPageCount = objTiffImageSpliter.GetPageCount(sFileName)
For iCount As Integer = 0 To iPageCount - 1
objPdfPage = New PdfPage
objTiffImg = objTiffImageSpliter.getTiffImage(sFileName, iCount)
objXImg = XImage.FromGdiPlusImage(objTiffImg)
'objPdfPage.Height = objXImg.PointWidth
'objPdfPage.Width = objXImg.PointHeight
objDoc.Pages.Add(objPdfPage)
objXgr = XGraphics.FromPdfPage(objDoc.Pages(iCount))
objXgr.DrawImage(objXImg, 10, 10)
Next
sPdfFile = System.Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\MY_FaxFile\"
If System.IO.Directory.Exists(sPdfFile) Then
objDir = New DirectoryInfo(sPdfFile)
objFile = objDir.GetFiles()
For Each objFileInfo In objFile
objFileInfo.Delete()
Next
sPdfFile &= "MyFax.pdf"
Else
System.IO.Directory.CreateDirectory(sPdfFile)
sPdfFile &= "MyFax.pdf"
End If
objDoc.Save(sPdfFile) ' This Line shows the Error.
objDoc.Close()
Catch ex As Exception
MsgBox(ex.ToString)
sPdfFile = Nothing
End Try
Return sPdfFile
I'm not familiar with this library, but based on your code and error message, I would guess that your App Data folder contains non-ASCII characters and that the PdfSharp library does not support non-ASCII characters in the filename.