Converting image into stream - asp.net

I'm using a function that uploads an image, takes the stream and resizes it using imageresizer.net, then uploads the stream to Amazon S3.
Now I want to take a local picture and convert it into a stream. (to resize and upload to amazonS3). Basically, how do you convert an image into a stream.
This might be a simple question, just could not find the answer anywhere.
Here is some basic code.
Public Shared Sub MoveToAmazon(strImg As String, SKU As String)
Dim fullImg As String = "C:\ImageLocation\" & strImg
Dim img As Image = Image.FromFile(fullImg)
'Here Im missing the code to convert it to a stream.
UploadImage(imgStream, SKU)
End Sub
Public Shared Sub UploadImage(imgStream As Stream, imgName As String)
Dim MainStream As Stream = New MemoryStream
Dim HomeStream As Stream = New MemoryStream
Dim SmallStream As Stream = New MemoryStream
Dim TinyStream As Stream = New MemoryStream
Dim MidStream As Stream = New MemoryStream
Dim GridStream As Stream = New MemoryStream
Dim ListStream As Stream = New MemoryStream
Dim c As New ImageResizer.Configuration.Config
Dim SourceImage As Bitmap = New Bitmap(imgStream)
Dim SourceMain As Bitmap = New Bitmap(SourceImage)
Dim SourceHome As Bitmap = New Bitmap(SourceImage)
Dim SourceSmall As Bitmap = New Bitmap(SourceImage)
Dim SourceTiny As Bitmap = New Bitmap(SourceImage)
Dim SourceMid As Bitmap = New Bitmap(SourceImage)
Dim SourceGrid As Bitmap = New Bitmap(SourceImage)
Dim SourceList As Bitmap = New Bitmap(SourceImage)
ImageResizer.ImageBuilder.Current.Build(SourceMain, MainStream, New ResizeSettings("width=300&height=372&scale=both&paddingWidth=40")) 'ProductPage
ImageResizer.ImageBuilder.Current.Build(SourceHome, HomeStream, New ResizeSettings("width=112&height=147&scale=both")) 'HomePage Products
ImageResizer.ImageBuilder.Current.Build(SourceGrid, GridStream, New ResizeSettings("width=149&height=149&scale=both")) 'Categories Grid
ImageResizer.ImageBuilder.Current.Build(SourceList, ListStream, New ResizeSettings("width=171&height=206&scale=both")) 'Categories List
ImageResizer.ImageBuilder.Current.Build(SourceSmall, SmallStream, New ResizeSettings("width=64&height=75&scale=both")) 'Accessories
ImageResizer.ImageBuilder.Current.Build(SourceTiny, TinyStream, New ResizeSettings("width=82&height=82&scale=both")) 'Cart
ImageResizer.ImageBuilder.Current.Build(SourceMid, MidStream, New ResizeSettings("width=155&height=116&scale=both")) 'CategoryMain
AmazonUploadFile("OriginalImages/" & imgName, imgStream)
AmazonUploadFile("MainImages/" & imgName, MainStream)
AmazonUploadFile("HomeImages/" & imgName, HomeStream)
AmazonUploadFile("GridImages/" & imgName, GridStream)
AmazonUploadFile("ListImages/" & imgName, ListStream)
AmazonUploadFile("SmallImages/" & imgName, SmallStream)
AmazonUploadFile("TinyImages/" & imgName, TinyStream)
AmazonUploadFile("MidImages/" & imgName, MidStream)
End Sub
Public Shared Sub AmazonUploadFile(S3Key As String, FileStream As Stream)
Dim request As New PutObjectRequest()
request.WithBucketName(BUCKET_NAME)
request.WithKey(S3Key).InputStream = FileStream
request.WithCannedACL(S3CannedACL.PublicRead)
GetS3Client.PutObject(request)
End Sub

