戻る

並べるのはボタン4つにイメージコントロール1つ(つくるのが面倒だったらサンプルはこちら)
コードはWEB上での拾いものを適当に加工しただけで、中身の多くは自分でも理解できてません。

API関数の引数用Constは使った分のみ記述(本当はすごくいっぱいある。こちらに隔離しておきます)

あと色指定の書き方。
ここでは、RGB(r, g, b)でやってますが、vbRed, vbGreenみたいな書き方でも、整数値一発でもいけるはずです。

とりあえずOfficeVBAでも出来ないわけじゃないんだなと、これは単なる確認作業。
さらに深く突っ込むのは自分には無理(VBAからWindowsAPIフルに使ってまともな画像加工ソフトつくる人がいたら、皮肉でもなんでもなく本気で拍手ものだと思います)


Option Compare Database '←Excel, Wordでは不要
Option Explicit

Private Type BITMAPFILEHEADER
       bfType       As String * 2
       bfSize       As Long
       bfReserved1  As Integer
       bfReserved2  As Integer
       bfOffBits    As Long
End Type

Private Type BITMAPINFOHEADER
    biSize As Long
    biWidth As Long
    biHeight As Long
    biPlanes As Integer
    biBitCount As Integer
    biCompression As Long
    biSizeImage As Long
    biXPelsPerMeter As Long
    biYPelsPerMeter As Long
    biClrUsed As Long
    biClrImportant As Long
End Type

Private Type BITMAPINFO
    bmiHeader As BITMAPINFOHEADER
End Type
'↑の3つのTypeは必須


'↓線を描くときに使用
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


'以下API関数。Bitmapファイルを作る以上、最初の7つは何があろうと必須
Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32" (ByVal hdc As Long, pbmi As BITMAPINFO, _
                                                    ByVal iUsage As Long, ByVal ppvBits As Long, _
                                                    ByVal hSection As Long, ByVal dwOffset As Long) As Long
Private Declare Function GetDIBits Lib "gdi32" (ByVal aHDC As Long, ByVal hBitmap As Long, _
                                                ByVal nStartScan As Long, ByVal nNumScans As Long, _
                                                lpBits As Any, lpBI As BITMAPINFO, _
                                                ByVal wUsage As Long) As Long
Private Declare Function SelectObject Lib "gdi32.dll" (ByVal hdc As Long, ByVal hgdiobj As Long) As Long
Private Declare Function DeleteObject Lib "gdi32.dll" (ByVal hObject As Long) As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long


'↓線や図形を描くのに必要
Private Declare Function CreatePen Lib "gdi32.dll" (ByVal fnPenStyle As Long, ByVal nWidth As Long, _
                                                    ByVal crColor As Long) As Integer

'↓塗りつぶしに必要
Private Declare Function GetStockObject Lib "gdi32" (ByVal nIndex As Long) As Long


'↓四角形描画
Private Declare Function Rectangle Lib "gdi32" (ByVal hdc As Long, _
                                                ByVal X1 As Long, ByVal Y1 As Long, _
                                                ByVal X2 As Long, ByVal Y2 As Long) As Long

'↓楕円形描画
Private Declare Function Ellipse Lib "gdi32.dll" (ByVal hdc As Long, _
                                                ByVal nLeftRect As Long, ByVal nTopRect As Long, _
                                                ByVal nRightRect As Long, ByVal nBottomRect As Long) As Long
'↓以下2つは線を引くのに必要
Private Declare Function MoveToEx Lib "gdi32" (ByVal hdc As Long, _
                                            ByVal x As Long, ByVal y As Long, _
                                            ByRef lpPoint As POINTAPI) As Long
Private Declare Function LineTo Lib "gdi32.dll" (ByVal hdc As Long, _
                                                ByVal nXEnd As Long, ByVal nYEnd As Long) As Integer

'↓以下4つは文字入れに必要
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 IfdwItalic 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, _
                                                                lpRect As RECT, _
                                                                ByVal wFormat As Long) As Long
Private Declare Function SetBkColor Lib "gdi32.dll" (ByVal hdc As Long, ByVal crColor As Long) As Long
Private Declare Function SetTextColor Lib "gdi32.dll" (ByVal hdc As Long, ByVal crColor As Long) As Integer



