Excel VBA質問箱 IV

当質問箱は、有志のボランティア精神のおかげで成り立っています。
問題が解決したら、必ずお礼をしましょうね。
本サイトの基本方針をまとめました。こちら をご一読ください。

投稿種別の選択が必要です。ご注意ください。
迷惑投稿防止のため、URLの入力を制限しています。ご了承ください。


4843 / 13646 ツリー ←次へ | 前へ→

【54075】フォーム上のイメージに文字を追加する方法 BRG 08/2/23(土) 12:45 質問[未読]
【54091】Re:フォーム上のイメージに文字を追加する... ichinose 08/2/24(日) 9:16 発言[未読]
【54098】Re:フォーム上のイメージに文字を追加する... bykin 08/2/24(日) 14:15 回答[未読]
【54109】Re:フォーム上のイメージに文字を追加する... ichinose 08/2/24(日) 21:02 発言[未読]
【54130】Re:フォーム上のイメージに文字を追加する... BRG 08/2/25(月) 21:37 お礼[未読]
【54104】Re:フォーム上のイメージに文字を追加する... BRG 08/2/24(日) 17:11 お礼[未読]

【54075】フォーム上のイメージに文字を追加する方...
質問  BRG  - 08/2/23(土) 12:45 -

引用なし
パスワード
   フォルダー内の画像にまとめて(c)マークのような文字を追加したいと考えています。
エクセルVBAでファイル管理システムを作ったので、できればVBA上でできればと考えています。
今のところ各種画像をBMP化して、別フォーム上にImage表示させるところまでは行ったのですが、VBと違いPrintやLine等、VBAには描画の機能が一切無い為に、その後の一切の加工ができずに困っています。
ひととおりdllやAPI等も探してみましたが、見つけることができませんでした。
有効な方法をご存知の方、ぜひアドバイスをいただけませんでしょうか?
よろしくお願いします。

【54091】Re:フォーム上のイメージに文字を追加す...
発言  ichinose  - 08/2/24(日) 9:16 -

引用なし
パスワード
   ▼BRG さん:
おはようございます。


>今のところ各種画像をBMP化して、別フォーム上にImage表示させるところまでは行ったのですが、VBと違いPrintやLine等、VBAには描画の機能が一切無い為に、その後の一切の加工ができずに困っています。
この掲示板では、取り合えず出来てるコードは、提示されたほうがよいですよ!!


>フォルダー内の画像にまとめて(c)マークのような文字を追加したいと考えています。
>エクセルVBAでファイル管理システムを作ったので、できればVBA上でできればと考えています。

方法としては、

・画像をシートに取り込む
・オートシェイプを使って、Cマークを作成する
・上記の二つの図形をグループ化し、クリップボードにコピーする。
・クリップボードの内容をユーザーフォームのイメージコントロールに取り込む
・何とかImageコントロールに画像が取り込めれば、SavePictureメソッドで
 ファイルの保存を行える

という方針でアプローチしました。

先に結果を申し上げると、
Cマークが付いた画像をイメージコントロールに表示し、
そこから、ファイルの保存までは成功しました。

が、作成したbmpファイルをクリックして開こうとすると、
形式が違うという趣旨のエラーが出て、開きません。

↑これは、よくわかりません。

但し、ExcelやWordでの図の挿入や
Imageコントロールへの読み込みは可能です。

保存の方法に別案があれば・・・ですが。
取り合えず、コードを提示します。

尚、クリップボードの図形からStdpictureを作るコードは、
りんさん投稿の

www.vbalab.net/vbaqa/c-board.cgi?cmd=one;no=46923;id=excel

↑これを使わせてもらいました。


新規ブックにユーザーフォーム(UserForm1)だけ作成してください。
コントロールは、コードで挿入しますから、何も配置しないで下さい。

まず、Userform1のモジュールに


