c# - ¿Cómo crear una imagen jpg dinámicamente en memoria con.NET?
graphics jpeg (4)
Tengo una biblioteca .NET (3.5 SP1) (DLL) escrita en C #. Tengo que extender esta biblioteca por un método de clase que tendrá la siguiente firma:
public byte[] CreateGridImage(int maxXCells, int maxYCells,
int cellXPosition, int cellYPosition)
{
...
}
Se supone que este método hace lo siguiente:
- Los parámetros de entrada
maxXCells
ymaxYCells
definen el tamaño de una cuadrícula de celdas en la dirección X e Y.maxXCells
ymaxYCells
es el número de celdas en cada dirección. Las celdas individuales tienen forma cuadrada. (Así que es una especie de tablero de ajedrez asimétrico). - Los parámetros de entrada
cellXPosition
ycellYPosition
identifican una celda especial dentro de esta cuadrícula y esta celda debe rellenarse con una cruz. - No son necesarios gráficos sofisticados, realmente solo líneas de cuadrícula negras sobre un fondo blanco y una X en una de las celdas.
- El gráfico resultante debe tener formato jpg.
- La creación de este gráfico debe ocurrir en la memoria y nada debe almacenarse en un archivo en el disco ni pintarse en la pantalla.
- El método devuelve la imagen generada como un
byte[]
No estoy muy familiarizado con las funciones gráficas en .NET, por lo que mis preguntas son:
- ¿Es esto posible en absoluto con .NET 3.5 SP1 sin bibliotecas adicionales de terceros (que me gustaría evitar)?
- ¿Cuáles son los pasos básicos que debo seguir y cuáles son los espacios de nombres, clases y métodos importantes de .NET que debo conocer para lograr este objetivo (especialmente para dibujar líneas y otros elementos gráficos simples "en la memoria" y convertir el resultado en un byte?) matriz en formato jpg)?
Gracias por las sugerencias de antemano!
Crear un objeto System.Drawing.Bitmap.
Crea un objeto Graphics para hacer tu dibujo.
Guarde el mapa de bits en un MemoryStream como un objeto JPEG.
¡No olvides llamar a Dispose en tu bitmap temporal!
El código de muestra se encuentra a continuación, puede cambiar los formatos de píxeles y varias opciones a continuación, consulte la documentación de MSDN.
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();
}
}
El siguiente es un ejemplo de código completo que utilizará GDI para dibujar una cuadrícula y colocar una cruz (con un fondo rojo) como en la imagen de ejemplo a continuación. Utiliza GDI al igual que las otras respuestas, pero el trabajo real tiene lugar al recorrer las celdas y dibujar líneas de cuadrícula.
El siguiente codigo
byte[] bytes = CreateGridImage(10,10, 9, 9, 30);
creará una cuadrícula de 10x10 con una cruz en la posición 9x9:
Una nueva adición a CreateGridImage()
es la adición de un argumento boxSize que establece el tamaño de cada "cuadrado" en la cuadrícula
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();
}
}
En primer lugar, sobre el dibujo, puede:
- Usa la clase de gráficos para usar lo que GDI te da
- Bloquea el mapa de bits y dibuja en él manualmente.
En cuanto al guardado, puede usar la clase MemoryStream
para mantener sus bytes y luego obtener una matriz de bytes.
El código de ejemplo podría verse así (asumiendo que desea usar el objeto Graphics
para dibujar en el mapa de bits:
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
Aquí hay otra manera, que utiliza el control DataGridView de WindowsForm para dibujar la cuadrícula.
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;
}
=== En el cliente app.config (reemplace esta línea):
<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />
===
¡Feliz codificación!