Memory Stream Byte Array vs ImageConverter Byte Array - c#

I am converting a image to a byte array, then converting the bytes into something my epson printer can print
this piece of code converts the picture into bytes fast
ImageConverter converter = new ImageConverter();
buff = (byte[])converter.ConvertTo(signature, typeof(byte[]));
this one is slow but works
public static byte[] ImageToByte2(Image img)
{
byte[] byteArray = new byte[0];
using (MemoryStream stream = new MemoryStream())
{
img.Save(stream, System.Drawing.Imaging.ImageFormat.Bmp);
stream.Close();
byteArray = stream.ToArray();
}
return byteArray;
}
Both of these result in a different byte array and i can not figure out why, the memory stream one is the one that works for me but the conversion is slow
Can anyone perhaps hint as to why these bytes arrays are different converting the same picture
ex image converter byte array
ex memorystream conv
string display = BitConverter.ToString(buff);
MessageBox.Show(display);
Bitmap signature;
pictureBox1.Image=signature;
string Base64String = "79,27:79,27:79,26:79,26:79,26:79,27:79,28:77,30:73,33:69,38:66,44:62,52:56,62:48,72:42,79:39,82:39,81:#,#:79,29:79,29:78,28:80,26:82,26:81,30:77,36:75,40:74,44:75,47:76,50:78,51:84,48:92,41:101,33:108,27:110,26:109,26:109,28:109,30:109,31:109,34:107,40:103,49:97,58:93,65:88,71:87,74:#,#:133,38:133,38:133,38:132,40:129,47:124,54:121,59:117,65:114,70:#,#:130,39:130,39:130,39:135,35:145,29:157,24:166,23:#,#:125,52:125,52:122,53:125,52:136,48:147,47:152,48:#,#:114,69:114,69:112,69:117,68:129,65:139,63:147,62:#,#:199,30:199,30:197,31:196,35:195,40:195,45:191,54:182,63:174,72:171,76:173,76:182,72:198,69:216,67:231,66:239,66:240,67:238,68:#,#:";
string[] cord = Base64String.Split(new Char[]{',',':'},StringSplitOptions.RemoveEmptyEntries);
Graphics g;
g = Graphics.FromImage(signature);
g.Clear(Color.White);
Pen mypen = new Pen(new SolidBrush(Color.Black));
mypen.Width = 2;
mypen.EndCap = System.Drawing.Drawing2D.LineCap.Square;
mypen.StartCap = System.Drawing.Drawing2D.LineCap.Square;
mypen.MiterLimit = mypen.Width * 1.25f;
mypen.LineJoin = System.Drawing.Drawing2D.LineJoin.Round;
for (int i = 0; i < cord.Length; i=i+4)
{
//MessageBox.Show(cord[i]);
Point p;
Point p2;
if (cord[i] != "#" && cord[i + 1] != "#")
{
p = new Point(int.Parse(cord[i]), int.Parse(cord[i + 1]));
if (cord[i + 2] != "#" && cord[i + 3] != "#")
{
p2 = new Point(int.Parse(cord[i + 2]), int.Parse(cord[i + 3]));
}
else
{
p2 = new Point(int.Parse(cord[i]), int.Parse(cord[i + 1]));
}
}
else
{
}
}
g.Dispose();
signature = BitmapTo1Bpp(signature);
public static Bitmap BitmapTo1Bpp(Bitmap img)
{
int w = img.Width;
int h = img.Height;
Bitmap bmp = new Bitmap(w, h, PixelFormat.Format1bppIndexed);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, w, h), ImageLockMode.ReadWrite, PixelFormat.Format1bppIndexed);
byte[] scan = new byte[(w + 7) / 8];
for (int y = 0; y < h; y++)
{
for (int x = 0; x < w; x++)
{
if (x % 8 == 0) scan[x / 8] = 0;
Color c = img.GetPixel(x, y);
if (c.GetBrightness() >= 0.5) scan[x / 8] |= (byte)(0x80 >> (x % 8));
}
Marshal.Copy(scan, 0, (IntPtr)((long)data.Scan0 + data.Stride * y), scan.Length);
}
bmp.UnlockBits(data);
return bmp;
}