'===============================================================
Option Explicit
Private WithEvents btn_fl_select As MSForms.CommandButton
Private WithEvents img_pic As MSForms.Image
Private Const CF_ENHMETAFILE = 14
Private Declare Function IsClipboardFormatAvailable Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function OpenClipboard Lib "user32.dll" (ByVal hwnd As Long) As Long
Private Declare Function GetClipboardData Lib "user32.dll" (ByVal wFormat As Long) As Long
Private Declare Function CloseClipboard Lib "user32.dll" () As Long
Private Const vbPicTypeBitmap = 1
Private Const vbPicTypeIcon = 3
Private Const vbPicTypeEMetafile = 4
Private Type TPICTDESC
  cbSizeofStruct As Long
  picType As Long
  hImage As Long
  Option1 As Long
  Option2 As Long
End Type
Private Type TGUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(1 To 8) As Byte
End Type
Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" _
              (lpPictDesc As TPICTDESC, _
               RefIID As TGUID, _
               ByVal fPictureOwnsHandle As Long, _
               ByRef IPic As IPicture) As Long
'========================================================================
Public Function Clipboard_GetMetafile() As StdPicture
  Dim hEmf As Long
  Dim TPICTDESC As TPICTDESC
  Dim TGUID As TGUID
  
  Set Clipboard_GetMetafile = Nothing
  
  If IsClipboardFormatAvailable(CF_ENHMETAFILE) = False Then Exit Function
  If OpenClipboard(CLng(0)) = False Then Exit Function
  
  hEmf = GetClipboardData(CF_ENHMETAFILE)
  Call CloseClipboard
  If hEmf = 0 Then Exit Function

  With TPICTDESC
    .cbSizeofStruct = Len(TPICTDESC)
    .picType = vbPicTypeEMetafile
    .hImage = hEmf
  End With
  With TGUID
    .Data1 = &H20400
    .Data4(1) = &HC0
    .Data4(8) = &H46
  End With
  Call OleCreatePictureIndirect(TPICTDESC, TGUID, True, Clipboard_GetMetafile)
End Function
'========================================================================
Private Sub btn_fl_select_Click()
  Dim flnm As Variant
  Dim crng As Range
  Dim 元画像 As Shape
  Dim c_mark As Shape
  With Workbooks.Add
    Set crng = .ActiveSheet.Range("a1")
    End With
  'On Error Resume Next
  flnm = Application.GetOpenFilename(, , "Select picture files")
  If TypeName(flnm) <> "Boolean" Then
    Set 元画像 = crng.Parent.Pictures.Insert(flnm).ShapeRange.Item(1)
    If Err.Number = 0 Then
     With crng.MergeArea
       元画像.left = .left
       元画像.top = .top
       End With
     Set c_mark = mk_c(crng.Parent, crng.left, crng.top, CLng(元画像.Width / 10))
     With c_mark
       .left = 元画像.Width - .Width
       .top = 元画像.Height - .Height
       End With
     With crng
       With .Parent.Shapes.Range(Array(c_mark.Name, 元画像.Name)).Group
        .CopyPicture Appearance:=xlScreen, Format:=xlBitmap
        
        End With
       With .Parent.Pictures.Paste
        .Copy
        End With
       img_pic.Picture = Clipboard_GetMetafile()
       DoEvents
       Call SavePicture(img_pic.Picture, ThisWorkbook.Path & "\sample.bmp")
       .Parent.Parent.Close False
       End With
     Me.Repaint
     Application.CutCopyMode = False
     End If
    End If
End Sub
'========================================================================
Function mk_c(ByVal sht As Worksheet, left As Single, top As Single, Optional ByVal sz As Long = 14) As Shape
  Set mk_c = sht.Shapes.AddTextbox(msoTextOrientationHorizontal, _
                    left, top, 20, 20)
  With mk_c
    .Line.Visible = msoFalse
    .Fill.Transparency = 1#
    With .TextFrame
      .AutoSize = True
      With .Characters
       .Text = ChrW(&H24B8)
       .Font.Size = sz
       End With
      End With
  End With
