-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMaker.cs
More file actions
318 lines (260 loc) · 11.5 KB
/
Copy pathMaker.cs
File metadata and controls
318 lines (260 loc) · 11.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
using System;
using System.Collections.Generic;
using System.IO;
using System.Drawing;
using System.Text;
namespace a32system.CSProgram.AnimMaker
{
/// <summary>
/// 保存結果を表します。
/// </summary>
struct SaveResult
{
/// <summary>
/// アニメーションのフレーム数を表します。
/// </summary>
public int Count { get; set; }
/// <summary>
/// アニメーションのサイズを表します。
/// </summary>
public Size Size { get; set; }
}
/// <summary>
/// アニメーションのタイプを表します。
/// </summary>
[Flags]
enum AnimMode
{
// 値に関しては、Enum_AnimMode.txtを参照
/// <summary>
/// グレースケール
/// </summary>
GrayScale = 2,
/// <summary>
/// カラー
/// </summary>
Color = 4,
/// <summary>
/// チャンネル独立版カラー
/// </summary>
Color_2 = 8,
/// <summary>
/// 使用しないでください (内部用)
/// </summary>
WithHeader = 16,
/// <summary>
/// ヘッダ付きグレースケール
/// </summary>
GrayScaleWithHeader = 18,
/// <summary>
/// ヘッダ付きカラー
/// </summary>
ColorWithHeader = 20,
/// <summary>
/// ヘッダ付きチャンネル独立版カラー
/// </summary>
Color_2WithHeader = 24,
}
class Maker
{
// 非公開フィールド
private ConvertImageList imageList;
private Size animationSize;
// 公開フィールド
/// <summary>
/// アニメーションに追加するフレーム(コマ)画像のリストを取得します。
/// </summary>
public ConvertImageList ImageList
{
get { return this.imageList; }
}
/// <summary>
/// アニメーションのサイズを表します。
/// </summary>
public Size AnimationSize
{
get { return this.animationSize; }
set { this.animationSize = value; }
}
// 公開イベント
/// <summary>
/// SaveToStreamメソッドで1フレーム書き込まれるごとに発生します。
/// </summary>
public event EventHandler<FrameSavedEventArgs> FrameSaved;
// コンストラクタ
/// <summary>
/// 新しいMaker型オブジェクトインスタンスを初期化します。
/// </summary>
public Maker()
{
// データフィールドの初期化
this.imageList = new ConvertImageList();
this.animationSize = new Size(160, 120);
// イベントデリゲートの初期化
this.FrameSaved = delegate { };
}
// 非公開メソッド
/// <summary>
/// 指定したBinaryWriterを使用してヘッダを書き込みます。
/// </summary>
/// <param name="writer"></param>
private void _writeHeader(BinaryWriter writer, AnimMode mode)
{
// ヘッダ付きであることを表す先頭コード
writer.Write((byte) 0xFF);
writer.Write((byte) 0xFE);
// アニメのモード
writer.Write((byte) 0x00);
if ((mode & AnimMode.GrayScale) == AnimMode.GrayScale) writer.Write((byte) 0x01); // グレースケール
else if ((mode & AnimMode.Color) == AnimMode.Color) writer.Write((byte) 0x03); // カラー
else if ((mode & AnimMode.Color_2) == AnimMode.Color_2) writer.Write((byte) 0x09); // 独自形式カラー
// エンディアン反転の準備
MemoryStream ms = new MemoryStream();
BinaryWriter mbw = new BinaryWriter(ms);
byte[] mbuf;
// エンディアン反転をしてから書き込むActionを定義
Action<ushort> writeUShort = value =>
{
// MemoryStreamの頭のところに2バイトで値を書き込む
mbw.Seek(0, SeekOrigin.Begin);
mbw.Write(value);
mbw.Flush();
// byte配列へ変換し、逆の順番で書き込む
mbuf = ms.ToArray();
writer.Write(mbuf[1]);
writer.Write(mbuf[0]);
};
// 階調モード (各2バイト, 符号なし整数, 127固定)
writeUShort(0x7F);
// アニメのサイズ (各2バイト, 符号なし整数)
writeUShort((ushort) this.animationSize.Width);
writeUShort((ushort) this.animationSize.Height);
// アニメのフレーム数
writeUShort((ushort) this.imageList.Count);
writer.Flush();
}
// 公開メソッド
/// <summary>
/// 指定したストリームへグレースケールのアニメーションを出力します。
/// </summary>
/// <param name="stream"></param>
/// <returns></returns>
public SaveResult SaveToStream(Stream stream)
{
return this.SaveToStream(stream, AnimMode.GrayScale);
}
/// <summary>
/// 指定したストリームへアニメーションを出力します。
/// </summary>
/// <param name="stream"></param>
/// <param name="mode"></param>
public SaveResult SaveToStream(Stream stream, AnimMode mode)
{
// 書き込み可能かチェック
if (!stream.CanWrite)
throw new Exception("保存先には書き込み可能なストリームを設定してください。");
// BinaryWriter初期化
BinaryWriter bw = new BinaryWriter(stream);
// ストリームへのヘッダの書き込み
if ((mode & AnimMode.WithHeader) == AnimMode.WithHeader)
{
// WithHeaderフラグが指定されている
// → ヘッダを書き込む
this._writeHeader(bw, mode);
}
// アニメーションの書き込み
int i = 0;
foreach (Image img in this.imageList)
{
// img = 現在のフレーム
// 書き込み用の画像を生成
// 無理やりアニメーションのサイズにリサイズ
Bitmap canv = new Bitmap(this.animationSize.Width, this.animationSize.Height);
Graphics g = Graphics.FromImage(canv);
g.DrawImage(img, new Rectangle(0, 0, canv.Width, canv.Height));
g.Dispose();
// ストリームへのフレームの書き込み
int x, y;
if ((mode & AnimMode.GrayScale) == AnimMode.GrayScale)
{
// 輝度1チャンネル
// グレースケール
for (y = 0; y < canv.Height; y++)
for (x = 0; x < canv.Width; x++)
// 画像のx, yピクセル部分の色情報取得 → 輝度取得(0 ~ 1) → 0~127のbyte値に直して書き込み
bw.Write((byte)(canv.GetPixel(x, y).GetBrightness() * 127));
/*
* 書き込む値の値域について
*
* rawファイルの調色は128階調。これは演習の資料にも記述してあった模様。
* 終端符号が負の値になるということと128階調であることから推察するに、rawファイルには8ビットの符号付き整数で書き込まれている模様。
* 読み込んだ際にintへキャストしてから値を使用していることがクライアントのソースコードからも分かる。
*
*/
}
else if ((mode & AnimMode.Color_2) == AnimMode.Color_2)
{
// 各原色計3チャンネル
// カラーモード (開発中)
// 画像のx, yピクセル部分の色情報取得 → 各チャンネルの値(0 ~ 255) → 0 ~ 127のbyte値に直して書き込み
// Rチャンネル
for (y = 0; y < canv.Height; y++)
for (x = 0; x < canv.Width; x++)
bw.Write((byte)(Math.Max((canv.GetPixel(x, y).R / 2) - 1, 0)));
//Console.WriteLine(i + "フレーム目Rチャンネル書き込み完了");
// Gチャンネル
for (y = 0; y < canv.Height; y++)
for (x = 0; x < canv.Width; x++)
bw.Write((byte)(Math.Max((canv.GetPixel(x, y).G / 2) - 1, 0)));
//Console.WriteLine(i + "フレーム目Gチャンネル書き込み完了");
// Bチャンネル
for (y = 0; y < canv.Height; y++)
for (x = 0; x < canv.Width; x++)
bw.Write((byte)(Math.Max((canv.GetPixel(x, y).B / 2) - 1, 0)));
//Console.WriteLine(i + "フレーム目Bチャンネル書き込み完了");
}
else if ((mode & AnimMode.Color) == AnimMode.Color)
{
// 各原色計3チャンネル
// RGB順番に書き込む
for (y = 0; y < canv.Height; y++)
for (x = 0; x < canv.Width; x++)
{
Color pixel = canv.GetPixel(x, y);
bw.Write((byte)(Math.Max((pixel.R / 2) - 1, 0)));
bw.Write((byte)(Math.Max((pixel.G / 2) - 1, 0)));
bw.Write((byte)(Math.Max((pixel.B / 2) - 1, 0)));
}
}
// イベントを発生する
this.FrameSaved(this, new FrameSavedEventArgs() { Count = i });
// カウントアップ
i++;
}
// 終端符号の書き込み
// → 先頭ビットが負の符号を示すような値を書き込む。
// → …… 200ぐらい?(適当)
bw.Write((byte) 200);
// BinaryWriterをFlush
// → Closeすると元のStreamまで閉じられてしまい、このメソッド利用後にStreamを利用できなくなってしまうため
bw.Flush();
// SaveResultの初期化
// SaveResult構造体は、このメソッドの戻り値専用の型。書き込まれたフレーム数とアニメーションの縦横サイズを格納する。
SaveResult result = new SaveResult()
{
Count = this.imageList.Count,
Size = this.animationSize,
};
// SaveResultを返す
return result;
}
// 内部クラス
public class FrameSavedEventArgs : EventArgs
{
/// <summary>
/// 書き込みが完了したフレームの番号
/// </summary>
public int Count { get; set; }
}
}
}