web-dev-qa-db-ja.com

.NETを使用してメモリ内に動的にjpg画像を作成するにはどうすればよいですか?

C#で記述された.NET(3.5 SP1)ライブラリ(DLL)があります。次の署名を持つクラスメソッドによってこのライブラリを拡張する必要があります。

public byte[] CreateGridImage(int maxXCells, int maxYCells,
    int cellXPosition, int cellYPosition)
{
    ...
}

このメソッドは、次のことを行うことになっています。

  • 入力パラメーターmaxXCellsおよびmaxYCellsは、XおよびY方向のセルのグリッドのサイズを定義します。 maxXCellsおよびmaxYCellsは、各方向のセルの数です。個々のセルは正方形です。 (つまり、非対称のチェス盤のようなものです。)
  • 入力パラメータcellXPositionおよびcellYPositionは、このグリッド内の1つの特別なセルを識別し、このセルは十字で埋める必要があります。
  • 派手なグラフィックは必要ありません。実際には、白い背景に黒いグリッド線があり、セルの1つにXがあります。
  • 結果のグラフィックはjpg形式である必要があります。
  • このグラフィックの作成はメモリ内で行う必要があり、ディスク上のファイルに保存したり、画面にペイントしたりすることはできません。
  • このメソッドは、生成された画像をbyte[]として返します。

私は.NETのグラフィック関数にあまり詳しくないので、質問は次のとおりです。

  • これは、追加のサードパーティライブラリなしで.NET 3.5 SP1でまったく可能ですか(これは避けたいです)?
  • 私が従わなければならない基本的な手順と、この目標を達成するために知っておく必要のある重要な.NET名前空間、クラス、およびメソッドは何ですか(特に、「メモリ内」に線やその他の単純なグラフィカル要素を描画し、結果をバイトに変換するため) jpg形式の配列)?

よろしくお願いします!

18
Slauma

以下は、以下の例の画像のように、GDIを使用してグリッドを描画し、(背景が赤の)十字を配置する完全なコードサンプルです。GDI他の回答と同じですが、実際の作業はセルをループしてグリッド線を描画することによって行われます。

次のコード

_byte[] bytes = CreateGridImage(10,10, 9, 9, 30);
_

9x9の位置に十字が付いた10x10グリッドを作成します。

enter image description here

CreateGridImage()への新しい追加は、グリッド内の各「正方形」のサイズを設定するboxSize引数の追加です。

_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();
    }
}
_
32
NakedBrunch
  1. System.Drawing.Bitmapオブジェクトを作成します。

  2. 描画を行うためのGraphicsオブジェクトを作成します。

  3. ビットマップをJPEGオブジェクトとしてMemoryStreamに保存します。

一時ビットマップでDisposeを呼び出すことを忘れないでください!

サンプルコードは以下のとおりです。以下のピクセル形式とさまざまなオプションを変更できます。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();
        }
    }
7
Peter Tate

まず、描画については、次のいずれかを実行できます。

  • Graphicsクラスを使用して、GDIが提供するものを使用します
  • ビットマップをロックして手動で描画する

保存に関しては、MemoryStreamクラスを使用してバイトを保持し、そこからバイトの配列を取得できます。

サンプルコードは次のようになります(ビットマップに描画するためにGraphicsオブジェクトを使用する場合:

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();
}
4
Marcin Deptuła

スラウマ、

これは、WindowsFormのDataGridViewコントロールを使用してグリッドを描画するさらに別の方法です。

    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;
    }

===クライアントapp.configで(この行を置き換えます):

<readerQuotas maxDepth="32" maxStringContentLength="2147483647" maxArrayLength="2147483647" maxBytesPerRead="2147483647" maxNameTableCharCount="2147483647" />

===

ハッピーコーディング!

2