'以下、定数。とりあえずここで使うものだけ(実際にはうんざりするほど沢山ある)

'↓線の種類
Private Const PS_SOLID = 0
'PS_DASH = 1 とか PS_DOT = 2 とか色々あるんだけど、やってみても全然効かない。
'もう面倒だからこんな定数使わずに引数決め打ちゼロでもいいと思う。

'↓塗りつぶし方
Private Const WHITE_BRUSH = 0
Private Const GRAY_BRUSH = 2
Private Const BLACK_BRUSH = 4

'↓文字入れに関していろいろ
Private Const FW_NORMAL = 400
Private Const FW_BOLD = 700
Private Const DEFAULT_CHARSET = 1
Private Const OUT_DEFAULT_PRECIS = 0
Private Const CLIP_DEFAULT_PRECIS = 0
Private Const DEFAULT_QUALITY = 0
Private Const DEFAULT_PITCH = 0
Private Const FF_SCRIPT = 64
Private Const DT_CENTER = &H1
Private Const DT_SINGLELINE = &H20


'↓てきとうに決めたBitmapのサイズ
Private Const CWIDTH = 320
Private Const CHEIGHT = 240

Private Sub DeleteTmpBMP(strFile As String) 'これは必要ないかも(ざっと見たところ、残したままでも上書きしてる)

    Dim MyFSO As Variant '実はVariantじゃなくObjectなんじゃないかと最近気づいた(どっちでも動く。As以下省略でも動く)

    
    Set MyFSO = CreateObject("Scripting.FileSystemObject")
    If MyFSO.FileExists(strFile) = True Then
        MyFSO.DeleteFile strFile
    End If
    Set MyFSO = Nothing
End Sub

Private Sub CommandButton0_Click() 'とりあえずまっさらのBitmapをつくってみる(生まれたては真っ黒)
    Dim MyStrFile As String
    Dim MyDC0, MyDC1 As Long
    Dim MyBMP As Long
    Dim MyBMPInf As BITMAPINFO
    Dim MyBMPFLHdr As BITMAPFILEHEADER
    Dim MyBMPBits() As Byte
    Dim MyFNUM As Long
    
    MyStrFile = ThisWorkbook.Path & "\tmp00.bmp" 'Excelの場合
    MyStrFile = ActiveDocument.Path & "\tmp00.bmp" 'Wordの場合
    MyStrFile = CurrentProject.Path & "\tmp00.bmp" 'Accessの場合

    Call DeleteTmpBMP(MyStrFile) '←この1行はたぶん省略可
    MyDC0 = GetDC(0&)
    MyDC1 = CreateCompatibleDC(MyDC0)
    With MyBMPInf.bmiHeader
        .biSize = 40 '←意味不明(書かないと怒られる)
        .biWidth = CWIDTH
        .biHeight = CHEIGHT
        .biPlanes = 1
        .biBitCount = 24 '32でも24でも8でも4でも好きなように(8だと256色、4だと16色しか使えないけど)
    End With
    MyBMP = CreateDIBSection(MyDC1, MyBMPInf, 0, 0, 0, 0)
    Call SelectObject(MyDC1, MyBMP)
    
    '↓
    
    'いろいろ描きたいときは、ここに処理を書く
    
    '↑
        
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
    ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
    MyFNUM = FreeFile
    Open MyStrFile For Binary As #MyFNUM
    With MyBMPFLHdr
        .bfType = "BM"
        .bfReserved1 = 0
        .bfReserved2 = 0
        .bfSize = Len(MyBMPFLHdr) + Len(MyBMPInf) + UBound(MyBMPBits) + 1
        .bfOffBits = Len(MyBMPFLHdr) + Len(MyBMPInf)
    End With
    Put #MyFNUM, , MyBMPFLHdr
    Put #MyFNUM, , MyBMPInf
    Put #MyFNUM, , MyBMPBits
    Close #MyFNUM

    Call DeleteObject(MyBMP)
    Call DeleteObject(MyDC1)
    Call ReleaseDC(0&, MyDC0)
    
    Image1.Picture = LoadPicture(MyStrFile) 'Excel, Wordの場合
    Image1.Picture = MyStrFile 'Accessの場合
End Sub

