C#でレイヤー付きの画像を実装する part1

こんにちは、Takymです。
最近、更新できていなくてすみません。
今回は、C#で画像のレイヤー機能を実装したいと思います。
今回作成するプログラムは、DotnetExlibに追加します。

仕様

今回、作るレイヤーは以下の様な感じにしたいと思います。

  • レイヤーの中にレイヤーを埋め込めるようにする。
  • レイヤーはList<Image>を継承したクラスにする。
  • レイヤーはImageを継承したクラスにして、PictureBox等で簡単に使えるようにする。

Imageクラスは継承できない

実はImageクラスは継承する事ができません。
仕方がないので以下のImageクラス代わりのクラスを実装して使おうと思います。

using System;
using System.Drawing;
using DotnetExlib.Properties;
namespace DotnetExlib.Graphics
{
/// <summary>
///  画像を表すオブジェクトです。
/// </summary>
[Author("Takym", copyright: "Copyright (C) 2017 Takym.")]
public abstract class Picture : IDisposable, ICloneable
{
/// <summary>
///  現在のオブジェクトが破棄されている場合は<c>true</c>、されていない場合は<c>false</c>です。
/// </summary>
protected bool IsDisposed { get; private set; }
/// <summary>
///  この画像の大きさです。
/// </summary>
public virtual Size Size
{
get
{
return ToImage().Size;
}
}
/// <summary>
///  <see cref="DotnetExlib.Graphics.Picture"/>の新しいインスタンスを生成します。
/// </summary>
public Picture()
{
this.IsDisposed = false;
}
/// <summary>
///  このクラスのデストラクタです。
/// </summary>
~Picture()
{
this.Dispose(false);
}
/// <summary>
///  現在のオブジェクトを、<see cref="System.Drawing.Image"/>に変換します。
/// </summary>
/// <returns>変換後の<see cref="System.Drawing.Image"/>です。</returns>
public abstract Image ToImage();
/// <summary>
///  現在のオブジェクトのコピーを作成します。
/// </summary>
/// <returns>現在のオブジェクトのコピーです。</returns>
public abstract object Clone();
/// <summary>
///  現在のオブジェクトの全てのリソースを破棄します。
/// </summary>
public void Dispose()
{
this.Dispose(true);
GC.SuppressFinalize(this);
}
/// <summary>
///  現在のオブジェクトのリソースを解放します。
/// </summary>
/// <param name="disposing">マネージドオブジェクトを解放するかどうかです。</param>
protected virtual void Dispose(bool disposing)
{
this.IsDisposed = true;
}
/// <summary>
///  <see cref="DotnetExlib.Graphics.Picture"/>を<see cref="System.Drawing.Image"/>にキャストする機能を提供します。
/// </summary>
/// <param name="obj">変換する<see cref="DotnetExlib.Graphics.Picture"/>です。</param>
public static implicit operator Image(Picture obj)
{
return obj.ToImage();
}
}
}

上記のクラスはImageクラスへ変換可能です。
しかし、Imageクラスから上記のPictureクラスに変換する事はできません。
なので、以下のようなラッパークラスを作成します。

using System.Drawing;
using DotnetExlib.Properties;
namespace DotnetExlib.Graphics
{
/// <summary>
///  <see cref="System.Drawing.Image"/>クラスを<see cref="DotnetExlib.Graphics.Picture"/>にラップするクラスです。
///  このクラスは継承できません。
/// </summary>
[Author("Takym", copyright: "Copyright (C) 2017 Takym.")]
public sealed class ImageWrapper : Picture
{
private Image _img;
/// <summary>
///  ラップする<see cref="System.Drawing.Image"/>オブジェクトを指定して、
///  新しいインスタンスを生成します。
/// </summary>
/// <param name="img">ラップする<see cref="System.Drawing.Image"/>オブジェクトです。</param>
public ImageWrapper(Image img)
{
_img = img;
}
/// <summary>
///  ラップしている画像の大きさです。
/// </summary>
public override Size Size
{
get
{
return _img.Size;
}
}
/// <summary>
///  このオブジェクトがラップしている<see cref="System.Drawing.Image"/>オブジェクトを返します。
/// </summary>
/// <returns>このオブジェクトがラップしている<see cref="System.Drawing.Image"/>オブジェクトです。</returns>
public override Image ToImage()
{
return _img;
}
/// <summary>
///  このオブジェクトのコピーを作成します。
/// </summary>
/// <returns>作成されたコピーです。</returns>
public override object Clone()
{
return new ImageWrapper(_img.Clone() as Image);
}
/// <summary>
///  現在のオブジェクトのリソースを解放します。
/// </summary>
/// <param name="disposing">マネージドオブジェクトを解放するかどうかです。</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
_img.Dispose();
}
base.Dispose(disposing);
}
/// <summary>
///  <see cref="System.Drawing.Image"/>を<see cref="DotnetExlib.Graphics.ImageWrapper"/>にキャストする機能を提供します。
/// </summary>
/// <param name="obj">変換する<see cref="System.Drawing.Image"/>です。</param>
public static implicit operator ImageWrapper(Image obj)
{
return new ImageWrapper(obj);
}
}
}

