Displaying TIF image using byte array to writeable bitmap(C#) - 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.

Related

Convert a raw RGB byte array to a JPG encoded string base64

I am successfully converting a JPG image file into a base64 string, and then that string into a JPG image again.
string str64 = ImageToStrBase64(My.Resources.ImageJpg);
PictureBox1.Image = Base64StrToImage(str64);
ImageToStrBase64() and Base64StrToImage() are custom functions just to explain the idea, but I can place the code if necessary.
I am also converting a raw byte array (RGB or BGR, no matters) into a base64.
However, I do now need to convert a raw byte array into a JPG encoded base64 string. I am finding solutions that involves only an image file saving, but file management it's high time consuming. How to encode then a BGR byte array into a JPG byte array using, for example a memory stream?
Function use to convert jpg into a formatted byte array:
public static string ImagetoStrBase64(System.Drawing.Image imageToEncode)
{
string base64String = "";
using (System.Drawing.Image image = imageToEncode)
{
using (MemoryStream m = new MemoryStream())
{
image.Save(m, image.RawFormat);
byte[] imageBytes = m.ToArray();
base64String = Convert.ToBase64String(imageBytes);
}
}
return base64String;
}
Update (regarding to chat)
Let's simplify it... We have a byte[] with single green pixel:
byte[] rawPixelArray = new byte[] {0, 255, 0};
Then, GetJpgBytes(rawPixelArray) must return an encoded byte[] for a Jpeg image of 1x1 pixel. This is more clear I guess :)
Before you read the answer, read the bullet points:
A real useful conversion, should return JPEG encoded image which is equivalent to content of a Jpeg file, which is not pixel data.
When you get an array of pixel data of a Jpeg image, you will have non of benefits of a Jpeg image. It's no more Jpeg encoded image, it's an array of pixel data which can be used to create a BitMap.
To better understand the point, for example for a 10K JPEG white image, the pixel data will be 2MB!
I've shared a few methods in this answer which are really useful standalone, and I've showed how you can combine them to get what you want. (While I cannot see any benefit in the conversion which you are trying to do.)
These are very useful pieces which you can put together to solve the puzzle:
ImageData: In addition to a byte[] of image pixels, you need to know about width, height and pixel format of the image. Then you can describe the image and create an Image from that data. Without having all these information a byte[] is meaningless on its own.
GetImageDataFromImage: Gets image data (width, height, pixel format, pixel data) from an Image
CreateImageFromImageData: Creates an Image from image data
ConvertImageToJpegImage: Converts an Image to Jpeg Image
ByteArrayToBase64: Converts a byte[] to Base64 string.
Then after having these pieces, you can achieve what you want.
Assuming you have a byte[] of pixel data, width, height and pixel format of your data, this is what you need:
// A 2x2 image having 24 bit RGB pixel format, all pixels are #FF0000 (Red)
var imageData = new ImageData()
{
Width = 2,
Height = 2,
PixelFormat = PixelFormat.Format24bppRgb,
PixelData = new byte[] {
0x0, 0x0, 0xFF, 0x0, 0x0, 0xFF,
0xF, 0x0, 0xFF, 0x0, 0x0, 0xFF
}
};
var image = CreateImageFromImageData(imageData);
var jpeg = ConvertImageToJpegImage(image);
var jpegImageData = GetImageDataFromImage(jpeg);
var jpegPixelsBase64 = ByteArrayToBase64(jpegImageData.PixelData);
Which result in AAD+AAD+AAD+AAD+ which is in fact an image having #FE0000 color!
Note: I didn't dispose images to keep it clear, in action, you need to dispose image and jpeg.
ImageData
Required information about an image, including width, height, pixel format, and pixel data array:
public class ImageData
{
public int Width { get; set; }
public int Height { get; set; }
public PixelFormat PixelFormat { get; set; }
public byte[] PixelData { get; set; }
}
GetImageDataFromImage
Gets image data from an image.
ImageData GetImageDataFromImage(Image image)
{
using (var bitmap = new Bitmap(image.Width, image.Height, image.PixelFormat))
{
using (var g = Graphics.FromImage(bitmap))
g.DrawImage(image, new Rectangle(0, 0, image.Width, image.Height));
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadOnly, bitmap.PixelFormat);
var rowLength = image.Width * Image.GetPixelFormatSize(image.PixelFormat) / 8;
var bytes = new byte[image.Height * rowLength];
var ptr = data.Scan0;
for (var i = 0; i < image.Height; i++)
{
Marshal.Copy(ptr, bytes, i * rowLength, rowLength);
ptr += data.Stride;
}
bitmap.UnlockBits(data);
return new ImageData
{
Width = bitmap.Width,
Height = bitmap.Height,
PixelFormat = bitmap.PixelFormat,
PixelData = bytes
};
}
}
We rely on LockBits to get or set image byte array.
CreateImageFromImageData
Creates image from image data:
Image CreateImageFromImageData(ImageData imageData)
{
var bitmap = new Bitmap(imageData.Width, imageData.Height, imageData.PixelFormat);
var data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
ImageLockMode.ReadWrite, bitmap.PixelFormat);
var rowLength = imageData.Width * Image.GetPixelFormatSize(imageData.PixelFormat) / 8;
var bytes = new byte[imageData.Height * rowLength];
var ptr = data.Scan0;
for (var i = 0; i < imageData.Height; i++)
{
Marshal.Copy(imageData.PixelData, i * rowLength, ptr, rowLength);
ptr += data.Stride;
}
bitmap.UnlockBits(data);
return bitmap;
}
We rely on LockBits to get or set image byte array.
ConvertImageToJpegImage
Converts an image to Jpeg Image:
public Image ConvertImageToJpegImage(Image img)
{
using (var stream = new MemoryStream())
{
img.Save(stream, ImageFormat.Jpeg);
var bytes = stream.ToArray();
return (Image)new ImageConverter().ConvertFrom(bytes);
}
}
If you care about compression level use jpeg encoder.
ByteArrayToBase64
Conversion from byte[] to Base64String and is straightforward, but to have better readability of the answer and the code:
public string ByteArrayToBase64(byte[] bytes)
{
return Convert.ToBase64String(bytes);
}

