Introduction
Ever wanted to make a report out of an html document and have it sent to the
client for offline use in Word or Excel? An RFC - compliant Multipart MIME
Message (mhtml web archive) is one single file containing all related material
such as linked documents and images serialized to their Base64 inline encoding
representations. There is no native support for creating mhtml archives in .NET
but thanks to the Windows CDO library this is easy accomplished.
The code
The projects contains 3 classes; mht
, mhtImage
and mhtImageCollection
.
The mht class contains the conversion functions like convertWebControlToMHTString
which takes a webControl and a collection of images and returns a string
representation of the created mht archive. Use this function when the
converting webControl is dependent on user specific Session and Application
variables for rendering or when you use dynamically created images.
Public Function convertWebControlToMHTString(ByVal control As WebControl, _
ByVal MHTimages As mhtImageCollection) As String
Dim html As String = getHtml(control)
If Not MHTimages Is Nothing Then
fixImageLocation(html, MHTimages)
End If
Dim msg As New CDO.MessageClass
Dim stm As ADODB.Stream = Nothing
Dim MS As System.IO.MemoryStream = Nothing
Dim iBp As CDO.IBodyPart
Dim mainBody As CDO.IBodyPart
mainBody = msg
mainBody.ContentMediaType = "multipart/related"
iBp = mainBody.AddBodyPart()
iBp.ContentMediaType = "text/html"
iBp.ContentTransferEncoding = "quoted-printable"
stm = iBp.GetDecodedContentStream
stm.WriteText(html)
stm.Flush()
If Not MHTimages Is Nothing Then
Dim oMhtImage As mhtImage
For Each oMhtImage In MHTimages
iBp = mainBody.AddBodyPart()
With iBp
.ContentMediaType = "image/" + _
oMhtImage.ImageFormat.ToString().ToLower()
.ContentTransferEncoding = "base64"
.Fields.Append("urn:schemas:mailheader:content-location", _
DataTypeEnum.adBSTR, , , oMhtImage.ContentLocation)
.Fields.Update()
.Fields.Refresh()
End With
Try
MS = New System.IO.MemoryStream
oMhtImage.Image.Save(MS, oMhtImage.ImageFormat)
Dim bytearray As Byte() = MS.ToArray()
stm = iBp.GetDecodedContentStream
stm.Write(bytearray)
stm.Flush()
Finally
MS.Close()
stm.Close()
End Try
Next
End If
stm = mainBody.GetStream()
Return stm.ReadText(stm.Size)
End Function
The convertWebPageToMHTString
function converts an html document
from a specific URL to a mht archive, all images included. Use this function
for public html documents not dependent on user specific Session
and
Application
variables.
Public Function convertWebPageToMHTString(ByVal url As String) As String
Dim msg As New CDO.MessageClass
Dim stm As ADODB.Stream = Nothing
Try
msg.MimeFormatted = True
msg.CreateMHTMLBody(url, CDO.CdoMHTMLFlags.cdoSuppressNone, "", "")
stm = msg.GetStream()
Return stm.ReadText(stm.Size)
Finally
stm.Close()
End Try
End Function
The fixImageLocation
appends the string "http://" at the beginning
of each ContentLocation
if not already there, for Word compliance
Private Sub fixImageLocation( _
ByRef html As String, ByRef MHTimages As mhtImageCollection)
Dim curContentLocation As String
Dim curIndex As Integer
Dim oMhtImage As mhtImage
For Each oMhtImage In MHTimages
curContentLocation = oMhtImage.ContentLocation
If curContentLocation.IndexOf(":") = -1 Then
curIndex = html.IndexOf(curContentLocation)
While curIndex <> -1
html = html.Insert(curIndex, "http://")
curIndex = html.IndexOf(curContentLocation, curIndex + _
curContentLocation.Length)
End While
oMhtImage.ContentLocation = "http://" + curContentLocation
End If
Next
End Sub
The mhtImage
class contains image information.
Property Image
contains the actual image.
Property ContentLocation
contains the path to the image, must be exactly
the same as the source for the image in the html part.
Property ImageFormat
contains the image format (jpg, gif, bmp...)
The mhtImageCollection
class contains a collection of mhtImages.
Using the code
Example on how to make a mht archive from a Panel webControl containing one
image.
Dim oMhtCol As New mhtImageCollection
oMhtCol.add(New mhtImage(System.Drawing.Image.FromFile( _
Server.MapPath("/mhtml/images/myComputer.jpg")), _
"images/myComputer.jpg", System.Drawing.Imaging.ImageFormat.Jpeg))
sendMHTFile(ConvertWebControlToMHTString(Panel1, oMhtCol), "myFirstMht.mht")