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
'Render WebControl to html
Dim html As String = getHtml(control)
'If WebControl has images, make the html Word compatible
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
'Make a multipart mhtml document
Dim mainBody As CDO.IBodyPart
mainBody = msg
mainBody.ContentMediaType = "multipart/related"
'Make the html part of the document
iBp = mainBody.AddBodyPart()
iBp.ContentMediaType = "text/html"
iBp.ContentTransferEncoding = "quoted-printable"
stm = iBp.GetDecodedContentStream
stm.WriteText(html)
stm.Flush()
'Make the image parts of the document
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"
'ContentLocation must be the same as in the
'html part to make them linked
.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")