Private Sub CommandButton1_Click() '真っ黒のままでは描画しにくいので真っ白に染めてみる
    Dim MyStrFile As String
    Dim MyDC0, MyDC1 As Long
    Dim MyBMP As Long
    Dim MyPen As Long
    Dim MyBrush As Long
    Dim MyBMPInf As BITMAPINFO
    Dim MyBMPFLHdr As BITMAPFILEHEADER
    Dim MyBMPBits() As Byte
    Dim MyFNUM As Long
    
    MyStrFile = ThisWorkbook.Path & "\tmp00.bmp" 'Excelの場合
    MyStrFile = ActiveDocument.Path & "\tmp00.bmp" 'Wordの場合
    MyStrFile = CurrentProject.Path & "\tmp00.bmp" 'Accessの場合

    Call DeleteTmpBMP(MyStrFile)
    MyDC0 = GetDC(0&)
    MyDC1 = CreateCompatibleDC(MyDC0)
    With MyBMPInf.bmiHeader
        .biSize = 40
        .biWidth = CWIDTH
        .biHeight = CHEIGHT
        .biPlanes = 1
        .biBitCount = 24
    End With
    MyBMP = CreateDIBSection(MyDC1, MyBMPInf, 0, 0, 0, 0)
    Call SelectObject(MyDC1, MyBMP)
    '↑ここまでの処理は共通
    
    
    MyPen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255)) 'ペンを決めて(白)
    Call SelectObject(MyDC1, MyPen)
    MyBrush = GetStockObject(WHITE_BRUSH) '塗りつぶし方を決めて(白)
    Call SelectObject(MyDC1, MyBrush)
    Call Rectangle(MyDC1, 0, 0, CWIDTH, CHEIGHT) 'Bitmapと同じ大きさの四角形を描く(とうぜん真っ白になる)
    
    '用済みになったペンとブラシを破棄
    Call DeleteObject(MyPen)
    Call DeleteObject(MyBrush)
    
        
    '↓ここからの処理は共通
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
    ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
    MyFNUM = FreeFile
    Open MyStrFile For Binary As #MyFNUM
    With MyBMPFLHdr
        .bfType = "BM"
        .bfReserved1 = 0
        .bfReserved2 = 0
        .bfSize = Len(MyBMPFLHdr) + Len(MyBMPInf) + UBound(MyBMPBits) + 1
        .bfOffBits = Len(MyBMPFLHdr) + Len(MyBMPInf)
    End With
    Put #MyFNUM, , MyBMPFLHdr
    Put #MyFNUM, , MyBMPInf
    Put #MyFNUM, , MyBMPBits
    Close #MyFNUM

    Call DeleteObject(MyBMP)
    Call DeleteObject(MyDC1)
    Call ReleaseDC(0&, MyDC0)
    
    Image1.Picture = LoadPicture(MyStrFile) 'Excel, Wordの場合
    Image1.Picture = MyStrFile 'Accessの場合
End Sub

