質問編集履歴

2

別解決方法のソース追加

2015/09/29 07:16

投稿

退会済みユーザー
test CHANGED
File without changes
test CHANGED
@@ -197,3 +197,397 @@
197
197
  ただ稀にこの待機処理を通しても正しく読み込まれない( 又は完全にファイルクローズする前にアクセスしている? )事があるらしく挙動がおかしくなることがあります.
198
198
 
199
199
  なのでもう少し何かしらの解決策が無いか調べてみようと思います.
200
+
201
+
202
+
203
+
204
+
205
+ 今のところCaptureScreenshot()のデータ書き込みを検知する方法が見つからないのでsho_csさんの回答の別の取り方を参考にソースを組み直しました.
206
+
207
+ コルーチン内で1ピクセルずつデータを取り出しTexture2Dにしてそれをコールバックで返してから別スレッドでそのファイルを保存することで安定して動かすことが出来ました.
208
+
209
+ 別スレッドではなくコルーチン内で画像を作成しているのはUnityのクラスはどうやら別スレッドから操作できないらしくメインスレッド内で画像を作成する必要が出てきたからです.
210
+
211
+
212
+
213
+ タイトルとは違う解決方法になりましたが今回はこの方法で解決ということにしました.
214
+
215
+ ```C#
216
+
217
+ using UnityEngine;
218
+
219
+ using System.Collections;
220
+
221
+ using System.IO;
222
+
223
+ using System.Collections.Generic;
224
+
225
+ using System;
226
+
227
+ using System.Threading; // スレッド使用.
228
+
229
+
230
+
231
+
232
+
233
+ // スクリーンショット撮影クラス.
234
+
235
+ // 現在PC上ではできるがAndroidではうまく動かない.
236
+
237
+ // スクリーンショットの撮影時点でエラーが発生する.
238
+
239
+ public class ScreenCapture{
240
+
241
+
242
+
243
+
244
+
245
+ //--- クラス宣言 ---
246
+
247
+ private class CaptureInfo{
248
+
249
+
250
+
251
+ private string path;
252
+
253
+ private string id;
254
+
255
+ private bool isFinished;
256
+
257
+ private Texture2D tex;
258
+
259
+
260
+
261
+ public string Path { get{ return this.path; } }
262
+
263
+ public string Id { get{ return this.id; } }
264
+
265
+ public bool IsFinished { get{ return this.isFinished; } }
266
+
267
+ public Texture2D Tex { get{ return this.tex; } }
268
+
269
+
270
+
271
+ public CaptureInfo(
272
+
273
+ string path,
274
+
275
+ string id,
276
+
277
+ Texture2D tex ){
278
+
279
+ this.path = path;
280
+
281
+ this.id = id;
282
+
283
+ this.tex = tex;
284
+
285
+ this.isFinished = false;
286
+
287
+ }
288
+
289
+
290
+
291
+ public void finish(){
292
+
293
+ this.isFinished = true;
294
+
295
+ }
296
+
297
+
298
+
299
+ }
300
+
301
+
302
+
303
+
304
+
305
+ //--- 定数 ---
306
+
307
+ private const string PICTURE_EXTENSION = ".png";
308
+
309
+
310
+
311
+ //--- 変数&プロパティ ---
312
+
313
+ public delegate void CallBackTex2D( Texture2D tex, string filePath ); // コールバック( Texture2D ver ).
314
+
315
+ public delegate void CallBackSprite( Sprite spr, string filePath ); // コールバック( Sprite ver ).
316
+
317
+ private Dictionary< string, CaptureInfo > captureList; // キャプチャ情報リスト.
318
+
319
+
320
+
321
+
322
+
323
+ //--- メソッド ---
324
+
325
+
326
+
327
+ public ScreenCapture(){
328
+
329
+
330
+
331
+ this.captureList = new Dictionary< string, CaptureInfo >();
332
+
333
+ }
334
+
335
+
336
+
337
+
338
+
339
+
340
+
341
+ // スクリーンショットを撮影し,コールバックでTexture2Dとファイルパスを返す.
342
+
343
+ public void captureScreenshot(
344
+
345
+ MonoBehaviour mono,
346
+
347
+ CallBackTex2D callback,
348
+
349
+ string fileName,
350
+
351
+ string folderPath = "",
352
+
353
+ bool isOverWrite = false ){
354
+
355
+
356
+
357
+ mono.StartCoroutine( captureScreenshotCor( callback, fileName, folderPath, isOverWrite ) );
358
+
359
+ }
360
+
361
+ private IEnumerator captureScreenshotCor(
362
+
363
+ CallBackTex2D callback,
364
+
365
+ string fileName,
366
+
367
+ string folderName,
368
+
369
+ bool isOverWrite ){
370
+
371
+
372
+
373
+ #if !UNITY_EDITOR && UNITY_ANDROID
374
+
375
+ // 出力パス( 指定したフォルダが無ければ作成 ).
376
+
377
+ folderName = ( folderName != "" ) ? folderName + "/" : Application.productName + "Images/";
378
+
379
+ {
380
+
381
+ string folderPath = Application.persistentDataPath + "/" + folderName;
382
+
383
+ if ( !Directory.Exists( folderPath ) ){
384
+
385
+ Directory.CreateDirectory( folderPath );
386
+
387
+ }
388
+
389
+ }
390
+
391
+
392
+
393
+ fileName += PICTURE_EXTENSION;
394
+
395
+ string filePath = Application.persistentDataPath + "/" + folderName + fileName; // 最終的な保存先.
396
+
397
+
398
+
399
+ yield return new WaitForEndOfFrame();
400
+
401
+
402
+
403
+ // 撮影.
404
+
405
+ Texture2D tex = new Texture2D( Screen.width, Screen.height, TextureFormat.ARGB32, false );
406
+
407
+ tex.ReadPixels( new Rect( 0, 0, Screen.width, Screen.height ), 0, 0, false );
408
+
409
+ tex.Apply();
410
+
411
+
412
+
413
+ // キャプチャ用の情報を作成.
414
+
415
+ string captureID = this.getNowTimeString();
416
+
417
+ CaptureInfo info = new CaptureInfo( filePath, captureID, tex );
418
+
419
+ this.captureList.Add( captureID, info );
420
+
421
+
422
+
423
+ // コールバックでスプライトを先に渡す.
424
+
425
+ callback( tex, filePath );
426
+
427
+
428
+
429
+ // 別スレッドを作成しそっちで保存.
430
+
431
+ Thread thread = new Thread( new ParameterizedThreadStart( this.saveCaptureImage ) );
432
+
433
+ thread.Start( captureID );
434
+
435
+ while ( !this.captureList[ captureID ].IsFinished ){
436
+
437
+ yield return new WaitForSeconds( 0 );
438
+
439
+ }
440
+
441
+ #endif
442
+
443
+
444
+
445
+ yield return new WaitForEndOfFrame();
446
+
447
+ }
448
+
449
+
450
+
451
+
452
+
453
+
454
+
455
+ // 指定したパスのバイナリデータをbyte型配列で返す.
456
+
457
+ private byte[] readBinary(
458
+
459
+ string path ){
460
+
461
+
462
+
463
+ byte[] bytes = ( File.Exists( path ) ) ? File.ReadAllBytes( path ) : null;
464
+
465
+ if ( bytes == null )
466
+
467
+ Debug.LogError( "ファイルが存在しません." );
468
+
469
+ return bytes;
470
+
471
+ }
472
+
473
+
474
+
475
+
476
+
477
+ // 指定したパス,サイズのTexture2Dを作成し,返す.
478
+
479
+ private Texture2D readTexture2D(
480
+
481
+ string path,
482
+
483
+ int width,
484
+
485
+ int height ){
486
+
487
+
488
+
489
+ byte[] data = this.readBinary( path );
490
+
491
+ Texture2D tex = new Texture2D( width, height );
492
+
493
+ tex.LoadImage( data );
494
+
495
+
496
+
497
+ return tex;
498
+
499
+ }
500
+
501
+
502
+
503
+
504
+
505
+ // 指定したパス,サイズのスプライトを作成し,返す.
506
+
507
+ private Sprite readSprite(
508
+
509
+ string path,
510
+
511
+ int width,
512
+
513
+ int height ){
514
+
515
+
516
+
517
+ Texture2D tex = this.readTexture2D( path, width, height );
518
+
519
+ Sprite spr = Sprite.Create( tex, new Rect( 0, 0, width, height ), Vector2.zero );
520
+
521
+
522
+
523
+ return spr;
524
+
525
+ }
526
+
527
+
528
+
529
+
530
+
531
+
532
+
533
+ // 現在時刻のストリングを取得.
534
+
535
+ // フォーマット : YY-MM-DD-OO-MM-SS.
536
+
537
+ private string getNowTimeString(){
538
+
539
+
540
+
541
+ string ret = DateTime.Now.Year.ToString() + "-";
542
+
543
+ ret += DateTime.Now.Month.ToString() + "-";
544
+
545
+ ret += DateTime.Now.Day.ToString() + "-";
546
+
547
+ ret += DateTime.Now.Hour.ToString() + "-";
548
+
549
+ ret += DateTime.Now.Minute.ToString() + "-";
550
+
551
+ ret += DateTime.Now.Second.ToString();
552
+
553
+ return ret;
554
+
555
+ }
556
+
557
+
558
+
559
+
560
+
561
+
562
+
563
+ // 指定されたIDの画像を保存( 別スレッドで起動 ).
564
+
565
+ private void saveCaptureImage(
566
+
567
+ object id ){
568
+
569
+
570
+
571
+ string captureID = ( string )id;
572
+
573
+ CaptureInfo info = this.captureList[ captureID ];
574
+
575
+
576
+
577
+
578
+
579
+ // 画像を保存.
580
+
581
+ byte[] byteData = this.captureList[ captureID ].Tex.EncodeToPNG();
582
+
583
+ File.WriteAllBytes( this.captureList[ captureID ].Path, byteData );
584
+
585
+ this.captureList[ captureID ].finish();
586
+
587
+ }
588
+
589
+
590
+
591
+ }
592
+
593
+ ```

