VBAからGDI+を使う資料集
inet上の達人の方々から御教示いただいたコードを少しアレンジさせてもらっています(切り貼りとも言います)。
  1. ホーム
  2. EMF
  3. cell2bmp


選択範囲を高画素数・高解像度Jpegで保存

Office 2010 で印刷すると図が不鮮明になる
https://support.microsoft.com/en-us/kb/2578497/ja
SP2で解消された筈の不具合に悩まされているのは当方だけなのでしょうか?
苦肉の策で、選択セル範囲を高画素数のビットマップに変換するのをやってみました。
ついでに貼り付ける時に楽な様に、解像度も高く出来る様にしてみました。
(更新)
QAサイトで、セル選択範囲をJpegで保存するお題が出されたので、高画素Jpeg保存版を回答しようと改造していたら
閉じられてしまいました。
高さ1倍でも、ビットマップ形式でコピー版よりも高画素になってしまいますが、深く追求しておりません。


Option Explicit


'====== 構造体 ======

'Globally Unique Identifier構造体
Private Type uuid
  Data1 As Long
  Data2 As Integer
  Data3 As Integer
  Data4(0 To 7) As Byte
End Type
'Picture Descriptor構造体 MSDN(Eng)参照
Private Type PICTDESC
  cbSizeofstruct As Long
  picType As Long
  hBitmap As Long
  hpal As Long
  unused_wmf_yExt As Long
End Type

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

Private Type METAFILEPICT
  mm As Long
  xExt As Long
  yExt As Long
  hmf As Long
End Type

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

Private Type SIZEL
  cx As Long
  cy As Long
End Type

Type BITMAPINFOHEADER
  biSize As Long              'ヘッダーのサイズ
  biWidth As Long             '幅(ピクセル単位)
  biHeight As Long            '高さ(ピクセル単位)
  biPlanes As Integer         '常に1
  biBitCount As Integer       '1ピクセルあたりのカラービット数
  biCompression As Long       '圧縮方法
  biSizeImage As Long         'ピクセルデータの全バイト数
  biXPelsPerMeter As Long     '0または水平解像度
  biYPelsPerMeter As Long     '0または垂直解像度
  biClrUsed As Long           '通常は0
  biClrImportant As Long      '通常は0
End Type

Type RGBQUAD
  rgbBlue As Byte             '青の濃さ
  rgbGreen As Byte            '緑の濃さ
  rgbRed As Byte              '赤の濃さ
  rgbReserved As Byte         '未使用(常に0)
End Type

Type BITMAPINFO
  bmiHeader As BITMAPINFOHEADER
  bmiColors As RGBQUAD
End Type

Private Type ENHMETAHEADER
  iType As Long
  nSize As Long
  rclBounds As RECTL
  rclFrame As RECTL '0.01mm単位
  dSignature As Long
  nVersion As Long
  nBytes As Long
  nRecords As Long
  nHandles As Integer
  sReserved As Integer
  nDescription As Long
  offDescription As Long
  nPalEntries As Long
  szlDevice As SIZEL
  szlMillimeters As SIZEL
End Type

'GDI+
'Private Type uuid
' Data1 As Long
' Data2 As Integer
' Data3 As Integer
' Data4(7) As Byte
' End Type
Private Type GdiplusStartupInput
  GdiplusVersion As Long
  DebugEventCallback As Long
  SuppressBackgroundThread As Long
  SuppressExternalCodecs As Long
End Type

Private Type EncoderParameter
  uuid As uuid
  NumberOfValues As Long
  Type As Long
  Value As Long
End Type

Private Type EncoderParameters
  Count As Long
  Parameter(15) As EncoderParameter
End Type

