Raspberry Pi and framebuffer input with mono - c#

I'm trying to render a bitmap in Memory using mono. This image should be displayed on Adafruits 2.8" touch TFT (320*240). The Programm is developed with Visual Studio 2013 Community Edition. I want to host a ASP.NET Web Api and Show
some data on the Display. The ASP.NET part is working fine and the image is rendered. My idea was to write the Image to the framebuffer Input, but doing this I get an Exception saying that file is to large. I'm just writing raw data without BMP Header. Has someone managed doing this? Maybe creation of image is
wrong.
It seems as something is happening because the display changes and I can see white areas which might be from my image.
I don't want to use any extra libraries to keep it simple. So my idea is to use FBI directly. Does anyone know this problem and the solution?
Here is some of my code:
using (Bitmap bmp = new Bitmap(240, 320, PixelFormat.Format16bppRgb555))
{
[...]
Byte[] image = null;
using(MemoryStream memoryStream = new MemoryStream())
{
bitmap.Save(memoryStream, ImageFormat.Bmp);
Byte[] imageTemp = memoryStream.GetBuffer();
//Remove BMP header
image = new Byte[imageTemp.Length - 54];
Buffer.BlockCopy(imageTemp, 54, image, 0, image.Length);
//153600 byte
using (FileStream fb1 = new FileStream("/dev/fb1", FileMode.Open, FileAccess.ReadWrite, FileShare.ReadWrite))
{
fb1.Write(image, 0, image.Length);
fb1.Close();
}
}
}

Take a look at http://computerstruggles.blogspot.de/2013/02/how-to-program-directfb-in-c-on.html - the idea is to install the directfb library and use it from C# with PInvoke. The blog's author uses a mini wrapper in C to make using it even easier. BTW why don't you like to install additional libraries and to profit from the work others have done for you?

You may be running out of memory when the MemoryStream reallocates memory. When it needs to grow, it doubles in size. With this large of a write, the internal buffer is probably exceeding available memory. See Why does C# memory stream reserve so much memory? for more information.

Related

How to load a 16bit (rgb565) bmp into a byte array with c# standard

So I had this bit of code, that works great in my windows c# application or a framework DLL.
private static Icon? LoadSync(string filepath)
{
Stream imageStreamSource = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.Read);
BmpBitmapDecoder decoder = new BmpBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
BitmapSource bitmapSource = decoder.Frames[0];
if (bitmapSource.Format != System.Windows.Media.PixelFormats.Bgr565)
{
Debug.Print($"Image at path `{filepath}` is not RGB565!");
return null;
}
byte[] icon = new byte[bitmapSource.PixelHeight * bitmapSource.PixelWidth * sizeof(short)];
bitmapSource.CopyPixels(icon, bitmapSource.PixelWidth * sizeof(short), 0);
return new Icon() { Width = (ushort)bitmapSource.PixelWidth, Height = (ushort)bitmapSource.PixelHeight, Data = icon };
}
It loads a 16 bit .bmp file into memory, and then gives the pixels to me in the form of a byte array.
However, I encountered a weird compile bug, and my online searches seemed to turn up that it was caused by some odd difference in how a function is declared as an extension method in one instance, but an actual member in another. I forget the details but the proposed solution was to switch to a standard dll from framework. I tried it and it fixed my problem.
But now, reintroducing the above code, I no longer have access to System.Windows.Media.Imaging. So I'm wondering what options I have to be able to accomplish the same thing.
Using the plain old bitmap library, the data is converted to (I think) rgb888 without any option to preserve the format.
If you're wondering why I need a byte array, I'm sending the data on to an arduino with a screen.
I have never done exactly what you're trying to do, but I did recently have to work with images in some C# code. I added the System.Drawing NuGet package and made use of the Image class. This might be a help: https://learn.microsoft.com/en-us/dotnet/api/system.drawing.image?view=windowsdesktop-5.0

C# Best approach to send screen difference over socket

