// OpenTween - Client of Twitter // Copyright (c) 2015 spx (@5px) // 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.Drawing; using System.IO; using System.Linq; using System.Threading; namespace OpenTween { public interface IMediaItem { /// /// メディアへの絶対パス /// string Path { get; } /// /// メディア名 /// string Name { get; } /// /// メディアの拡張子 /// string Extension { get; } /// /// メディアが存在するかどうかを示す真偽値 /// bool Exists { get; } /// /// メディアのサイズ(バイト単位) /// long Size { get; } /// /// メディアが画像であるかどうかを示す真偽値 /// bool IsImage { get; } /// /// 代替テキスト (アップロード先が対応している必要がある) /// string AltText { get; set; } /// /// 表示用の MemoryImage を作成する /// /// /// 呼び出し側にて破棄すること /// MemoryImage CreateImage(); /// /// メディアの内容を読み込むための Stream を開く /// /// /// 呼び出し側にて閉じること /// Stream OpenRead(); /// /// メディアの内容を Stream へ書き込む /// void CopyTo(Stream stream); } /// /// ファイル用の MediaItem クラス /// public class FileMediaItem : IMediaItem { public FileInfo FileInfo { get; } public string AltText { get; set; } public FileMediaItem(string path) { this.FileInfo = new FileInfo(path); } public FileMediaItem(FileInfo fileInfo) : this(fileInfo.FullName) { } public string Path { get { return this.FileInfo.FullName; } } public string Name { get { return this.FileInfo.Name; } } public string Extension { get { return this.FileInfo.Extension; } } public bool Exists { get { return this.FileInfo.Exists; } } public long Size { get { return this.FileInfo.Length; } } public bool IsImage { get { if (this.isImage == null) { try { // MemoryImage が生成できるかを検証する using (var image = this.CreateImage()) { } this.isImage = true; } catch (InvalidImageException) { this.isImage = false; } } return this.isImage.Value; } } /// IsImage の検証結果をキャッシュする。未検証なら null private bool? isImage = null; public MemoryImage CreateImage() { using (var fs = this.FileInfo.OpenRead()) { return MemoryImage.CopyFromStream(fs); } } public Stream OpenRead() { return this.FileInfo.OpenRead(); } public void CopyTo(Stream stream) { using (var fs = this.FileInfo.OpenRead()) { fs.CopyTo(stream); } } } /// /// MemoryImage 用の MediaItem クラス /// /// /// 用途の関係上、メモリ使用量が大きくなるため、不要になればできるだけ破棄すること /// public class MemoryImageMediaItem : IMediaItem, IDisposable { public const string PathPrefix = "<>MemoryImage://"; private static int _fileNumber = 0; private bool _disposed = false; private readonly MemoryImage _image; public MemoryImageMediaItem(MemoryImage image) { this._image = image ?? throw new ArgumentNullException(nameof(image)); var num = Interlocked.Increment(ref _fileNumber); this.Path = PathPrefix + num + this._image.ImageFormatExt; } public string Path { get; } public string AltText { get; set; } public string Name { get { return this.Path.Substring(PathPrefix.Length); } } public string Extension { get { return this._image.ImageFormatExt; } } public bool Exists { get { return this._image != null; } } public long Size { get { return this._image.Stream.Length; } } public bool IsImage { get { return true; } } public bool IsDisposed { get { return this._disposed; } } public MemoryImage CreateImage() { return this._image.Clone(); } public Stream OpenRead() { MemoryStream memstream = null; try { // コピーを作成する memstream = new MemoryStream(); this._image.Stream.WriteTo(memstream); memstream.Seek(0, SeekOrigin.Begin); return memstream; } catch { memstream?.Dispose(); throw; } } public void CopyTo(Stream stream) { this._image.Stream.WriteTo(stream); } protected virtual void Dispose(bool disposing) { if (this._disposed) return; if (disposing) { this._image.Dispose(); } this._disposed = true; } public void Dispose() { this.Dispose(true); // 明示的にDisposeが呼ばれた場合はファイナライザを使用しない GC.SuppressFinalize(this); } ~MemoryImageMediaItem() => this.Dispose(false); } }