午後わてんのブログ

ベランダ菜園とWindows用アプリ作成(WPFとC#)

無限の透明市松模様をWriteableBitmapとImageBrushのタイル表示で作成

ウィンドウのサイズに合わせて背景の市松模様が表示される
イメージ 1
どこまでも続く透明市松模様
 
 
デザイン画面
MainWindow.xaml

f:id:gogowaten:20191213190816p:plain

GridにMyGridっていう名前をつけただけ
 
 
MainWindow.xaml.cs
using System.Windows;
using System.Windows.Media;
using System.Windows.Media.Imaging;

namespace _20190328_透明市松模様作成タイル表示
{
    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();

            WriteableBitmap bitmap = MakeCheckeredPattern(10, Colors.LightGray);
            MyGrid.Background = MakeTileBrush(bitmap);
        }
        /// <summary>
        /// 市松模様画像作成
        /// </summary>
        /// <param name="cellSize">タイル1辺のサイズ</param>
        /// <param name="gray">白じゃない方の色指定</param>
        /// <returns></returns>
        private WriteableBitmap MakeCheckeredPattern(int cellSize, Color gray)
        {
            int width = cellSize * 2;
            int height = cellSize * 2;
            var wb = new WriteableBitmap(width, height, 96, 96, PixelFormats.Rgb24, null);
            int stride = wb.Format.BitsPerPixel / 8 * width;
            byte[] pixels = new byte[stride * height];
            int p = 0;
            Color iro;
            for (int y = 0; y < height; y++)
            {
                for (int x = 0; x < width; x++)
                {
                    if ((y < cellSize & x < cellSize) | (y >= cellSize & x >= cellSize))
                    {
                        iro = Colors.White;
                    }
                    else { iro = gray; }

                    p = y * stride + x * 3;
                    pixels[p] = iro.R;
                    pixels[p + 1] = iro.G;
                    pixels[p + 2] = iro.B;
                }
            }
            wb.WritePixels(new Int32Rect(0, 0, width, height), pixels, stride, 0);
            return wb;
        }
        /// <summary>
        /// BitmapからImageBrush作成
        /// 引き伸ばし無しでタイル状に敷き詰め
        /// </summary>
        /// <param name="bitmap"></param>
        /// <returns></returns>
        private ImageBrush MakeTileBrush(BitmapSource bitmap)
        {
            var imgBrush = new ImageBrush(bitmap);
            imgBrush.Stretch = Stretch.None;//これは必要ないかも
            //タイルモード、タイル
            imgBrush.TileMode = TileMode.Tile;
            //タイルサイズは元画像のサイズ
            imgBrush.Viewport = new Rect(0, 0, bitmap.PixelWidth, bitmap.PixelHeight);
            //タイルサイズ指定方法は絶対値、これで引き伸ばされない
            imgBrush.ViewportUnits = BrushMappingMode.Absolute;
            return imgBrush;
        }

    }
}
 
市松模様の画像をWriteableBitmapで作成して
その画像からImageBrushを作成、ブラシの設定を引き伸ばしなしのタイルに設定
そのブラシを背景に設定
 
 
 
市松模様の画像をWriteableBitmapで作成
イメージ 3
16行目で26行目から市松模様画像作成
引数の10は市松模様のマス(セル)の1辺の長さ、Colors.LightGrayは模様の色
 
白と、指定した色のマスを交互に置いて合計4つのマス
背景が白だから判りづらいw
 
セルサイズの2倍の画像を作成するので縦横2倍、28,29行目
左上と右下を白、それ以外を指定した色にしたいから
画像のピクセル位置x,yが
共に0~セルサイズ未満のとき、または
共にセルサイズ以上のとき
白にして、それ以外の時を指定した色にする
これが39~43行目
 
これでできあがる画像は
イメージ 4
これ
 
 
あとはこの画像をタイル状に敷き詰めれば市松模様になる
ImageBrushは画像からブラシを作成できる
Brushには敷き詰めた状態で表示するタイルモードがある
 
画像からImageBrushを作成、ブラシの設定を引き伸ばしなしのタイルに設定
イメージ 5
この設定で目的のブラシができたけど、よくわかっていない
ImageBrushの設定で必要だったのは以下の3つ
  • TileModeをTile
  • ViewportにするRectのサイズをタイルにする画像サイズにする
  • ViewportUnitsをAbsolute
 
 
失敗例
イメージ 6
元画像を引き伸ばし無しでタイル状に敷き詰めたブラシにするから
それっぽいプロパティをそれっぽく指定して
StretchをNoneブラシの引き伸ばしなし
TileModeをTileタイルモードをタイル
これで実行すると
 
イメージ 7
違う
タイルモードはあっていると思うからStretchが違うのかなあと
イメージ 16
StretchをUniformにしてみたら
イメージ 17
これも違う
 
ググって流れ変わる
方法: TileBrush のタイル サイズを設定する | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/graphics-multimedia/how-to-set-the-tile-size-for-a-tilebrush
ViewportとViewportUnitsでタイルのサイズを決めるみたい、これが必要だった
 
 
Viewport
イメージ 9
これでタイルの位置とサイズを設定できる
作っているのはImageBrushなんだけど、説明見るとこれはTileBrush用?
引き伸ばしされたくないのでタイルのサイズは元画像と同じに指定
 
 
VIewportUnits
イメージ 8
Viewportで指定した数値をどう受け取るかの設定みたい
2種類しかない、絶対値(Absolute)指定か相対値指定っぽい
指定しないときの初期値はRelativeになっていたので
ここはAbsoluteを選択して
 
イメージ 10
┗(゜ω ゜)┛
[答 無限透明市松模様 ]
 
あとAbsoluteでサイズ指定したせいか、引き伸ばし設定のStretchは無視されるみたいなのでいらないかも
イメージ 13
66行目、この状態でも正しく表示される
 
 
 
RelativeToBoundingBox
イメージ 11
ViewportUnitsをRelativeToBoundingBox
ViewportをRect(0,0,0.2,0.2)
これだと
 
イメージ 12
Relativeにして0.2を指定すると0.2ごとの場所に表示されるみたい
こういうのも面白いねえ
 
 
 
セルサイズと色の変更
イメージ 14
セルサイズを50、色をトマトで実行
 
イメージ 15
 
 
2019/03/30追記
WPF のブラシの概要 | Microsoft Docs
https://docs.microsoft.com/ja-jp/dotnet/framework/wpf/graphics-multimedia/wpf-brushes-overview
ここにあるDrawingBrush、こっちのほうがいいかも?
追記ここまで
 
 
ギットハブ
関連記事、2019/03/30は明日
画像の使用色数とその色のピクセル数を表示するアプリその5 ( ソフトウェア ) - 午後わてんのブログ - Yahoo!ブログ
https://blogs.yahoo.co.jp/gogowaten/15918266.html