OSDN Git Service

PostClass.Mediaを1つのURLごとに複数の画像URLを保持できるように修正
[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.Drawing;
29 using System.IO;
30 using System.Threading.Tasks;
31
32 namespace OpenTween
33 {
34     /// <summary>
35     /// Image と Stream を対に保持するためのクラス
36     /// </summary>
37     /// <remarks>
38     /// Image.FromStream() を使用して Image を生成する場合、
39     /// Image を破棄するまでの間は元となった Stream を破棄できないためその対策として使用する。
40     /// </remarks>
41     public class MemoryImage : ICloneable, IDisposable
42     {
43         public readonly Stream Stream;
44         public readonly Image Image;
45
46         protected bool disposed = false;
47
48         /// <exception cref="InvalidImageException">
49         /// ストリームから読みだされる画像データが不正な場合にスローされる
50         /// </exception>
51         protected MemoryImage(Stream stream)
52         {
53             try
54             {
55                 this.Image = Image.FromStream(stream);
56             }
57             catch (ArgumentException e)
58             {
59                 stream.Dispose();
60                 throw new InvalidImageException("Invalid image", e);
61             }
62             catch (OutOfMemoryException e)
63             {
64                 // GDI+ がサポートしない画像形式で OutOfMemoryException がスローされる場合があるらしい
65                 stream.Dispose();
66                 throw new InvalidImageException("Invalid image?", e);
67             }
68             catch (ExternalException e)
69             {
70                 // 「GDI+ で汎用エラーが発生しました」という大雑把な例外がスローされる場合があるらしい
71                 stream.Dispose();
72                 throw new InvalidImageException("Invalid image?", e);
73             }
74             catch (Exception)
75             {
76                 stream.Dispose();
77                 throw;
78             }
79
80             this.Stream = stream;
81         }
82
83         /// <summary>
84         /// MemoryImage インスタンスを複製します
85         /// </summary>
86         /// <remarks>
87         /// メソッド実行中にストリームのシークが行われないよう注意して下さい。
88         /// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
89         /// </remarks>
90         /// <returns>複製された MemoryImage</returns>
91         public MemoryImage Clone()
92         {
93             this.Stream.Seek(0, SeekOrigin.Begin);
94
95             return MemoryImage.CopyFromStream(this.Stream);
96         }
97
98         /// <summary>
99         /// MemoryImage インスタンスを非同期に複製します
100         /// </summary>
101         /// <remarks>
102         /// メソッド実行中にストリームのシークが行われないよう注意して下さい。
103         /// 特に PictureBox で Gif アニメーションを表示している場合は Enabled に false をセットするなどして更新を止めて下さい。
104         /// </remarks>
105         /// <returns>複製された MemoryImage を返すタスク</returns>
106         public Task<MemoryImage> CloneAsync()
107         {
108             this.Stream.Seek(0, SeekOrigin.Begin);
109
110             return MemoryImage.CopyFromStreamAsync(this.Stream);
111         }
112
113         object ICloneable.Clone()
114         {
115             return this.Clone();
116         }
117
118         protected virtual void Dispose(bool disposing)
119         {
120             if (this.disposed) return;
121
122             if (disposing)
123             {
124                 this.Image.Dispose();
125                 this.Stream.Dispose();
126             }
127
128             this.disposed = true;
129         }
130
131         public void Dispose()
132         {
133             this.Dispose(true);
134
135             // 明示的にDisposeが呼ばれた場合はファイナライザを使用しない
136             GC.SuppressFinalize(this);
137         }
138
139         ~MemoryImage()
140         {
141             this.Dispose(false);
142         }
143
144         /// <summary>
145         /// 指定された Stream から MemoryImage を作成します。
146         /// </summary>
147         /// <remarks>
148         /// ストリームの内容はメモリ上に展開した後に使用されるため、
149         /// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
150         /// </remarks>
151         /// <param name="stream">読み込む対象となる Stream</param>
152         /// <returns>作成された MemoryImage</returns>
153         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
154         public static MemoryImage CopyFromStream(Stream stream)
155         {
156             var memstream = new MemoryStream();
157
158             stream.CopyTo(memstream);
159
160             return new MemoryImage(memstream);
161         }
162
163         /// <summary>
164         /// 指定された Stream から MemoryImage を非同期に作成します。
165         /// </summary>
166         /// <remarks>
167         /// ストリームの内容はメモリ上に展開した後に使用されるため、
168         /// 引数に指定した Stream を MemoryImage より先に破棄しても問題ありません。
169         /// </remarks>
170         /// <param name="stream">読み込む対象となる Stream</param>
171         /// <returns>作成された MemoryImage を返すタスク</returns>
172         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
173         public async static Task<MemoryImage> CopyFromStreamAsync(Stream stream)
174         {
175             var memstream = new MemoryStream();
176
177             await stream.CopyToAsync(memstream).ConfigureAwait(false);
178
179             return new MemoryImage(memstream);
180         }
181
182         /// <summary>
183         /// 指定されたバイト列から MemoryImage を作成します。
184         /// </summary>
185         /// <param name="bytes">読み込む対象となるバイト列</param>
186         /// <returns>作成された MemoryImage</returns>
187         /// <exception cref="InvalidImageException">不正な画像データが入力された場合</exception>
188         public static MemoryImage CopyFromBytes(byte[] bytes)
189         {
190             return new MemoryImage(new MemoryStream(bytes));
191         }
192     }
193
194     /// <summary>
195     /// 不正な画像データに対してスローされる例外
196     /// </summary>
197     public class InvalidImageException : Exception
198     {
199         public InvalidImageException() : base() { }
200         public InvalidImageException(string message) : base(message) { }
201         public InvalidImageException(string message, Exception innerException) : base(message, innerException) { }
202         public InvalidImageException(SerializationInfo info, StreamingContext context) : base(info, context) { }
203     }
204 }