'===== GDI+ 関係
Public Enum myPixelFormat
  PixelFormatUndefined = &H0
  PixelFormat1bppIndexed = &H30101
  PixelFormat4bppIndexed = &H30402
  PixelFormat8bppIndexed = &H30803
  PixelFormat16bppGrayScale = &H101004
  PixelFormat16bppRGB555 = &H21005
  PixelFormat16bppRGB565 = &H21006
  PixelFormat16bppARGB1555 = &H61007
  PixelFormat24bppRGB = &H21808
  PixelFormat32bppRGB = &H22009
  PixelFormat32bppARGB = &H26200A
  PixelFormat32bppPARGB = &HE200B
  PixelFormat48bppRGB = &H10300C
  PixelFormat64bppARGB = &H34400D
  PixelFormat64bppPARGB = &H1A400E
End Enum

Private Const QUALITY_PARAMS As String = "{1D5BE4B5-FA4A-452D-9CDD-5DB35105E7EB}"
Private Const ENCODER_BMP    As String = "{557CF400-1A04-11D3-9A73-0000F81EF32E}"
Private Const ENCODER_JPG    As String = "{557CF401-1A04-11D3-9A73-0000F81EF32E}"
Private Const ENCODER_GIF    As String = "{557CF402-1A04-11D3-9A73-0000F81EF32E}"
Private Const ENCODER_TIF    As String = "{557CF405-1A04-11D3-9A73-0000F81EF32E}"
Private Const ENCODER_PNG    As String = "{557CF406-1A04-11D3-9A73-0000F81EF32E}"