Private Sub CommandButton2_Click() '図形や線を描いてみる
    Dim MyStrFile As String
    Dim MyDC0, MyDC1 As Long
    Dim MyBMP As Long
    Dim MyPen As Long
    Dim MyBrush As Long
    Dim MyPnt As POINTAPI
    Dim MyBMPInf As BITMAPINFO
    Dim MyBMPFLHdr As BITMAPFILEHEADER
    Dim MyBMPBits() As Byte
    Dim MyFNUM As Long
    
    MyStrFile = ThisWorkbook.Path & "\tmp00.bmp" 'Excelの場合
    MyStrFile = ActiveDocument.Path & "\tmp00.bmp" 'Wordの場合
    MyStrFile = CurrentProject.Path & "\tmp00.bmp" 'Accessの場合

    Call DeleteTmpBMP(MyStrFile)
    MyDC0 = GetDC(0&)
    MyDC1 = CreateCompatibleDC(MyDC0)
    With MyBMPInf.bmiHeader
        .biSize = 40
        .biWidth = CWIDTH
        .biHeight = CHEIGHT
        .biPlanes = 1
        .biBitCount = 24
    End With
    MyBMP = CreateDIBSection(MyDC1, MyBMPInf, 0, 0, 0, 0)
    Call SelectObject(MyDC1, MyBMP)
    '↑ここまでの処理は共通
    
    
    
     'まずは真っ白に塗りつぶし
    MyPen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255))
    Call SelectObject(MyDC1, MyPen)
    MyBrush = GetStockObject(WHITE_BRUSH)
    Call SelectObject(MyDC1, MyBrush)
    Call Rectangle(MyDC1, 0, 0, CWIDTH, CHEIGHT)
    Call DeleteObject(MyPen) '次に描こうとしているものは違う色の線だったり、違う色の塗りつぶし方だったりするので
    Call DeleteObject(MyBrush) 'とりあえずペンとブラシを破棄
    
    
    'あらためてペンとブラシを用意して円形描画
    MyPen = CreatePen(PS_SOLID, 6, RGB(255, 0, 0))
    Call SelectObject(MyDC1, MyPen)
    MyBrush = GetStockObject(BLACK_BRUSH)
    Call SelectObject(MyDC1, MyBrush)
    Call Ellipse(MyDC1, 100, 110, 200, 210)
    Call DeleteObject(MyPen) 'ペンとブラシ破棄
    Call DeleteObject(MyBrush)
    
    
    'あらためてペンとブラシを用意して四角形描画
    MyPen = CreatePen(PS_SOLID, 10, RGB(0, 0, 255))
    Call SelectObject(MyDC1, MyPen)
    MyBrush = GetStockObject(GRAY_BRUSH)
    Call SelectObject(MyDC1, MyBrush)
    Call Rectangle(MyDC1, 10, 50, 60, 100)
    Call DeleteObject(MyPen) 'ペンとブラシ破棄
    Call DeleteObject(MyBrush)
    
    'あらためてペンを用意して直線引き
    MyPen = CreatePen(PS_SOLID, 2, RGB(0, 255, 0))
    Call SelectObject(MyDC1, MyPen)
    Call MoveToEx(MyDC1, 150, 50, MyPnt) 'スタート地点を決めて
    Call LineTo(MyDC1, 300, 50) 'ここまで線を引く
    Call DeleteObject(MyPen) 'ペンを破棄
    
        
    '↓ここからの処理は共通
    '正直いって何やってるのかさっぱりわからない
    '何となく、空中に浮かんだキャンバスから虚無のビットマップファイルに絵柄をうつしている感じ
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
    ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
    MyFNUM = FreeFile
    Open MyStrFile For Binary As #MyFNUM
    With MyBMPFLHdr
        .bfType = "BM"
        .bfReserved1 = 0
        .bfReserved2 = 0
        .bfSize = Len(MyBMPFLHdr) + Len(MyBMPInf) + UBound(MyBMPBits) + 1
        .bfOffBits = Len(MyBMPFLHdr) + Len(MyBMPInf)
    End With
    Put #MyFNUM, , MyBMPFLHdr
    Put #MyFNUM, , MyBMPInf
    Put #MyFNUM, , MyBMPBits
    Close #MyFNUM

    '何やってるかわからなくてもとにかく用済みになったものは破棄するのがこの世界の掟
    Call DeleteObject(MyBMP)
    Call DeleteObject(MyDC1)
    Call ReleaseDC(0&, MyDC0)
    
    Image1.Picture = LoadPicture(MyStrFile) 'Excel, Wordの場合
    Image1.Picture = MyStrFile 'Accessの場合
End Sub

