保存前にJPEGの実サイズを取得するには?

解決


ぺそみ  2007-08-27 22:36:54  No: 137264

いつもお世話になっております。

開発環境は
 ・Windows XP
 ・VB6.0(SP6)
です。

PictureBoxに描画したイメージをGDI+を使用し、あるフォルダへ保存する処理を作っております。
ソースは、以下の通りです。
------------------------------------------------------------
'//GDI+を起動する
rGdiplusStartupInput.GdiplusVersion = 1
rRet = GdiplusStartup(lGDIPToken, rGdiplusStartupInput, 0&)
If (rRet <> GDIPlusStatusConstants.Ok) Then
    GoTo LABexit
End If
    
    
'// GID+BITMAPに変換する
rRet = GdipCreateBitmapFromHBITMAP(ffrmPreview.picPreview.Image.Handle, 0&, lBitmap)
If (rRet = GDIPlusStatusConstants.Ok) Then
    '// JPEGに変換しイメージを出力する
    rEncoderParameters.Count = 1
    With rEncoderParameters.Parameter(0)
        CLSIDFromString StrPtr(Chr(123) & "1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}"), rUUID       
        .Guid = rUUID
        .NumberOfValues = 1
        .TypeAPI = 4
        .Value = VarPtr(conQuality)     
    End With
        
    CLSIDFromString StrPtr(Chr(123) & "557CF401-1A04-11D3-9A73-0000F81EF32E}"), rUUID           
    rRet = GdipSaveImageToFile(lBitmap, StrPtr(sFileName), rUUID, VarPtr(rEncoderParameters))
        
    '// GDI+BITMAPを破棄する
    GdipDisposeImage lBitmap
End If
    
'// GDI+を終了する
GdiplusShutdown lGDIPToken
------------------------------------------------------------

GdipSaveImageToFile で保存する前に
JPEGファイルのサイズとメモリ空き容量を比較し保存可能かチェックを行いたいのですが、
JPEGファイルのサイズの取得方法、色々調べましたが分かりませんでした。

ご存じの方がおいででしたら、ご教授お願い致します。


魔界の仮面弁士  2007-08-27 23:52:10  No: 137265

> PictureBoxに描画したイメージをGDI+を使用し
描画そのものは、(GDI+ではなく) GDI を使っているのですね。

> StrPtr(Chr(123) & "557CF401-1A04-11D3-9A73-0000F81EF32E}")
ここは素直に、
 StrPtr("{557CF401-1A04-11D3-9A73-0000F81EF32E}")
で良いと思いますよ。

# 私の blog を参考にしたのであれば、あそこで Chr(123) が使われているのは、
# yaplog の制限で {…} 形式の文字列を使えないことによる苦肉の策なので。

> JPEGファイルのサイズの取得方法、色々調べましたが分かりませんでした。
画像の縦横サイズという意味であれば、.Image.Width / .Height 等で。

ファイルサイズの意味であれば、実際に圧縮してみないと得られないので、
GdipSaveImageToFile API を用いるのをやめて、かわりに 
GdipSaveImageToStream でストリーム経由で保存するようにすれば、
そこからサイズを調べることもできるかと思います。


ぺそみ  2007-08-28 02:02:47  No: 137266

魔界の仮面弁士さん、早速のご回答ありがとうございます。

> ここは素直に、
>  StrPtr("{557CF401-1A04-11D3-9A73-0000F81EF32E}")
> で良いと思いますよ。
ご指摘の通り、魔界の仮面弁士さんの掲載内容を参考にさせて頂きました。
修正します。

> ファイルサイズの意味であれば、
質問の仕方が悪かったようで、すみません。
ファイルサイズの取得で悩んでおります。

> GdipSaveImageToFile API を用いるのをやめて、かわりに 
> GdipSaveImageToStream でストリーム経由で保存するようにすれば、
> そこからサイズを調べることもできるかと思います。
教えて頂きました GdipSaveImageToStream の使い方を
よければ教えて頂けないでしょうか?

使用した事が無いのでネットで検索したのですが分かりませんでした。
再度、ご教授お願い致します。


魔界の仮面弁士  2007-08-28 03:33:36  No: 137267

> .Value = VarPtr(conQuality)
これ、conQuality を Long 型にしておいてくださいね。

> 教えて頂きました GdipSaveImageToStream の使い方を
> よければ教えて頂けないでしょうか?

引数宣言は、GdipSaveImageToFile とほとんど一緒です。
第2引数が ByVal String から ByVal IStream になるだけで。

