Set image from bitmap - c#

Image image = new Image ();
Bitmap bitmap = Bitmap.CreateBitmap (200, 100, Bitmap.Config.Argb8888);
Canvas canvas = new Canvas(bitmap);
var paint = new Paint();
paint.Color = Android.Graphics.Color.Red;
paint.SetStyle(Paint.Style.Fill);
Rect rect = new Rect(0, 0, 200, 100);
canvas.DrawRect(rect, paint);
Android.Widget.ImageView contains method SetImageBitmap.
What the best way to set Xamarin.Forms.Image from my bitmap?

Convert the Bitmap to byte[] via http://forums.xamarin.com/discussion/5950/how-to-convert-from-bitmap-to-byte-without-bitmap-compress
There are two solutions mentioned.
var byteArray = ByteBuffer.Allocate(bitmap.ByteCount);
bitmap.CopyPixelsToBuffer(byteArray);
byte[] bytes = byteArray.ToArray<byte>();
return bytes;
(in case first solution is still broken)
ByteBuffer buffer = ByteBuffer.Allocate(bitmap.ByteCount);
bitmap.CopyPixelsToBuffer(buffer);
buffer.Rewind();
IntPtr classHandle = JNIEnv.FindClass("java/nio/ByteBuffer");
IntPtr methodId = JNIEnv.GetMethodID(classHandle, "array", "()[B");
IntPtr resultHandle = JNIEnv.CallObjectMethod(buffer.Handle, methodId);
byte[] byteArray = JNIEnv.GetArray<byte>(resultHandle);
JNIEnv.DeleteLocalRef(resultHandle);
And then use
var image = new Image();
image.Source = ImageSource.FromStream(() => new MemoryStream(byteArray));
to create an Image.

I tried #Wosi's answer, but for some reason the rendering of the image after that didn't work and the code is specific to Android. I needed to work from a byte array to a bitmap and then back again. This is what I did:
Code for turning a bitmap into a byte array:
byte[] bitmapData;
using (var stream = new MemoryStream())
{
tempBitmap.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 0, stream);
bitmapData = stream.ToArray();
}
And the code for turning a byte array into a bitmap:
Android.Graphics.Bitmap tempBitmap = Android.Graphics.BitmapFactory.DecodeByteArray(imageByteArray, 0, imageByteArray.Length, options);
Where "options" is defined as follows:
Android.Graphics.BitmapFactory.Options options = new Android.Graphics.BitmapFactory.Options
{
InJustDecodeBounds = true
};
Android.Graphics.Bitmap result = Android.Graphics.BitmapFactory.DecodeByteArray(bitmapArray, 0, byteArrayLength, options);
//int imageHeight = options.OutHeight;
//int imageWidth = options.OutWidth;
In this part the Bitmap gets decoded. This is done to get the image height and width properties. For my case I required this information to encode it as a byte array again.
There with this it is possible to encode a byte array to a string and then back again.
Setting an image source from a byte array is done as follows:
var imageSource = ImageSource.FromStream(() => new MemoryStream(ImageByteArray, 0, ImageByteArray.Length));

Related

How to crop a captured screenshot?