Private Sub CommandButton3_Click() '文字を入れてみる
    Dim MyStrFile As String
    Dim MyDC0, MyDC1 As Long
    Dim MyBMP As Long
    Dim MyPen As Long
    Dim MyBrush As Long
    Dim MyFont As Long
    Dim MyFntFamily As String
    Dim MyRct As RECT
    Dim MyBMPInf As BITMAPINFO
    Dim MyBMPFLHdr As BITMAPFILEHEADER
    Dim MyBMPBits() As Byte
    Dim MyFNUM As Long
    
    MyStrFile = ThisWorkbook.Path & "\tmp00.bmp" 'Excelの場合
    MyStrFile = ActiveDocument.Path & "\tmp00.bmp" 'Wordの場合
    MyStrFile = CurrentProject.Path & "\tmp00.bmp" 'Accessの場合

    Call DeleteTmpBMP(MyStrFile)
    MyDC0 = GetDC(0&)
    MyDC1 = CreateCompatibleDC(MyDC0)
    With MyBMPInf.bmiHeader
        .biSize = 40
        .biWidth = CWIDTH
        .biHeight = CHEIGHT
        .biPlanes = 1
        .biBitCount = 24
    End With
    MyBMP = CreateDIBSection(MyDC1, MyBMPInf, 0, 0, 0, 0)
    Call SelectObject(MyDC1, MyBMP)
    '↑ここまでの処理は共通
    
    
    'まずは真っ白に塗りつぶし
    MyPen = CreatePen(PS_SOLID, 0, RGB(255, 255, 255))
    Call SelectObject(MyDC1, MyPen)
    MyBrush = GetStockObject(WHITE_BRUSH)
    Call SelectObject(MyDC1, MyBrush)
    Call Rectangle(MyDC1, 0, 0, CWIDTH, CHEIGHT)
    Call DeleteObject(MyPen) 'ペンとブラシ破棄
    Call DeleteObject(MyBrush)
    
    

    '以下、文字入れ。
    '文字を入れるだけならペンはいらない。
    '用意するのはフォント
    MyFont = CreateFont(18, 0, 0, 0, FW_NORMAL, _
            0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, _
            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, _
            DEFAULT_PITCH Or FF_SCRIPT, MyFntFamily)
    Call SelectObject(MyDC1, MyFont)
    
    MyRct.Left = 10 '限界ワクを決めて
    MyRct.Top = 50
    MyRct.Right = 310
    MyRct.Bottom = 75
    Call SetTextColor(MyDC1, RGB(255, 0, 0)) '文字色を決めて
    Call SetBkColor(MyDC1, RGB(0, 0, 0)) '背景色を決めて
    Call DrawText(MyDC1, "あいうえおかきくけこ", -1, MyRct, DT_CENTER Or DT_SINGLELINE)
    
    MyRct.Top = 70
    MyRct.Bottom = 95
    Call SetTextColor(MyDC1, RGB(255, 255, 255))
    Call SetBkColor(MyDC1, RGB(0, 255, 0))
    Call DrawText(MyDC1, "さしすせそたちつてとなにぬねの", -1, MyRct, DT_CENTER Or DT_SINGLELINE)
    
    
    '次に入れようとしている文字は、違うサイズ、違うデザインなので、とりあえず用済みになったフォントを破棄
    Call DeleteObject(MyFont)
    
    
    'あらためてフォントを用意
    MyFont = CreateFont(24, 0, 0, 0, FW_BOLD, _
            0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, _
            CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, _
            DEFAULT_PITCH Or FF_SCRIPT, MyFntFamily)
    Call SelectObject(MyDC1, MyFont)
    
    MyRct.Top = 90
    MyRct.Bottom = 115
    Call SetTextColor(MyDC1, RGB(0, 0, 255))
    Call SetBkColor(MyDC1, RGB(255, 0, 0))
    Call DrawText(MyDC1, "はひふへほ", -1, MyRct, DT_CENTER Or DT_SINGLELINE)
    
    Call DeleteObject(MyFont) 'フォントを破棄
    
        
        
    '↓ここからの処理は共通
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, ByVal 0&, MyBMPInf, 0)
    ReDim MyBMPBits(MyBMPInf.bmiHeader.biSizeImage - 1)
    Call GetDIBits(MyDC1, MyBMP, 0, CHEIGHT, MyBMPBits(0), MyBMPInf, 0)
    MyFNUM = FreeFile
    Open MyStrFile For Binary As #MyFNUM
    With MyBMPFLHdr
        .bfType = "BM"
        .bfReserved1 = 0
        .bfReserved2 = 0
        .bfSize = Len(MyBMPFLHdr) + Len(MyBMPInf) + UBound(MyBMPBits) + 1
        .bfOffBits = Len(MyBMPFLHdr) + Len(MyBMPInf)
    End With
    Put #MyFNUM, , MyBMPFLHdr
    Put #MyFNUM, , MyBMPInf
    Put #MyFNUM, , MyBMPBits
    Close #MyFNUM

    Call DeleteObject(MyBMP)
    Call DeleteObject(MyDC1)
    Call ReleaseDC(0&, MyDC0)
    
    Image1.Picture = LoadPicture(MyStrFile) 'Excel, Wordの場合
    Image1.Picture = MyStrFile 'Accessの場合
End Sub