Using httpwebrequest to get image from website to byte[] - silverlight

I want to read the raw binary of a PNG file on a website and store it into a byte[], so far I have something like this:
Uri imageUri = new Uri("http://www.example.com/image.png");
// Create a HttpWebrequest object to the desired URL.
HttpWebRequest imgRequest = (HttpWebRequest)WebRequest.Create(imageUri);
using (HttpWebResponse imgResponse = (HttpWebResponse)imgRequest.GetResponse())
{
using (BinaryReader lxBR = new BinaryReader(imgResponse.GetResponseStream()))
{
using (MemoryStream lxMS = new MemoryStream())
{
lnBuffer = lxBR.ReadBytes(1024);
while (lnBuffer.Length > 0)
{
lxMS.Write(lnBuffer, 0, lnBuffer.Length);
lnBuffer = lxBR.ReadBytes(1024);
}
lnFile = new byte[(int)lxMS.Length];
lxMS.Position = 0;
lxMS.Read(lnFile, 0, lnFile.Length);
}
}
}
but I can't use GetResponse on Silverlight because it is not Asynchronous (I think that's the reason) so instead I should be using BeginGetResponse, but I'm not completely clear on how to go about it. This is what I have so far:
HttpWebResponse imgResponse = (HttpWebResponse)imgRequest.BeginGetResponse(new AsyncCallback(WebComplete), imgRequest);
using (imgResponse)
{
using (BinaryReader lxBR = new BinaryReader(imgResponse.GetResponseStream()))
{
/*Same*/
}
}
and
void WebComplete(IAsyncResult a)
{
HttpWebRequest req = (HttpWebRequest)a.AsyncState;
HttpWebResponse res = (HttpWebResponse)req.EndGetResponse(a);
//...? Do I need something else here?
}
can someone explain me a little bit how to use the BeginGetResponse property and how do I use the AsyncCallback.
Thanks!
Note:
I'm new to silverlight and I've been following tutorials and borrowing from other responses here on StackOverflow:
(stackoverflow responce) what I need to do but not in silverlight
tutorial
WebRequest_in_Silverlight
is this valid Silverlight code?
HttpWebResponse imgResponse = (HttpWebResponse)imgRequest.BeginGetResponse(new AsyncCallback(WebComplete), imgRequest);

Got it working, want to post it here in case anyone needs it.
I need to get this image and then modify it (byte level) Silverlight didn't let me save the image directly to a WriteableBitmap and thus I had to get the image with a WebClient as a stream and then save it to a byte[]
this is how I get the image (I already have the specific Uri):
WebClient wc = new WebClient();
wc.OpenReadCompleted += new OpenReadCompletedEventHandler(wc_OpenReadCompleted);
wc.OpenReadAsync(uri)
so when the image is loaded the wc_OpenReadCompleted method is called and it does something like this:
int lengthInBytes = Convert.ToInt32(e.Result.Length);
BinaryReader br = new BinaryReader(e.Result);
byte[] buffer = new byte[lengthInBytes];
using (br)
{
for (int i = 0; i < lengthInBytes; i++)
{
buffer[i] = br.ReadByte();
}
}
at the end the buffer[] has all the bytes of the image (what I wanted)
I'm sure there are better ways of doing this but this is working for me ! )
note: at some point I need to convert the byte[] to a BitmapImage (that was easier than expected):
//imageInBytes is a byte[]
if (imageInBytes != null)
{
MemoryStream rawBytesStream = new MemoryStream(imageInBytes);
BitmapImage img = new BitmapImage();
img.SetSource(rawBytesStream);
return img;
}
I hope this helps anyone.

Use the OpenReadAsync method of the WebClient object. Attach to the OpenReadCompleted event of the WebClient. Use the Stream provided by the Result property of the event args.
Consider setting AllowReadStreamBuffering, this will fill the entire stream before raising the OpenReadCompleted. In either case its likely you can use this stream to complete you real task rather than coping it into a MemoryStream.

Related

How to open PDF from memory using iTextsharp in Windows Application [duplicate]