Capturing a screen shot is quite easy but cropping is a different story, or at least appears so. We are attempting to emulate the solution here in Xamarin using SkiaSharp (System.Drawing not supported in Xamarin).
Currently we are able to capture the screenshot and return the image BUT if we crop our image the image returned is all black.
How do we crop a captured screenshot correctly?
NOTE*: image = image.Subset(rec); under the "crop image" section is how we are trying to crop.
iOS screenshot
public byte[] Capture()
{
var capture = UIScreen.MainScreen.Capture();
using (NSData data = capture.AsPNG())
{
var bytes = new byte[data.Length];
Marshal.Copy(data.Bytes, bytes, 0, Convert.ToInt32(data.Length));
return bytes;
}
}
Droid screenshot
public byte[] Capture()
{
var rootView = context.Window.DecorView.RootView;
using (var screenshot = Bitmap.CreateBitmap(
rootView.Width,
rootView.Height,
Bitmap.Config.Argb8888))
{
var canvas = new Canvas(screenshot);
rootView.Draw(canvas);
using (var stream = new MemoryStream())
{
screenshot.Compress(Bitmap.CompressFormat.Png, 90, stream);
return stream.ToArray();
}
}
}
Attempting to crop captured screenshot
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create initial pixel map
using SKPixmap pixmap = new SKPixmap(info, addr);
// Release
gch.Free();
// create bitmap
using SKBitmap bitmap = new SKBitmap();
// assign pixel data
bitmap.InstallPixels(pixmap);
// create surface
using SKSurface surface = SKSurface.Create(info);
// create a canvas for drawing
using SKCanvas canvas = surface.Canvas;
// draw
canvas.DrawBitmap(bitmap, info.Rect);
// get an image subset to save
SKImage image = surface.Snapshot();
SKRectI rec = new SKRectI((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
// crop image
image = image.Subset(rec);
byte[] bytes = SKBitmap.FromImage(image).Bytes;
image.Dispose();
return bytes;
}
EDIT: Alternative solution attempt (not working)
// Use this function to crop a screen shot to a specific element.
public byte[] test(byte[] screenshotData, View element)
{
// locate IntPtr to byte[] of uncropped screenshot
GCHandle gch = GCHandle.Alloc(screenshotData, GCHandleType.Pinned);
IntPtr addr = gch.AddrOfPinnedObject();
// assign initial bounds
SKImageInfo info = new SKImageInfo((int)App.Current.MainPage.Width,
(int)App.Current.MainPage.Height);
// create bitmap
SKBitmap bitmap = new SKBitmap();
bitmap.InstallPixels(info, addr);
// boundaries
SKRect cropRect = new SKRect((int)element.Bounds.Left, (int)element.Bounds.Top,
(int)element.Bounds.Right, (int)element.Bounds.Bottom);
SKBitmap croppedBitmap = new SKBitmap((int)cropRect.Width,
(int)cropRect.Height);
SKRect dest = new SKRect(0, 0, cropRect.Width, cropRect.Height);
SKRect source = new SKRect(cropRect.Left, cropRect.Top,
cropRect.Right, cropRect.Bottom);
// draw with destination and source rectangles
// to extract a subset of the original bitmap
using SKCanvas canvas = new SKCanvas(croppedBitmap);
canvas.DrawBitmap(bitmap, source, dest);
return croppedBitmap.Bytes;
//return bitmap.Bytes;
}
iOS solution - As seen here.
// crop the image, without resizing
private UIImage CropImage(UIImage sourceImage, int crop_x, int crop_y, int width, int height)
{
var imgSize = sourceImage.Size;
UIGraphics.BeginImageContextWithOptions(new System.Drawing.SizeF(width, height), false, 0.0f);
var context = UIGraphics.GetCurrentContext();
var clippedRect = new RectangleF(0, 0, width, height);
context.ClipToRect(clippedRect);
var drawRect = new RectangleF(-crop_x, -crop_y, imgSize.Width, imgSize.Height);
sourceImage.Draw(drawRect);
var modifiedImage = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return modifiedImage;
}
Android solution - getNavigationBarSize(context) as seen here
// crop the image, without resizing
private byte[] CropImage(byte[] screenshotBytes, int top)
{
Android.Graphics.Bitmap bitmap = Android.Graphics.BitmapFactory.DecodeByteArray(
screenshotBytes, 0, screenshotBytes.Length);
int viewStartY = (int)(top * 2.8f);
int viewHeight = (int)(bitmap.Height - (top * 2.8f));
var navBarXY = getNavigationBarSize(context);
int viewHeightMinusNavBar = viewHeight - navBarXY.Y;
Android.Graphics.Bitmap crop = Android.Graphics.Bitmap.CreateBitmap(bitmap,
0, viewStartY,
bitmap.Width, viewHeightMinusNavBar
);
bitmap.Dispose();
using MemoryStream stream = new MemoryStream();
crop.Compress(Android.Graphics.Bitmap.CompressFormat.Jpeg, 100, stream);
return stream.ToArray();
}
*NOTE: Unsure why a multiplication of 2.8 is required, though this works correctly. It should be stated testing was only done in the Android emulator. Perhaps it's emulator specific.
*NOTE2: x = 0 and width is equal to the entire width of the screen as that's per our requirement. Likewise top is Element.Bounds.Top.

Displaying TIF image using byte array to writeable bitmap(C#)

I've a byte array of a tiff image. I want to form 3 images from it,that i'll do later but the problem is i'm not able to display the original image as it is.
Here is my xaml:
<Image Grid.Row="0" Grid.Column="0" Name="ReferenceImage"/>
xaml.cs code:
public MainWindow()
{
InitializeComponent();
ImagePath = #"G:\TiffImage\Test.TIF"
DisplayAllImages();
}
private void DisplayAllImages()
{
byte[] imageSize = File.ReadAllBytes(ImagePath);
ReferenceImage.Source = DisplayAllImages(imageSize, 64, 64);
}
private WriteableBitmap DisplayAllImages(byte[] imageData,int height,int width)
{
if (imageData != null)
{
PixelFormat format = PixelFormats.Gray8;
WriteableBitmap wbm = new WriteableBitmap(height, width, 96, 96, format, null);
wbm.WritePixels(new Int32Rect(0, 0, height, width), imageData, 1*width, 0);
return wbm;
}
else
{
return null;
}
}
My main aim is to display image using byte array like this way only, so that i can extract byte array to form other image as per requirements.
The image file contains encoded bitmap data. In order to access the raw pixels you would first have to decode the bitmap:
BitmapSource bitmap;
using (var fileStream = new FileStream(ImagePath, FileMode.Open, FileAccess.Read))
{
bitmap = BitmapFrame.Create(
fileStream, BitmapCreateOptions.None, BitmapCacheOption.OnLoad);
}
Now you would get the raw pixels by calling the CopyPixels method of the BitmapSource:
var width = bitmap.PixelWidth;
var height = bitmap.PixelHeight;
var stride = (width * bitmap.Format.BitsPerPixel + 7) / 8;
var imageData = new byte[height * stride];
bitmap.CopyPixels(imageData, stride, 0);
I'm not getting the expected images.Although i'm able to generate images which is matching almost 75% but not completely.

SharpAvi Image to ByteArray to Frame to AVI

I'm having some trouble converting an image to a video using the SharpAVI.dll.
I have managed to produce a video file using a randomly generated byte array by using the documentation on SharpAVI's website:
Getting Started with SharpAVI
So the next step I thought I would take was to take an Image, create a Bitmap image, convert the bitmap to a byte array and then simply save the byte array to each frame of the video file. When I run the program, I get no errors or anything and a video file of an appropriate file size is produced however the video file is unreadable and will not open. I'm really struggling to see why this won't work. Any help would be greatly appreciated!
My Code:
private void GenerateSingleImageVideo()
{
string imagePath = textBoxImagePath.Text;
Bitmap thisBitmap;
//generate bitmap from image file
using (Stream BitmapStream = System.IO.File.Open(imagePath, FileMode.Open))
{
Image img = Image.FromStream(BitmapStream);
thisBitmap = new Bitmap(img);
}
//convert the bitmap to a byte array
byte[] byteArray = BitmapToByteArray(thisBitmap);
//creates the writer of the file (to save the video)
var writer = new AviWriter(textBoxFileName.Text + ".avi")
{
FramesPerSecond = int.Parse(textBoxFrameRate.Text),
EmitIndex1 = true
};
var stream = writer.AddVideoStream();
stream.Width = thisBitmap.Width;
stream.Height = thisBitmap.Height;
stream.Codec = KnownFourCCs.Codecs.Uncompressed;
stream.BitsPerPixel = BitsPerPixel.Bpp32;
int numberOfFrames = ((int.Parse(textBoxFrameRate.Text)) * (int.Parse(textBoxVideoLength.Text)));
int count = 0;
while (count <= numberOfFrames)
{
stream.WriteFrame(true, byteArray, 0, byteArray.Length);
count++;
}
writer.Close();
MessageBox.Show("Done");
}
private byte[] BitmapToByteArray(Bitmap img)
{
ImageConverter converter = new ImageConverter();
return (byte[])converter.ConvertTo(img, typeof(byte[]));
}
You're wrong in assuming that you should pass a Bitmap object to WriteFrame method. It expects pixel data in bottom to top 32bpp format. See example in
// Buffer for pixel data
var buffer = new byte[width * height * 4];
...
// Copy pixels from Bitmap assuming it has expected 32bpp pixel format
var bits = bitmap.LockBits(new Rectangle(0, 0, width, height), ImageLockMode.ReadOnly, PixelFormat.Format32bppRgb);
Marshal.Copy(bits.Scan0, buffer, 0, buffer.Length);
bitmap.UnlockBits(bits);
You can see code of a sample app as a reference
https://github.com/baSSiLL/SharpAvi/blob/master/Sample/Recorder.cs

Convert Byte Array to Bitmap Object in wpf

I want to convert byte array to bitmap. I get this byte array from capture card. Rgb24 data include for this array. When i convert this array to bitmap object i got the "Parameter is not valid" error.
This is my byte array
myByteArray{byte[921600]}
MemoryStream mStream = new MemoryStream(myByteArray);
Bitmap bi = new Bitmap(mStream );
and
using (MemoryStream mStream = new MemoryStream(myByteArray))
{
Bitmap bi = (Bitmap)System.Drawing.Image.FromStream(mStream );
}
and
using (MemoryStream mStream = new MemoryStream())
{
mStream.Write(myByteArray, 0, myByteArray.Length);
mStream.Seek(0, SeekOrigin.Begin);
Bitmap bm = new Bitmap(mStream);
return bm;
}
Is this happen because of the size of the array?
Can any one give a method to do this task?
It will be greatly appreciated.
thank you
If your myByteArray is raw image data, this should work:
Bitmap bmp = null;
unsafe
{
fixed (byte* p = myByteArray)
{
IntPtr unmanagedPointer = (IntPtr)p;
// Deduced from your buffer size
int width = 640;
int height = 480;
bmp = new Bitmap(width, height, width * 3, System.Drawing.Imaging.PixelFormat.Format24bppRgb, unmanagedPointer);
}
}

asp.net c# convert filestream to image

i have a filestream which im trying to convert into a image. i have the following code
FileStream imageFile = image["file"] as FileStream;
image is a map holding information on the image. please can some one direct me on what I should do next.
Image.FromStream will take a stream and return an image. Incidentally, if you use Bitmap.FromStream or Image.FromStream, or indeed any of these methods, they all return a Bitmap, so they can all be upcast to Bitmap from Image if you want them to be.
you can do the following:
int width = 128;
int height = width;
int stride = width / 8;
byte[] pixels = new byte[height * stride];
// Define the image palette
BitmapPalette myPalette = BitmapPalettes.Halftone256;
// Creates a new empty image with the pre-defined palette
BitmapSource image = BitmapSource.Create(
width,
height,
96,
96,
PixelFormats.Indexed1,
myPalette,
pixels,
stride);
FileStream stream = new FileStream("new.jpg", FileMode.Create);
JpegBitmapEncoder encoder = new JpegBitmapEncoder();
encoder.FlipHorizontal = true;
encoder.FlipVertical = false;
encoder.QualityLevel = 30;
encoder.Rotation = Rotation.Rotate90;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);

Categories