I am developing a functionality that involves saving the fingerprint, for this function I have used the Digital Persona U 4500 reader.
Download and install the personal digital SDK and build a windows form c # application.
I added the control whose name: DigitalPersona Fingerprint Enrollment Control and in effect captures the fingerprint
The objective is to be able to visualize the footprint that has been placed in the reader to see in detail how it has been, for this purpose I added a picturebox to be displayed in it and additionally include the following:
public DPFP.Sample Sample = new DPFP.Sample();// instancia la muestra
DPFP.Capture.SampleConversion Convertor = new DPFP.Capture.SampleConversion();
Bitmap bitmap = null;
Convertor.ConvertToPicture(sample, ref bitmap);
PicBoxHuella.Image = bitmap;
With the previous action it should show the sample in the picture, but it is not. Valid and identified that the sample arrives in null.
I can't understand the Null value, if when putting a footprint I should capture the value, I would appreciate your guidance a bit on the subject.
On the OnCaptured event, you get the image data from the Fiv en Data.Views:
Note: pbFingerprint is an PictureBox where the image will display.
private void enrollment_OnCaptured(EnrollmentControl enrollmentControl, CaptureResult captureResult, int fingerPosition)
{
if (captureResult.ResultCode == Constants.ResultCode.DP_SUCCESS)
{
if (captureResult.Data != null)
{
foreach (Fid.Fiv fiv in captureResult.Data.Views)
{
pbFingerprint.Image = CreateBitmap(fiv.RawImage, fiv.Width, fiv.Height);
}
}
}
}
/// <summary>
/// Create a bitmap from raw data in row/column format.
/// </summary>
/// <param name="bytes"></param>
/// <param name="width"></param>
/// <param name="height"></param>
/// <returns></returns>
private Bitmap CreateBitmap(byte[] bytes, int width, int height)
{
byte[] rgbBytes = new byte[bytes.Length * 3];
for (int i = 0; i <= bytes.Length - 1; i++)
{
rgbBytes[(i * 3)] = bytes[i];
rgbBytes[(i * 3) + 1] = bytes[i];
rgbBytes[(i * 3) + 2] = bytes[i];
}
Bitmap bmp = new Bitmap(width, height, PixelFormat.Format24bppRgb);
BitmapData data = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.WriteOnly, PixelFormat.Format24bppRgb);
for (int i = 0; i <= bmp.Height - 1; i++)
{
IntPtr p = new IntPtr(data.Scan0.ToInt64() + data.Stride * i);
System.Runtime.InteropServices.Marshal.Copy(rgbBytes, i * bmp.Width * 3, p, bmp.Width * 3);
}
bmp.UnlockBits(data);
return bmp;
}
Related
I am trying to create movie from images.
I am following following links :
https://www.leadtools.com/support/forum/posts/t11084- // Here I am trying option 2 mentioned & https://social.msdn.microsoft.com/Forums/sqlserver/en-US/b61726a4-4b87-49c7-b4fc-8949cd1366ac/visual-c-visual-studio-2017-how-do-you-convert-jpg-images-to-video-in-visual-c?forum=csharpgeneral
void convert()
{
bmp = new Bitmap(320, 240, System.Drawing.Imaging.PixelFormat.Format24bppRgb);
// create sample source object
SampleSource smpsrc = new SampleSource();
ConvertCtrl convertCtrl = new ConvertCtrl();
// create a new media type wrapper
MediaType mt = new MediaType();
double AvgTimePerFrame = (10000000 / 15);
// set the type to 24-bit RGB video
mt.Type = Constants.MEDIATYPE_Video;
mt.SubType = Constants.MEDIASUBTYPE_RGB24;
// set the format
mt.FormatType = Constants.FORMAT_VideoInfo;
VideoInfoHeader vih = new VideoInfoHeader();
int bmpSize = GetBitmapSize(bmp);
// setup the video info header
vih.bmiHeader.biCompression = 0; // BI_RGB
vih.bmiHeader.biBitCount = 24;
vih.bmiHeader.biWidth = bmp.Width;
vih.bmiHeader.biHeight = bmp.Height;
vih.bmiHeader.biPlanes = 1;
vih.bmiHeader.biSizeImage = bmpSize;
vih.bmiHeader.biClrImportant = 0;
vih.AvgTimePerFrame.lowpart = (int)AvgTimePerFrame;
vih.dwBitRate = bmpSize * 8 * 15;
mt.SetVideoFormatData(vih, null, 0);
// set fixed size samples matching the bitmap size
mt.SampleSize = bmpSize;
mt.FixedSizeSamples = true;
// assign the source media type
smpsrc.SetMediaType(mt);
// select the LEAD compressor
convertCtrl.VideoCompressors.MCmpMJpeg.Selected = true;
convertCtrl.SourceObject = smpsrc;
convertCtrl.TargetFile = #"D:\Projects\LEADTool_Movie_fromImage\ImageToVideo_LeadTool\ImageToVideo_LeadTool\Images\Out\aa.avi";
//convertCtrl.TargetFile = "C:\\Users\\vipul.langalia\\Documents\\count.avi";
convertCtrl.TargetFormat = TargetFormatType.WMVMux;
convertCtrl.StartConvert();
BitmapData bmpData;
int i = 1;
byte[] a = new byte[bmpSize];
System.Drawing.Rectangle rect = new System.Drawing.Rectangle(0, 0, bmp.Width, bmp.Height);
var imgs = GetAllFiles();
foreach (var item in imgs)
{
bmpSize = GetBitmapSize(item);
MediaSample ms = smpsrc.GetSampleBuffer(30000);
ms.SyncPoint = true;
bmpData = item.LockBits(rect, ImageLockMode.ReadWrite, item.PixelFormat);
Marshal.Copy(bmpData.Scan0, a, 0, bmpSize);
item.UnlockBits(bmpData);
ms.SetData(bmpSize, a);
SetSampleTime(ms, i, AvgTimePerFrame);
smpsrc.DeliverSample(1000, ms);
i++;
}
smpsrc.DeliverEndOfStream(1000);
}
byte[] GetByteArrayFroMWritableBitmap(WriteableBitmap bitmapSource)
{
var width = bitmapSource.PixelWidth;
var height = bitmapSource.PixelHeight;
var stride = width * ((bitmapSource.Format.BitsPerPixel + 7) / 8);
var bitmapData = new byte[height * stride];
bitmapSource.CopyPixels(bitmapData, stride, 0);
return bitmapData;
}
private int GetBitmapSize(WriteableBitmap bmp)
{
int BytesPerLine = (((int)bmp.Width * 24 + 31) & ~31) / 8;
return BytesPerLine * (int)bmp.Height;
}
private int GetBitmapSize(Bitmap bmp)
{
int BytesPerLine = ((bmp.Width * 24 + 31) & ~31) / 8;
return BytesPerLine * bmp.Height;
}
It is throwing out of memory exception when execute ms.SetData(bmpSize, a); statement. Plus If I directly pass byte[] by var a = System.IO.File.ReadAllBytes(imagePath); in ms.SetData(bmpSize, a); statement then it will not throw error but video file is not properly created.
Can anybody please help me?
There are a couple of problems with your code:
Are all your images 320x240 pixels? If not, you should resize them to these exact dimensions before delivering them as video samples to the Convert control.
If you want to use a different size, you can, but it should be the same size for all images, and you should modify the code accordingly.
You are setting the TargetFormat property to WMVMux, but the name of the output file has “.avi” extension. If you want to save AVI files, set TargetFormat = TargetFormatType.AVI.
If you still face problems after this, feel free to contact support#leadtools.com and provide full details about what you tried and what errors you’re getting. Email support is free for LEADTOOLS SDK owners and also for free evaluation users.
I'm making a program which can capture a small area on screen and will run something if there is any color on image that match the target colors. My program run as the following Sequence:
Get image from a specific area from screen
Save to a folder
using CountPixel to detect any target_color
However, after I click the button5 twice times (not double click), it through an exception at below line :
b.Save(#"C:\Applications\CaptureImage000.jpg", ImageFormat.Jpeg);
Exception :
An unhandled exception of type
'System.Runtime.InteropServices.ExternalException' occurred in
System.Drawing.dll
Additional information: A generic error occurred in GDI+
My questions are :
How can i fix this exception ?
I want to use another method instead of CountPixel() to improve performance, because I just need to detect only one target color to rise event.
Step 2 is troublesome. I wonder if i can skip it and use the other way to call: (#"C:\Applications\CaptureImage000.jpg", ImageFormat.Jpeg) , because using this long string isn't comfortable and result error when im trying to use with GetPixel,... or add it into some "value example" code on internet for improvement purpose.
private int CountPixels(Bitmap bm, Color target_color)
{
// Loop through the pixels.
int matches = 0;
for (int y = 0; y < bm.Height; y++)
{
for (int x = 0; x < bm.Width; x++)
{
if (bm.GetPixel(x, y) == target_color) matches++;
}
}
return matches;
}
private Bitmap CapturedImage(int x, int y)
{
Bitmap b = new Bitmap(XX, YY);
Graphics g = Graphics.FromImage(b);
g.CopyFromScreen(x, y, 0, 0, new Size(XX, YY));
b.Save(#"C:\Applications\CaptureImage000.jpg", ImageFormat.Jpeg);
/* Run 3 line below will lead to question 1 - through exception
Bitmap bm = new Bitmap(#"C:\Applications\CaptureImage000.jpg");
int black_pixels = CountPixels(b, Color.FromArgb(255, 0, 0, 0));
textBox3.Text = black_pixels + " black pixels";
*/
return b;
}
private void button5_Click(object sender, EventArgs e)// Do screen cap
{
Bitmap bmp = null;
bmp = CapturedImage(X0, Y0);
}
[EDIT] Worked on this tonight with OP, made some improvements
This now accounts for endianness of the machine and correctly compares colors by converting them to integers with the Color.ToArgb() function
the below code will work, I have added comments for clarity and given you some options. I wrote the code without an IDE but I am confident it is fine.
In both cases below, just keep the handle to the bitmap, don't need to save and reopen regardless of if you need a copy.
Exception issue and improvements to CapturedImage function
option A (recommended)
Don't save the bitmap, you already have a handle, the graphics object just modified the BMP. Just leave the below code as is for this function and it will work fine without un-commenting one of the other options.
Code and other options:
private Bitmap CapturedImage(Bitmap bm, int x, int y)
{
Bitmap b = new Bitmap(XX, YY);
Graphics g = Graphics.FromImage(b);
g.CopyFromScreen(x, y, 0, 0, new Size(XX, YY));
//option B - If you DO need to keep a copy of the image use PNG and delete the old image
/*
try
{
if(System.IO.File.Exists(#"C:\Applications\CaptureImage.png"))
{
System.IO.File.Delete(#"C:\Applications\CaptureImage.png");
}
b.Save(#"C:\Applications\CaptureImage.png", ImageFormat.Png);
}
catch (System.Exception ex)
{
MessageBox.Show("There was a problem trying to save the image, is the file in open in another program?\r\nError:\r\n\r\n" + ex.Message);
}
*/
//option C - If you DO need to keep a copy of the image AND keep all copies of all images when you click the button use PNG and generate unique filename
/*
int id = 0;
while(System.IO.File.Exists(#"C:\Applications\CaptureImage" + id.ToString().PadLeft('0',4) + ".png"))
{
//increment the id until a unique file name is found
id++;
}
b.Save(#"C:\Applications\CaptureImage" + id.ToString().PadLeft('0',4) + ".png", ImageFormat.Png);
*/
int black_pixels = CountPixels(b, Color.FromArgb(255, 0, 0, 0));
textBox3.Text = black_pixels + " black pixels";
return b;
}
Now for the CountPixels function, you have 3 options but really, you have one really solid option, so I am omitting the others.
This locks the bits in the BMP, uses marshalling to copy the data into an array and scans the array for data, very, very fast, and you will likely not even need to remove the count. If you do STILL want to remove the count, just add "return 1;" right underneath where it increments the matches variable.
Speed issue and improvements to CountPixels function
private int CountPixels(Bitmap bm, Color target_color)
{
int matches = 0;
Bitmap bmp = (Bitmap)bm.Clone();
BitmapData bmpDat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
int size = bmpDat.Stride * bmpDat.Height;
byte[] subPx = new byte[size];
System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0, subPx, 0, size);
//change the 4 (ARGB) to a 3 (RGB) if you don't have an alpha channel, this is for 32bpp images
//ternary operator to check endianess of machine and organise pixel colors as A,R,G,B or B,G,R,A (little endian is reversed);
Color temp = BitConverter.IsLittleEndian ? Color.FromArgb(subPx[i + 2], subPx[i + 1], subPx[i]) : Color.FromArgb(subPx[i + 1], subPx[i + 2], subPx[i + 3]);
for (int i = 0; i < size; i += 4 ) //4 bytes per pixel A, R, G, B
{
if(temp.ToArgb() == target_color.ToArgb())
{
matches++;
}
}
System.Runtime.InteropServices.Marshal.Copy(subPx, 0, bmpDat.Scan0, subPx.Length);
bmp.UnlockBits(bmpDat);
return matches;
}
Finally the same function but allowing for a tolerance percent
private int CountPixels(Bitmap bm, Color target_color, float tolerancePercent)
{
int matches = 0;
Bitmap bmp = (Bitmap)bm.Clone();
BitmapData bmpDat = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, bmp.PixelFormat);
int size = bmpDat.Stride * bmpDat.Height;
byte[] subPx = new byte[size];
System.Runtime.InteropServices.Marshal.Copy(bmpDat.Scan0, subPx, 0, size);
for (int i = 0; i < size; i += 4 )
{
byte r = BitConverter.IsLittleEndian ? subPx[i+2] : subPx[i+3];
byte g = BitConverter.IsLittleEndian ? subPx[i+1] : subPx[i+2];
byte b = BitConverter.IsLittleEndian ? subPx[i] : subPx[i+1];
float distancePercent = (float)Math.Sqrt(
Math.Abs(target_color.R-r) +
Math.Abs(target_color.G-g) +
Math.Abs(target_color.B-b)
) / 7.65f;
if(distancePercent < tolerancePercent)
{
matches++;
}
}
System.Runtime.InteropServices.Marshal.Copy(subPx, 0, bmpDat.Scan0, subPx.Length);
bmp.UnlockBits(bmpDat);
return matches;
}
public Rgb Jasnosc()
{
Byte rob =(byte)(0.299*this.r + 0.587*this.g + 0.114*this.b);
Rgb ret;
ret.r = rob;
ret.g = rob;
ret.b = rob;
return ret;
}
So i have this kind of structure, and i am changing the loaded image to a grayscaled.
My Problem is that i would like to use a similar method to perform DCT on the image, but i totally do not know how to do it. Here is the code i used to perform it:
public static Bitmap Jasnosc(Bitmap bitmapaWe)
{
int wysokosc = bitmapaWe.Height;
int szerokosc = bitmapaWe.Width;
Bitmap bitmapaWy = new Bitmap(szerokosc, wysokosc, PixelFormat.Format24bppRgb);
BitmapData bmWeData = bitmapaWe.LockBits(new Rectangle(0, 0, wysokosc, wysokosc), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
BitmapData bmWyData = bitmapaWy.LockBits(new Rectangle(0, 0, wysokosc, wysokosc), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
int strideWe = bmWeData.Stride;
int strideWy = bmWeData.Stride;
IntPtr scanWe = bmWeData.Scan0;
IntPtr scanWy = bmWyData.Scan0;
unsafe
{
for (int y = 0; y < wysokosc; y++)
{
byte* pWe = (byte*)(void*)scanWe + y * strideWe;
byte* pWy = (byte*)(void*)scanWy + y * strideWy;
for (int x = 0; x < szerokosc; x++)
{
((Rgb*)pWy)[x] = ((Rgb*)pWe)[x].Jasnosc();
((Rgb*)pWy)[y] = ((Rgb*)pWe)[y].Jasnosc();
}
}
}
bitmapaWy.UnlockBits(bmWyData);
bitmapaWe.UnlockBits(bmWeData);
return bitmapaWy;
I would suggest that you use "emguCV" ("OpenCV") for such operations.
This library is well designed in perfomance & exposes a lot of usefull Computer-Vision-Functions.
An example for DCT can be found in the Git repo.
/// <summary>
/// performs forward or inverse transform of 2D floating-point image
/// </summary>
/// <param name="type">Transformation flags</param>
/// <returns>The result of DCT</returns>
[ExposableMethod(Exposable = true, Category = "Discrete Transforms")]
public Image<TColor, Single> DCT(CvEnum.CV_DCT_TYPE type)
{
Image<TColor, Single> res = new Image<TColor, float>(Width, Height);
CvInvoke.cvDCT(Ptr, res.Ptr, type);
return res;
}
The DCT-Function of EMGUCV is declared as:
public static void Dct(
IInputArray src,
IOutputArray dst,
DctType flags
)
I use below code to convert DIB from scanner with TWAIN to BitmapSource, but I found that the edge of image is cutted off. Image size is different with source image. Is there any thing wrong in below code when handel image?
/// <summary>
/// Get managed BitmapSource from a DIB provided as a low level windows hadle
///
/// Notes:
/// Data is copied from the source so the windows handle can be saftely discarded
/// even when the BitmapSource is in use.
///
/// Only a subset of possible DIB forrmats is supported.
///
/// </summary>
/// <param name="dibHandle"></param>
/// <returns>A copy of the image in a managed BitmapSource </returns>
///
public static BitmapSource FormHDib(IntPtr dibHandle)
{
BitmapSource bs = null;
IntPtr bmpPtr = IntPtr.Zero;
bool flip = true; // vertivcally flip the image
try {
bmpPtr = Win32.GlobalLock(dibHandle);
Win32.BITMAPINFOHEADER bmi = new Win32.BITMAPINFOHEADER();
Marshal.PtrToStructure(bmpPtr, bmi);
if (bmi.biSizeImage == 0)
bmi.biSizeImage = (uint)(((((bmi.biWidth * bmi.biBitCount) + 31) & ~31) >> 3) * bmi.biHeight);
int palettSize = 0;
if (bmi.biClrUsed != 0)
throw new NotSupportedException("DibToBitmap: DIB with pallet is not supported");
// pointer to the beginning of the bitmap bits
IntPtr pixptr = (IntPtr)((int)bmpPtr + bmi.biSize + palettSize);
// Define parameters used to create the BitmapSource.
PixelFormat pf = PixelFormats.Default;
switch (bmi.biBitCount) {
case 32:
pf = PixelFormats.Bgr32;
break;
case 24:
pf = PixelFormats.Bgr24;
break;
case 8:
pf = PixelFormats.Gray8;
break;
case 1:
pf = PixelFormats.BlackWhite;
break;
default: // not supported
throw new NotSupportedException("DibToBitmap: Can't determine picture format (biBitCount=" + bmi.biBitCount + ")");
// break;
}
int width = bmi.biWidth;
int height = bmi.biHeight;
int stride = (int)(bmi.biSizeImage / height);
byte[] imageBytes = new byte[stride * height];
//Debug: Initialize the image with random data.
//Random value = new Random();
//value.NextBytes(rawImage);
if (flip) {
for (int i = 0, j = 0, k = (height - 1) * stride; i < height; i++, j += stride, k -= stride)
Marshal.Copy(((IntPtr)((int)pixptr + j)), imageBytes, k, stride);
} else {
Marshal.Copy(pixptr, imageBytes, 0, imageBytes.Length);
}
int xDpi = (int)Math.Round(bmi.biXPelsPerMeter * 2.54 / 100); // pels per meter to dots per inch
int yDpi = (int)Math.Round(bmi.biYPelsPerMeter * 2.54 / 100);
// Create a BitmapSource.
bs = BitmapSource.Create(width, height, xDpi, yDpi, pf, null, imageBytes, stride);
Win32.GlobalUnlock(pixptr);
Win32.GlobalFree(pixptr);
pixptr = IntPtr.Zero;
imageBytes = null;
bmi = null;
} catch (Exception ex) {
//string msg = ex.Message;
}
finally {
// cleanup
if (bmpPtr != IntPtr.Zero) { // locked sucsessfully
Win32.GlobalUnlock(dibHandle);
}
}
Win32.GlobalUnlock(bmpPtr);
Win32.GlobalFree(bmpPtr);
bmpPtr = IntPtr.Zero;
return bs;
}
This code is from here.
I find the root reason now, it's caused by wrong TWAIN setting.
Set the Edge padding to nothing will solve this problem.
I have a .NET (3.5 SP1) library (DLL) written in C#. I have to extend this library by a class method which will have the following signature:
public byte[] CreateGridImage(int maxXCells, int maxYCells,
int cellXPosition, int cellYPosition)
{
...
}
This method is supposed to do the following:
Input parameters maxXCells and maxYCells define the size of a grid of cells in X and Y direction. maxXCells and maxYCells is the number of cells in each direction. The individual cells are square-shaped. (So it's kind of an asymmetric chess board.)
Input parameters cellXPosition and cellYPosition identify one special cell within this grid and this cell has to be filled with a cross.
No fancy graphics are necessary, really only black grid lines on a white background and a X in one of the cells.
The resulting graphic must have jpg format.
Creation of this graphic must happen in memory and nothing should be stored in a file on disk nor painted on the screen.
The method returns the generated image as a byte[]
I'm very unfamiliar with graphics functions in .NET so my questions are:
Is this possible at all with .NET 3.5 SP1 without additional third-party libraries (which I would like to avoid)?
What are the basic steps I have to follow and what are the important .NET namespaces, classes and methods I need to know to achieve this goal (epecially to draw lines and other simple graphical elements "in memory" and convert the result into an byte array in jpg format)?
Thank you for suggestions in advance!
The following is a full code sample that will use GDI to draw a grid and place a cross (with a red background) just like in the example image below. It uses GDI just like the other answers but the real work takes places by looping through the cells and drawing gridlines.
The following code
byte[] bytes = CreateGridImage(10,10, 9, 9, 30);
will create a 10x10 grid with a cross in the 9x9 position:
A new addition to CreateGridImage() is the addition of a boxSize argument which sets the size of each "square" in the grid
public static byte[] CreateGridImage(
int maxXCells,
int maxYCells,
int cellXPosition,
int cellYPosition,
int boxSize)
{
using (var bmp = new System.Drawing.Bitmap(maxXCells * boxSize+1, maxYCells * boxSize+1))
{
using (Graphics g = Graphics.FromImage(bmp))
{
g.Clear(Color.Yellow);
Pen pen = new Pen(Color.Black);
pen.Width = 1;
//Draw red rectangle to go behind cross
Rectangle rect = new Rectangle(boxSize * (cellXPosition - 1), boxSize * (cellYPosition - 1), boxSize, boxSize);
g.FillRectangle(new SolidBrush(Color.Red), rect);
//Draw cross
g.DrawLine(pen, boxSize * (cellXPosition - 1), boxSize * (cellYPosition - 1), boxSize * cellXPosition, boxSize * cellYPosition);
g.DrawLine(pen, boxSize * (cellXPosition - 1), boxSize * cellYPosition, boxSize * cellXPosition, boxSize * (cellYPosition - 1));
//Draw horizontal lines
for (int i = 0; i <= maxXCells;i++ )
{
g.DrawLine(pen, (i * boxSize), 0, i * boxSize, boxSize * maxYCells);
}
//Draw vertical lines
for (int i = 0; i <= maxYCells; i++)
{
g.DrawLine(pen, 0, (i * boxSize), boxSize * maxXCells, i * boxSize);
}
}
var memStream = new MemoryStream();
bmp.Save(memStream, ImageFormat.Jpeg);
return memStream.ToArray();
}
}
Create a System.Drawing.Bitmap Object.
Create a Graphics object to do your drawing.
Save the Bitmap to a MemoryStream as a JPEG object.
Don't forget to call Dispose on your temporary bitmap!
Sample code is below, you can change the pixel formats and various options below, have a look at the MSDN documentation.
public static byte[] CreateGridImage(
int maxXCells,
int maxYCells,
int cellXPosition,
int cellYPosition)
{
// Specify pixel format if you like..
using(var bmp = new System.Drawing.Bitmap(maxXCells, maxYCells))
{
using (Graphics g = Graphics.FromImage(bmp))
{
// Do your drawing here
}
var memStream = new MemoryStream();
bmp.Save(memStream, ImageFormat.Jpeg);
return memStream.ToArray();
}
}
First of all, about drawing, you can either:
Use Graphics class to use what GDI gives you
Lock bitmap and draw on it manually
As for saving, you could use MemoryStream class do keep your bytes and then get array of bytes out of it.
Sample code could look like this (assuming you want to use Graphics object to draw on bitmap:
public byte[] CreateGridImage(int maxXCells, int maxYCells,
int cellXPosition, int cellYPosition)
{
int imageWidth = 1;
int imageHeight = 2;
Bitmap bmp = new Bitmap(imageWidth, imageHeight);
using (Graphics g = Graphics.FromImage(bmp))
{
//draw code in here
}
MemoryStream imageStream = new MemoryStream();
bmp.Save(imageStream, System.Drawing.Imaging.ImageFormat.Jpeg);
bmp.Dispose();
return imageStream.ToArray();
}
Slauma,
Here is yet another way, which uses WindowsForm's DataGridView control to draw grid.
public byte[] GetData()
{
Form form = new Form();
//Create a new instance of DataGridView(WindowsForm) control.
DataGridView dataGridView1 = new DataGridView();
form.Controls.Add(dataGridView1);
//Customize output.
dataGridView1.RowHeadersVisible = false;
dataGridView1.ColumnHeadersVisible = false;
dataGridView1.ScrollBars = ScrollBars.None;
dataGridView1.AutoSize = true;
//Set datasource.
dataGridView1.DataSource = GetDataTable();
//Export as image.
Bitmap bitmap = new Bitmap(dataGridView1.Width, dataGridView1.Height);
dataGridView1.DrawToBitmap(bitmap, new Rectangle(Point.Empty, dataGridView1.Size));
//bitmap.Save("sample.jpg", System.Drawing.Imaging.ImageFormat.Jpeg);
MemoryStream ms = new MemoryStream();
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Jpeg);
bitmap.Dispose();
form.Dispose();
return ms.ToArray();
}
/// <summary>
/// Helper method.
/// </summary>
DataTable GetDataTable()
{
DataTable dt = new DataTable();
for (int i = 0; i < 2; i++)
dt.Columns.Add(string.Format("Column{0}", i));
for (int i = 0; i < dt.Columns.Count; i++)
{
for (int j = 0; j < 10; j++)
{
dt.Rows.Add(new string[] { "X1", "Y1" });
}
}
return dt;
}
===
In the client app.config (replace this line):
<readerQuotas maxDepth="32"
maxStringContentLength="2147483647"
maxArrayLength="2147483647"
maxBytesPerRead="2147483647"
maxNameTableCharCount="2147483647" />
===
Happy Coding !