How to create a jpg image dynamically in memory with .NET?
Solution 1
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();
}
}
Solution 2
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();
}
}
Solution 3
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();
}
Solution 4
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 !
Slauma
Updated on September 07, 2020Comments
-
Slauma over 3 years
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
andmaxYCells
define the size of a grid of cells in X and Y direction.maxXCells
andmaxYCells
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
andcellYPosition
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!
- Input parameters
-
Slauma about 13 yearsThanks! In your example are already all important pieces together. To draw I need functions like g.DrawLine and Pen and Brush objects and so on, right? I do not really understand the difference between the two options you mentioned ("Use Graphics..." vs. "Lock bitmap..."). What does this mean exactly and which option is to prefer?
-
Marcin Deptuła about 13 yearsYes, DrawLines and Pen/Brush objects are perfectly fine, the other option is not to use Graphics, but operate on bitmap's memory by yourself. If you are happy with what Graphics object gives you and also - with how fast it works, you definately don't need to play with locking bitmaps.
-
Slauma about 13 yearsNumber of cells in X and Y direction will probably be always <= 60 (so that I have to draw 120 lines in the worst case) and this function will be called once in an hour of so. So, the graphical operations won't be huge, I guess. It can't be a performance problem, can it?
-
Slauma about 13 yearsHm, interesting solution! But I am not in a Windows Forms application, currently I don't reference any Windows Forms assemblies. The library which will contain this new function is part of a WCF service. Is your solution applicable in this case?
-
Karthik Mahalingam about 13 years@Slauma, This solution works under WCF too, I just tested it. But you have to add reference to "System.Windows.Forms.dll" and "System.Drawing.dll" in your project. Cheers.
-
Marcin Deptuła about 13 yearsIn that case - no. If you want aim into huge bitmaps or real time / sub real time rendering (like 10 frames per seconds) then you could start considering other options :).
-
Slauma about 13 yearsThat's awesome! I really didn't expect the detailed work. Thank you very much!
-
NakedBrunch about 13 yearsYup, there are many ways to skin this cat but the above code should definitely get you going.
-
Jonathan over 10 yearsThanks much for the detailed example - useful in a similar instance for me.
-
davvs over 10 yearsThank you. Excellent example!