End Function
'========================================================================
Private Sub UserForm_Initialize()
  With Me
    .Width = 360
    .Height = 400
    Set btn_fl_select = .Controls.Add("Forms.CommandButton.1", , True)
    With btn_fl_select
     .Caption = "ファイル選択"
     .left = 30
     .top = 12
     .Width = 72
     .Height = 24
     End With
    Set img_pic = .Controls.Add("Forms.Image.1", , True)
    With img_pic
     .left = 30
     .top = 48
     .Width = 264
     .Height = 252
     .PictureSizeMode = fmPictureSizeModeStretch
     End With
    End With
End Sub


標準モジュールに

'=================================================================
Sub main()
  UserForm1.Show vbModeless
End Sub


一度、ブックを保存してから、mainを実行してください。

ファイル選択ボタンをクリックして、Cマークを付けたい画像を
選択してください。

イメージコントロールにCマークの付いた画像が表示されます。
このブックと同じフォルダにsample.bmpとして、保存されます。

参考にしてみてください。

 尚、Win2000&Excel2002で確認しました。

【54098】Re:フォーム上のイメージに文字を追加す...
回答  bykin  - 08/2/24(日) 14:15 -

引用なし
パスワード
   こんにちわ。

ichinoseはん、

>作成したbmpファイルをクリックして開こうとすると、
>形式が違うという趣旨のエラーが出て、開きません。

↑これ、試してみたけどわての環境ではちゃんと開きまっせ。
(WindowsXP+Excel2003)

ところで、ワークシート使わん方法で考えてみました。
前提条件:
1.ユーザーフォームにImage1を配置
2.元画像ファイルは C:\test.bmp

Option Explicit

Private Const DT_LEFT As Long = &H0
Private Const DT_BOTTOM As Long = &H8
Private Const DT_SINGLELINE As Long = &H20
Private Const TRANSPARENT As Long = 1
Private Const GUID_IDISPATCH_INTERFACE As String = "{00020400-0000-0000-C000-000000000046}"
Private Const CF_BITMAP As Long = 2
Private Const CF_PALETTE As Long = 9
Private Const PICTYPE_BITMAP As Long = 1
Private Const IMAGE_BITMAP As Long = 0
Private Const LR_COPYRETURNORG As Long = &H4
Private Const LR_LOADFROMFILE As Long = &H10
Private Const LOGPIXELSX As Long = 88

Private Type POINTAPI
  X As Long
  Y As Long
End Type

Private Type RECT
  Left As Long
  Top As Long
  Right As Long
  Bottom As Long
End Type

Private Type BITMAP
  bmType As Long
  bmWidth As Long
  bmHeight As Long
  bmWidthBytes As Long
  bmPlanes As Integer
  bmBitsPixel As Integer
  bmBits As Long
End Type

Private Type SIZEAPI
  cx As Long
  cy As Long
End Type

Private Type GUID
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(0 To 7) As Byte
End Type

Private Type PictDesc
  cbSizeofStruct As Long
  picType As Long
  hImage As Long
  Option1 As Long
  Option2 As Long
End Type

Private Declare Function CLSIDFromString Lib "ole32" _
            (ByVal lpsz As Long, _
             ByRef ID As GUID) As Long

Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hDC As Long) As Long

Private Declare Function DeleteDC Lib "gdi32" (ByVal hDC As Long) As Long

Private Declare Function GetObject Lib "gdi32" _
             Alias "GetObjectA" _
            (ByVal hObject As Long, _
             ByVal nCount As Long, _
             ByRef lpObject As Any) As Long

Private Declare Function SelectObject Lib "gdi32" _
            (ByVal hDC As Long, _
             ByVal hObject As Long) As Long

Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long

Private Declare Function SetRect Lib "user32" _
            (ByRef lpRect As RECT, _
             ByVal X1 As Long, _
             ByVal Y1 As Long, _
             ByVal X2 As Long, _
             ByVal Y2 As Long) As Long

Private Declare Function CreateFont Lib "gdi32" _
             Alias "CreateFontA" _
            (ByVal nHeight As Long, _
             ByVal nWidth As Long, _
             ByVal nEscapement As Long, _
             ByVal nOrientation As Long, _
             ByVal fnWeight As Long, _
             ByVal fdwItaric As Long, _
             ByVal fdwUnderline As Long, _
             ByVal fdwStrikeOut As Long, _
             ByVal fdwCharSet As Long, _
             ByVal fdwOutputPrecision As Long, _
             ByVal fdwClipPrecision As Long, _
             ByVal fdwQuality As Long, _
             ByVal fdwPitchAndFamily As Long, _
             ByVal lpszFace As String) As Long

