OSDN Git Service

Dispose不要のメソッドにSuppressMessage属性を追加 (CA2000)
[opentween/open-tween.git] / OpenTween / MemoryImage.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2013 kim_upsilon (@kim_upsilon) <https://upsilo.net/~upsilon/>
3 // All rights reserved.
4 //
5 // This file is part of OpenTween.
6 //
7 // This program is free software; you can redistribute it and/or modify it
8 // under the terms of the GNU General Public License as published by the Free
9 // Software Foundation; either version 3 of the License, or (at your option)
10 // any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14 // or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 // for more details.
16 //
17 // You should have received a copy of the GNU General Public License along
18 // with this program. If not, see <http://www.gnu.org/licenses/>, or write to
19 // the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
20 // Boston, MA 02110-1301, USA.
21
22 using System;
23 using System.Collections.Generic;
24 using System.Linq;
25 using System.Runtime.InteropServices;
26 using System.Runtime.Serialization;
27 using System.Text;
28 using System.Diagnostics.CodeAnalysis;
29 using System.Drawing;
30 using System.IO;
31 using System.Threading.Tasks;
32
33 namespace OpenTween
34 {
35     /// <summary>
36     /// Image と Stream を対に保持するためのクラス
37     /// </summary>
38     /// <remarks>
39     /// Image.FromStream() を使用して Image を生成する場合、
40     /// Image を破棄するまでの間は元となった Stream を破棄できないためその対策として使用する。
41     /// </remarks>
42     public class MemoryImage : ICloneable, IDisposable
43     {
44         public readonly Stream Stream;
45         public readonly Image Image;
46
47         protected bool disposed = false;
48
49         /// <exception cref="InvalidImageException">
50         /// ストリームから読みだされる画像データが不正な場合にスローされる
51         /// </exception>
52         protected MemoryImage(Stream stream)
53         {
54             try
55             {
56                 this.Image = Image.FromStream(stream);
57             }
58             catch (ArgumentException e)
59             {
60                 stream.Dispose();
61                 throw new InvalidImageException("Invalid image", e);
62             }
63             catch (OutOfMemoryException e)
64             {
65                 // GDI+ がサポートしない画像形式で OutOfMemoryException がスローされる場合があるらしい
66                 stream.Dispose();
67                 throw new InvalidImageException("Invalid image?", e);
68             }
69             catch (ExternalException e)
70             {
71                 // 「GDI+ で汎用エラーが発生しました」という大雑把な例外がスローされる場合があるらしい
72                 stream.Dispose();
73                 throw new InvalidImageException("Invalid image?", e);
74             }
75             catch (Exception)
76             {
77                 stream.Dispose();
78                 throw;
79             }
80
81             this.Stream = stream;
82         }
83
84         /// <summary>
85         /// MemoryImage インスタンスを複製します
86         /// </summary>
87         /// <remarks>
88         /// メソッド実行中にストリームのシークが行われないよう注意して下さい。
89         /// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
90         /// </remarks>
91         /// <returns>複製された MemoryImage</returns>
92         public MemoryImage Clone()
93         {
94             this.Stream.Seek(0, SeekOrigin.Begin);
95
96             return MemoryImage.CopyFromStream(this.Stream);
97         }
98
99         /// <summary>
100         /// MemoryImage インスタンスを非同期に複製します
101         /// </summary>
102         /// <remarks>
103         /// メソッド実行中にストリームのシークが行われないよう注意して下さい。
104         /// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
105         /// </remarks>
106         /// <returns>複製された MemoryImage を返すタスク</returns>
107         public Task<MemoryImage> CloneAsync()
108         {
109             this.Stream.Seek(0, SeekOrigin.Begin);
110
111             return MemoryImage.CopyFromStreamAsync(this.Stream);
112         }
113
114         object ICloneable.Clone()
115         {
116             return this.Clone();
117         }
118
119         protected virtual void Dispose(bool disposing)
120         {
121             if (this.disposed) return;
122
123             if (disposing)
124             {
125                 this.Image.Dispose();
126                 this.Stream.Dispose();
127             }
128
129             this.disposed = true;
130         }
131
132         public void Dispose()
133         {
134             this.Dispose(true);
135
136             // 明示的にDisposeが呼ばれた場合はファイナライザを使用しない
137             GC.SuppressFinalize(this);
138         }
139
140         ~MemoryImage()
141         {
142             this.Dispose(false);
143         }
144
145         /// <summary>
146         /// 指定された Stream から MemoryImage を作成します。
147         /// </summary>
148         /// <remarks>
149         /// ストリームの内容はメモリ上に展開した後に使用されるため、
150         /// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
151         /// </remarks>
152         /// <param name="stream">読み込む対象となる Stream</param>
153         /// <returns>作成された MemoryImage</returns>
154         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
155         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
156         public static MemoryImage CopyFromStream(Stream stream)
157         {
158             var memstream = new MemoryStream();
159
160             stream.CopyTo(memstream);
161
162             return new MemoryImage(memstream);
163         }
164
165         /// <summary>
166         /// 指定された Stream から MemoryImage を非同期に作成します。
167         /// </summary>
168         /// <remarks>
169         /// ストリームの内容はメモリ上に展開した後に使用されるため、
170         /// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
171         /// </remarks>
172         /// <param name="stream">読み込む対象となる Stream</param>
173         /// <returns>作成された MemoryImage を返すタスク</returns>
174         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
175         public async static Task<MemoryImage> CopyFromStreamAsync(Stream stream)
176         {
177             var memstream = new MemoryStream();
178
179             await stream.CopyToAsync(memstream).ConfigureAwait(false);
180
181             return new MemoryImage(memstream);
182         }
183
184         /// <summary>
185         /// 指定されたバイト列から MemoryImage を作成します。
186         /// </summary>
187         /// <param name="bytes">読み込む対象となるバイト列</param>
188         /// <returns>作成された MemoryImage</returns>
189         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
190         [SuppressMessage("Microsoft.Reliability", "CA2000:DisposeObjectsBeforeLosingScope")]
191         public static MemoryImage CopyFromBytes(byte[] bytes)
192         {
193             return new MemoryImage(new MemoryStream(bytes));
194         }
195     }
196
197     /// <summary>
198     /// 不正な画像データに対してスローされる例外
199     /// </summary>
200     [Serializable]
201     public class InvalidImageException : Exception
202     {
203         public InvalidImageException() : base() { }
204         public InvalidImageException(string message) : base(message) { }
205         public InvalidImageException(string message, Exception innerException) : base(message, innerException) { }
206         protected InvalidImageException(SerializationInfo info, StreamingContext context) : base(info, context) { }
207     }
208 }