I am doing html to pdf file . Its Downloading instantly . I dont want download instantly. i want to save the file in my project folder once converted.
My C# Code
string html ="<table><tr><td>some contents</td></tr></table>";
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=WelcomeLetter.pdf");
Response.Cache.SetCacheability(HttpCacheability.NoCache);
StringWriter sw = new StringWriter();
HtmlTextWriter hw = new HtmlTextWriter(sw);
StringReader sr = new StringReader(table);
Document ResultPDF = new Document(iTextSharp.text.PageSize.A4, 25, 10, 20, 30);
PdfPTable Headtable = new PdfPTable(7);
Headtable.TotalWidth = 525f;
Headtable.LockedWidth = true;
Headtable.HeaderRows = 5;
Headtable.FooterRows = 2;
Headtable.KeepTogether = true;
HTMLWorker htmlparser = new HTMLWorker(ResultPDF);
PdfWriter.GetInstance(ResultPDF, Response.OutputStream);
ResultPDF.Open();
htmlparser.Parse(sr);
ResultPDF.Close();
Response.Write(ResultPDF);
Response.End();
For saving pdf file locally in your project folder you can use FileStream class like this.
FileStream stream = new FileStream(filePath, FileMode.Create);//Here filePath is path of your project folder.
Now use this stream instead of using Response.OutputStream when you create instance of PdfWriter object.
PdfWriter.GetInstance(ResultPDF, stream);
Now do not use Responce.Write as you don't want to download your file.And close your stream at end.
stream.Close();
I'm going to combine everyone's answer into one that you should be able to drop in and use. If this works, I would accept Manish Parakhiya's answer because that had the most important part.
First, I'm going to assume you are using a recent version of iTextSharp. I think 5.5.5 is the most recent version. Second, because of this, I'm going to restructure your code a bit in order to use the using pattern. If you're stuck on an older obsolete unsupported version like 4.1.6 you'll need to re-adjust.
Almost every tutorial out there shows you that you can bind directly the Response.OutputStream. This is 100% valid but I would argue that it is also a really bad idea. Instead, bind to a more generic MemoryStream. This makes debugging much easier and your code will port and adapt that much easier.
The below code includes comments about each of the changes and what things are actually doing. The top section is all about creating a PDF from a string of HTML. The bottom actually does something with it, including writing it to disk and/or streaming it to a browser.
//Will hold our PDF eventually
Byte[] bytes;
//HTML that we want to parse
string html = "<table><tr><td>some contents</td></tr></table>";
//Create a MemoryStream to write our PDF to
using (var ms = new MemoryStream()) {
//Create our document abstraction
using (var ResultPDF = new Document(iTextSharp.text.PageSize.A4, 25, 10, 20, 30)) {
//Bind a writer to our Document abstraction and our stream
using (var writer = PdfWriter.GetInstance(ResultPDF, ms)) {
//Open the PDF for writing
ResultPDF.Open();
//Parse our HTML using the old, obsolete, not support parser
using (var sw = new StringWriter()) {
using (var hw = new HtmlTextWriter(sw)) {
using (var sr = new StringReader(html)) {
using (var htmlparser = new HTMLWorker(ResultPDF)) {
htmlparser.Parse(sr);
}
}
}
}
//Close the PDF
ResultPDF.Close();
}
}
//Grab the raw bytes of the PDF
bytes = ms.ToArray();
}
//At this point, the bytes variable holds a valid PDF file.
//You can write it disk:
System.IO.File.WriteAllBytes("your file path here", bytes);
//You can also send it to a browser:
Response.ContentType = "application/pdf";
Response.AddHeader("content-disposition", "attachment;filename=WelcomeLetter.pdf");
Response.BinaryWrite(bytes);
Response.Cache.SetCacheability(HttpCacheability.NoCache);
//Never do the next line, it doesn't do what you think it does and actually produces corrupt PDFs
//Response.Write(ResultPDF); //BAD!!!!!!
Response.End();
string tempDirectory = Session.SessionID.ToString();
string location = Path.Combine(Server.MapPath(
WebConfigurationManager.AppSettings["PathSet"].ToString()), tempDirectory);
if (!Directory.Exists(location))
{
Directory.CreateDirectory(location);
}
string fileName="abc.pdf";
filePath = Path.Combine(location, fileName);

RestSharp - Download / Use image in WPF/Silverlight