で、サイズを得る部分に関してはこんな感じ。

  Dim stm As ADODB.Stream
  Set stm = New ADODB.Stream
  stm.Type = adTypeBinary
  stm.Open

  Dim o As IStream
  Set o = stm
  ret = GdipSaveImageToStream(hGdipBmp, o, ConvCLSID(CLSID_JPEG), VarPtr(EncodParameters))

  '★ファイルサイズを得る
  fileSize = stm.Size

  '★ストリームからファイル化
  stm.Position = 0
  stm.SaveToFile FName, adSaveCreateOverWrite

  stm.Close
  Set stm = Nothing


ぺそみ  2007-08-28 23:44:03  No: 137268

魔界の仮面弁士さん、再度のご回答ありがとうございます。

教えて頂いたサンプルを参考に再度チャレンジしてみましたが、
上手く行きませんでした。

まず、
> Dim o As IStream
は、VB6.0では利用できないようなので
CreateStreamOnHGlobal で IStream を作成するように変更してみました。

自分なりに調査して作ったソースを以下に記載します。
教えて頂いたサンプルと異なる部分は★印の部分です。

------------------------------------------------------------
'// API宣言
Public Declare Function GdipSaveImageToStream Lib "GDIPlus" ( _
    ByVal Image As Long, _
    ByRef pStream As Long, _
    ByRef clsidEncoder As UUID, _
    ByVal encoderParams As Long) As GDIPlusStatusConstants

------------------------------
'// その1
Dim stm As ADODB.Stream
Set stm = New ADODB.Stream
stm.Type = adTypeBinary
stm.Open

Dim o As IUnknown  [★]
lRet = CreateStreamOnHGlobal(0&, True, o)  [★]
Set o = stm

ret = GdipSaveImageToStream(hGdipBmp, ObjPtr(o), ConvCLSID(CLSID_JPEG), VarPtr(EncodParameters))  [★第二引数変更]

[結果]
・GdipSaveImageToStream を実行するとシステムが落ちてしまう。

------------------------------
'// その2
Dim o As IUnknown  [★]
lRet = CreateStreamOnHGlobal(0&, True, o)  [★]

ret = GdipSaveImageToStream(hGdipBmp, ObjPtr(o), ConvCLSID(CLSID_JPEG), VarPtr(EncodParameters))  [★第二引数変更]

[結果]
・GdipSaveImageToStream は成功するが、IStreamよりどうやって
  情報を取得するのかが分かりません。
  OleSaveToStream?
  (↑検索して出てきましたが使い方が分かりませんでした。)
------------------------------------------------------------

色々試したのですが、全て上手く行きませんでした。
もう一度、お力をお貸し下さい。お願い致します。


魔界の仮面弁士  2007-08-29 03:05:43  No: 137269

>> Dim o As IStream
> は、VB6.0では利用できないようなので
タイプライブラリを作って、参照設定しましょう。
自作が面倒なら、下記の OLELIB.TLB あたりがおすすめです。
http://www.mvps.org/emorcillo/en/code/vb6/index.shtml

> CreateStreamOnHGlobal で IStream を作成するように変更してみました。
おぉ。CreateStreamOnHGlobal で得られる IStream からサイズを得た事は無かったです。(^^;
私は、ADODB.Stream から得られる IStream を使うことが多いので。

> ・GdipSaveImageToStream は成功するが、IStreamよりどうやって
>   情報を取得するのかが分かりません。

MSDN を見ると、IStream_Size という API がありました。
http://msdn2.microsoft.com/en-us/library/ms628654.aspx

どうやら、shlwapi.dll 内の無名関数のようですね。序数は 214 らしいので、こうかな。

Private Declare Function CreateStreamOnHGlobal Lib "ole32" _
    (ByVal hGlobal As Long, ByVal fDeleteOnRelease As Long, ByRef ppstm As IUnknown) As Long

Private Declare Function IStream_Size Lib "shlwapi" Alias "#214" _
    (ByVal pstm As IUnknown, ByRef pui As Currency) As Long

Dim Stm As IUnknown
lRet = CreateStreamOnHGlobal(hMem, 1, Stm)
If lRet = S_OK Then
    SavePictureJpg = GdipSaveImageToStream(GdipBmpHdl, Stm, pJPEG, pEncodParameters)
    GlobalFree hMem
End If

Dim cSize As Currency, lSize As Long
lRet = IStream_Size(Stm, cSize)
lSize = cSize * 10000


ぺそみ  2007-08-29 20:06:58  No: 137270

魔界の仮面弁士さん、ありがとうございます!!

ご教授頂いた2つのパターン、どちらも試してみました。
どちらも成功です!!

今回も色々と勉強させて頂きました。
>タイプライブラリを作って、参照設定しましょう。
は、今の私のレベルでは難しくすぐに出来そうにありませんでしたので
時間をみてチャレンジしてみたいと思います。

何度も何度もご回答頂き本当にありがとうございました。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加