レイヤークラスを実装する

using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using DotnetExlib.Properties;
using Grap = System.Drawing.Graphics;
namespace DotnetExlib.Graphics
{
/// <summary>
///  複数の画像のレイヤーです。
/// </summary>
[Author("Takym", copyright: "Copyright (C) 2017 Takym.")]
public class PictureLayer : Picture, IList<Picture>
{
/// <summary>
///  このオブジェクトに格納されている全ての画像です。
/// </summary>
public List<Picture> Items { get; private set; }
/// <summary>
///  この画像の大きさです。
/// </summary>
public override Size Size
{
get
{
return _size;
}
}
private Size _size;
/// <summary>
///  <see cref="DotnetExlib.Graphics.PictureLayer"/>の新しいインスタンスを生成します。
/// </summary>
public PictureLayer()
{
this.Items = new List<Picture>();
_size = new Size(600, 800);
}
/// <summary>
///  このオブジェクトに格納されている全ての画像を重ねた画像を返します。
/// </summary>
/// <returns>重ねた後の<see cref="System.Drawing.Image"/>です。</returns>
public override Image ToImage()
{
Image result = new Bitmap(_size.Width, _size.Height);
using (Grap g = Grap.FromImage(result)) {
foreach (var img in this.Items) {
g.DrawImage(img.ToImage(), 0, 0);
}
}
return result;
}
/// <summary>
///  現在のオブジェクトのコピーを作成します。
/// </summary>
/// <returns>現在のオブジェクトのコピーです。</returns>
public override object Clone()
{
PictureLayer result = new PictureLayer();
result.Items = new List<Picture>(this.Items.ToArray());
return result;
}
/// <summary>
///  このオブジェクトに新しいサイズを設定します。
/// </summary>
/// <param name="size">設定するサイズです。</param>
public void SetSize(Size size)
{
_size = size;
}
/// <summary>
///  現在のオブジェクトのリソースを解放します。
/// </summary>
/// <param name="disposing">マネージドオブジェクトを解放するかどうかです。</param>
protected override void Dispose(bool disposing)
{
if (disposing) {
foreach (var img in this.Items) {
img.Dispose();
}
}
this.Items.Clear();
base.Dispose(disposing);
}
#region IList
public Picture this[int index]
{
get
{
return ((IList<Picture>)Items)[index];
}
set
{
((IList<Picture>)Items)[index] = value;
}
}
public int Count
{
get
{
return ((IList<Picture>)Items).Count;
}
}
public bool IsReadOnly
{
get
{
return ((IList<Picture>)Items).IsReadOnly;
}
}
public void Add(Picture item)
{
((IList<Picture>)Items).Add(item);
}
public void Clear()
{
((IList<Picture>)Items).Clear();
}
public bool Contains(Picture item)
{
return ((IList<Picture>)Items).Contains(item);
}
public void CopyTo(Picture[] array, int arrayIndex)
{
((IList<Picture>)Items).CopyTo(array, arrayIndex);
}
public IEnumerator<Picture> GetEnumerator()
{
return ((IList<Picture>)Items).GetEnumerator();
}
public int IndexOf(Picture item)
{
return ((IList<Picture>)Items).IndexOf(item);
}
public void Insert(int index, Picture item)
{
((IList<Picture>)Items).Insert(index, item);
}
public bool Remove(Picture item)
{
return ((IList<Picture>)Items).Remove(item);
}
public void RemoveAt(int index)
{
((IList<Picture>)Items).RemoveAt(index);
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IList<Picture>)Items).GetEnumerator();
}
#endregion
}
}

上記の様な実装で動く筈です。
次回、デバッグしてみたいと思います。
分からない事・間違い等はこの記事のコメント欄にお願いします。
最後まで読んでくださってありがとうございました!
デバッグ編できました→C#でレイヤー付きの画像を実装する part2

コメントを残す

WordPress.com で次のようなサイトをデザイン
始めてみよう