Private Declare Function GdiplusStartup Lib "gdiplus.dll" (ByRef token As Long, ByRef inputBuf As GdiplusStartupInput, ByVal outputBuf As Long) As Long
Private Declare Sub GdiplusShutdown Lib "gdiplus.dll" (ByVal token As Long)
Private Declare Function GdipBitmapGetPixel Lib "gdiplus" (ByVal bitmap As Long, ByVal x As Long, ByVal y As Long, color As Long) As Long
Private Declare Function GdipBitmapSetPixel Lib "gdiplus" (ByVal bitmap As Long, ByVal x As Long, ByVal y As Long, ByVal color As Long) As Long
Private Declare Function GdipBitmapSetResolution Lib "gdiplus" (ByVal bitmap As Long, ByVal xdpi As Single, ByVal ydpi As Single) As Long
Private Declare Function GdipCreateBitmapFromFile Lib "gdiplus" (fileName As Any, bitmap As Long) As Long
Private Declare Function GdipCreateBitmapFromScan0 Lib "gdiplus.dll" (ByVal nWidth As Long, ByVal Height As Long, ByVal stride As Long, ByVal PixelFormat As Long, scan0 As Any, nBitmap As Long) As Long
Private Declare Function GdipCreateBitmapFromHBITMAP Lib "gdiplus" (ByVal hbm As Long, ByVal hpal As Long, ByRef bitmap As Long) As Long
Private Declare Function GdipDeleteGraphics Lib "gdiplus" (ByVal graphics As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus.dll" (ByVal image As Long) As Long
Private Declare Function GdipDrawImageRectI Lib "gdiplus" (ByVal graphics As Long, ByVal image As Long, ByVal x As Long, ByVal y As Long, ByVal Width As Long, ByVal Height As Long) As Long
Private Declare Function GdipGetImageGraphicsContext Lib "gdiplus" (ByVal image As Long, graphics As Long) As Long
Private Declare Function GdipGetImageHeight Lib "gdiplus" (ByVal image As Long, Height As Long) As Long
Private Declare Function GdipGetImageWidth Lib "gdiplus" (ByVal image As Long, Width As Long) As Long
Private Declare Function GdipGraphicsClear Lib "gdiplus" (ByVal graphics As Long, ByVal lColor As Long) As Long
Private Declare Function GdipSaveImageToFile Lib "gdiplus.dll" (ByVal image As Long, ByVal fileName As Long, ByRef clsidEncoder As uuid, ByVal encoderParams As Long) As Long

'===== GDI無印関係等
Private Const PICTYPE_BITMAP = 1        'pictdescに与えるpictureのタイプ
Private Const PICTYPE_ENHMETAFILE = 4
Private Const DIB_RGB_COLORS = 0&

Private Declare Function CreateCompatibleBitmap Lib "gdi32" (ByVal hdc As Long, ByVal nWidth As Long, ByVal nHeight As Long) As Long
Private Declare Function CreateCompatibleDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function CreateDIBSection Lib "gdi32.dll" (ByVal hdc As Long, pbmi As BITMAPINFO, ByVal iUsage As Long, ppvBits As Long, ByVal hSection As Long, ByVal dwOffset As Long) As Long
Private Declare Function DeleteDC Lib "gdi32" (ByVal hdc As Long) As Long
Private Declare Function DeleteObject Lib "gdi32" (ByVal hObject As Long) As Long
Private Declare Function SelectObject Lib "gdi32" (ByVal hdc As Long, ByVal hgdiobj As Long) As Long
Private Declare Function SetDIBits Lib "gdi32" (ByVal hdc 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 SetPixelV Lib "gdi32.dll" (ByVal hdc As Long, ByVal x As Long, ByVal y As Long, ByVal crColor As Long) As Long

'===== enhancedmetafile関係
Private Declare Function CopyEnhMetaFile Lib "gdi32" Alias "CopyEnhMetaFileA" (ByVal hemfSrc As Long, ByVal lpszFile As String) As Long
Private Declare Function DeleteEnhMetaFile Lib "gdi32" (ByVal hEmf As Long) As Long
Private Declare Function GetEnhMetaFile Lib "gdi32" Alias "GetEnhMetaFileA" (ByVal lpszMetaFile As String) As Long
Private Declare Function GetMetaFile Lib "gdi32" Alias "GetMetaFileA" (ByVal lpFileName As String) As Long
Private Declare Function GetMetaFileBitsEx Lib "gdi32" (ByVal hmf As Long, ByVal nSize As Long, lpvData As Any) As Long
Private Declare Function GetEnhMetaFileHeader Lib "gdi32" (ByVal hEmf As Long, ByVal MetaHeaderSize As Long, ByRef MetaHeader As ENHMETAHEADER) As Long
Private Declare Function PlayEnhMetaFile Lib "gdi32" (ByVal hdc As Long, ByVal hEmf As Long, lpRect As RECT) As Long
Private Declare Function SetWinMetaFileBits Lib "gdi32" (ByVal cbBuffer As Long, lpbBuffer As Byte, ByVal hdcRef As Long, lpmfp As METAFILEPICT) As Long
Private Declare Function SetWinMetaFileBitsByNull Lib "gdi32" Alias "SetWinMetaFileBits" (ByVal cbBuffer As Long, lpbBuffer As Byte, ByVal hdcRef As Long, lpmfp As Long) As Long

Private Declare Function GetDC Lib "user32" (ByVal hwnd As Long) As Long
Private Declare Function GetLastError Lib "KERNEL32" () As Long
Private Declare Function ReleaseDC Lib "user32" (ByVal hwnd As Long, ByVal hdc As Long) As Long

Private Declare Function CLSIDFromString Lib "ole32" (ByVal lpszCLSID As Long, ByRef pclsid As uuid) As Long

'===== Clipboard関係
Const CF_ENHMETAFILE = 14

Private Declare Function OpenClipboard Lib "user32" (ByVal hWndNewOwner As Long) As Long
Private Declare Function CloseClipboard Lib "user32" () As Long
Private Declare Function GetClipboardData Lib "user32" (ByVal uFormat As Long) As Long
  
'Usage
Sub test()
  '引数は元画像サイズの何倍にするか、解像度dpi
  saveRangeAsHipixelJpeg GetDesktopPath & "\" & "rangeToHighPix.jpg", 2, 200
End Sub

Private Sub saveRangeAsHipixelJpeg(strOutName As String, multiplyingFactor As Long, myDpi As Long)
  Dim hBmp As Long
  Dim hbmpOld As Long
  Dim hdc As Long, hdcDesktop As Long
  Dim hEmf As Long '拡張メタファイルのハンドル
  Dim r As RECT '描画する領域
  Dim mh As ENHMETAHEADER '取得結果のメタファイルヘッダ
  Dim emfWidth As Long, emfHeight As Long
  Dim bmpInfo As BITMAPINFO
  Dim GDIsi As GdiplusStartupInput, gToken As Long
  Dim fileName As String
  Dim encBMP As uuid
  Dim pNewImage As Long, nStatus As Long, pDstBmp As Long, pGraphics As Long
  Dim i As Long, j As Long
  Dim lngWidth As Long, lngHeight As Long
 
  Const DIB_RGB_COLORS As Long = 0        ' RGBパタン
  
  If TypeName(Selection) <> "Range" Then Exit Sub
  Selection.CopyPicture Appearance:=xlPrinter, Format:=xlPicture
  
  'クリップボードからemf形式で取得
  If OpenClipboard(0) Then
    hEmf = GetClipboardData(CF_ENHMETAFILE)
    ' ハンドルを複製してから使用する
    hEmf = CopyEnhMetaFile(hEmf, vbNullString)
    CloseClipboard
  End If
  If hEmf = 0 Then
    MsgBox "emf取得に失敗"
    Exit Sub
  End If
 
  'GDI+初期化
  On Error Resume Next
  GDIsi.GdiplusVersion = 1&
  GdiplusStartup gToken, GDIsi, 0&
  If Err Then
    Err.Clear
    Exit Sub
  ElseIf gToken = 0& Then
    Exit Sub
  End If
  On Error GoTo 0
  
  'emfヘッダからサイズの取得
  GetEnhMetaFileHeader hEmf, Len(mh), mh
  With mh
     emfWidth = .rclBounds.Right - .rclBounds.Left
     emfHeight = .rclBounds.Bottom - .rclBounds.Top
  End With
  'デスクトップ互換のデバイスコンテキスト生成
  hdcDesktop = GetDC(0)
  hdc = CreateCompatibleDC(hdcDesktop)
  
  With bmpInfo.bmiHeader '構造体初期化
    .biSize = 40
    .biWidth = emfWidth * multiplyingFactor
    .biHeight = emfHeight * multiplyingFactor
    .biPlanes = 1
    .biBitCount = 24 '24ビット
    .biCompression = 0 'BI_RGB
    .biSizeImage = 0 'BI_RGBの時は0
    .biClrUsed = 0
  End With
  Dim hDIB As Long
   'DIB作成
  hBmp = CreateDIBSection(hdc, bmpInfo, DIB_RGB_COLORS, 0, 0, 0)
  hbmpOld = SelectObject(hdc, hBmp)
  '描画領域の設定
  r.Left = 0
  r.Top = 0
  r.Right = emfWidth * multiplyingFactor
  r.Bottom = emfHeight * multiplyingFactor
    
  '透明背景に黒文字だとbmpが真っ黒になるため、背景を白で塗りつぶし
  For i = 0 To emfWidth * multiplyingFactor - 1
    For j = 0 To emfHeight * multiplyingFactor - 1
      Call SetPixelV(hdc, i, j, &HFFFFFF)
    Next j
  Next i

  '拡張メタファイルの描画
   Call PlayEnhMetaFile(hdc, hEmf, r)
   
  'デバイス依存ビットマップオブジェクトHBITMAPから、ビットマップオブジェクトに変換
  'デスクトップ互換DCに描画しているので、当然デバイス依存になっていると考えれば良い?
  nStatus = GdipCreateBitmapFromHBITMAP(hBmp, 0&, pNewImage)
 
  ' 元画像サイズの取得
  GdipGetImageWidth pNewImage, lngWidth
  GdipGetImageHeight pNewImage, lngHeight
  
  ' コピー先Bitmap作成
  nStatus = GdipCreateBitmapFromScan0(lngWidth, lngHeight, 0, PixelFormat24bppRGB, ByVal 0&, pDstBmp)
  
  'dpiの指定
  nStatus = GdipBitmapSetResolution(pDstBmp, myDpi, myDpi)
  If nStatus = 0 Then
    ' コピー用Graphics作成
    If GdipGetImageGraphicsContext(pDstBmp, pGraphics) = 0 Then
        '白で初期化
        GdipGraphicsClear pGraphics, &HFFFFFFFF
        
        ' イメージのコピー
        GdipDrawImageRectI pGraphics, pNewImage, 0, 0, lngWidth, lngHeight
        
        'Graphicsの始末
        GdipDeleteGraphics pGraphics
    End If
  End If
  
  'BMP保存
'  strOutName = GetDesktopPath & "\emf2bmpKai.bmp"
'  CLSIDFromString StrPtr("{557CF400-1A04-11D3-9A73-0000F81EF32E}"), encBMP
'  GdipSaveImageToFile pDstBmp, StrPtr(strOutName), encBMP, ByVal 0&

  'Jpeg保存
'  strOutName = GetDesktopPath & "\emf2bmpKai.jpg"
  SaveImageToFile pDstBmp, strOutName, "JPG", 90
  
  '後始末
  GdipDisposeImage pDstBmp
  GdipDisposeImage pNewImage
  GdiplusShutdown gToken
  
  SelectObject hdc, hbmpOld
  DeleteObject hBmp
  DeleteDC hdc
  DeleteEnhMetaFile hEmf
  
End Sub

' // 文字列から CLSID を取得する
Private Function pvToCLSID(ByVal S As String) As uuid
    CLSIDFromString StrPtr(S), pvToCLSID
End Function

' // GDI+ hBitmap からファイルへ書き出し
'KenKenSPさんのコードを小変更 GdipCreateBitmapFromHBITMAPを削除
Public Function SaveImageToFile( _
    ByVal hBmp As OLE_HANDLE, _
    ByVal sFilename As String, _
    Optional ByVal sFormat As String = "JPG", _
    Optional ByVal nQuarity As Long = 90 _
) As Boolean
    
    Dim sEncoderStr As String
    Dim uEncoderParams   As EncoderParameters
    Dim nStatus   As Long
    
    If hBmp = 0 Then Exit Function
    Select Case UCase$(sFormat)
        Case "JPG": sEncoderStr = ENCODER_JPG
        Case "GIF": sEncoderStr = ENCODER_GIF
        Case "TIF": sEncoderStr = ENCODER_TIF
        Case "PNG": sEncoderStr = ENCODER_PNG
        Case Else: sEncoderStr = ENCODER_BMP
    End Select
    ' Jpeg のクオリティー設定
    If UCase$(sFormat) = "JPG" Then
        nQuarity = Abs(nQuarity)
        If nQuarity > 100 Then nQuarity = 100
        uEncoderParams.Count = 1
        With uEncoderParams.Parameter(0)
            .uuid = pvToCLSID(QUALITY_PARAMS)
            .Type = 4 ' Type Long
            .Value = VarPtr(nQuarity)
            .NumberOfValues = 1
        End With
    End If
    
    ' 保存処理
    If nStatus = 0 Then
        If UCase$(sFormat) = "JPG" Then
            nStatus = GdipSaveImageToFile(hBmp, _
                                          StrPtr(sFilename), _
                                          pvToCLSID(sEncoderStr), _
                                          VarPtr(uEncoderParams))
        Else
            nStatus = GdipSaveImageToFile(hBmp, _
                                          StrPtr(sFilename), _
                                          pvToCLSID(sEncoderStr), _
                                          ByVal 0&)
        End If
        SaveImageToFile = CBool(nStatus = 0)
        Call GdipDisposeImage(hBmp)
    End If
End Function

' // クリップボード hBitmap を取得する
Private Function pvGetHBitmapFromClipboard() As OLE_HANDLE
    If OpenClipboard(0&) <> 0 Then
        pvGetHBitmapFromClipboard = GetClipboardData(CF_BITMAP)
        Call CloseClipboard
    Else
        pvGetHBitmapFromClipboard = 0
    End If
End Function

Private Function GetDesktopPath() As String
  Dim wScriptHost As Object, strInitDir As String
  Set wScriptHost = CreateObject("Wscript.Shell")
  GetDesktopPath = wScriptHost.SpecialFolders("Desktop")
  Set wScriptHost = Nothing
End Function