I am working on screen sharing project. I am sending only screen differences over socket comparing previous and actual buffer. It working
I am sending 8 to 9 FPS to client using Format16bppRgb555 to reduce overall bytes size of Bitmap
byte[] wholescreensize= new byte[1360 * 768 * 2];// Its around 2 Mb
My problem Is when full screen is changed.
I am getting about 45-60 kb of PNG image using below function
45kb * 10 (FPS) = 450 kb
It is possible to reduce beyond 45 kb.
I am not interested to reduce FPS as it live screen sharing app.
JPEG Compression or LZ4/GZIP also not making much difference as PNG image already compressed
private void SendImgDiffToClient(byte[] contents,Rectangle rectangle)
{
//Converting Small Portion to Bitmap.Bcoz Image.FromStrem not working here error Parameter is not Valid
byte[] byteArrayout = new byte[contents.Length];
var bitmap = new Bitmap(rectangle.Width, rectangle.Height, PixelFormat.Format16bppRgb555);
var bitmap_data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format16bppRgb555);
Marshal.Copy(contents, 0, bitmap_data.Scan0, byteArrayout.Length);
bitmap.UnlockBits(bitmap_data);
//Converting Small Bitmap to Png Byte Array and Sending to Client
using (MemoryStream ms = new MemoryStream())
{
Image msImage = (Image)bitmap;
msImage.Save(ms, ImageFormat.Png);
msImage.Dispose();
byteArrayout = ms.ToArray();
}
SendtoClient(byteArrayout);
}
My Questing is what is a best approach to reduce bytes in such scenario.
Video streaming is essentially what you're doing; and modern video compression algorithms have lots of enhancements. Perhaps they can track or move an artifact, or otherwise distort said artifact as part of their functionality. Perhaps they can stream the data in a progressively building manner, so that static items eventually acquire more detail (similar to progressive jpeg images.) They do lots of things all at the same time. You can try to research them further, and take inspiration from them, or you could pick and use one.
This is to say that many people here seem to prefer the solution of using a readily available video compression library. Especially if you are worried about streaming bandwidth.
If you don't want to use an existing video library, then you have to decide how much effort you want to put in, versus how sloppy you want to be with consuming more bandwidth than otherwise necessary.

Saving Image In UWP Then Loading In WinForms

Good morning StackOverflow,
I come to you today with a scenario that is driving me slowly insane. Im hopeful you can aid me with this, as I’m certain this must be possible but I can’t solve it myself.
My issue is that I’m working on two different applications at present. The first is a UWP application to deliver packages for an internal mail system. The idea here is that upon receipt of the package the person will sign the application using a InkCanvas signature. This should then be saved to the database as a byte array, and then reloaded in either a WinForm or WebForm app (I’m currently doing the WinForm one first) as a regular old image file. However, I’m absolutely stuck on converting between the WriteableBitmap that I get from UWP and the regular Bitmap I need to load in WinForms. Any ideas?
Here’s what I’m doing presently:
Saving the UWP image:
private byte[] SaveImage()
{
var canvasStrokes = SignatureCanvas.InkPresenter.StrokeContainer.GetStrokes();
if (canvasStrokes.Count > 0)
{
var width = (int) SignatureCanvas.ActualWidth;
var height = (int) SignatureCanvas.ActualHeight;
var device = CanvasDevice.GetSharedDevice();
var renderTarget = new CanvasRenderTarget(device, width, height, 96);
using (var drawingSession = renderTarget.CreateDrawingSession())
{
drawingSession.Clear(Colors.White);
drawingSession.DrawInk(SignatureCanvas.InkPresenter.StrokeContainer.GetStrokes());
}
return renderTarget.GetPixelBytes();
}
return null;
}
Then I save the bytes to the database, and pull them from the database in the WinForms app... so am I making some boneheaded mistake here? Am I reading the signature in the wrong format? Or do I need to do something more to convert the formats from one to the other?
I’m stumped, after trying many different results from StackOverflow pages I don’t know what I’m doing wrong.
Any help would be amazing! And sorry if I’ve done something dumb.
You're actually saving raw bitmap data to your database.
I don't remember well how the Winform importer was working but I doubt it can import raw bitmap data.
You should encode your raw data to a PNG or JPEG image first and save the result. You will end with a regular old image file that should be readable from Winform.
using (IRandomAccessStream stream = /* the stream where you want to save the data */)
{
byte[] bytes = renderTarget.GetPixelBytes();
var encoder = await BitmapEncoder.CreateAsync(BitmapEncoder.JpegEncoderId, stream);
encoder.SetPixelData(BitmapPixelFormat.Bgra8,
BitmapAlphaMode.Ignore,
(uint)canvas.Width, (uint)canvas.Height,
96, 96, bytes);
await encoder.FlushAsync();
}

