I have an API that takes the base64string of an image of size 80x20(either JPG, PNG or GIF) and stores in database. In order to test this API I have to generate a random base64string which can be converted into a real image when decoded.
I have find the example here which seems to work with WPF application. How to use the same for a console application?
A variety of methods should work. How about the following:
public static string GenerateBase64ImageString()
{
// 1. Create a bitmap
using (Bitmap bitmap = new Bitmap(80, 20, PixelFormat.Format24bppRgb))
{
// 2. Get access to the raw bitmap data
BitmapData data = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, bitmap.PixelFormat);
// 3. Generate RGB noise and write it to the bitmap's buffer.
// Note that we are assuming that data.Stride == 3 * data.Width for simplicity/brevity here.
byte[] noise = new byte[data.Width * data.Height * 3];
new Random().NextBytes(noise);
Marshal.Copy(noise, 0, data.Scan0, noise.Length);
bitmap.UnlockBits(data);
// 4. Save as JPEG and convert to Base64
using (MemoryStream jpegStream = new MemoryStream())
{
bitmap.Save(jpegStream, ImageFormat.Jpeg);
return Convert.ToBase64String(jpegStream.ToArray());
}
}
}
Just be sure to add a reference to System.Drawing.
Related
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);
}
I have an .rgb file that I attached. It is a valid rgb file that I verified through other software. As far as I understand this is a raw RGB data file.
I need to load the file into byte[] and display it in PictureBox.
From all my searches here I came to this solution that seems correct and that works for others. Unfortunately it displays nothing for me:
string imgPath = Path.Combine(mInstallPath, "squirrel-720x576x50.rgb\\squirrel-720x576x50.rgb");
byte[] imageData = File.ReadAllBytes(imgPath);
using (var bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb))
{
BitmapData bmpData = bmp.LockBits(new Rectangle(0, 0,
bmp.Width,
bmp.Height),
ImageLockMode.WriteOnly,
bmp.PixelFormat);
Marshal.Copy(imageData, 0, bmpData.Scan0, width * height * 3);//imageData.Length);
//bmpSource.CopyPixels((Int32Rect.Empty, bmpData.Scan0, bmpData.Height * bmpData.Stride, bmpData.Stride);
bmp.UnlockBits(bmpData);
pictureBox.Image = bmp;
}
Any ideas why nothing is displayed in my pictureBox ?
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
I have a bitmap that I am performing a colorizing transformation on. I have the new array of pixels but I'm not sure how to then save them back to disk as an image
public static void TestProcessBitmap(string inputFile, string outputFile)
{
Bitmap bitmap = new Bitmap(inputFile);
Bitmap formatted = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
byte[] pixels = BitmapToPixelArray(formatted);
pixels = Process8Bits(pixels, System.Windows.Media.Colors.Red);
Bitmap output = new Bitmap(pixels); //something like this
}
How can I then save the new pixels as a bitmap on disk?
I do believe you can use the Bitmap.Save() method after you have loaded the bytes back into a Bitmap object. This post may give you some insight on how to do it.
According to this MSDN document, if you only specify a path while using Bitmap.Save(),
If no encoder exists for the file format of the image, the Portable
Network Graphics (PNG) encoder is used.
You can convert a byte array to a bitmap using a MemoryStream, and then feeding it into the Image.FromStream method. Your example with this in place would be..
public static void TestProcessBitmap(string inputFile, string outputFile)
{
Bitmap bitmap = new Bitmap(inputFile);
Bitmap formatted = bitmap.Clone(new Rectangle(0, 0, bitmap.Width, bitmap.Height), System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
byte[] pixels = BitmapToPixelArray(formatted);
pixels = Process8Bits(pixels, System.Windows.Media.Colors.Red);
using (MemoryStream ms = new MemoryStream(pixels))
{
Bitmap output = (Bitmap)Image.FromStream(ms);
}
}
I am writing a library to interface C# with the EPL2 printer language. One feature I would like to try to implement is printing images, the specification doc says
p1 = Width of graphic Width of graphic in bytes. Eight (8) dots = one (1) byte of data.
p2 = Length of graphic Length of graphic in dots (or print lines)
Data = Raw binary data without graphic file formatting. Data must be in bytes. Multiply the width in bytes (p1) by the number of print lines (p2) for the total amount of graphic data. The printer automatically calculates the exact size of the data block based upon this formula.
I plan on my source image being a 1 bit per pixel bmp file, already scaled to size. I just don't know how to get it from that format in to a byte[] for me to send off to the printer. I tried ImageConverter.ConvertTo(Object, Type) it succeeds but the array it outputs is not the correct size and the documentation is very lacking on how the output is formatted.
My current test code.
Bitmap i = (Bitmap)Bitmap.FromFile("test.bmp");
ImageConverter ic = new ImageConverter();
byte[] b = (byte[])ic.ConvertTo(i, typeof(byte[]));
Any help is greatly appreciated even if it is in a totally different direction.
If you just need to convert your bitmap into a byte array, try using a MemoryStream:
Check out this link: C# Image to Byte Array and Byte Array to Image Converter Class
public byte[] imageToByteArray(System.Drawing.Image imageIn)
{
MemoryStream ms = new MemoryStream();
imageIn.Save(ms,System.Drawing.Imaging.ImageFormat.Gif);
return ms.ToArray();
}
As SLaks said I needed to use LockBits
Rectangle rect = new Rectangle(0, 0, Bitmap.Width, Bitmap.Height);
System.Drawing.Imaging.BitmapData bmpData = null;
byte[] bitVaues = null;
int stride = 0;
try
{
bmpData = Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadOnly, Bitmap.PixelFormat);
IntPtr ptr = bmpData.Scan0;
stride = bmpData.Stride;
int bytes = bmpData.Stride * Bitmap.Height;
bitVaues = new byte[bytes];
System.Runtime.InteropServices.Marshal.Copy(ptr, bitVaues, 0, bytes);
}
finally
{
if (bmpData != null)
Bitmap.UnlockBits(bmpData);
}