How to stream a motion jpeg using owin/katana? - c#

I am self hosting OWIN/KATANA in a windows service. Right now I have implemented a way to grab a single image from a camera. I would like to grab multiple frames from the camera and stream them back to a img tag on an html page. Is this possible with OWIN/KATANA?

app.Map("/Camera/Video", a =>
{
a.Run(context =>
{
string connectionid = CurrentDevice.Value.ToString();
object ret = DeviceManager.Instance.SendMessageToDevice(connectionid, "startmovie");
context.Response.Headers.Add("Content-Type", new string[] { "multipart/x-mixed-replace; boundary=--jpgboundary" });
bool con = true;
StreamWriter writer = new StreamWriter(context.Response.Body);
while (con)
{
using (MemoryStream ms = new MemoryStream())
{
Image img = (Image)DeviceManager.Instance.SendMessageToDevice(connectionid, "capturestill");
img.Save(ms, ImageFormat.Jpeg);
byte[] buffer = ms.GetBuffer();
writer.WriteLine("--jpgboundary");
writer.WriteLine("Content-Type: image/jpeg");
writer.WriteLine(string.Format("Content-length: {0}", buffer.Length));
writer.WriteLine();
context.Response.Write(buffer);
//writer.WriteLine(Convert.ToBase64String(buffer));
writer.Flush();
}
Thread.Sleep(200);
}
DeviceManager.Instance.SendMessageToDevice(connectionid, "stopmovie");
return context.Response.WriteAsync("");
});
});
I figured out what my issue was. I was using WriteAsync and I needed to use just the Write. The above works great. I just need to figure out how to stop it now.

Related

How to save an Image to Clients System using .Net Core

I have an Image I am retrieving from the database as a byte array. I want to save it outside the Project i.e on the Clients System. I would appreciate if the code aspect can be assisted with. Here is a sample method I have so far:
public Image byteArrayToImage2()
{
var filePath = "C:\\cat.jpg";
byte[] fileBytes = System.IO.File.ReadAllBytes(filePath);
Image returnImage = null;
using (MemoryStream ms = new MemoryStream(fileBytes))
{
returnImage = Image.FromStream(ms);
returnImage.Save("cat2.jpg", ImageFormat.Jpeg);
}
return returnImage;
}
Try the below approach
PS: make sure your fileBytes is of type byte Array.
MemoryStream imageStream = new MemoryStream();
imageStream.Write(fileBytes, 0, fileBytes.Length);
// Include the file name along with extension (Eg: 'C:\TestImage.JPEG')
FileStream fs = File.Create("Give the path where you want to save the image");
imageStream.WriteTo(fs);
fs.Close();
imageStream.Close();

Server for displaying pictures in web browser

