OSDN Git Service

ステータスバーに各タブの更新回数(起動時からの回数)の表示を追加
[opentween/open-tween.git] / OpenTween / MediaItem.cs
1 // OpenTween - Client of Twitter
2 // Copyright (c) 2015 spx (@5px)
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 #nullable enable
23 #pragma warning disable SA1649
24
25 using System;
26 using System.Drawing;
27 using System.IO;
28 using System.Linq;
29 using System.Threading;
30
31 namespace OpenTween
32 {
33     public interface IMediaItem : IDisposable
34     {
35         /// <summary>
36         /// メディアのID
37         /// </summary>
38         Guid Id { get; }
39
40         /// <summary>
41         /// メディアが既に破棄されているかを示す真偽値
42         /// </summary>
43         bool IsDisposed { get; }
44
45         /// <summary>
46         /// メディアへの絶対パス
47         /// </summary>
48         string Path { get; }
49
50         /// <summary>
51         /// メディア名
52         /// </summary>
53         string Name { get; }
54
55         /// <summary>
56         /// メディアの拡張子
57         /// </summary>
58         string Extension { get; }
59
60         /// <summary>
61         /// メディアが存在するかどうかを示す真偽値
62         /// </summary>
63         bool Exists { get; }
64
65         /// <summary>
66         /// メディアのサイズ(バイト単位)
67         /// </summary>
68         long Size { get; }
69
70         /// <summary>
71         /// 代替テキスト (アップロード先が対応している必要がある)
72         /// </summary>
73         string? AltText { get; set; }
74
75         /// <summary>
76         /// 表示用の MemoryImage を作成する
77         /// </summary>
78         /// <remarks>
79         /// 呼び出し側にて破棄すること
80         /// </remarks>
81         MemoryImage CreateImage();
82
83         /// <summary>
84         /// メディアの内容を読み込むための Stream を開く
85         /// </summary>
86         /// <remarks>
87         /// 呼び出し側にて閉じること
88         /// </remarks>
89         Stream OpenRead();
90
91         /// <summary>
92         /// メディアの内容を Stream へ書き込む
93         /// </summary>
94         void CopyTo(Stream stream);
95     }
96
97     /// <summary>
98     /// ファイル用の MediaItem クラス
99     /// </summary>
100     public class FileMediaItem : IMediaItem
101     {
102         public FileInfo FileInfo { get; }
103
104         public string? AltText { get; set; }
105
106         public FileMediaItem(string path)
107             => this.FileInfo = new FileInfo(path);
108
109         public FileMediaItem(FileInfo fileInfo)
110             : this(fileInfo.FullName)
111         {
112         }
113
114         public Guid Id { get; } = Guid.NewGuid();
115
116         public bool IsDisposed { get; private set; } = false;
117
118         public string Path
119             => this.FileInfo.FullName;
120
121         public string Name
122             => this.FileInfo.Name;
123
124         public string Extension
125             => this.FileInfo.Extension;
126
127         public bool Exists
128             => this.FileInfo.Exists;
129
130         public long Size
131             => this.FileInfo.Length;
132
133         public MemoryImage CreateImage()
134         {
135             using var fs = this.FileInfo.OpenRead();
136             return MemoryImage.CopyFromStream(fs);
137         }
138
139         public Stream OpenRead()
140             => this.FileInfo.OpenRead();
141
142         public void CopyTo(Stream stream)
143         {
144             using var fs = this.FileInfo.OpenRead();
145             fs.CopyTo(stream);
146         }
147
148         public void Dispose()
149         {
150             if (this.IsDisposed)
151                 return;
152
153             this.IsDisposed = true;
154         }
155     }
156
157     /// <summary>
158     /// MemoryImage 用の MediaItem クラス
159     /// </summary>
160     /// <remarks>
161     /// 用途の関係上、メモリ使用量が大きくなるため、不要になればできるだけ破棄すること
162     /// </remarks>
163     public class MemoryImageMediaItem : IMediaItem
164     {
165         public const string PathPrefix = "<>MemoryImage://";
166         private static int fileNumber = 0;
167         private readonly MemoryImage image;
168
169         public bool IsDisposed { get; private set; } = false;
170
171         public MemoryImageMediaItem(MemoryImage image)
172         {
173             this.image = image ?? throw new ArgumentNullException(nameof(image));
174
175             var num = Interlocked.Increment(ref fileNumber);
176             this.Path = PathPrefix + num + this.image.ImageFormatExt;
177         }
178
179         public Guid Id { get; } = Guid.NewGuid();
180
181         public string Path { get; }
182
183         public string? AltText { get; set; }
184
185         public string Name
186             => this.Path.Substring(PathPrefix.Length);
187
188         public string Extension
189             => this.image.ImageFormatExt;
190
191         public bool Exists
192             => this.image != null;
193
194         public long Size
195             => this.image.Stream.Length;
196
197         public MemoryImage CreateImage()
198             => this.image.Clone();
199
200         public Stream OpenRead()
201         {
202             MemoryStream? memstream = null;
203             try
204             {
205                 // コピーを作成する
206                 memstream = new MemoryStream();
207
208                 this.image.Stream.WriteTo(memstream);
209                 memstream.Seek(0, SeekOrigin.Begin);
210
211                 return memstream;
212             }
213             catch
214             {
215                 memstream?.Dispose();
216                 throw;
217             }
218         }
219
220         public void CopyTo(Stream stream)
221             => this.image.Stream.WriteTo(stream);
222
223         protected virtual void Dispose(bool disposing)
224         {
225             if (this.IsDisposed) return;
226
227             if (disposing)
228             {
229                 this.image.Dispose();
230             }
231
232             this.IsDisposed = true;
233         }
234
235         public void Dispose()
236         {
237             this.Dispose(true);
238
239             // 明示的にDisposeが呼ばれた場合はファイナライザを使用しない
240             GC.SuppressFinalize(this);
241         }
242
243         ~MemoryImageMediaItem()
244             => this.Dispose(false);
245     }
246 }