Blog of Steve Savage A blog for business analysts and architects, and fellow user's of Sparx's EA

27Mar/060

Portable Network Graphics (PNG)

Problem addressed

Using Portable Network Graphics (PNG) as content in IE

One of the most annoying problems designers run in to for Win IE is it's apparent lack of
support for PNG Alpha transparencies. I say "apparent" because there is a way to display
PNG's properly in WIN IE 5.5+, it's just not quite automatic.

Solution

For this I rely on JavaScript to modify the page's Document Object Model (DOM) to replace <img> tags
with <span> tags with the above AlphaImageLoader filter applied as an inline style, with
the original PNG file as the source. The width and heigth defaults to the files actually width and height unless set in the style sheet.

01 function sf_applyPNGFilter() {
02  if(document.all&&document.getElementById
	&&(navigator.userAgent.lastIndexOf('mac')==-1)) {
03   for(var i=0; i<document.images.length; i++) {
04 	// loop through all the images on the page looking for PNG files.
05    o_image = document.images[i];
06    $imageName = o_image.src.toUpperCase();
07    if ($imageName.substring($imageName.length-3, $imageName.length)
	=="PNG") {
08	/* if the image ends in PNG convert it
09	You will need to re-apply the filter any
10	time you dynamically add content that contains a PNG file,
11 	so if the PNG filter has not already been applied to an image, then apply it.
12	*/
13     if(o_image.style.cssText.indexOf('AlphaImageLoader') == -1){
14      $imageID = (o_image.id) ? 'id="'
	+ o_image.id + '" ' : '';
15      $imageClass = (o_image.className) ? 'class="'
	+ o_image.className + '" ' : '';
16      $imageTitle = (o_image.title) ? 'title="'
	+ o_image.title + '" ' : 'title="' + o_image.alt + '" ';
17      $imageStyle = (o_image.style.cssText) ? o_image.style.cssText + ';' : '';
18      o_image.outerHTML = '<span ' + $imageID + $imageClass + $imageTitle
	+ ' style="' + $imageStyle
	+ ' width:' + o_image.width
	+ 'px; height:' + o_image.height + 'px; '
	+ 'filter:progid:DXImageTransform.Microsoft.'
	+ 'AlphaImageLoader(src=\'' + o_image.src + '\');">'
 	+ '</span>';
19      i = i - 1;
20     } //if
21    } //if($imageName...)
22   } //for
23  } //if(document.all...)
24 } //sf_applyPNGFilter
25 // only run this on IE Win,
	put script call inside of an IE
	Downlevel-hidden conditional comment for extra security
if(document.all&&document.getElementById&
&(navigator.userAgent.lastIndexOf('mac')==-1))
window.attachEvent("onload", sf_applyPNGFilter);

To make sure this is only runs on WIN IE 5.5+, I place the calling <script> tag inside of a
Downlevel-hidden conditional comment statement.

<!--[if gte IE 5.5]>
  <script src="/_interface/_javascripts/imageobjectpng.js"
		type="text/javascript" defer></script>
<![endif]-->
27Mar/060

Portable Network Graphics (PNG) in IE”

Problem addressed

Supporting Alpha chanel transparency in IE using CSS

Solution

As of IE 7.x you no longer need to use filters to support PNG Alpha Channels.

01 div##wantfancypngbackground {
02 /* turn off any current background image in place
	for other browsers, typically the png */
03  background-image:none;
04 /* reload the image using WIN IE's proprietary filter */
05  filter: progid:DXImageTransform.Microsoft.AlphaImageLoader
		(src="image.png",
		sizingMethod="crop|image|scale");}
06 /* sizingMethod:
07  crop: clips the image to fit the dimessions of the object.
08  image: Default.  Enlarges or reduces the
	border of the object to fit the dimensions of the image.
09  scale: Stretches or shrinks the image to
	fill the borders of the object */

Background

One of the most annoying problems designers run in to for Win IE is it's apparent lack of
support for PNG Alpha transparencies. I say "apparent" because there is a way to display
PNG's properly in WIN IE 5.5+, it's just not quite automatic.

For PNG images that are part of the sites content, I rely on JavaScript to modify the page's Document Object Model (DOM) to replace <img> tags
with <span> tags with the above AlphaImageLoader filter applied as an inline style, with
the original PNG file as the source. The width and heigth defaults to the files actually width and height unless set in the style sheet.

20Mar/060