Set image from bitmap

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));

How to resize images to display from database

I am doing a small project where I have to display all images from database to Listview.
I am passing image id,width,and height as querystring parameter.
<asp:Image ID="Image1" runat="server" ImageUrl='<%#"~/Handler/ImageHandler.ashx?ImgHeight=150&ImgWidth=200&ImgID="+Eval("Image_ID")%>' Height="150px" Width="200px"/>
public void ProcessRequest (HttpContext context)
{
string imgwidth = context.Request.QueryString["ImgWidth"];
string imgheight = context.Request.QueryString["ImgHeight"];
string imageid = context.Request.QueryString["ImgID"];
if (imgwidth != string.Empty && imgheight != string.Empty && (imgwidth != null && imgheight != null))
{
if (!System.Web.UI.WebControls.Unit.Parse(imgwidth).IsEmpty && !System.Web.UI.WebControls.Unit.Parse(imgheight).IsEmpty)
{
//create unit object for height and width. This is to convert parameter passed in differen unit like pixel, inch into generic unit.
System.Web.UI.WebControls.Unit widthUnit=System.Web.UI.WebControls.Unit.Parse(imgwidth);
System.Web.UI.WebControls.Unit heightUnit = System.Web.UI.WebControls.Unit.Parse(imgheight);
//AFTER THIS ???
}
}
}
when I display image directly from database some images get stretch and doesn't look good, this is because the image size is large. So I need to display the images just for thumbsnail in image gallery.
You could use GetThumbnailImage Method
refer the code
public Void GenerateImage(int iWidth,int iHeight,byte[] ImageBytes)
{
System.Drawing.Image image = byteArrayToImage(ImageBytes)
// create the actual thumbnail image
System.Drawing.Image thumbnailImage = image.GetThumbnailImage(iWidth, iHeight, new System.Drawing.Image.GetThumbnailImageAbort(ThumbnailCallback), IntPtr.Zero);
// make a memory stream to work with the image bytes
MemoryStream imageStream = new MemoryStream();
// put the image into the memory stream
thumbnailImage.Save(imageStream, System.Drawing.Imaging.Imageformat.Jpeg);
// make byte array the same size as the image
byte[] imageContent = new Byte[imageStream.Length];
// rewind the memory stream
imageStream.Position = 0;
// load the byte array with the image
imageStream.Read(imageContent, 0, (int)imageStream.Length);
// return byte array to caller with image type
Response.ContentType = "image/jpeg";
Response.BinaryWrite(imageContent);
}
public bool ThumbnailCallback()
{
return true;
}
public Image byteArrayToImage(byte[] byteArrayIn)
{
MemoryStream ms = new MemoryStream(byteArrayIn);
Image returnImage = Image.FromStream(ms);
return returnImage;
}
You could use this code to give the image a new size, while preserving the aspect ratio:
public static Image ResizeCanvas(Image original, Size newSize, Color background)
{
int xStart = (newSize.Width / 2) - (original.Width / 2);
int yStart = (newSize.Height / 2) - (original.Height / 2);
// Create blank canvas
Bitmap resizedImg = new Bitmap(newSize.Width, newSize.Height);
Graphics gfx = Graphics.FromImage(resizedImg);
// Fill canvas
gfx.FillRectangle(new SolidBrush(background), new Rectangle(new Point(0, 0), newSize));
gfx.DrawImage(original, xStart, yStart, original.Width, original.Height);
return resizedImg;
}

