Code:
Option Explicit
Private Type GdiplusStartupInput
GdiplusVersion As Long
DebugEventCallback As Long
SuppressBackgroundThread As Long
SuppressExternalCodecs As Long
End Type
Private Declare Function GdiplusStartup Lib "gdiplus" (Token As Long, inputbuf As GdiplusStartupInput, Optional ByVal outputbuf As Long = 0) As Long
Private Declare Sub GdiplusShutdown Lib "gdiplus" (ByVal Token As Long)
Private Type RECTF
nLeft As Single
nTop As Single
nWidth As Single
nHeight As Single
End Type
Private Declare Function GdipRecordMetafile Lib "gdiplus" (ByVal referenceHdc As Long, ByVal pType As Long, ByRef frameRect As RECTF, ByVal frameUnit As Long, ByVal description As Long, ByRef metafile As Long) As Long
Private Declare Function GdipEmfToWmfBits Lib "gdiplus" (ByVal hemf As Long, ByVal cbData16 As Long, ByVal pData16 As Long, ByVal iMapMode As Long, ByVal eFlags As Long) As Long
Private Declare Function GdipGetHemfFromMetafile Lib "gdiplus" (ByVal metafile As Long, ByRef hemf As Long) As Long
Private Declare Function GdipLoadImageFromStream Lib "gdiplus" (ByVal Stream As Long, Image As Long) As Long
Private Declare Function GdipGetImageBounds Lib "gdiplus.dll" (ByVal nImage As Long, srcRect As RECTF, srcUnit As Long) As Long
Private Declare Function GdipGetImageGraphicsContext Lib "gdiplus.dll" (ByVal pImage As Long, ByRef graphics As Long) As Long
Private Declare Function GdipDrawImageRectRect Lib "gdiplus" (ByVal hGraphics As Long, ByVal hImage As Long, ByVal dstX As Single, ByVal dstY As Single, ByVal dstWidth As Single, ByVal dstHeight As Single, ByVal srcX As Single, ByVal srcY As Single, ByVal srcWidth As Single, ByVal srcHeight As Single, ByVal srcUnit As Long, ByVal imageAttributes As Long, ByVal Callback As Long, ByVal callbackData As Long) As Long
Private Declare Function GdipDeleteGraphics Lib "gdiplus.dll" (ByVal mGraphics As Long) As Long
Private Declare Function GdipDisposeImage Lib "gdiplus" (ByVal Image As Long) As Long
Private Declare Function GdipLoadImageFromFile Lib "gdiplus" (ByVal FileName As Long, hImage As Long) As Long
Private Declare Function GetDesktopWindow Lib "user32.dll" () As Long
Private Declare Function GetDC Lib "user32.dll" (ByVal hWnd As Long) As Long
Private Declare Function ReleaseDC Lib "user32.dll" (ByVal hWnd As Long, ByVal hDC As Long) As Long
Private Declare Function DeleteEnhMetaFile Lib "gdi32.dll" (ByVal hemf As Long) As Long
Private Declare Function CreateStreamOnHGlobal Lib "ole32" (ByVal hGlobal As Long, ByVal fDeleteOnRelease As Long, ppstm As Any) As Long
Private Declare Function GlobalAlloc Lib "kernel32" (ByVal uFlags As Long, ByVal dwBytes As Long) As Long
Private Declare Function GlobalLock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Function GlobalUnlock Lib "kernel32" (ByVal hMem As Long) As Long
Private Declare Sub CopyMemory Lib "kernel32.dll" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
Private m_Token As Long
Private Sub Class_Initialize()
Dim GSI As GdiplusStartupInput
Dim pa As Long, hMod As Long
On Error Resume Next
GSI.GdiplusVersion = 1&
Call GdiplusStartup(m_Token, GSI)
End Sub
Private Sub Class_Terminate()
If m_Token Then GdiplusShutdown m_Token
End Sub
Public Function GetRTFpictureFormat_ImageArray(ImageData() As Byte, ByVal destWidth As Long, ByVal destHeight As Long) As String
' passing 0 for width,height will have image rendered at original width,height
Dim outData() As Byte, IStream As IUnknown, hImage As Long
If m_Token = 0 Then Exit Function
If Not Not ImageData() Then
Set IStream = pvIStreamFromArray(VarPtr(ImageData(LBound(ImageData))), (UBound(ImageData) - LBound(ImageData) - 1&))
If Not IStream Is Nothing Then
If GdipLoadImageFromStream(ObjPtr(IStream), hImage) = 0& Then
If pvImagetoWMFStream(hImage, outData(), destWidth, destHeight) = True Then
GetRTFpictureFormat_ImageArray = pvStreamToRTFwmf(outData(), destWidth, destHeight)
End If
End If
End If
End If
Debug.Assert App.hInstance
End Function
Public Function GetRTFpictureFormat_ImageFile(ByVal FileName As String, ByVal destWidth As Long, ByVal destHeight As Long) As String
' passing 0 for width,height will have image rendered at original width,height
Dim hImage As Long, outData() As Byte
If m_Token = 0 Then Exit Function
If GdipLoadImageFromFile(StrPtr(FileName), hImage) Then Exit Function
If pvImagetoWMFStream(hImage, outData(), destWidth, destHeight) = True Then
GetRTFpictureFormat_ImageFile = pvStreamToRTFwmf(outData(), destWidth, destHeight)
End If
End Function
Private Function pvImagetoWMFStream(hImage As Long, outArray() As Byte, Width As Long, Height As Long) As Boolean
Dim lSize As Long, hDC As Long
Dim hGraphics As Long, hMetaFile As Long
Dim sizeF As RECTF
Const UnitPixel As Long = 2&
Const MetafileTypeEmf As Long = 3&
Const MM_ANISOTROPIC As Long = 8&
GdipGetImageBounds hImage, sizeF, UnitPixel
hDC = GetDC(GetDesktopWindow)
If GdipRecordMetafile(hDC, MetafileTypeEmf, sizeF, UnitPixel, 0&, hMetaFile) = 0& Then
If GdipGetImageGraphicsContext(hMetaFile, hGraphics) = 0 Then
GdipDrawImageRectRect hGraphics, hImage, 0!, 0!, sizeF.nWidth, sizeF.nHeight, sizeF.nLeft, sizeF.nTop, sizeF.nWidth, sizeF.nHeight, UnitPixel, 0&, 0&, 0&
GdipDeleteGraphics hGraphics
Else
GdipDisposeImage hMetaFile: hMetaFile = 0&
End If
End If
ReleaseDC GetDesktopWindow(), hDC
GdipDisposeImage hImage
If hMetaFile Then
If GdipGetHemfFromMetafile(hMetaFile, hImage) = 0& Then
lSize = GdipEmfToWmfBits(hImage, 0&, 0&, MM_ANISOTROPIC, 0&)
If lSize Then
ReDim outArray(0 To lSize - 1&)
' modify width/height if proportional scaling desired. Use ratios btwn passed sizes & sizeF sizes
If Width < 1& Then Width = sizeF.nWidth
If Height < 1& Then Height = sizeF.nHeight
pvImagetoWMFStream = (GdipEmfToWmfBits(hImage, lSize, VarPtr(outArray(0)), MM_ANISOTROPIC, 0&) <> 0&)
End If
DeleteEnhMetaFile hImage
End If
GdipDisposeImage hMetaFile
End If
End Function
Private Function pvStreamToRTFwmf(inStream() As Byte, Width As Long, Height As Long) As String
Dim Header As String
Dim L As Long, c As Long, x As Long
Dim lSize As Long, sLUT(0 To 255) As String * 2
Const LineLen As Long = 256&
Header = "{\pict\wmetafile8" & _
"\picwgoal" & CStr(Width * Screen.TwipsPerPixelX) & _
"\pichgoal" & CStr(Height * Screen.TwipsPerPixelY) & _
" "
lSize = UBound(inStream) - LBound(inStream) + 1
pvStreamToRTFwmf = Space$(Len(Header) + 2 * (lSize \ LineLen + lSize) + 1)
For x = 0& To 15&: sLUT(x) = "0" & LCase$(Hex(x)): Next '
For x = 16& To 255&: sLUT(x) = LCase$(Hex(x)): Next
c = Len(Header)
Mid$(pvStreamToRTFwmf, 1, c) = Header
c = c + 1&: x = LBound(inStream)
For L = 1& To lSize \ LineLen
For x = x To x + LineLen - 1&
Mid$(pvStreamToRTFwmf, c, 2) = sLUT(inStream(x))
c = c + 2&
Next
Mid$(pvStreamToRTFwmf, c, 2) = vbCrLf
c = c + 2&
Next
For x = x To UBound(inStream)
Mid$(pvStreamToRTFwmf, c, 2) = sLUT(inStream(x))
c = c + 2&
Next
Mid$(pvStreamToRTFwmf, c, 1) = "}"
End Function
Private Function pvIStreamFromArray(ArrayPtr As Long, Length As Long) As stdole.IUnknown
' Purpose: Create an IStream-compatible IUnknown interface containing the
' passed byte aray. This IUnknown interface can be passed to GDI+ functions
' that expect an IStream interface -- neat hack
On Error GoTo HandleError
Dim o_hMem As Long
Dim o_lpMem As Long
If ArrayPtr = 0& Then
CreateStreamOnHGlobal 0&, 1&, pvIStreamFromArray
ElseIf Length <> 0& Then
o_hMem = GlobalAlloc(&H2&, Length)
If o_hMem <> 0 Then
o_lpMem = GlobalLock(o_hMem)
If o_lpMem <> 0 Then
CopyMemory ByVal o_lpMem, ByVal ArrayPtr, Length
Call GlobalUnlock(o_hMem)
Call CreateStreamOnHGlobal(o_hMem, 1&, pvIStreamFromArray)
End If
End If
End If
HandleError:
End Function