[Disclaimer - I'm the author of the ImageResizing.NET library the OP is asking the question about.]
Folks - do NOT use Bitmap and Image instances if you can possibly avoid it. There is a giant list of pitfalls that will crash your server. Do NOT use ANYTHING from System.Drawing without a server-safe wrapper around it.
#dash - Your code is almost right, aside from the memory leaks.
Decoding and encoding images safely isn't straightforward. Let the ImageResizing.Net library handle it.
Dim settings as New ResizeSettings("width=64&height=75&scale=both")
Using ms As New MemoryStream()
ImageBuilder.Current.Build("C:\ImageLocation\" & strImg, ms, settings)
ms.Seek(0, SeekOrigin.Begin)
UploadImage(ms, SKU)
End Using
Never load something into a Bitmap or Image instance if you're making multiple versions. Clone the file into a MemoryStream instead.
Using fs as New FileStream(...)
Using ms as MemoryStream = Util.StreamUtils.CopyStream(fs)
'For loop here with your setting variations
ms.Seek(0, SeekOrigin.Begin)
'Place upload and resize code here
'End Loop
End Using
End Using

The following code snippet should do what you want:
Using myImage = Image.FromFile(fullImg)
Using ms As New MemoryStream()
myImage.Save(ms, ImageFormat.Jpeg)
ms.Seek(0, SeekOrigin.Begin)
UploadImage(ms, SKU)
End Using
End Using
As an aside, you might find it easier to parameterize your methods and do all the work when calling them. Something like the following may make your life easier (this assumes the code you posted is code you are actually using and not a demo):
Public Shared Sub UploadImages()
'Call this for each image
MoveToAmazon("C:\ImageLocation\blah.jpg", "OriginalImage", 300, 300, 0, "whatever")
End Sub
Public Shared Sub MoveToAmazon(strImg As String, targetFolder As String, height as Integer, width as Integer, padding as Integer, SKU As String)
Dim fullImg As String = "" & strImg
Using img = Image.FromFile(fullImg)
'Here Im missing the code to convert it to a stream.
Using ms As New MemoryStream()
Image.Save(ms, ImageFormat.Jpeg)
ms.Seek(0, SeekOrigin.Begin)
UploadImage(ms, SKU)
End Using
End Using
End Sub
Public Shared Sub UploadImage(imgStream As Stream, imgName As String, targetFolder As String, height as Integer, width as Integer, padding as Integer, SKU As String)
Dim c As New ImageResizer.Configuration.Config
ImageResizer.ImageBuilder.Current.Build(SourceMain, imgStream, New ResizeSettings("width=" & CStr(width) & "&height=" & CStr(height) & "&scale=both&paddingWidth=" & CStr(padding))
AmazonUploadFile(targetFolder & "/" & imgName, imgStream)
End Sub
Public Shared Sub AmazonUploadFile(S3Key As String, FileStream As Stream)
Dim request As New PutObjectRequest()
request.WithBucketName(BUCKET_NAME)
request.WithKey(S3Key).InputStream = FileStream
request.WithCannedACL(S3CannedACL.PublicRead)
GetS3Client.PutObject(request)
End Sub
Using ms As New MemoryStream()
Image.Save(ms, ImageFormat.Jpeg)
ms.Seek(0, SeekOrigin.Begin)
UploadImage(ms, SKU)
End Using

Read the image bytes and then you wrap it in a MemoryStream
MemoryStream ms = new MemoryStream(imageBytes);

Related

Tweetsharp Twitter API - post multiple images

The code below works and will post to Twitter, but will only ever post one image to the account, even if three images are sent.
These are only jpg or png files, not video or animated gifs.
Any ideas would be appreciated.
Dim service = New TwitterService(key, secret)
service.AuthenticateWith(token, tokenSecret)
Dim opt As New SendTweetWithMediaOptions
Dim images As New Dictionary(Of String, IO.Stream)
Dim myStream As FileStream
If Len(ImgName1) > 0 Then
myStream = New FileStream(ImgName1, FileMode.Open)
images.Add("1", myStream)
End If
If Len(ImgName2) > 0 Then
myStream = New FileStream(ImgName2, FileMode.Open)
images.Add("2", myStream)
End If
If Len(ImgName3) > 0 Then
myStream = New FileStream(ImgName3, FileMode.Open)
images.Add("3", myStream)
End If
opt.Status = TweetText
opt.Images = images
Dim TwitterStatus = service.SendTweetWithMedia(opt)
The code I used to get it working using TweetInvi https://github.com/linvi/tweetinvi (installed via Nuget) is:
(Imports Tweetinvi)
Auth.SetUserCredentials(key, secret, token, tokenSecret)
Dim params As New Tweetinvi.Parameters.PublishTweetOptionalParameters()
params.Medias = New List(Of Models.IMedia)
Dim MediaIDs As String = String.Empty
Dim ids As New List(Of Long)
If Len(ImgName1) > 0 Then
Dim imgFile1 As Byte() = System.IO.File.ReadAllBytes(ImgName1)
Dim myMedia1 = Upload.UploadImage(imgFile1)
ids.Add(myMedia1.MediaId)
imgFile1 = Nothing
End If
If Len(ImgName2) > 0 Then
Dim imgFile2 As Byte() = System.IO.File.ReadAllBytes(ImgName2)
Dim myMedia2 = Upload.UploadImage(imgFile2)
ids.Add(myMedia2.MediaId)
imgFile2 = Nothing
End If
If Len(ImgName3) > 0 Then
Dim imgFile3 As Byte() = System.IO.File.ReadAllBytes(ImgName3)
Dim myMedia3 = Upload.UploadImage(imgFile3)
ids.Add(myMedia3.MediaId)
imgFile3 = Nothing
End If
params.MediaIds = ids
Dim myTweet = Tweet.PublishTweet("blah, blah, blah", params)
The API end point called by that TweetSharp method doesn't support multiple images (I don't think it ever did, but either way the current docs say no; https://dev.twitter.com/rest/reference/post/statuses/update_with_media).
What you need to do is use the UploadMedia endpoint to upload the image and capture the id for each, then send a tweet with the list of ids.
I'm not sure which variant of TweetSharp you're using. The official/original one has known bugs in the Nuget package, and while the source in the repo has those fixed it is lacking the newer API support.
You could try TweetMoaSharp (mostly maintained by me), as I believe this supports the new end points (but it's been a while since I looked). There's also tweetsharp-alternative on Nuget and a few others floating around that might have support.

Retrieve rtf text with images stored in SQL Server database

I want to retrieve rtf text with images stored in SQL Server database with Windows form in asp.net web form with exactly format and images.
This is the code to store in Windows form:
Dim cmd As New SqlCommand("UPDATE questions SET ques_rich = #ques_rich WHERE quest_no = 1 ", con)
con.Open()
cmd.Parameters.AddWithValue("#ques_rich", RichTextBox1.Rtf)
cmd.ExecuteNonQuery()
con.Close()
This is the code used to retrieve in asp.net:
Protected Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim con As New SqlConnection("Data Source=AHMEDHASHEM\SQLEXPRESS;Initial Catalog=test;Integrated Security=True")
Dim cmd1 As New SqlClient.SqlCommand
Dim tbl As New DataTable
Dim reader As SqlClient.SqlDataReader
Dim sql As String
sql = "select * from questions where quest_no = 1"
cmd1 = New SqlClient.SqlCommand(sql, con)
Dim ds1 As New DataSet()
Dim Adpt1 As New SqlDataAdapter(sql, con)
Adpt1.Fill(ds1, "questions")
'rc = ds1.Tables(0).Rows.Count
con.Open()
tbxTinymce.Text = ds1.Tables("questions").Rows(0)("ques_rich")
con.Close()
End Sub
Note: I use tinymce and freetextbox controls
Also use Word document with this code:
Dim wordApp As New Microsoft.Office.Interop.Word.ApplicationClass()
Dim nullobj As Object = System.Reflection.Missing.Value
Dim doc As Word.Document = wordApp.Documents.Open("c:\goinstall.doc")
Dim doc1 As Word.Document = wordApp.ActiveDocument
Dim m_Content As String = doc1.Content.Text
FreeTextBox1.Text = m_Content
doc.Close(nullobj, nullobj, nullobj)
That code retrieves text only without images and formatting
The following code accepts an image from a file upload stream, converts it to a byte array and stores it in the session object for later retrieval and storage into a blob in a Oracle database.
' Easy enough to load a file from a stream, here I get a image from a file upload
Dim TheStream As Stream = file1.PostedFile.InputStream
' Need a variable to store the image in
Dim origimage As System.Drawing.Image
' Same the uploaded image to the variable
origimage = System.Drawing.Image.FromStream(TheStream)
' Now we need to convert it to a bye array
Dim ms2 As New System.IO.MemoryStream
' First I scale it, I don't need a huge image, you won't need to do this
origimage = ScaleImage(origimage, 320, 200) ' new scaling method
' I save it to the memory stream in preparation to converting to a byte array
origimage.Save(ms2, Imaging.ImageFormat.Jpeg)
' Here I convert the file
Dim MyPhoto() As Byte = ms2.GetBuffer ' The scaled image is now stored in memory as a byte array
Session("ThePhoto") = MyPhoto ' put it into the session to retreive later
' Release the memory
ms2.Dispose()
origimage.Dispose()
Obviously some of this won't be relevant to your problem. You need to load your RTF file using a filestream of some sort and then convert the file to a byte array. Hopefully this will help to point you in the right direction.

How can I add an image as a pdf header?

I am using the code below to generate a pdf. Is there a way I can point to an image and use that as the header? "~/images/Header.png"? Any help would be appreciated. Thank you.
Dim myUniqueFileName = String.Format("{0}.pdf", random)
Dim pdfWrite As PdfWriter = PdfWriter.GetInstance(Doc1, New FileStream(path & myUniqueFileName, FileMode.Create))
Dim ev As New itsEvents
pdfWrite.PageEvent = ev
Doc1.Open()
Dim test As String
test = Session("PDF")
Doc1.Add(New Paragraph(test))
Doc1.Close()
End Sub
Public Class itsEvents
Inherits PdfPageEventHelper
Public Overrides Sub OnStartPage(ByVal writer As iTextSharp.text.pdf.PdfWriter, ByVal document As iTextSharp.text.Document)
Dim ch As New Chunk("This is my Header on page " & writer.PageNumber)
document.Add(ch)
End Sub
End Class
Try this:
Dim imagepath As String = Server.MapPath(".") & "/logo/Anjanlogo.jpg"
Dim image As iTextSharp.text.Image = iTextSharp.text.Image.GetInstance(imagepath)
image.ScalePercent(24F)
doc.Add(image)
Note: The 24F scaling comes from the fact that, by default, embedded images are 72 DPI and most commercial printers use 300 DPI, so 72/300 * 100 = 24%.
To move the image around the page you can use the SetAbsolutePosition method, like this:
image.SetAbsolutePosition(36F, 36F)
Note: 36F is the margin of the PDF, so this will push the logo to the top left of the corner of the PDF, but still maintain the border.

Using PostedFile.InputStream twice

I'm trying to resize one image to 5 different sizes (and then upload them to amazonS3).
I'm using imageresizer.net
the problem seems to be that i cannot use the inputstream twice. it works the first time.
Dim SmallStream As Stream = New MemoryStream
Dim TinyStream As Stream = New MemoryStream
If FileUpload1.HasFile Then
**ImageResizer.ImageBuilder.Current.Build(FileUpload1.PostedFile.InputStream, SmallStream, New ResizeSettings("maxwidth=100&maxheight=100"))
ImageResizer.ImageBuilder.Current.Build(FileUpload1.PostedFile.InputStream, TinyStream, New ResizeSettings("maxwidth=100&maxheight=100"))**
AmazonUploadFile("SmallImages/" & FileUpload1.FileName, SmallStream)
AmazonUploadFile("TinyImages/" & FileUpload1.FileName, TinyStream)
End If
Public Shared Function GetS3Client() As AmazonS3
Dim appConfig As NameValueCollection = ConfigurationManager.AppSettings
Dim s3Client As AmazonS3 = AWSClientFactory.CreateAmazonS3Client(AWS_ACCESS_KEY, AWS_SECRET_KEY)
Return s3Client
End Function
Public Sub AmazonUploadFile(S3Key As String, FileStream As Stream)
Dim request As New PutObjectRequest()
request.WithBucketName(BUCKET_NAME)
request.WithKey(S3Key).InputStream = FileStream
request.WithCannedACL(S3CannedACL.PublicRead)
GetS3Client.PutObject(request)
End Sub
The code breaks when i try to retrieve the FileUpload1.PostedFile.InputStream the second time.
I believe ImageResizer will accept Image objects to that method. So, you could read the InputStream into an Image object first (Image.FromStream()), then you can use that image object repeatedly.
[Disclaimer: I'm the author of http://imageresizing.net/]
Pass FileUpload1.PostedFile instead of FileUpload1.PostedFile.InputStream to the ImageResizer and it will automatically handle re-seeking the stream to the beginning after each read. (Make sure you're using 3.1.5 or later).
Alternatively, use the ImageJob class and set ResetSourceStream=true.

Why am I getting this generic, non-descript error in GDI+ when trying to save a PNG?

I have a function that dynamically adds text to an image in a predesignated spot. Originally I did it with jpegs, and it was working. I switched to PNG so the images would be better quality, as the original jpegs were kind of pixely. Anyway, here is my code. It executes down to the oBitmap.Save(), then dies with "A General Error Has Occurred in GDI+".
Public Sub ProcessRequest(ByVal context As HttpContext) Implements IHttpHandler.ProcessRequest
context.Response.ContentType = "image/png"
context.Response.Clear()
context.Response.BufferOutput = True
Try
Dim oText As String = context.Server.HtmlDecode(context.Request.QueryString("t"))
If String.IsNullOrEmpty(oText) Then oText = "Placeholder"
Dim oPType As String = context.Server.HtmlDecode(context.Request.QueryString("p"))
If String.IsNullOrEmpty(oPType) Then oPType = "none"
Dim imgPath As String = ""
Select Case oPType
Case "c"
imgPath = "img/banner_green.png"
Case "m"
imgPath = "img/banner_blue.png"
Case Else
Throw New Exception("no ptype")
End Select
Dim oBitmap As Bitmap = New Bitmap(context.Server.MapPath(imgPath))
Dim oGraphic As Graphics = Graphics.FromImage(oBitmap)
Dim frontColorBrush As New SolidBrush(Color.White)
Dim oFont As New Font(FONT_NAME, 30)
Dim oInfo() As ImageCodecInfo = ImageCodecInfo.GetImageEncoders
Dim oEncoderParams As New EncoderParameters(2)
Dim xOffset As Single = Math.Round((oBitmap.Height - oFont.Height) / 2, MidpointRounding.ToEven)
Dim oPoint As New PointF(275.0F, xOffset + 10)
oEncoderParams.Param(0) = New EncoderParameter(Encoder.Quality, 100L)
oEncoderParams.Param(1) = New EncoderParameter(Encoder.ColorDepth,8L)
oGraphic.TextRenderingHint = Drawing.Text.TextRenderingHint.AntiAlias
oGraphic.DrawString(oText, oFont, frontColorBrush, oPoint)
oBitmap.Save(context.Response.OutputStream, oInfo(4), oEncoderParams)
context.Response.Output.Write(oBitmap)
oFont.Dispose()
oGraphic.Dispose()
oBitmap.Dispose()
context.Response.Flush()
Catch ex As Exception
End Try
End Sub
The only changes I made to this from the jpeg version are:
context.Response.ContentType = "image/jpeg" changed to "image/png"
changed base images (img/banner_green.jpg, img/banner_blue.jpg) to .png
added the second encoding parameter specifying color depth
changed oInfo(1) (jpeg) to oInfo(4) (png)
Are there more things I need to tweak to get this routine to properly generate the PNG?
According to this post, Bitmap.Save requires a seekable stream to save as PNG, which HttpResponse.OutputStream isn't. You'll have to save the image into a MemoryStream first, and then copy the contents of it to Response.OutputStream, like:
Dim tempStream as New MemoryStream
oBitmap.Save(tempStream, ImageFormat.Png, oEncoderParams)
Response.OutputStream.Write(tempStream.ToArray(), 0, tempStream.Length)
Also note that the line
context.Response.Output.Write(oBitmap)
does something different then what you are probably expecting. HttpResponse.Output is a TextWriter, and the overload you use here, TextWriter.Write(object) will just call ToString on the object and write the results into the stream, what in this case results in writing "System.Drawing.Bitmap" to the output.
You're disposing of the bitmap before you're flushing the Response? Try flipping that around. Also, it looks like you're writing the bitmap to the stream twice. I'm not sure why you're doing that. Save the bitmap to the output stream or use the Write method of the Response object, but not both.

Resources