What I am trying to do is send a picture from the server to the client (web browser). So when I open the link in the browser, for example https://localhost:8080/geoserver/ (I set the port to 8080 at the beginning) it will display the message "hello world" which is fine but now I am trying to send image with the StreamWriter and all I got was some text like System.Drawing.Bitmap and there was no picture displayed in the browser. Im working with c# console application.
My code:
static void Main(string[] args)
{
HttpListener listen = new HttpListener();
string url = "http://localhost";
string port = "";
Console.Write("Nastavite port:");
port = Console.ReadLine();
url = url + ":" + port + "/geoserver/";
listen.Prefixes.Add(url);
listen.Start();
while (true)
{
Console.WriteLine("Cakam...");
HttpListenerContext kontekst = listen.GetContext();
string msg = "hello world";
kontekst.Response.ContentLength64 = Encoding.UTF8.GetByteCount(msg);
kontekst.Response.StatusCode = (int)HttpStatusCode.OK;
using(Stream stream = kontekst.Response.OutputStream)
{
using(StreamWriter writer = new StreamWriter(stream))
{
writer.Write(msg);
}
}
Console.WriteLine("Sporočilo poslano");
}
}
You can do it, by converting the image to base64 and display it in a html img tag.
1) Use the System.Drawing library to get the picture as a byte array
Image image = Image.FromFile("test-img.jpg");
MemoryStream ms = new MemoryStream();
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
byte[] imgBytes = ms.ToArray();
2) After you need to convert it to a base64 string
string base64 = Convert.ToBase64String(imgBytes);
3) Then you create the html response text
string html = $"<html><img src=\"data: image / png; base64, {base64} \"></html>";
4) Now you can write this text to the output stream
Stream stream = kontekst.Response.OutputStream;
StreamWriter writer = new StreamWriter(stream);
writer.WriteLine(html);
So the full working code looks like this
static void Main(string[] args)
{
HttpListener listen = new HttpListener();
string url = "http://localhost";
string port = "";
Console.Write("Nastavite port:");
port = Console.ReadLine();
url = url + ":" + port + "/geoserver/";
listen.Prefixes.Add(url);
listen.Start();
while (true)
{
Console.WriteLine("Cakam...");
HttpListenerContext kontekst = listen.GetContext();
kontekst.Response.StatusCode = (int)HttpStatusCode.OK;
using (Stream stream = kontekst.Response.OutputStream)
using (Image image = Image.FromFile("test-img.jpg"))
using (MemoryStream ms = new MemoryStream())
using (StreamWriter writer = new StreamWriter(stream))
{
image.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
string base64 = Convert.ToBase64String(ms.ToArray());
writer.WriteLine($"<html><img src=\"data: image / png; base64, {base64} \"></html>");
}
Console.WriteLine("Sporočilo poslano");
}
}
The minimal changes required to make your code work is to use the Save method to write the image to the stream, instead of Writer.Write(), which will call the ToString() of the object, (if it's not already a character array) resulting in sending the class name that you experienced.
//Can't set the response length upfront, if you really need to set it you need to
//calculate it from the size of the image.
//kontekst.Response.ContentLength64 = Encoding.UTF8.GetByteCount(msg);
//Most browsers figure it out without this, but good practice to set the type:
kontekst.Response.ContentType = "image/bmp";
kontekst.Response.StatusCode = (int)HttpStatusCode.OK;
var img = Image.FromFile(#"some.bmp");
using (Stream stream = kontekst.Response.OutputStream)
{
img.Save(stream, ImageFormat.Bmp);
}
I would also consider changing some other things:
Instead of System.Drawing.Bitmap, use System.Drawing.Image as I did if you don't need to edit the image on the server. Or even better, if you don't need to treat it as an image on the server side, just read it in with a FileStream and write it out to the Output stream.
Do you really want to implement your on server and deal with the low level HttpContext / listeners? Maybe you could use ASP.Net Core with Kestrel.

C# MVC save View as png

i have problem with png HTML renderer,
i am trying to send png of View to email, but on email i get 0B .png
PS: Ticket.pdf is ok
using (MemoryStream ms = new MemoryStream())
{
var pdf = PdfGenerator.GeneratePdf(RenderRazorViewToString("TicketTemplateBig", model), PdfSharp.PageSize.A4);
pdf.Save(ms, false);
/////////////////
//Bitmap bitmap = new Bitmap(Convert.ToInt32(1024), Convert.ToInt32(1024), System.Drawing.Imaging.PixelFormat.Format32bppArgb);
using (MemoryStream ms2 = new MemoryStream())
{
//Image image = TheArtOfDev.HtmlRenderer.WinForms.HtmlRender.RenderToImage(RenderRazorViewToString("TicketTemplateBig", model));
Bitmap bitmap = (Bitmap)Image.FromFile(#"C:\logo.png");
bitmap.Save(ms2, ImageFormat.Png);
/////////////////
await ms.FlushAsync();
await ms2.FlushAsync();
mm.Attachments.Add(new Attachment(ms, string.Format("Ticket.pdf"), "application/pdf"));
streams.Add(ms);
mm.Attachments.Add(new Attachment(ms2, string.Format("logo.png"), "application/png"));
streams.Add(ms2);
await client.SendMailAsync(mm);
}
}
You are trying to send the mail before having effectively written to ms2.
you need to do flush the ms2 stream buffer before adding it to mm . (as you did for ms, that's why the pdf part was handled correctly)
(Also, minor typo : "application/png" instead of "application/Png", probably not an issue)
problem : stream was on last position
result : ms2.Position = 0;
using (MemoryStream ms = new MemoryStream())
{
var pdf = PdfGenerator.GeneratePdf(RenderRazorViewToString("TicketTemplateBig", model), PdfSharp.PageSize.A4);
pdf.Save(ms, false);
using (MemoryStream ms2 = new MemoryStream())
{
Image image = TheArtOfDev.HtmlRenderer.WinForms.HtmlRender.RenderToImage(RenderRazorViewToString("TicketTemplateBig", model));
image.Save(ms2, ImageFormat.Png);
ms2.Position = 0;
await ms.FlushAsync();
await ms2.FlushAsync();
mm.Attachments.Add(new Attachment(ms, string.Format("Ticket.pdf"), "application/pdf"));
mm.Attachments.Add(new Attachment(ms2, string.Format("Ticket.png"), "application/png"));
await client.SendMailAsync(mm);
}
}
Thanks Guys

Adding Text on Image

I am trying to add some text on top of a photo take by the camera, and here is the method I am using, but unfortunately I either get a closedStream error, or that there is cross-thread access when I try use the dispatcher. Could someone please explain me what is going wrong?
void cam_CaptureImageAvailable(object sender, Microsoft.Devices.ContentReadyEventArgs e)
{
DateTime dt = DateTime.Now;
string fileName = dt.Year.ToString() + dt.Month.ToString() + dt.Day.ToString() + dt.Hour.ToString() + dt.Minute.ToString() + dt.Second.ToString() + ".jpg";
try
{
// Save picture to the library camera roll.
library.SavePictureToCameraRoll(fileName, e.ImageStream);
// Set the position of the stream back to start
e.ImageStream.Seek(0, SeekOrigin.Begin);
Deployment.Current.Dispatcher.BeginInvoke(() =>
{
// load photo to writable bitmap
WriteableBitmap writeableBitmap = PictureDecoder.DecodeJpeg(e.ImageStream);
writeableBitmap.Invalidate();
var renderText = new TextBlock
{
Text = "Hello World",
FontSize = 72,
Foreground = new SolidColorBrush(Colors.White),
FontWeight = FontWeights.Black,
Width = 500,
Height = 100
};
writeableBitmap.Render(renderText, new TranslateTransform() { X = 100, Y = 300 });
writeableBitmap.Invalidate();
using (var ms = new MemoryStream())
{
writeableBitmap.SaveJpeg(ms, 1024, 768, 0, 100);
ms.Seek(0, SeekOrigin.Begin);
library.SavePicture("x" + fileName, ms);
}
// e.ImageStream.Close();
});
// Save picture as JPEG to isolated storage.
using (IsolatedStorageFile isStore = IsolatedStorageFile.GetUserStoreForApplication())
{
using (IsolatedStorageFileStream targetStream = isStore.OpenFile(fileName, FileMode.Create, FileAccess.Write))
{
// Initialize the buffer for 4KB disk pages.
byte[] readBuffer = new byte[4096];
int bytesRead = -1;
// Copy the image to isolated storage.
while ((bytesRead = e.ImageStream.Read(readBuffer, 0, readBuffer.Length)) > 0)
{
targetStream.Write(readBuffer, 0, bytesRead);
}
}
}
}
finally
{
// Close image stream
e.ImageStream.Close();
}
}
With the code above I get the following error: Cannot access a closed Stream.
If i remove the Dispatcher, I get this error: Invalid cross-thread access.
Thanks.
place ui less code outside dispatcher scope.
or save your e.ImageStream to other stream can be gotted in dispatcher scope.
First, what is occurring?
Dispatcher.BeginInvoke postpones your code and tells the UI thread to execute it whenever it's available. Therefore, your e.ImageStream.Close(); line is executed before the code inside of the BeginInvoke. So when you're trying to read the contents of the stream, it's already closed.
Two ways to solve that:
Remove the e.ImageStream.Close(); from the finally block. But I don't know if the stream will remain open anyway.
If 1. doesn't work, copy the contents of the stream to a MemoryStream, then use this stream to create the WriteableBitmap:
var stream = new MemoryStream();
e.ImageStream.CopyTo(stream);
In both case, don't forget to close the stream when you're done creating the WriteableBitmap.

How do you retrieve a snapshot of a website in ASP.NET?

Could anyone tell me how I could retrieve an image or a thumbnail of a website through my ASP.NET application? I have seen this functionality in a few sites such as Alexa etc.
Try SnapCasa's free and easy to use service. Just form your image tag like this:
<img src="http://SnapCasa.com/Get.aspx?code=[code]&size=[size]&url=[url]" />
Requires sign-up, but it's free for 500,000 requests a month. [code] is an api key that they provide after sign-up. [size] is one of three sizes available. [url] is the website address to the site for which you want to display a thumbnail.
If you want to work with the image from your code, here are a couple of helper methods:
static public byte[] GetBytesFromUrl(string url)
{
byte[] b;
HttpWebRequest myReq = (HttpWebRequest)WebRequest.Create(url);
WebResponse myResp = myReq.GetResponse();
Stream stream = myResp.GetResponseStream();
//int i;
using (BinaryReader br = new BinaryReader(stream))
{
//i = (int)(stream.Length);
b = br.ReadBytes(500000);
br.Close();
}
myResp.Close();
return b;
}
static public void WriteBytesToFile(string fileName, byte[] content)
{
FileStream fs = new FileStream(fileName, FileMode.Create);
BinaryWriter w = new BinaryWriter(fs);
try
{
w.Write(content);
}
finally
{
fs.Close();
w.Close();
}
}
Then, in your code, just use:
//get byte array for image
var imageBytes = GetBytesFromUrl("http://SnapCasa.com/Get.aspx?code=[code]&size=[size]&url=[url]");
//save file to disk
WriteBytesToFile("c:\someImageFile.jpg", imageBytes);
Should be doable using a web-browser object and saving the view port to a bitmap resized to thumbnail.
I have not tested this code but try tweaking it after substituting for the thumbnail params.
using (WebBrowser wb = new WebBrowser()) {
wb.ScrollBarsEnabled = false;
wb.AllowNavigation = true;
wb.ScriptErrorsSuppressed = true;
wb.ClientSize = new Size(thumbInfo_viewportWidth, thumbInfo_viewportHeight);
if ((thumbInfo_Uri != null)) {
wb.Navigate(thumbInfo_Uri.AbsoluteUri);
} else {
wb.Navigate("about:blank");
HtmlDocument doc = wb.Document.OpenNew(true);
doc.Write(thumbInfo_HTML);
wb.Refresh(WebBrowserRefreshOption.Completely);
}
// create an image of the client area of the webbrowser control, than
// scale it down to the dimensions specified.
if ((wb.Document != null && wb.Document.Body != null)) {
Rectangle rec = default(Rectangle);
rec.Size = wb.ClientSize;
using (Bitmap fullSizeBitmap = new Bitmap(thumbInfo_viewportWidth, thumbInfo_viewportHeight)) {
wb.DrawToBitmap(fullSizeBitmap, wb.Bounds);
using (Bitmap scaledBitmap = new Bitmap(thumbInfo_width, thumbInfo_height)) {
using (Graphics gr = Graphics.FromImage(scaledBitmap)) {
gr.SmoothingMode = Drawing2D.SmoothingMode.HighQuality;
gr.CompositingQuality = Drawing2D.CompositingQuality.HighQuality;
gr.InterpolationMode = Drawing2D.InterpolationMode.High;
Rectangle rect = new Rectangle(0, 0, thumbInfo_width, thumbInfo_height);
gr.DrawImage(fullSizeBitmap, rect, 0, 0, rec.Size.Width, rec.Size.Height, GraphicsUnit.Pixel);
scaledBitmap.Save(thumbInfo_physicalPath);
}
}
}
}
}
One thing to note that it is an expensive process.

Categories