// OpenTween - Client of Twitter
// Copyright (c) 2013 kim_upsilon (@kim_upsilon)
// All rights reserved.
//
// This file is part of OpenTween.
//
// This program is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by the Free
// Software Foundation; either version 3 of the License, or (at your option)
// any later version.
//
// This program is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
// for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program. If not, see , or write to
// the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
// Boston, MA 02110-1301, USA.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Runtime.Serialization;
using System.Text;
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using System.IO;
using System.Threading.Tasks;
namespace OpenTween
{
///
/// Image と Stream を対に保持するためのクラス
///
///
/// Image.FromStream() を使用して Image を生成する場合、
/// Image を破棄するまでの間は元となった Stream を破棄できないためその対策として使用する。
///
public class MemoryImage : ICloneable, IDisposable
{
public readonly Stream Stream;
public readonly Image Image;
protected bool disposed = false;
///
/// ストリームから読みだされる画像データが不正な場合にスローされる
///
protected MemoryImage(Stream stream)
{
try
{
this.Image = Image.FromStream(stream);
}
catch (ArgumentException e)
{
stream.Dispose();
throw new InvalidImageException("Invalid image", e);
}
catch (OutOfMemoryException e)
{
// GDI+ がサポートしない画像形式で OutOfMemoryException がスローされる場合があるらしい
stream.Dispose();
throw new InvalidImageException("Invalid image?", e);
}
catch (ExternalException e)
{
// 「GDI+ で汎用エラーが発生しました」という大雑把な例外がスローされる場合があるらしい
stream.Dispose();
throw new InvalidImageException("Invalid image?", e);
}
catch (Exception)
{
stream.Dispose();
throw;
}
this.Stream = stream;
}
///
/// MemoryImage インスタンスを複製します
///
///
/// メソッド実行中にストリームのシークが行われないよう注意して下さい。
/// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
///
/// 複製された MemoryImage
public MemoryImage Clone()
{
this.Stream.Seek(0, SeekOrigin.Begin);
return MemoryImage.CopyFromStream(this.Stream);
}
///
/// MemoryImage インスタンスを非同期に複製します
///
///
/// メソッド実行中にストリームのシークが行われないよう注意して下さい。
/// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
///
/// 複製された MemoryImage を返すタスク
public Task CloneAsync()
{
this.Stream.Seek(0, SeekOrigin.Begin);
return MemoryImage.CopyFromStreamAsync(this.Stream);
}
object ICloneable.Clone()
{
return this.Clone();
}
protected virtual void Dispose(bool disposing)
{
if (this.disposed) return;
if (disposing)
{
this.Image.Dispose();
this.Stream.Dispose();
}
this.disposed = true;
}
public void Dispose()
{
this.Dispose(true);
// 明示的にDisposeが呼ばれた場合はファイナライザを使用しない
GC.SuppressFinalize(this);
}
~MemoryImage()
{
this.Dispose(false);
}
///
/// 指定された Stream から MemoryImage を作成します。
///
///
/// ストリームの内容はメモリ上に展開した後に使用されるため、
/// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
///
/// 読み込む対象となる Stream
/// 作成された MemoryImage
/// 不正な画像データが入力された場合
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
public static MemoryImage CopyFromStream(Stream stream)
{
var memstream = new MemoryStream();
stream.CopyTo(memstream);
return new MemoryImage(memstream);
}
///
/// 指定された Stream から MemoryImage を非同期に作成します。
///
///
/// ストリームの内容はメモリ上に展開した後に使用されるため、
/// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
///
/// 読み込む対象となる Stream
/// 作成された MemoryImage を返すタスク
/// 不正な画像データが入力された場合
public async static Task CopyFromStreamAsync(Stream stream)
{
var memstream = new MemoryStream();
await stream.CopyToAsync(memstream).ConfigureAwait(false);
return new MemoryImage(memstream);
}
///
/// 指定されたバイト列から MemoryImage を作成します。
///
/// 読み込む対象となるバイト列
/// 作成された MemoryImage
/// 不正な画像データが入力された場合
[SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
public static MemoryImage CopyFromBytes(byte[] bytes)
{
return new MemoryImage(new MemoryStream(bytes));
}
}
///
/// 不正な画像データに対してスローされる例外
///
[Serializable]
public class InvalidImageException : Exception
{
public InvalidImageException() : base() { }
public InvalidImageException(string message) : base(message) { }
public InvalidImageException(string message, Exception innerException) : base(message, innerException) { }
protected InvalidImageException(SerializationInfo info, StreamingContext context) : base(info, context) { }
}
}