I'm trying to use RestSharp to download an image from a WCF/Rest service. The result should be saved in a file and displayed in a Image control an a WPF/SL page.
private void GetImage()
{
RestClient _Client = new RestClient(BASE_URI);
RestRequest request = new RestRequest("/api/img/{FileName}");
request.AddParameter("FileName", "dummy.jpg", ParameterType.UrlSegment);
_Client.ExecuteAsync<MemoryStream>(
request,
Response =>
{
if (Response != null)
{
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = Response.Data;
String fn = String.Format(#"c:\temp\{0}.jpg", Guid.NewGuid().ToString());
System.IO.File.WriteAllBytes(fn,Response.Data.ToArray());
bitmapImage.EndInit();
img.Source = bitmapImage;
}
});
}
When I look in fiddler the image got downloaded correctly BUT no image is saved and nothing is displayd. There is no exception thown. ANy suggestions ?
UPDATED
A part of the problem turns out that RestSharp is not returning the expected memorystream. Moving to another methed and accessing the raw data in byte[] format solves part of the problem, saving the picutere to disk.
private void GetImage()
{
RestClient _Client = new RestClient(BASE_URI);
RestRequest request = new RestRequest("/api/img/{FileName}");
request.AddParameter("FileName", "dummy.jpg", ParameterType.UrlSegment);
_Client.ExecuteAsync(
request,
Response =>
{
if (Response != null)
{
byte[] imageBytes = Response.RawBytes;
var bitmapImage = new BitmapImage();
bitmapImage.BeginInit();
bitmapImage.StreamSource = new MemoryStream(imageBytes);
bitmapImage.CreateOptions = BitmapCreateOptions.None;
bitmapImage.CacheOption = BitmapCacheOption.Default;
bitmapImage.EndInit();
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
Guid photoID = System.Guid.NewGuid();
String photolocation = String.Format(#"c:\temp\{0}.jpg", Guid.NewGuid().ToString());
encoder.Frames.Add(BitmapFrame.Create(bitmapImage));
using (var filestream = new FileStream(photolocation, FileMode.Create))
encoder.Save(filestream);
this.Dispatcher.Invoke((Action)(() => { img.Source = bitmapImage; }));
;
}
});
}
Although calling this.dispatcher.Invoke I still get the error : The calling thread cannot acces this object because a different thread owns it.
As the BitmapImage is created in another thread than the UI thread, you also have to call Freeze to make it accessible in the UI thread.
Although not strictly necessary here, it is good practise to always dispose of any IDisposable objects, including MemoryStream. Therefore you will also have to set the BitmapImage.CacheOption property to OnLoad.
using (var memoryStream = new MemoryStream(imageBytes))
{
bitmapImage.BeginInit();
bitmapImage.CacheOption = BitmapCacheOption.OnLoad;
bitmapImage.StreamSource = memoryStream;
bitmapImage.EndInit();
bitmapImage.Freeze();
}
The frozen BitmapImage is accessible in the UI thread:
Dispatcher.Invoke((Action)(() => img.Source = bitmapImage));
Are you checking for exceptions using the debugger? If an exception is thrown on a background task, it won't be rethrown on the caller code unless you access Task.Result or use the await operator.
My guess is that you don't have access to the location of C: you are writing to. That block of code seems unnecessary anyway though, you should be able to directly set the source of the image to the stream you have without writing it to disk. Try commenting the writing to drive piece of code out and see if that solves the issue.

Convert HttpPostedFileBase to byte[]

In my MVC application, I am using following code to upload a file.
MODEL
public HttpPostedFileBase File { get; set; }
VIEW
#Html.TextBoxFor(m => m.File, new { type = "file" })
Everything working fine .. But I am trying to convert the result fiel to byte[] .How can i do this
CONTROLLER
public ActionResult ManagePhotos(ManagePhotos model)
{
if (ModelState.IsValid)
{
byte[] image = model.File; //Its not working .How can convert this to byte array
}
}
As Darin says, you can read from the input stream - but I'd avoid relying on all the data being available in a single go. If you're using .NET 4 this is simple:
MemoryStream target = new MemoryStream();
model.File.InputStream.CopyTo(target);
byte[] data = target.ToArray();
It's easy enough to write the equivalent of CopyTo in .NET 3.5 if you want. The important part is that you read from HttpPostedFileBase.InputStream.
For efficient purposes you could check whether the stream returned is already a MemoryStream:
byte[] data;
using (Stream inputStream = model.File.InputStream)
{
MemoryStream memoryStream = inputStream as MemoryStream;
if (memoryStream == null)
{
memoryStream = new MemoryStream();
inputStream.CopyTo(memoryStream);
}
data = memoryStream.ToArray();
}
You can read it from the input stream:
public ActionResult ManagePhotos(ManagePhotos model)
{
if (ModelState.IsValid)
{
byte[] image = new byte[model.File.ContentLength];
model.File.InputStream.Read(image, 0, image.Length);
// TODO: Do something with the byte array here
}
...
}
And if you intend to directly save the file to the disk you could use the model.File.SaveAs method. You might find the following blog post useful.
byte[] file = new byte[excelFile.ContentLength];
excelFile.InputStream.Read(file, 0, file.Length);
//Create memory stream object from your bytes
MemoryStream ms = new MemoryStream(file);
// Set WorkbookPart , Sheet
using (var myDoc = DocumentFormat.OpenXml.Packaging.SpreadsheetDocument.Open(ms, true))

Silverlight - Exception when trying to POST to webservice

I'm using the "Post" method so I can send a custom object. But I keep getting the following exception on the request.BeginGetResponse():
{System.Net.ProtocolViolationException: Operation is not valid due to the current state of the object.
at System.Net.Browser.BrowserHttpWebRequest.BeginGetResponseImplementation()}
public void Send()
{
HttpWebRequest client = WebRequest.Create(new Uri(BaseUrl)) as HttpWebRequest;
client.Method = "POST";
client.ContentLength = MaxSerializationSize;
client.BeginGetRequestStream(new AsyncCallback(RequestProceed), client);
}
private void RequestProceed(IAsyncResult asuncResult)
{
HttpWebRequest request = (HttpWebRequest) asuncResult.AsyncState;
StreamWriter postDataWriter = new StreamWriter(request.EndGetRequestStream(asuncResult));
MemoryStream ms = new MemoryStream();
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(MyCustomClass));
ser.WriteObject(ms, MyCustomClassObject);
postDataWriter.Write(ms);
postDataWriter.Close();
request.BeginGetResponse(new AsyncCallback(ResponceProceed), request);
}
private void ResponceProceed(IAsyncResult asuncResult)
{
var request = (HttpWebRequest) asuncResult.AsyncState;
using (var resp = (HttpWebResponse) request.EndGetResponse(asuncResult))
{
using (var stream = resp.GetResponseStream())
{
}
}
}
I have tried so many ways to get this to work. Hoping someone can tell me where i'm going wrong. Thanks.
You need to close the request stream. You are just closing the StreamWriter and not the underlying request stream. While you are at it eliminate the superflous MemoryStream and have the DataContractJsonSerializer write directly to the Request stream.
HttpWebRequest request = (HttpWebRequest) asuncResult.AsyncState;
using (Stream outStream = request.EndGetRequestStream(asyncResult));
{
DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(MyCustomClass));
ser.WriteObject(outStream, MyCustomClassObject);
outStream.Flush();
outStream.Close();
}
request.BeginGetResponse(new AsyncCallback(ResponceProceed), request);
Also get rid of this line:-
client.ContentLength = MaxSerializationSize;
Without also turning off AllowWriteStreamBuffering (which is only possible on the ClientHTTP implementation anyway) there is no need to set the ContentLength, that is done for you.

