Tag: HtmlLoader smoothing class
How to Smooth The Adobe Air HtmlLoader
by Charles on Jan.29, 2010, under Software
- The area with the blue box is actualy a smoothed AIR HtmlLoader
- The area with the blue box is another instance of the AIR HtmlLoader
In a recent project we worked on; the client was very adamant about being able to display a plethora of different types of unstructured data inside of a kiosk. This included information that contained tables and images inside of the same display at the same time. The content also included a plethora of font variations. The length of content was greatly variable and really didn’t have any defined or repeatable structure.
If you are familiar with the flash text fields htmlText capabilities, you will see that it can render basic html. However, this just wasn’t enough for this project so we decided to implement the Adobe AIR HtmlLoader which; from my understanding runs an instance of webkit inside of AIR. It’s awesome being able to load web content directly into a project; but there is one huge problem with the HtmlLoader. You can’t smooth the HtmlLoader! If you rotate or resize the loader, you will quickly find yourself with an ugly, poorly rendered mess.
After thinking about the issue for a while, I came up with a solution. The trick is to load the web content inside of the HtmlLoader, then use the BitmapData, and Bitmap classes to render out a bitmap of the HtmlLoader. You will then be able to apply smoothing, size, and rotate the newly created bitmap without much distortion.
When using this technique you lose the ability to scroll and navigate web content. Our whole point was to not let people know there was a web page being displayed inside the kiosk; so this methodology worked very well for us.
Below I have provided the class that I use in order to implement the smooth html loader functionality. Be careful because my class is using some external references. Namely Tweener as well as GenericNotifyEvent.
package com.bostonproductions.web {
import flash.display.MovieClip;
import flash.display.Sprite;
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.events.Event;
import flash.html.HTMLLoader;
import flash.events.HTMLUncaughtScriptExceptionEvent;
import flash.geom.Matrix;
import com.bostonproductions.events.GenericNotifyEvent;
import com.caurina.transitions.Tweener;
public class smoothHtmlLoader extends MovieClip {
public static var HTMLREADY:String = “smoothHtmlLoader_HTMLREADY”;
private var theBrowser:HTMLLoader;
private var htmlToRender:String;
private var smoothCap:Sprite;
private var rawSmoothCap:Bitmap;
private var scrollPosition:int = 0;
private var tryCenter:Boolean = false;
private var targetHeight:Number = 650;
private var targetWidth:Number = 720;
// Alter the native height based on the resize ratio
private var HeightResizeRatio:Number = 1;
public function smoothHtmlLoader(_HeightResizeRatio:Number = 1, _targetWidth:Number = 0, _targetHeight:Number = 0):void {
HeightResizeRatio = _HeightResizeRatio;
if (_targetWidth != 0) {
targetWidth = _targetWidth;
}
if (_targetHeight != 0) {
targetHeight = _targetHeight;
}
createHtmlViewer();
}
/*
* DATE: 10/14/2009
* AUTHOR: Charles Palen
* NAME: displayHtml
* DESCRIPTION: Tries to fit all the html into the instance of
* the HTMLLoader. If it cant fit it all, it MUST return the
* non-fitting html.
*/
public function displayHtml(_HtmlToDisplay:String):String {
var nonFittingHtml:String = “”;
htmlToRender = _HtmlToDisplay;
loadTargetLocation();
return nonFittingHtml;
}
/*
* DATE: 10/15/2009
* UPDATE: 10/28/2009
* The html parser now splits html up into chunks in instances where there are tables and images
* If this occurs – especially in the case of a table – we want to be able to CENTER it.
*
* Added optional boolean to specify we want to examine the content height, and resize/center the browser
* based on it!
*
* AUTHOR: Charles Palen
* NAME: setScrollPosition
* DESCRIPTION: Stores what should be the vertical scroll for this. Once the html content loads it can be set.
*/
public function setScrollPosition(_VerticalScroll:int = 0, _TryCenterBrowser:Boolean = false):void {
scrollPosition = _VerticalScroll;
tryCenter = _TryCenterBrowser;
}
private function createHtmlViewer():void {
theBrowser = new HTMLLoader();
theBrowser.width = targetWidth;
//theBrowser.height = targetHeight;
theBrowser.placeLoadStringContentInApplicationSandbox = true;
theBrowser.addEventListener(Event.COMPLETE, htmlLoaded, false, 0, true);
theBrowser.addEventListener(HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION, scriptException, false, 0, true);
theBrowser.addEventListener(Event.LOCATION_CHANGE, htmlClicked, false, 0, true);
theBrowser.paintsDefaultBackground = false;
}
private function destroyHtmlViewer():void {
if (theBrowser != null) {
theBrowser.removeEventListener(Event.COMPLETE, htmlLoaded);
theBrowser.removeEventListener(HTMLUncaughtScriptExceptionEvent.UNCAUGHT_SCRIPT_EXCEPTION, scriptException);
theBrowser.removeEventListener(Event.LOCATION_CHANGE, htmlClicked);
theBrowser.cancelLoad();
if (contains(theBrowser) ) {
removeChild(theBrowser);
}
theBrowser = null;
}
}
private function loadTargetLocation():void {
if( theBrowser != null ) {
theBrowser.loadString(htmlToRender);
}
}
private function htmlLoaded(e:Event) {
// Remove the event
e.currentTarget.removeEventListener(Event.COMPLETE, htmlLoaded);
// Set the vertical scroll
theBrowser.scrollV = scrollPosition;
// If the try resize boolean is set – lets try it!
// Dont center – just shrink it if possible
if (tryCenter == true) {
var resizedHeight:Number = theBrowser.contentHeight;
var resizedWidth:Number = theBrowser.contentWidth;
if (resizedHeight > targetHeight) {
resizedHeight = targetHeight;
}
if (resizedWidth > targetWidth) {
resizedWidth = targetWidth;
}
theBrowser.width = resizedWidth;
theBrowser.height = resizedHeight;
targetWidth = resizedWidth;
targetHeight = resizedHeight;
}
theBrowser.width = targetWidth;
theBrowser.height = targetHeight * HeightResizeRatio;
//var bitmapAsset:Bitmap = e.target.content as Bitmap;
//bitmapAsset.smoothing = true;
Tweener.addTween(this, { alpha:1, time:.1, onComplete:generateSmoothVersion } );
}
private function generateSmoothVersion():void {
// Create the smoothed version
var tmpImage:BitmapData = new BitmapData(targetWidth, targetHeight, true,0×000000);
// Draw it – the last parameter set to true is SMOOTHING – tmpImage will be smoothed
var transformMatrix:Matrix = new Matrix();
//transformMatrix.translate(0, 500);
tmpImage.draw(theBrowser, null, null, null, null, true);
//tmpImage.draw(theBrowser,
// Create the bitmap
rawSmoothCap = new Bitmap(tmpImage);
rawSmoothCap.smoothing = true;
smoothCap = new Sprite();
smoothCap.addChild(rawSmoothCap);
//rawSmoothCap.x = 50;
//rawSmoothCap.y = 50;
addChild(smoothCap);
// Destroy the heavy html components to free up some memory
destroyHtmlViewer();
//swapChildren(theBrowser, smoothCap);
//theBrowser.alpha = 1;
//smoothCap.x = 300;
//smoothCap.y = 100;
// Broadcast so that we know its ready
if(tryCenter == true) {
dispatchEvent(new GenericNotifyEvent(smoothHtmlLoader.HTMLREADY, false, true, true));
}
}
private function destroySmoothVersion():void {
if (smoothCap != null) {
if (rawSmoothCap != null) {
if (smoothCap.contains(rawSmoothCap) ) {
smoothCap.removeChild(rawSmoothCap);
}
rawSmoothCap = null;
}
if ( contains(smoothCap) ) {
removeChild(smoothCap);
}
smoothCap = null;
}
}
private function htmlClicked(e:Event):void {
// Auto go back to wherever we were
//theBrowser.reload();
//loadTargetLocation();
}
private function scriptException(e:HTMLUncaughtScriptExceptionEvent):void {
trace(”ScriptException:” + e);
}
public function destroyInternals():void {
destroyHtmlViewer();
destroySmoothVersion();
}
}
}