Based on the MSDN documentation found here, the ImageConverter function is converting the internal .NET representation of the image object reference to a byte array rather than the image data it contains.

Related

Convert image to byte array C# in a proper way

My problem is that I need to convert an image to a byte array to obtain its pixels.
My image size is 268x188 and when I use the property PixelsFormat it returns Format24bppRgb, so I understand that each pixel contains 3 bytes.
If this is true, the size of the pixels should be 268*188*3 = 151152 bytes, but the byte array that I am creating has a size of 4906 bytes, which is the size of the image file in my computer.
I donĀ“t know if there is another way to obtain these pixels or you can only obtain image file size.
If you want to ignore the header and the compression of the file you can do the following.
var path = ...
using(var image = Image.FromFile(path))
using(var bitmap = new Bitmap(image))
{
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat);
var bytesPerPixel = 4; // bitmapData.PixelFormat (image.PixelFormat and bitmapData.PixelFormat can be different)
var ptr = bitmapData.Scan0;
var imageSize = bitmapData.Width * bitmapData.Height * bytesPerPixel;
var data = new byte[imageSize];
for (int x = 0; x < imageSize; x += bytesPerPixel)
{
for(var y = 0; y < bytesPerPixel; y++)
{
data[x + y] = Marshal.ReadByte(ptr);
ptr += 1;
}
}
bitmap.UnlockBits(bitmapData);
}
To get image pixel try this:
public static byte[] GetImageRaw(Bitmap image)
{
if (image == null)
{
throw new ArgumentNullException(nameof(image));
}
if (image.PixelFormat != PixelFormat.Format24bppRgb)
{
throw new NotSupportedException("Invalid pixel format.");
}
const int PixelSize = 3;
var data = image.LockBits(
new Rectangle(Point.Empty, image.Size),
ImageLockMode.ReadWrite,
image.PixelFormat);
try
{
var bytes = new byte[data.Width * data.Height * PixelSize];
for (var y = 0; y < data.Height; ++y)
{
var source = (IntPtr)((long)data.Scan0 + y * data.Stride);
// copy row without padding
Marshal.Copy(source, bytes, y * data.Width * PixelSize, data.Width * PixelSize);
}
return bytes;
}
finally
{
image.UnlockBits(data);
}
}
Take a look at Bitmap.LockBits
I use this code in ASP.NET application. Very simple:
var imagePath = GetFilePathToYourImage();
using (var img = System.IO.File.OpenRead(imagePath))
{
var imageBytes = new byte[img.Length];
img.Read(imageBytes, 0, (int)img.Length);
}

Wrong generated TIf image using WriteableBitmap::WritePixels in c#