Private Declare Function DrawText Lib "user32" _
             Alias "DrawTextA" _
            (ByVal hDC As Long, _
             ByVal lpStr As String, _
             ByVal nCount As Long, _
             ByRef lpRect As RECT, _
             ByVal wFormat As Long) As Long

Private Declare Function SetTextColor Lib "gdi32" _
            (ByVal hDC As Long, _
             ByVal crColor As Long) As Long

Private Declare Function SetBkMode Lib "gdi32" _
            (ByVal hDC As Long, _
             ByVal nBkMode As Long) As Long

Private Declare Function GetTextExtentPoint32 Lib "gdi32" _
             Alias "GetTextExtentPoint32A" _
            (ByVal hDC As Long, _
             ByVal lpString As String, _
             ByVal cbString As Long, _
             ByRef lpSize As SIZEAPI) As Long

Private Declare Function OleCreatePictureIndirect Lib "olepro32.dll" _
            (ByRef lpPicDesc As PictDesc, _
             ByRef RefIID As GUID, _
             ByVal fPictureOwnsHandle As Long, _
             ByRef iPic As stdole.IPictureDisp) As Long

Private Declare Function IsClipboardFormatAvailable Lib "user32" (ByVal wFormat As Long) As Long

Private Declare Function OpenClipboard Lib "user32" (ByVal hWnd As Long) As Long

Private Declare Function CloseClipboard Lib "user32" () As Long

Private Declare Function EmptyClipboard Lib "user32" () As Long

Private Declare Function GetClipboardData Lib "user32" (ByVal wFormat As Long) As Long

Private Declare Function SetClipboardData Lib "user32" _
            (ByVal wFormat As Long, _
             ByVal hMem As Long) As Long

Private Declare Function LoadImage Lib "user32" Alias "LoadImageA" (ByVal hInst As Long, ByVal lpsz As String, ByVal un1 As Long, ByVal n1 As Long, ByVal n2 As Long, ByVal un2 As Long) As Long

Private Declare Function GetDeviceCaps Lib "gdi32" _
            (ByVal hDC As Long, _
             ByVal nIndex As Long) As Long