WPF BitmapImage Serialization/Deserialization

I've been trying to Serialize and Deserialize BitmapImages. I've been using methods which supposedly works which I found in this thread: error in my byte[] to WPF BitmapImage conversion?
Just to iterate what is going on, here is part of my Serialization code:
using (MemoryStream ms = new MemoryStream())
{
// This is a BitmapImage fetched from a dictionary.
BitmapImage image = kvp.Value;
PngBitmapEncoder encoder = new PngBitmapEncoder();
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(ms);
byte[] buffer = ms.GetBuffer();
// Here I'm adding the byte[] array to SerializationInfo
info.AddValue((int)kvp.Key + "", buffer);
}
And here is the deserialization code:
// While iterating over SerializationInfo in the deserialization
// constructor I pull the byte[] array out of an
// SerializationEntry
using (MemoryStream ms = new MemoryStream(entry.Value as byte[]))
{
ms.Position = 0;
BitmapImage image = new BitmapImage();
image.BeginInit();
image.StreamSource = ms;
image.EndInit();
// Adding the timeframe-key and image back into the dictionary
CapturedTrades.Add(timeframe, image);
}
Also, I'm not sure if it matters but earlier when I populated my dictionary I encoded Bitmaps with PngBitmapEncoder to get them into BitmapImages. So not sure if double-encoding has something to do with it. Here's the method that does that:
// Just to clarify this is done before the BitmapImages are added to the
// dictionary that they are stored in above.
private BitmapImage BitmapConverter(Bitmap image)
{
using (MemoryStream ms = new MemoryStream())
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
BitmapImage bImg = new BitmapImage();
bImg.BeginInit();
bImg.StreamSource = new MemoryStream(ms.ToArray());
bImg.EndInit();
ms.Close();
return bImg;
}
}
So the problem is, serialization and deserialization works fine. No errors, and the dictionary has entries with what seems to be BitmapImages, however their width/height and
some other properties are all set to '0' when I look at them in debugging-mode. And of course, nothing is shown when I try to display the images.
So any ideas as to why they aren't properly deserialized?
Thanks!
1) You should not dispose MemoryStream, used from image initializing. Remove using in this line
using (MemoryStream ms = new MemoryStream(entry.Value as byte[]))
2) After
encoder.Save(ms);
Try adding
ms.Seek(SeekOrigin.Begin, 0);
ms.ToArray();

Resources