レイヤーをつかった画像を保存します。レイヤーが存在する状態で保存するので、あとでレイヤーの位置を変更することもできます。
保存しなければならない情報として、レイヤーの名前と位置、レイヤーがもつビットマップが考えられます。
Layerクラスを一部修正します。追加したのはBitmapBas64プロパティとBitmapの幅と高さをあらわすWidthプロパティとHeightプロパティです。テキストデータとして保存するのでビットマップデータを文字列に変換しています。またBitmapプロパティはシリアル化しません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
public class Layer { [XmlIgnore] public Bitmap Bitmap { get; set; } public string BitmapBas64 { get { using(MemoryStream ms = new MemoryStream()) { if(Bitmap == null) return ""; Bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png); byte[] vs = ms.ToArray(); return Convert.ToBase64String(vs); } } set { if(value == "") { Bitmap = null; return; } byte[] vs = Convert.FromBase64String(value); using(MemoryStream ms = new MemoryStream(vs)) { if(Bitmap != null) Bitmap.Dispose(); Bitmap = new Bitmap(ms); } } } public string Name { get; set; } public int X { get; set; } = 0; public int Y { get; set; } = 0; public int Width { get { if(Bitmap == null) return 0; else return Bitmap.Width; } } public int Height { get { if(Bitmap == null) return 0; else return Bitmap.Height; } } } |
まずデザイナでメニューを追加します。
最初にファイルの保存から考えます。はじめてファイルに名前をつけて保存するときはダイアログを表示させて名前をつけさせます。そして保存したファイルのパスをフィールド変数editFilePathに保存します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 |
public class Doc { public List<Layer> Layers = new List<Layer>(); public int LastLayerNumber = 0; } public partial class Form1 : Form { string editFilePath = ""; private void SaveAsFileMenuItem_Click(object sender, EventArgs e) { SaveAsFile(); } void SaveAsFile() { SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "ImageEditorファイル(*.ief)|*.ief"; if(dlg.ShowDialog() == DialogResult.OK) { SaveFile(dlg.FileName); editFilePath = dlg.FileName; } dlg.Dispose(); } void SaveFile(string filePath) { Doc doc = new Doc(); doc.Layers = Layers; if(LayerNumber > Layers.Count) doc.LastLayerNumber = LayerNumber; else doc.LastLayerNumber = Layers.Count; XmlSerializer xml = new XmlSerializer(typeof(Doc)); StreamWriter sw = new StreamWriter(filePath); xml.Serialize(sw, doc); sw.Close(); } } |
上書き保存の場合は上書き対象のファイルが存在するかどうか確認してSaveFile(string filePath)メソッドを呼び出します。ファイルが存在しない場合はSaveAsFile()メソッドを呼び出します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public partial class Form1 : Form { private void SaveFileMenuItem_Click(object sender, EventArgs e) { SaveFile(); } void SaveFile() { if(File.Exists(editFilePath)) SaveFile(editFilePath); else SaveAsFile(); } } |
次にファイルを読み込むときの処理を考えます。
ファイルを読み込んでLayersプロパティに値をセットすることができたらあとはPictureBox.Invalidate()メソッドで再描画をすれば保存されていた画像が表示されます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
using System.IO; using System.Xml.Serialization; public partial class Form1 : Form { private void OpenFileMenuItem_Click(object sender, EventArgs e) { OpenFile(); } void OpenFile() { OpenFileDialog dlg = new OpenFileDialog(); dlg.Filter = "ImageEditorファイル(*.ief)|*.ief"; if(dlg.ShowDialog() == DialogResult.OK) { XmlSerializer xml = new XmlSerializer(typeof(Doc)); StreamReader sr = new StreamReader(dlg.FileName); Doc doc = (Doc)xml.Deserialize(sr); sr.Close(); Layers = doc.Layers; LayerNumber = doc.LastLayerNumber; pictureBox1.Invalidate(); editFilePath = dlg.FileName; } dlg.Dispose(); } } |
それから普通の画像としても保存できるようにしてみましょう。
まず保存すべきビットマップを取得します。取得できたら保存します。
レイヤーを調べれば左上の座標とビットマップの幅と高さがわかります。ここから保存すべきビットマップの大きさを求めています。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
public partial class Form1 : Form { private void SaveImageFileMenuItem_Click(object sender, EventArgs e) { SaveImageFile(); } Bitmap GetSaveBitmap() { List<Layer> layers = Layers.ToList(); layers = layers.Where(x => x.Bitmap != null).ToList(); if(layers.Count == 0) return null; int width = layers.Max(x => x.X + x.Width); int height = layers.Max(x => x.Y + x.Height); Bitmap bitmap = new Bitmap(width, height); Graphics g = Graphics.FromImage(bitmap); layers.Reverse(); foreach(Layer layer in layers) { g.DrawImage(layer.Bitmap, new Point(layer.X, layer.Y)); } g.Dispose(); return bitmap; } void SaveImageFile() { Bitmap bmp = GetSaveBitmap(); if(bmp == null) { MessageBox.Show("有効なレイヤーが存在しません", "エラー", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } SaveFileDialog dlg = new SaveFileDialog(); dlg.Filter = "Bitmap(*.bmp)|*.bmp|PNG(*.png)|*.png|JPEG(*.jpg)|*.jpg|Gif(*.gif)|*.gif"; dlg.FilterIndex = 0; if(dlg.ShowDialog() == DialogResult.OK) { bmp.Save(dlg.FileName); } bmp.Dispose(); dlg.Dispose(); } } |