Private Sub UserForm_Click()
  Const COPYRIGHT As String = "Copyright(c) 2008 bykin"
  Const FILE_ORIGINAL As String = "C:\test.bmp"
  Const FILE_MODIFIED As String = "C:\test2.bmp"
  Const FONT_SIZE As Long = 11
  Const FONT_NAME As String = "MS ゴシック"
  Dim hDC As Long
  Dim hBmp As Long
  Dim hFont As Long
  Dim hOrgBmp As Long
  Dim hOrgFont As Long
  Dim hPalette As Long
  Dim hImg As Long
  Dim tBitmap As BITMAP
  Dim tRect As RECT
  Dim tSize As SIZEAPI
  Dim PicDesc As PictDesc
  Dim IdispatchID As GUID
  Dim Pic As stdole.IPictureDisp
  Dim Pos As POINTAPI
  Dim Ratio As Single
  
  On Error Resume Next
  With Me.Image1
  
    '一旦Image1に元画像を表示(=確認用)
    .Picture = stdole.LoadPicture(FILE_ORIGINAL)
    .AutoSize = False
    .AutoSize = True
    MsgBox "変換前"
    
    '元画像BMPファイルからデバイスコンテキストを直接作成
    hBmp = LoadImage(0, FILE_ORIGINAL, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE)
    hDC = CreateCompatibleDC(0)
    hOrgBmp = SelectObject(hDC, hBmp)
    GetObject hBmp, Len(tBitmap), tBitmap
    
    '文字描画用オブジェクト設定
    Ratio = 72 / GetDeviceCaps(hDC, LOGPIXELSX)
    hFont = CreateFont(CLng(Int(FONT_SIZE / Ratio)), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, FONT_NAME)
    hOrgFont = SelectObject(hDC, hFont)
    SetTextColor hDC, vbBlack
    SetBkMode hDC, TRANSPARENT
    
    '文字列の幅と高さで描画範囲(画像の右下)を設定
    GetTextExtentPoint32 hDC, COPYRIGHT, LenB(StrConv(COPYRIGHT, vbFromUnicode)), tSize
    Pos.X = tBitmap.bmWidth - tSize.cx
    Pos.Y = tBitmap.bmHeight - tSize.cy
    SetRect tRect, Pos.X, Pos.Y, tBitmap.bmWidth, tBitmap.bmHeight
    
    '文字出力
    DrawText hDC, COPYRIGHT, -1, tRect, DT_BOTTOM Or DT_SINGLELINE Or DT_LEFT
    
    '画像をクリップボードにコピー
    If OpenClipboard(0) <> 0 Then
      EmptyClipboard
      SetClipboardData CF_BITMAP, hBmp
      CloseClipboard
    End If
    
    '描画オブジェクト/デバイスコンテキストの後始末
    SelectObject hDC, hOrgFont
    DeleteObject hFont
    SelectObject hDC, hOrgBmp
    DeleteDC hDC
    DeleteObject hBmp
  
    'クリップボードからImage1に画像をコピー
    If IsClipboardFormatAvailable(CF_BITMAP) <> 0 Then
      If OpenClipboard(0) <> 0 Then
        hImg = GetClipboardData(CF_BITMAP)
        hPalette = GetClipboardData(CF_PALETTE)
        PicDesc.Option1 = hPalette
        If hImg <> 0 Then
          CLSIDFromString ByVal StrPtr(GUID_IDISPATCH_INTERFACE), IdispatchID
          With PicDesc
            .cbSizeofStruct = Len(PicDesc)
            .picType = PICTYPE_BITMAP
            .hImage = hImg
          End With
          If OleCreatePictureIndirect(PicDesc, IdispatchID, 0, Pic) = 0 Then
            Set .Picture = Pic
            MsgBox "変換後"
            
            '新規BMPファイルに出力
            stdole.SavePicture .Picture, FILE_MODIFIED
            
            'このままではImage1に表示された画像が消える場合がある
            '(フォームが他のウィンドウの背面に回ったとき等)ので
            '出力したファイルを読み込む(=確認用)
            .Picture = stdole.LoadPicture(FILE_MODIFIED)
            MsgBox "保存しました"
          End If
        End If
        EmptyClipboard
        CloseClipboard
      End If
    End If
  End With
End Sub

ユーザーフォームを表示させ、クリックしてください。
Copyrightの文字列が画像右下に追加され、新しいファイルC:\test2.bmpとして保存されます。
(フォームを表示させるコードは書いてまへんがF5キーでも表示できます。)

試してみてな。
ほな。

【54104】Re:フォーム上のイメージに文字を追加す...
お礼  BRG  - 08/2/24(日) 17:11 -

引用なし
パスワード
   ▼ichinose さん:
大変貴重なアドバイスをありがとうございました。

コードを記載しなかった件については大変申し訳ありませんでした。というのも私が素人なもので作成途中にどんどん追加削除を繰り返した挙句、どこがどうなっているのか簡潔に記載できなかったため、混乱させてもいけないと思い、控えさせていただきました。

さて、本日お返事をいただいてから試行錯誤の結果、下記のことがわかりました。

◆VBA作成したBMPは通常のBMPと異なるファイルになる
ichinoseさんがご指摘されているとおり、このマクロというより、VBAで作成したもの全てになると思いますが、私のKBC.dllを利用してBMPに変換したファイルでも同様の症状で、JPGへの変換ができなかったりWindowsフォトギャラリー等でも開けませんでした。ただ、一度ペイントで開いて保存しなおせば有効なファイルになりました。(どの色数でも)

◆明熊さんのSaveJPG.DLLで直接クリップボードファイルのものをjpgに変換すると上記の問題は起こらない。

