Embed An Image in HTML
Web development often requires us to do strange things to get something done. The Yahoo Avatars API (which is undocumented) sends the small version of your avatar back as Base64 encoded string. You cannot just do am IMG link to this to get it to display in the browser. I was doing a small example using this API and I needed to display the image. In FireFox, this is easy.
XHTML/HTML
<img src=”data:image/png;base64,base64_data_goes_here“>
CSS
background-image: url(data:image/png;base64,base64_data_goes_here)
Voila, you are done.
This isn’t so easy in IE. Microsoft Internet Explorer does not support the data mechanism for embedding images.
A simple solution is to create a simple web service which accepts the base64 data and returns it as an image. However, this requires a separate call back to the server to get the image.
PHP Example
$b = base64_decode($_GET['img']);
header(’Content-Type: image/jpg’);
print $b;
RFC822 Solution
The second solution is to use a little known facility in Internet Explorer. Firefox does not need this solution so whatever application is outputting the HTML needs to send different information based on what browser is in use. Internet Explorer has the ability to save an HTML page with all its resources as a single file. It does this by using RFC822 which was originally created for email. Use MHTML and VML to create the references and embed the data.
Using this approach, all the resources and the HTML are packed into a single file. The file is separated into multiple parts where each part is one resource. In the HTML part, it is possible to refer to the resources in the other parts almost as if they were files.
Getting this to work was tricky. I wrote the code as a FireFox only page. It took quite a while to get this working and it was not obvious what the problem was.
This solution is in PHP.
The first thing to do is to detect IE. Do it like this:
if (eregi("MSIE",$_SERVER['HTTP_USER_AGENT'])) $MHTML=true;
else $MHTML = false;
Now you can check the variable $MHTML for true or false when different output is needed.
Next, output a header to tell the browser what type of content this is.
if($MHTML){
//see http://www.w3schools.com/media/media_mimeref.asp
//for details about Content-type:message/rfc822
header('Content-type:message/rfc822');
}
Output some more headers to turn of caching.
header('Cache-Control: no-cache');
header('Cache-Control: no-store');
header('Cache-Control: private');
Now for the weird stuff. The following code segment only gets generated for IE. It sets up the MIME version we want to use and starts marking off the multiple parts of the file. The boundary of each file part is indicated by “—-=_NextPart”.
<?php if($MHTML) : ?> MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_NextPart" ------=_NextPart Content-Location: file:///X:/ Content-Transfer-Encoding: quoted-printable Content-Type: text/html; charset="us-ascii" <?php endif ?> <!doctype html public '-//w3c//dtd html 4.01//en' 'http://www.w3.org/tr/html4/strict.dtd'> <html xmlns:v= "urn:schemas-microsoft-com:vml"> <head>
The first part of the multi=part document is the HTML itself. Notice the extra line before —–=_NextPart. If you do not have a blank line here, this will not work. Also, the blank line before ‘doctype’ MUST be there.
The HTML tag references Microsoft VML which is part of what is used to render the image. Throughout the example, you should notice that all the attributes are written with two or more spaces after the ‘=’. For some reason, this is necessary. The attribute :
v= "urn:schemas-microsoft-com:vml"
Must include at least 2 spaces after the = or it will not work. This drove me nuts until I figured that out.
<title>Test Embedded Image</title>
Nothing special here.
Now for some more special stuff.
<style type= "text/css">
v\:* {behavior:url(#default#VML);display:inline-block;}
</style>
Again, notice the spaces after the ‘=’.
This style tells HTML to use VML to render the image.
<?php if($MHTML):?> <v:shape style=3D"width:16px;height:16px;" ><v:imagedata src= my_jpg_image /></v:shape> <?php else : ?> <img src= "data:image/jpg;base64,base64_image_data_goes_here"> <?php endif ?>
The above will render the image in IE or non-IE as needed. Notice the attribute v:imagedata src= my_jpg_image. The name my_jpg_image can be any name you want. So long as it matches the name in the data section of the document.
Finally, after the <html> tag, the image data is included. Remember to leave a blank line before the —–=_NextPart marker.
</html> <?php if($MHTML):?> ------=_NextPart Content-Location: file:///X:/my_jpg_image Content-Transfer-Encoding: base64 Content-Type: image/jpg <?php echo $small ?> <?php endif ?>
Notice “Content-Location: file:///X:/my_jpg_image”. This names this section as if it is a file. This has to match the v:imagedata attribute of v:shape.
You can try out this example: Show Yahoo Avatar.
PHP source code: showavatar.php