I changed pixel RGB value for a TIF image, but the generated tif image is not correct.
I use C# since there are some APIS for encoding and decoding TIF image format. My code is shown below.
public partial class Form1 : Form
{
private static int bytesPerPixel = 4;
private int width;
private int height;
byte[] bytes;
BitmapSource bitmapSource;
FormatConvertedBitmap convertedBitmap;
public Form1()
{
InitializeComponent();
}
private void openToolStripMenuItem_Click(object sender, EventArgs e)
{ .....
if (openFileDialog1.ShowDialog() == DialogResult.OK)
{
// Open the selected file to read.
string fileName = openFileDialog1.FileName;
pictureBox1.Load(fileName);
// Open a Stream and decode a TIFF image
Stream imageStreamSource = new FileStream(fileName, FileMode.Open, FileAccess.Read, FileShare.Read);
TiffBitmapDecoder decoder = new TiffBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
bitmapSource = decoder.Frames[0];
convertedBitmap = new FormatConvertedBitmap(bitmapSource, PixelFormats.Bgra32, null, 0);
bytesPerPixel = (convertedBitmap.Format.BitsPerPixel + 7) / 8;
width = convertedBitmap.PixelWidth;
height = convertedBitmap.PixelHeight;
bytes = new byte[width * height * bytesPerPixel];
convertedBitmap.CopyPixels(bytes, (convertedBitmap.PixelWidth * convertedBitmap.Format.BitsPerPixel + 7) / 8, 0);
for (int i = 0; i < width; i++) {
for (int j = 0; j < height; j++) {
Color color = GetPixel(bytes, i,j, bytesPerPixel);
if (i < width / 2 || j < height / 2)
setPixel(bytes, i, j, bytesPerPixel, (byte)(0), (byte)(0), (byte)(0));
else {
setPixel(bytes, i, j, bytesPerPixel, (byte)(255), (byte)(255), (byte)(255));
}
}
}
}
}
private static Color GetPixel(byte[] bgraBytes, int x, int y, int width)
{
var index = (y * (width * bytesPerPixel) + (x * bytesPerPixel));
return Color.FromArgb(
bgraBytes[index + 3],
bgraBytes[index + 2],
bgraBytes[index + 1],
bgraBytes[index]);
}
private static void setPixel(byte[] bytes, int x, int y, int width, byte r, byte g, byte b) {
var index = (y * (width * bytesPerPixel) + (x * bytesPerPixel));
bytes[index] = r; bytes[index + 1] = g; bytes[index + 2] = b;
}
private void saveToolStripMenuItem_Click(object sender, EventArgs e)
{ ................
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
int stride = width *8;
// Define the image palette
BitmapPalette myPalette = BitmapPalettes.WebPalette;
// Creates a new empty image with the pre-defined palette
var image = new WriteableBitmap(convertedBitmap);
image.WritePixels(new Int32Rect(0, 0, convertedBitmap.PixelWidth, convertedBitmap.PixelHeight), bytes,
(convertedBitmap.PixelWidth * convertedBitmap.Format.BitsPerPixel + 7) / 8, 0);
FileStream stream = new FileStream(saveFileDialog1.FileName, FileMode.Create);
TiffBitmapEncoder encoder = new TiffBitmapEncoder();
TextBlock myTextBlock = new TextBlock();
myTextBlock.Text = "Codec Author is: " + encoder.CodecInfo.Author.ToString();
encoder.Compression = TiffCompressOption.Zip;
encoder.Frames.Add(BitmapFrame.Create(image));
encoder.Save(stream);
stream.Dispose();
}
}
}
In the code, a tif image is read and its pixel RGB is copied to the byte[] bytes which is a class field member. After modifying all pixel RGB color (by 255 -), the bytes is then used to initilize another image and writen to the disk.
There is no error during runtime, but the generated tif image is not the same as i expected. The generated image is the same as original one, which is not correct.
Could anyone explain the reason that the generated image the same as input one? It seems the writePixel() does not take effect. During debug, i do find the bytes parameter in writePixel has been updated. I do not know the reason, as i am not very skill at C#, nor Image format. The original code are from
https://msdn.microsoft.com/en-us/library/aa969817%28v=vs.110%29.aspx?cs-save-lang=1&cs-lang=csharp#code-snippet-1
and
TIFF file parsing in C#

Parameter is not valid when using MemoryStream

