※当方C#も読めるというのと、C#の方が人口が多いだろうという理由でタグをつけました。
C#での回答も歓迎しております。
前提・実現したいこと
PCに接続したカメラで画像を撮影、保存するプログラムを作成しています。
ですが、たまに例外が出て保存ができない時があります。
保存できない条件が判明していないため、「こういった場合だと保存出来ないことがある」等の
アドバイスがございましたら、ご教授いただければ幸いです。
発生している問題・エラーメッセージ
GDI+ で一般的なエラーが発生しました 場所 System.Drawing.Image.Save(String filename, ImageCodecInfo encoder, EncoderParameters encoderParams) 場所 System.Drawing.Image.Save(String filename, ImageFormat format) 場所 ***.SaveShotImage() 場所 ***.vb:行 664
該当のソースコード
コード一部抜粋(保存先は本来コンフィグファイルで設定していますが、今は固定で入れています)
VB
1 Private Sub SaveShotImage() 2 Dim saveDir As String 3 Dim savePath As String 4 For Each data As DataDto In DataDtoList 5 If data.SnapShotImage Is Nothing Then Continue For 6 7 Try 8 saveDir = System.IO.Path.Combine("C:\Users\MYNAME\Desktop", Strings.Format(Now, "yyyyMMdd")) 9 If Not System.IO.Directory.Exists(saveDir) Then System.IO.Directory.CreateDirectory(saveDir) 10 11 Do 12 savePath = System.IO.Path.Combine(saveDir, Strings.Format(Now, "yyMMddHHmmss") & ".jpg") 13 If Not System.IO.File.Exists(savePath) Then Exit Do 14 Loop 15 16 data.SnapShotImage.Save(savePath, Imaging.ImageFormat.Jpeg) 'ここで落ちる 17 Catch ex As Exception 18 Throw New Exception("画像保存に失敗しました。" & ex.Message, ex) 19 End Try 20 21 data.ImageFilePath = savePath 22 Next 23 End Sub
DataDto.vb
VB
1Namespace Test 2 3 Public Class DataDto 4 5#Region "プロパティ" 6 7 ''' <summary>画像ファイルパス</summary> 8 Public Property ImageFilePath As String 9 10 ''' <summary>画像格納用(スナップショット格納用)</summary> 11 Public Property SnapShotImage As System.Drawing.Image = Nothing 12 13#End Region 14 15#Region "メソッド" 16 17 ''' <summary> 18 ''' データをコピーする 19 ''' </summary> 20 ''' <param name="target">コピー先対象</param> 21 ''' <remarks></remarks> 22 Public Sub CopyData(ByRef target As DataDto) 23 target.ImageFilePath = ImageFilePath 24 target.SnapShotImage = SnapShotImage?.Clone 25 End Sub 26 27 ''' <summary> 28 ''' データをクリアにする 29 ''' </summary> 30 ''' <remarks></remarks> 31 Public Sub Clear() 32 ImageFilePath = Nothing 33 SnapShotImage = Nothing 34 End Sub 35 36 ''' <summary> 37 ''' 同一データの作成(別インスタンス) 38 ''' </summary> 39 ''' <remarks></remarks> 40 Public Function Clone() As DataDto 41 Dim dto As New DataDto With { 42 .ImageFilePath = ImageFilePath, 43 .SnapShotImage = SnapShotImage?.Clone 44 } 45 46 Return dto 47 End Function 48 49#End Region 50 51#Region "コンストラクタ" 52 53 Public Sub New() 54 Me.Clear() 55 End Sub 56 57#End Region 58 59 End Class 60 61End Namespace
他にこういった個所のコードを開示してほしい等ありましたら随時開示いたします。
試したこと
書き込み権限が無い→保存できる時とできない時があるので権限が無いわけではなさそうです。
imageインスタンスのデータがおかしい→保存できる時とできない時でのデータに差はなさそうです。
補足情報(FW/ツールのバージョンなど)
VB 2012
.NET Framework 4
どうぞよろしくお願いいたします。
追記1
カメラの実装部分です。
VB
1Imports System.Drawing 2Imports System.Runtime.InteropServices 3 4#Region "Private変数" 5 6 Private mGrp As IGraphBuilder 'グラフ 7 Private mFlt As IBaseFilter 'キャプチャフィルタ 8 Private mPin As IPin 'キャプチャフィルタの出力ピン 9 Private mSmp As ISampleGrabber 'サンプルグラバフィルタ 10 11 Private mSize As Size '映像サイズ 12 Private mBuff As IntPtr 'ビットマップ取得用バッファ 13 14 Private mFmt As PIXELFORMATYPE 'ピクセル形式 15 16 Private mVisible As Boolean 'カメラ映像を表示するか? 17 18#End Region 19 20'----一部省略---- 21 22 Public Function snapShot() As Bitmap 23 If mGrp Is Nothing Or mSmp Is Nothing Then Throw New Exception("キャプチャーが取得できません。") 24 25 'イメージの取得 26 Try 27 '画像データサイズ取得 28 Dim bmpsz As Integer = 0 29 mSmp.GetCurrentBuffer(bmpsz, IntPtr.Zero) 30 31 '画像取得領域確保 32 Dim bmpptr As IntPtr = Marshal.AllocHGlobal(bmpsz) 33 34 'イメージ取得 35 mSmp.GetCurrentBuffer(bmpsz, bmpptr) 36 37 '画像サイズを取得 38 Dim vsz As Size 39 vsz = GetVideoSize(mGrp) 40 '描画 41 Dim bmpdata As Bitmap 42 bmpdata = New Bitmap(vsz.Width, vsz.Height, vsz.Width * 3, Imaging.PixelFormat.Format24bppRgb, bmpptr) 43 bmpdata.RotateFlip(RotateFlipType.RotateNoneFlipY) '上下反転させる 44 45 snapShot = bmpdata 46 Catch ex As Exception 47 Throw New Exception("スナップショットに失敗しました。" & " : " & ex.Message, ex) 48 End Try 49 End Function
追記2
色々調べてIDisposable実装してみました……。
これでうまく動くのが一番理想ですがまだ動きません……。
DataDto.vb
VB
1 Public Class DataDto 2 Implements IDisposable 3 4#Region "プロパティ" 5 6 ''' <summary>画像ファイルパス</summary> 7 Public Property ImageFilePath As String 8 9 ''' <summary>画像格納用(スナップショット格納用)</summary> 10 Public Property SnapShotImage As System.Drawing.Image = Nothing 11 12#End Region 13 14#Region "メソッド" 15 16 ''' <summary> 17 ''' データをコピーする 18 ''' </summary> 19 ''' <param name="target">コピー先対象</param> 20 ''' <remarks></remarks> 21 Public Sub CopyData(ByRef target As DataDto) 22 target.ImageFilePath = ImageFilePath 23 target.SnapShotImage = SnapShotImage?.Clone 24 End Sub 25 26 ''' <summary> 27 ''' データをクリアにする 28 ''' </summary> 29 ''' <remarks></remarks> 30 Public Sub Clear() 31 ImageFilePath = Nothing 32 SnapShotImage = Nothing 33 End Sub 34 35 ''' <summary> 36 ''' 同一データの作成(別インスタンス) 37 ''' </summary> 38 ''' <remarks></remarks> 39 Public Function Clone() As DataDto 40 Dim dto As New DataDto With { 41 .ImageFilePath = ImageFilePath, 42 .SnapShotImage = SnapShotImage?.Clone 43 } 44 45 Return dto 46 End Function 47 48#End Region 49 50#Region "コンストラクタ" 51 52 Public Sub New() 53 Me.Clear() 54 End Sub 55 56#End Region 57 58#Region "IDisposable Support" 59 Private disposedValue As Boolean ' 重複する呼び出しを検出するには 60 61 ' IDisposable 62 Protected Overridable Sub Dispose(disposing As Boolean) 63 If Not disposedValue Then 64 If disposing Then 65 SnapShotImage.Dispose() 66 End If 67 68 ' TODO: アンマネージド リソース (アンマネージド オブジェクト) を解放し、下の Finalize() をオーバーライドします。 69 ' TODO: 大きなフィールドを null に設定します。 70 End If 71 disposedValue = True 72 End Sub 73 74 ' TODO: 上の Dispose(disposing As Boolean) にアンマネージド リソースを解放するコードが含まれる場合にのみ Finalize() をオーバーライドします。 75 Protected Overrides Sub Finalize() 76 ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(disposing As Boolean) に記述します。 77 Dispose(False) 78 MyBase.Finalize() 79 End Sub 80 81 ' このコードは、破棄可能なパターンを正しく実装できるように Visual Basic によって追加されました。 82 Public Sub Dispose() Implements IDisposable.Dispose 83 ' このコードを変更しないでください。クリーンアップ コードを上の Dispose(disposing As Boolean) に記述します。 84 Dispose(True) 85 ' TODO: 上の Finalize() がオーバーライドされている場合は、次の行のコメントを解除してください。 86 GC.SuppressFinalize(Me) 87 End Sub 88#End Region 89 90 End Class
VB
1 Private Sub SaveShotImage() 2 Dim saveDir As String 3 Dim savePath As String 4 For Each data As DataDto In DataDtoList 5 If data.SnapShotImage Is Nothing Then Continue For 6 7 Try 8 saveDir = System.IO.Path.Combine("C:\Users\MYNAME\Desktop", Strings.Format(Now, "yyyyMMdd")) 9 If Not System.IO.Directory.Exists(saveDir) Then System.IO.Directory.CreateDirectory(saveDir) 10 11 Do 12 savePath = System.IO.Path.Combine(saveDir, Strings.Format(Now, "yyMMddHHmmss") & ".jpg") 13 If Not System.IO.File.Exists(savePath) Then Exit Do 14 Loop 15 16 Using image As New Bitmap(data.SnapShotImage) 17 image.Save(savePath, Config.ImageFormat) ' ここで落ちる 18 image.Dispose() 19 data.Dispose() 20 End Using 21 Catch ex As Exception 22 Throw New Exception("画像保存に失敗しました。" & ex.Message, ex) 23 End Try 24 25 data.ImageFilePath = savePath 26 Next 27 End Sub
回答4件
あなたの回答
tips
プレビュー