C# Generic Error with GDI+ on Bitmap.Save

public void EditAndSave(String fileName) {
Bitmap b = new Bitmap(fileName);
/**
* Edit bitmap b... draw stuff on it...
**/
b.Save(fileName); //<---------Error right here
b.Dispose();
}
My code is similar to the above code. When i try to save the file i just opened, it won't work. When i try saving it with a different path, it works fine. Could it be that the file is already open in my program so it cannot be written to? I'm very confused.
You are correct in that it is locked by your program and therefore you can't write to it. It's explained on the msdn-page for the Bitmap class (http://msdn.microsoft.com/en-us/library/3135s427.aspx).
One way around this (from the top of my head, might be easier ways though) would be to cache image in a memorystream first and load it from there thus being able to close the file lock.
static void Main(string[] args)
{
MemoryStream ms = new MemoryStream();
using(FileStream fs = new FileStream(#"I:\tmp.jpg", FileMode.Open))
{
byte[] buffer = new byte[fs.Length];
fs.Read(buffer, 0, buffer.Length);
ms.Write(buffer, 0, buffer.Length);
}
Bitmap bitmap = new Bitmap(ms);
// do stuff
bitmap.Save(#"I:\tmp.jpg");
}
I've not been in exactly the same situation as you, but I have had problems with open image files being kept open.
One suggestion is that you load the image into memory using the BitmapCacheOption.OnLoad, see my answer to this post: Locked resources (image files) management.
Then, after editing, that image can be saved to the the same file using a FileStream, that is described for example here: Save BitmapImage to File.
I'm not sure it is the easiest or most elegant way, but I guess it should work for you.
Indeed there may be many reasons for seeing this exception.
Note that if you're using PixelFormat.Format16bppGrayScale, it's not supported in GDI+ and fails in the way shown. It seems the only workaround for using proper 16-bit gray scale is to use the newer System.Windows.Media namespace from WPF.

C# - How to use Jpeg to compress images and send to a server?

I want to build a Screen Sharing program in C#.(with TCP)
I sniffed around the web and found out that the most efficient way to do it is by sending alot of screenshots from the client to the server.
The point is - how can I compress a Bitmap to Jpeg - receive it on the server and decompress again to Bitmap (so I can show it in a form) ?
I've tried using the JpegBitmapEncoder with no luck, here's my code:
Bitmap screen = TakeScreenshot();
MemoryStream ms = new MemoryStream();
byte[] Bytes = BmpToBytes_Unsafe(screen);
ms.Write(Bytes, 0, Bytes.Length);
Jpeg = new JpegBitmapEncoder();
Jpeg.Frames.Add(BitmapFrame.Create(ms));
Jpeg.QualityLevel = 40;
Jpeg.Save(ms);
BinaryReader br = new BinaryReader(ms);
SendMessage(br.ReadBytes((int)ms.Length));
It throws an NotSupportedException at Jpeg.Frames.Add(BitmapFrame.Create(ms));
No imaging component suitable to complete this operation was found.
So I need a way to convert a Bitmap to Jpeg, then to byte[], then send it over TCP.
And on the other end, do the exact opposite. Any suggestions ?
Thank you.
JPEG was designed for photographs, not for screen captures. Also, most of the screen doesn't change so better to just send the changed portions and only a full screen when much of the screen has changed.
Unless you're just doing this for fun, you are going about this all wrong. VNC has been doing this for years and the source code is free so you could look to see how that's done.

Categories