I'm making some Bitmap image manipulation application in c# so I need to implicitly convert image to bmp so I can manipulate it like byte[] (byte array). Problem appears when this image is not bmp format - in that case after I convert it to Bitmap and after I convert this Bitmap into byte[] and apply some functions (by the way I "avoided" first 53 bytes - the header bytes) app breaks and I get "Parameter is not valid" message while trying to instance new Bitmap using MemoryStream on this byte[].
This is the code:
public void load(PictureBox pom)
{
OpenFileDialog o = new OpenFileDialog();
//o.Filter = "bin files (*.bin)|*.bin";
if (o.ShowDialog() == DialogResult.OK)
{
Bitmap b = (Bitmap)Image.FromFile(o.FileName);
pom.Image = b;
//pom.Image = new Bitmap(o.FileName);
this.p = pom;
this.input_bin_fajl = File.ReadAllBytes(o.FileName);
this.output_bin_fajl = new byte[this.input_bin_fajl.Length];
}
}
public static Bitmap ByteToImage(byte[] blob)
{
using (MemoryStream mStream = new MemoryStream())
{
mStream.Write(blob, 0, blob.Length);
mStream.Seek(0, SeekOrigin.Begin);
// this is the breaking point
Bitmap bm = new Bitmap(mStream);
//
return bm;
}
}
Here is the code it works with unsafe thanks again :)
void preview(Bitmap bm, int i)
{
BitmapData bmData = bm.LockBits(new Rectangle(0,0,bm.Width,bm.Height), ImageLockMode.ReadWrite, bm.PixelFormat);
int stride = bmData.Stride;
System.IntPtr Scan0 = bmData.Scan0;
unsafe
{
byte* p = (byte*)(void*)Scan0;
int nOffset = stride - bm.Width * 3;
int nWidth = bm.Width * 3;
for (int y = 0; y < bm.Height; ++y)
{
for (int x = 0; x < bm.Width; ++x)
{
switch (i)
{
case 0:
{
p[0] = (byte)0;
p[1] = (byte)0;
break;
}
case 1:
{
p[0] = (byte)0;
p[2] = (byte)0;
break;
}
default:
{
p[1] = (byte)0;
p[2] = (byte)0;
break;
}
}
p+=3;
}
p += nOffset;
}
}
bm.UnlockBits(bmData);
}

libtiff.net writeScanLine returns false