‘Streaming’ Flash FLV video using Coldfusion, PHP or ASP

Problem Addressed

Allowing users to jump to any point in a movie without having to wait for the entire movie to download and without purchasing expensive media server software

Solution

  1. Convert you movie file to an FLV file
  2. Run Buraks - FLV MetaData Injector on the file. This will 'inject' the byte position of the videos 'keyframes' as additional information in the FLV.
  3. Install either:
  4. Select a player:
<cfsetting enablecfoutputonly="NO">
<!--- the function that sends the feed --->
<cfscript>
 function f_StreamFLV(s_file,i_seek) {
 // i_seek = the byte position of a key frame in the video
 var i_position = i_seek;
 var i_buffer = 10000;
 var byteClass = createObject("java",
 	"java.lang.Byte");
 var byteArray = createObject("java",
 	"java.lang.reflect.Array")
	.newInstance(byteClass.TYPE, i_buffer);
 var context = getPageContext();
 var response = context.getResponse().getResponse();
 var flvinstream = createObject("java",
 	"java.io.FileInputStream");
 // take over control of the feed to the browser
 var flvoutstream = response.getOutputStream();
 byteClass.Init(1);
 flvinstream.init(s_file);
 context.setFlushOutput(false);
 try {
  if(i_seek GT 0) {
   // jump to a location of a key frame
   flvinstream.skip(i_seek);
   // output the header bytes
   flvoutstream.write(toBinary('RkxWAQEAAAAJAAAACQ=='));
  }
  do {
   i_length = flvinstream.read(byteArray,0,i_buffer);
   if (i_length neq -1) {
   flvoutstream.write(byteArray);
   flvoutstream.flush();
  }
  }
	while (i_length neq -1);
	// keep going until there's nothing left to read.
 }
 catch(any excpt) {}
 flvoutstream.flush(); // send any remaining bytes
 response.reset(); // reset the feed to the browser
 flvoutstream.close(); // close the stream to flash
 flvinstream.close(); // close the file stream
}
</cfscript>

<!--- set to false to allow the file name
	to be passed, true for a numeric ID --->
<cfset b_secure = true>

<!--- path for the movie --->
<cfset s_path = ...>
<!--- must use the extended path either in the
	form c:/path/file.flv or c:\\path\\file.flv. --->
<!--- the application.root variable is set
	in my application.cfc file,
and gives the absolute path to the root of my site --->

<cfparam name="position" default="0">
<cfif isNumeric(position)>
 <cfset i_seek = position><cfelse><cfset i_seek = 0>
</cfif>

<!--- create an array for possible movies,
or this could read an XML file, or the vidID
could be used to reference a database record --->
<cfset a_movies=ArrayNew(1)>
<cfset a_movies[1] = "##s_path##movie1.flv">
<cfset a_movies[2] = "##s_path##movie2.flv">
<cfset s_file = a_movies[1]> <!--- set the default movie ---> 

<cfif b_secure>
 <!--- I decided to use a file ID instead
	of a file name to make the script more secure --->
 <cfif isDefined("url.vidID")
 	and isNumeric(url.vidID) and url.vidID LTE arrayLen(a_movies)>
  <cfset s_file = a_movies[url.vidID]>
 </cfif>
<cfelseif isDefined("url.vidFile")>
 <cfset s_file = "##s_path####url.vidFile##">
</cfif>
<cfset f_StreamFLV(s_file,i_seek)>
<cfsetting enablecfoutputonly="NOS">

How this works

When you 'seek' to a new position in the movie, the player will determine the location of the nearest key frame (as a byte position) and passes that number to the server.

The server opens a file stream to the video, and seeks to the specified position, outputs the standard FLV header bytes, and then starts sending the file starting at that point.

Background

This is the result of a major geekout weekend, the code works, but could probably use some refactoring.

I was trying to figure out a way to stream video for a hobby site I was planning, and I came across an article on streaming flash FLV files using PHP, great I thought, but I use Coldfusion hosting services (no PHP support), I took a look at the PHP script, and it seemed fairly straight forward, but I wasn't sure how to do a binary stream in coldfusion, some more research and I found Christian Cantrell's site, with entries on Byte Arrays and Writing Binary Data to Browser putting this together with some java that I know I managed to create a script for Streaming FLV video via ColdFusion.

For the video, I compressed an AVI file (Space Quest promo video) using sorensen Squeeze 3.5, and injected the key-frame position metadata using Buraks - FLV MetaData Injector