上記の結果に基づいて、SaveJPG.DLLのインストール後、いただいたコードの一部に下記のように追加することにより、イメージ通りの作業ができるようになりました。
ありがとうございました。

'--------------------------------------------------------------
Public Declare Function CliptoJPEG Lib "SaveJPG.DLL" _
(ByVal jpgf As String, ByVal Value As Byte, ByVal Prgrs As Boolean) As Integer
'--------------------------------------------------------------
========================================================================
Private Sub btn_fl_select_Click()
  Dim flnm As Variant
  Dim crng As Range
  Dim 元画像 As Shape
  Dim c_mark As Shape
  With Workbooks.Add
    Set crng = .ActiveSheet.Range("a1")
    End With
  'On Error Resume Next
  flnm = Application.GetOpenFilename(, , "Select picture files")
  If TypeName(flnm) <> "Boolean" Then
    Set 元画像 = crng.Parent.Pictures.Insert(flnm).ShapeRange.Item(1)
    If Err.Number = 0 Then
     With crng.MergeArea
       元画像.left = .left
       元画像.top = .top
       End With
     Set c_mark = mk_c(crng.Parent, crng.left, crng.top, CLng(元画像.Width / 10))
     With c_mark
       .left = 元画像.Width - .Width
       .top = 元画像.Height - .Height
       End With
     With crng
       With .Parent.Shapes.Range(Array(c_mark.Name, 元画像.Name)).Group
        .CopyPicture Appearance:=xlScreen, Format:=xlBitmap
        
        End With
       With .Parent.Pictures.Paste
        .Copy
        End With
       img_pic.Picture = Clipboard_GetMetafile()
'----------------------------------------------------------
Dim s As Integer
  ActiveSheet.Pictures(1).CopyPicture xlScreen, xlBitmap
  s = CliptoJPEG(”保存するファイル名”, 80, False)
'----------------------------------------------------------
       DoEvents
       Call SavePicture(img_pic.Picture, ThisWorkbook.Path & "\sample.bmp")
       .Parent.Parent.Close False
       End With
     Me.Repaint
     Application.CutCopyMode = False
     End If
    End If
End Sub
'========================================================================

【54109】Re:フォーム上のイメージに文字を追加す...
発言  ichinose  - 08/2/24(日) 21:02 -

引用なし
パスワード
   こんばんは。

bykinさん

>>作成したbmpファイルをクリックして開こうとすると、
>>形式が違うという趣旨のエラーが出て、開きません。
>
>↑これ、試してみたけどわての環境ではちゃんと開きまっせ。
>(WindowsXP+Excel2003)

そうですかあ。私の環境では、何度やってもダメでした。
Excel2003で直したのかなあ・・・。


>
>ところで、ワークシート使わん方法で考えてみました。
>前提条件:
>1.ユーザーフォームにImage1を配置
>2.元画像ファイルは C:\test.bmp
>

私もbykinさんおコードを試しました。

速いですねえ・・・、それにきちんと私の環境でもBMPがクリックで開きました。

容量の大きいBmpファイルは、シートに読み込んでしまうのは無理かなあ!!

コードは、参考にさせていただきます。


BRGさん

>◆明熊さんのSaveJPG.DLLで直接クリップボードファイルのものをjpgに変換すると上記の問題は起こらない。

一応↑のリンクを貼っておきますが、

www.vector.co.jp/soft/win95/prog/se093621.html

これで良いのですよね?

せっかくコードを投稿されてもこれDWしないと動かないものね!!

【54130】Re:フォーム上のイメージに文字を追加す...
お礼  BRG  - 08/2/25(月) 21:37 -

引用なし
パスワード
   bykinさん

ありがとうございました。また来週末にでも試してみます。(すぐに試せればいいのですが、素人なもので解読するのにかなり時間がかかるもので・・・)


ichinoseさん

たびたびすみませんでした。そのdllです。
何度も助けていただきありがとうございました。

4843 / 13646 ツリー ←次へ | 前へ→
ページ:  ┃  記事番号:
2610219
(SS)C-BOARD v3.8 is Free