I'm using libtiff.net to make a tiff from a jpeg.
The problem apears when I try to write, because the tiff.writeScanLine returns false, meaning the image isn't written in the tiff.
Why is this happening? And how can I figure out what's wrong?
Here's the code:
private bool creatingTiff()
{
using (Bitmap bmp = new Bitmap(targetFile))
{
using (Tiff tif = Tiff.Open("BitmapTo24BitColorTiff.tif", "w"))
{
byte[] raster = getImageRasterBytes(bmp, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
tif.SetField(TiffTag.IMAGEWIDTH, bmp.Width);
tif.SetField(TiffTag.IMAGELENGTH, bmp.Height);
tif.SetField(TiffTag.COMPRESSION, Compression.OJPEG);
tif.SetField(TiffTag.PHOTOMETRIC, Photometric.YCBCR);
tif.SetField(TiffTag.SUBFILETYPE, 0);
tif.SetField(TiffTag.ROWSPERSTRIP, bmp.Height);
tif.SetField(TiffTag.ORIENTATION, BitMiracle.LibTiff.Classic.Orientation.TOPLEFT);
tif.SetField(TiffTag.XRESOLUTION, bmp.HorizontalResolution);
tif.SetField(TiffTag.YRESOLUTION, bmp.VerticalResolution);
tif.SetField(TiffTag.RESOLUTIONUNIT, ResUnit.INCH);
tif.SetField(TiffTag.BITSPERSAMPLE, 8);
tif.SetField(TiffTag.SAMPLESPERPIXEL, 3);
tif.SetField(TiffTag.JPEGIFOFFSET, 768);
tif.SetField(TiffTag.PLANARCONFIG, PlanarConfig.CONTIG);
for (int i = 0, offset = 0; i < bmp.Height; i++)
{
bool b = tif.WriteScanline(raster, offset, i, 0);
Console.WriteLine("write succes: " + b);
offset += stride;
}
}
System.Diagnostics.Process.Start("BitmapTo24BitColorTiff.tif");
return true;
}
}
private static byte[] getImageRasterBytes(Bitmap bmp, System.Drawing.Imaging.PixelFormat format)
{
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
byte[] bits = null;
try
{
// Lock the managed memory
BitmapData bmpdata = bmp.LockBits(rect, ImageLockMode.ReadWrite, format);
// Declare an array to hold the bytes of the bitmap.
bits = new byte[bmpdata.Stride * bmpdata.Height];
// Copy the values into the array.
System.Runtime.InteropServices.Marshal.Copy(bmpdata.Scan0, bits, 0, bits.Length);
// Release managed memory
bmp.UnlockBits(bmpdata);
}
catch
{
return null;
}
return bits;
}
private static void convertSamples(byte[] data, int width, int height)
{
int stride = data.Length / height;
const int samplesPerPixel = 3;
for (int y = 0; y < height; y++)
{
int offset = stride * y;
int strideEnd = offset + width * samplesPerPixel;
for (int i = offset; i < strideEnd; i += samplesPerPixel)
{
byte temp = data[i + 2];
data[i + 2] = data[i];
data[i] = temp;
}
}
}
The tif-tags are written, but the image itself isn't. Perhaps if someone can point me in the direction of the library developers blog (BitMiracle), I can direct my problem to them directly.
I think your code has the following errors:
You can not use Compression.OJPEG for new images. Old-JPEGs can only be de-compressed.
You probably should not specify TiffTag.JPEGIFOFFSET value by hand. The library will specify proper value itself.
You are trying to write the whole strip using WriteScanline method. You should use WriteEncodedStrip instead.
It also helps to review warnings emitted by the library (it emits them into console).

Color to Bitmap

How do I go about setting a Bitmap with a Color of the pixels. I created a program with LockBits and it is very fast but now I need to set a PictureBox with that image I ran through the LockBits I do not want to use SetPixels My current code is:
Bitmap imageFile = new Bitmap(bmpPath);
BitmapData imageData = imageFile.LockBits(new Rectangle(0, 0, imageFile.Width, imageFile.Height), ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb);
IntPtr Pointer = imageData.Scan0;
int ArraySize = Math.Abs(imageData.Stride) * imageFile.Height;
byte[] PixelArray = new byte[ArraySize];
Marshal.Copy(Pointer, PixelArray, 0, ArraySize);
int PixelAmount = 4; //ArGb
Color ArGBformat;
Bitmap RenderedImage = new Bitmap(imageFile.Width, imageFile.Height);
byte NewAlpha;
byte NewRed;
byte NewGreen;
byte NewBlue;
unsafe
{
for (int y = 0; y < imageData.Height; y++)
{
byte* row = (byte*)imageData.Scan0 + (y * imageData.Stride);
for (int x = 0; x < imageData.Width; x++)
{
int offSet = x * PixelAmount;
// read pixels
byte blue = row[offSet];
byte green = row[offSet + 1];
byte red = row[offSet + 2];
byte alpha = row[offSet + 3];
//Manipulates pixels
NewAlpha = Convert.ToByte(Math.Abs(alpha - _Alpha));
NewRed = Convert.ToByte(Math.Abs(red - _Red));
NewBlue = Convert.ToByte(Math.Abs(blue - _Blue));
NewGreen = Convert.ToByte(Math.Abs(green - _Green));
ArGBformat = Color.FromArgb(NewAlpha, NewRed, NewGreen, NewBlue);
RenderedImage.SetPixel(x, y, ArGBformat); //Slow and want something else
}
}
}
I would like to set my PictureBox1 to the pixels that get ran through the program.
Found the answer. I needed to set the pixels back.
//Sets image
row[offSet] = NewBlue;
row[offSet + 1] = NewGreen;
row[offSet + 2] = NewRed;
row[offSet + 3] = NewAlpha;

Categories