Is it possible to reduce the size of an image comes from byte array

I have a byte array that contains a jpeg image. I was just wondering if it is possible to reduce its size?
Edit: Ok. I acknowledged my mistake. Then my question is how can I reduce the quality of the image comes from a byte array.
Please understand that there is no free lunch. Decreasing the size of a JPEG image by increasing the compression will also decrease the quality of the image. However, that said, you can reduce the size of a JPEG image using the Image class. This code assumes that inputBytes contains the original image.
var jpegQuality = 50;
Image image;
using (var inputStream = new MemoryStream(inputBytes)) {
image = Image.FromStream(inputStream);
var jpegEncoder = ImageCodecInfo.GetImageDecoders()
.First(c => c.FormatID == ImageFormat.Jpeg.Guid);
var encoderParameters = new EncoderParameters(1);
encoderParameters.Param[0] = new EncoderParameter(Encoder.Quality, jpegQuality);
Byte[] outputBytes;
using (var outputStream = new MemoryStream()) {
image.Save(outputStream, jpegEncoder, encoderParameters);
outputBytes = outputStream.ToArray();
}
}
Now outputBytes contains a recompressed version of the image using a different JPEG quality.
By decreasing the jpegQuality (should be in the range 0-100) you can increase the compression at the cost of lower image quality. See the Encoder.Quality field for more information.
Here is an example where you can see how jpegQuality affects the image quality. It is the same photo compressed using 20, 50 and 80 as the value of jpegQuality. Sizes are 4.99, 8.28 and 12.9 KB.
Notice how the text becomes "smudged" even when the quality is high. This is why you should avoid using JPEG for images with uniformly colored areas (images/diagrams/charts created on a computer). Use PNG instead. For photos JPEG is very suitable if you do not lower the quality too much.
Please try:
// Create a thumbnail in byte array format from the image encoded in the passed byte array.
// (RESIZE an image in a byte[] variable.)
public static byte[] CreateThumbnail(byte[] PassedImage, int LargestSide)
{
byte[] ReturnedThumbnail;
using (MemoryStream StartMemoryStream = new MemoryStream(),
NewMemoryStream = new MemoryStream())
{
// write the string to the stream
StartMemoryStream.Write(PassedImage, 0, PassedImage.Length);
// create the start Bitmap from the MemoryStream that contains the image
Bitmap startBitmap = new Bitmap(StartMemoryStream);
// set thumbnail height and width proportional to the original image.
int newHeight;
int newWidth;
double HW_ratio;
if (startBitmap.Height > startBitmap.Width)
{
newHeight = LargestSide;
HW_ratio = (double)((double)LargestSide / (double)startBitmap.Height);
newWidth = (int)(HW_ratio * (double)startBitmap.Width);
}
else
{
newWidth = LargestSide;
HW_ratio = (double)((double)LargestSide / (double)startBitmap.Width);
newHeight = (int)(HW_ratio * (double)startBitmap.Height);
}
// create a new Bitmap with dimensions for the thumbnail.
Bitmap newBitmap = new Bitmap(newWidth, newHeight);
// Copy the image from the START Bitmap into the NEW Bitmap.
// This will create a thumnail size of the same image.
newBitmap = ResizeImage(startBitmap, newWidth, newHeight);
// Save this image to the specified stream in the specified format.
newBitmap.Save(NewMemoryStream, System.Drawing.Imaging.ImageFormat.Jpeg);
// Fill the byte[] for the thumbnail from the new MemoryStream.
ReturnedThumbnail = NewMemoryStream.ToArray();
}
// return the resized image as a string of bytes.
return ReturnedThumbnail;
}
// Resize a Bitmap
private static Bitmap ResizeImage(Bitmap image, int width, int height)
{
Bitmap resizedImage = new Bitmap(width, height);
using (Graphics gfx = Graphics.FromImage(resizedImage))
{
gfx.DrawImage(image, new Rectangle(0, 0, width, height),
new Rectangle(0, 0, image.Width, image.Height), GraphicsUnit.Pixel);
}
return resizedImage;
}
The byte array size can always be reduced but you will lose data about your image. You could reduce the quality of the jpeg then it would take up less data as a byte array.
Think of the JPEG bytes as being a very compressed representation of a much larger number of bytes.
So if you try to apply some function to reduce the number of bytes it would be like trying to compress an already compressed thing.

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