1

参考サイトをもとに書き直したソースの追加.

2015/09/29 07:16

投稿

退会済みユーザー
test CHANGED
File without changes
test CHANGED
@@ -75,3 +75,125 @@
75
75
  又それらの方法が無い場合の代替案としてはどのようなものが有るのでしょうか?
76
76
 
77
77
  よろしくお願いします.
78
+
79
+
80
+
81
+
82
+
83
+ **sho_csさんの紹介した参考ページの情報をもとにプログラム組み直してみました.**
84
+
85
+ 待機する処理は指定のファイルが有るか否か,そのファイルを開くことができるかどうかで二重にチェックをかけ.
86
+
87
+ ファイルが存在していてファイルへのアクセスができない間は待機する...というようにしました.
88
+
89
+ ```lang-C#
90
+
91
+ private IEnumerator captureScreenshotCor(
92
+
93
+ CallBackSprite callback,
94
+
95
+ string fileName,
96
+
97
+ string folderName,
98
+
99
+ bool fileOverWrite ){
100
+
101
+
102
+
103
+
104
+
105
+ // 出力パス( 指定したフォルダが無ければ作成 ).
106
+
107
+ folderName = ( folderName != "" ) ? folderName + "/" : Application.productName + "Images/";
108
+
109
+ {
110
+
111
+ string folderPath = Application.persistentDataPath + "/" + folderName;
112
+
113
+ if ( !Directory.Exists( folderPath ) ){
114
+
115
+ Directory.CreateDirectory( folderPath );
116
+
117
+ }
118
+
119
+ }
120
+
121
+
122
+
123
+ fileName += PICTURE_EXTENSION;
124
+
125
+ Application.CaptureScreenshot( folderName + fileName );
126
+
127
+ string filePath = Application.persistentDataPath + "/" + folderName + fileName; // 最終的な保存先.
128
+
129
+
130
+
131
+ // ファイルが存在していて且つアクセス可能になったらファイルの保存処理が終了している.
132
+
133
+ bool isFileComplete = false;
134
+
135
+ while ( !isFileComplete ){
136
+
137
+
138
+
139
+ Debug.Log( "Saving !! " );
140
+
141
+ yield return new WaitForEndOfFrame();
142
+
143
+
144
+
145
+ bool isFileExists = File.Exists( filePath );
146
+
147
+ bool isFileLocked = false;;
148
+
149
+ FileStream stream = null;
150
+
151
+ try{
152
+
153
+ stream = new FileStream( filePath, FileMode.Open, FileAccess.ReadWrite, FileShare.None );
154
+
155
+ }catch{
156
+
157
+ Debug.Log( "ファイルがロックされているか又は開けない." );
158
+
159
+ isFileLocked = true;
160
+
161
+ }finally{
162
+
163
+ if ( stream != null )
164
+
165
+ stream.Close();
166
+
167
+ }
168
+
169
+
170
+
171
+
172
+
173
+ isFileComplete = ( isFileExists == true && isFileLocked != true ) ? true : false;
174
+
175
+ }
176
+
177
+
178
+
179
+
180
+
181
+ // コールバック用スプライト作成及びコールバク呼び出し.
182
+
183
+ Sprite spr = this.readSprite( filePath, Screen.width, Screen.height );
184
+
185
+ callback( spr, filePath );
186
+
187
+
188
+
189
+ yield return null;
190
+
191
+ }
192
+
193
+ ```
194
+
195
+ 一応これで動くようにはなりました.
196
+
197
+ ただ稀にこの待機処理を通しても正しく読み込まれない( 又は完全にファイルクローズする前にアクセスしている? )事があるらしく挙動がおかしくなることがあります.
198
+
199
+ なのでもう少し何かしらの解決策が無いか調べてみようと思います.