Introducing the Scale9Bitmap class

 

scale9bitmap

The Scale9Bitmap class applies a scale9Grid to a Bitmap. It takes advantage of a technique I used for DestroyTwitter’s window drop shadow, scaling nine Bitmap instances. When developing the MAX Companion, I tried Didier Brun’s ScaleBitmap class, but discovered a costly memory leak in which it instantiates a new BitmapData instance with every resize call. This wouldn’t be a big deal for a once-and-done resize, but as a window drop shadow, memory skyrockets.

I decided to start from scratch and develop a class that is super fast and slim as can be. The Bitmaps are only updated when the BitmapData is set. After that, the only process that takes place is the resizing of each Bitmap—no BitmapData manipulation needed. Setup requires a single method to set the BitmapData and the Rectangle that indicates the stretchable portion of the Bitmap. BitmapData can be changed on the fly and there is a scale property that sets both scaleX and scaleY.

The source code is on GitHub, so feel free to give it a whirl.

Two feet of snow and the Canon 50mm f/1.2L

 

Jen in the snow

Yesterday, Jen asked if we would still be able to go out today because of the snow forecast. I said, “I don’t see why not. It’s probably going to flurry.” Two feet of snow later, we decided to take the camera out for a walk. It was a lot colder than expected, so we didn’t stay out very long. At f/2.8 with my new 50mm f/1.2, I was able to snag a few beauties of Jen.

A trip down memory lane

 

In high school, a few friends and I played a game during study hall. We called it Flips. The game combined handball, hacky sack, and horse. We used a paper ball wrapped in tape and hit it between each other with our hands. If a player faults, they earn a letter. Once a player spells “Flips,” they are out of the game. A fault occurs if a player hits the ceiling with the ball, hits the ball out of bounds, hits a malicious ball, or is unable to return the ball. The last two players in the game go one on one in a “championship”. Whoever survives wins and a tally is added to their score. We easily surpassed 300 games throughout the year.

Senior year, I took a film course. Flips was a year-long production and my submission for the class’s film festival. We filmed all year just so we would be able to play. A number of the people involved were simply given a job to get out of study hall. After the film festival, the hall monitors were onto us and reported us to the principal. Through some smooth talking, we were given permission to play and even got to play in the principal’s office! I can easily say Flips made me wake up in the morning and want to go to school.

Here, in its entirety, is the Flips documentary:

Taking a break from DestroyTwitter

 

It has been exactly one year since I decided to enter the Twitter app world with DestroyTwitter. Within this year, there has been 45 public releases and over 300,000 installs. After working tirelessly on it, all the while juggling college and a job, it’s time to take a break. As much as I love developing DestroyTwitter, I want to experience a life away from the computer for those hours after 5 pm.

Anyone who knows me has probably seen me in front of a computer more often than not. And with every year that goes by, I feel one step closer to burning out. I want to be able to code for as long as I can, but I know it isn’t healthy to maintain my current pace. In college, the morning/day/night work schedule made sense—I was surrounded by peers who worked around the clock as well. Now that I have a full-time job and a family, it’s time to balance the work with a period of downtime and recreation.

I will continue to respond to emails regarding DestroyTwitter as best I can, but I have no plans to post the source code. If you have any questions, feel free to ask them in the comments. It has been a fun year and I can’t thank you enough for contributing to the project.

Introducing the Console class and debug package

 

I realized I need a more…official…way of debugging my apps, so I wrote the Console class. It’s primary function is to record activity to a specified log file. So far, I have a few methods that write entries—success, error, cancel, and print. I definitely plan to add more, but these are the main ones I intend to use in the near future. Since the name “trace” is off limits in AS3, I referenced my PHP background and named the trace method, “print”.

The class also includes the ability to automatically trace entries to Eclipse’s console along with writing them to a file. Files are written asynchronously, but I also added a delay property that combines entries, so the writing process is less likely to slow down the app. Taking advantage of AIR 2.0’s UncaughtErrors feature, the Console automatically logs fatal errors and their stack traces, if possible. Here’s an example of its usage:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
var path:String = File.applicationStorageDirectory.nativePath;
 
// params: log file path, LoaderInfo
// automatically writes a session start entry to the log
Console.init(path, loaderInfo);
 
Console.delay = 1000;
Console.traceError = true;
 
// params: id, message
Console.success("wp post", "wrote blog post");
 
// params: id, message
Console.error("wp post", "previous post was depressing");
 
// params: id, message
Console.cancel("Christmas", "why would you want to do that?");
 
// params: message
Console.print("this is a test");
[Fri Dec 18 00:31:31 GMT-0500 2009] Session Start
[Fri Dec 18 00:31:31 GMT-0500 2009] [success] [wp post] wrote blog post
[Fri Dec 18 00:31:31 GMT-0500 2009] [error] [wp post] previous post was depressing
[Fri Dec 18 00:31:31 GMT-0500 2009] [cancel] [Christmas] why would you want to do that?
[Fri Dec 18 00:31:31 GMT-0500 2009] [print] this is a test

I do expect to build the class over time, eventually adding TextField support. In the meantime, the source code is available on GitHub.

Outroducing Introducing the CurrentDate class

 

Always test, never assume. I was so caught up with how cool typing CurrentDate.time looks, I forgot to test the class for performance. Kristopher Schultz pointed out in the comments that instantiating a new Date instance is much faster than any method in the CurrentDate class. Taking it one step further, I tested it for memory and found similar results.

CurrentDate will be removed from DestroyFramework, but it will always have a place in my heart.

[note] I know “outroducing” is not a word, but it damn well should be.

I’m working on a debug package for DestroyFramework and found the need, in my Log class, to retrieve the current timestamp whenever entries are made. I looked through the almost laughably redundant Date class and found no methods for updating the instance to show the current date and time. Since I’m an avid recycler, there was no way I would instantiate a Date instance each call. Immediately, I thought of the getTimer method. Because it tallies the number of milliseconds since the SWF or AIR app starts, I should be able to add that to the Date.milliseconds property to return the current date. It worked!

1
2
3
4
5
var date:Date = new Date();
 
// delay a few seconds
 
date.milliseconds += getTimer();

Since I can’t assume a CurrentDate method will be called when getTimer() == 0, all I needed to do was include an offsetTimestamp variable that records getTimer when the Date instance is instantiated. I then subtract that variable from getTimer and I have the right number of milliseconds to update the Date instance with.

1
2
3
4
5
6
var offsetTimestamp:int = getTimer();
var date:Date = new Date();
 
// delay a few seconds
 
date.milliseconds += getTimer() - offsetTimestamp;

The class itself is as easy as pie to use. All of the methods are static, so you can simply call CurrentDate.time and it returns the Date.time property for the current time. I included every get and toString method found in Date. I also included two extra methods, antemeridian and postmeridian that indicate whether the current time is AM or PM. Since it can be formatted in different ways, I made the return values boolean.

1
2
3
4
5
6
CurrentDate.month; // 11 (months start at 0)
CurrentDate.date; // 15
CurrentDate.fullYear; // 2009
CurrentDate.toString(); // Tue Dec 15 8:13:08 GMT-0500 2009
CurrentDate.antemeridian; // true
CurrentDate.postmeridian; // false

As always, the source code for the new class can be found on GitHub.

Improved text handling in TextFieldPlus

 

This past week, I wrote a post regarding the sluggish TextField.text method. I also shared an alternative that shows incredible gains—storing the text prior to modifying it. I originally found it was 11 times faster, but after redoing the tests, I discovered that TextField.text’s speed is dependent on the number of characters in the String. Here are the results, including the new TextFieldPlus.text:

1 lorem ipsum paragraph (584 characters)
var text...........................42 / 0.071 msec/char (100,000 iterations)
TextFieldPlus.text.................63 / 0.107 msec/char (100,000 iterations)
TextField.text....................458 / 0.784 msec/char (100,000 iterations)
 
2 lorem ipsum paragraph (1,168 characters)
var text..........................42 / 0.035 msec/char (100,000 iterations)
TextFieldPlus.text................64 / 0.054 msec/char (100,000 iterations)
TextField.text...................1098 / 0.94 msec/char (100,000 iterations)
 
3 lorem ipsum paragraph (1,752 characters)
var text..........................42 / 0.023 msec/char (100,000 iterations)
TextFieldPlus.text................64 / 0.036 msec/char (100,000 iterations)
TextField.text..................2379 / 1.357 msec/char (100,000 iterations)

As you can see, the pre-stored method and TextFieldPlus.text maintain the same speed as the String grows, but TextField.text slows. TextFieldPlus.text uses the pre-stored method, but isn’t as fast because it’s a getter and includes a conditional to play nice with htmlText. Even so, the less work for the developer is worth the extra 20 milliseconds.

Along with TextField.text, I tackled TextField.text += String. This is even slower because it requires both getting and setting. It’s so slow, in fact, that the debugger displays a warning and suggests using TextField.append instead. This is considerably faster, but still slow.

To combat the speed issues, I developed a transaction-based system, inspired the SQLConnection class. With beginText and commitText, you can batch-modify a TextField’s text with either += or appendText. The latter is still faster, but by a slighter margin. Here are the speed results:

1,000 iterations
var text +=...............................................................1
TextField.text +=.......................................................620
TextField.append........................................................583
TextFieldPlus.text +=...................................................571
TextFieldPlus.appendText................................................578
TextFieldPlus.text += (transaction).......................................2
TextFieldPlus.appendText (transaction)....................................1
 
100,000 iterations
var text +=..............................................................53
TextField.text +=.................................................timed out
TextField.append..................................................timed out
TextFieldPlus.text +=.............................................timed out
TextFieldPlus.appendText..........................................timed out
TextFieldPlus.text += (transaction).....................................116
TextFieldPlus.appendText (transaction)...................................93

Just as before, TextFieldPlus’s methods are slightly slower, but the difference is worth it from a developer’s standpoint. While writing the new appendText method, I discovered a fun fact about TextField.appendText—the method actually calls TextField.replaceText(TextField.length, TextField.length, text). With this new knowledge, I figured I’d skip the middleman and call super.replaceText from appendText. Surprisingly, this is slower, so I stuck with super.appendText.

The updated source code is on GitHub, so TextFieldPlus is ready to go with the new implementation.

SpellCheckHighlighter class, demo app, and screencast

 

SpellCheckHighlighterDemo

This past week, I spent my spare time writing the SpellCheckHighlighter class. It allows non-Flex developers to use Adobe’s spellchecker, Squiggly, which only provides a UI for Flex components. Currently, SpellCheckHighlighter includes a number of additional settings like underline type and color. I’ve provided a screencast of the demo app below and the source code can be found on GitHub.

Please note, the volume on this screencast is a low because it was recorded at about 8 a.m. and everyone wasn’t awake yet.

Accessing TextField.text is slower than a bag of dried apricots

 

I always assumed accessing TextField.text would be slow, since we’re warned against TextField.text += String in the ASDocs, but I didn’t realize how slow. I switched to my test project for a quick verification. Lo and behold, it’s over 11 times slower than storing to a String variable and accessing that. Here are the results and test code:

TextField.text.................................454 (100000 iterations)
text............................................41 (100000 iterations)
bag of dried apricots..........................376 (100000 iterations)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
package {
	import com.gskinner.utils.PerformanceTest;
 
	import flash.display.Sprite;
	import flash.text.TextField;
	import flash.utils.setTimeout;
 
	public class Test extends Sprite {
		public var p:PerformanceTest;
 
		public var textfield:TextField;
		public var text:String;
 
		public function Test() {
			p = PerformanceTest.getInstance();
 
			textfield = new TextField();
 
			textfield.text = 
				"Lorem Ipsum is simply dummy text of the printing and typesetting industry. " +
				"Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, " +
				"when an unknown printer took a galley of type and scrambled it to make a type " +
				"specimen book. It has survived not only five centuries, but also the leap into " +
				"electronic typesetting, remaining essentially unchanged. It was popularised in " +
				"the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, " +
				"and more recently with desktop publishing software like Aldus PageMaker " +
				"including versions of Lorem Ipsum.";
 
			text = textfield.text;
 
			setTimeout(run, 1000);
		}
 
		public function run():void {
			p.testFunction(testTextFieldText, 100000);
			p.testFunction(testText, 100000);
		}
 
		public function testTextFieldText():void {
			textfield.text;
		}
		public function testText():void {
			text;
		}
	}
}

ScreenCapture class, demo app and screencast

 

ScreenCaptureDemo

I felt like working on something new this past weekend, so I devoted a few hours to the new AIR 2.0 Beta. One feature that really caught my eye is the NativeProcess class, which allows developers to communicate with the system through an executable. This is a game-changer in the AIR world, opening more doors than you or I can ever imagine. I’ve always wanted screen capture support in AIR, so with this new class, I developed it myself.

Surprisingly, my efforts proved successful!—I had a working class, ScreenCapture, and application, ScreenCaptureDemo, up and running within a few hours. Tired of staring at the Spark components, I decided to add a touch of DT to the app by designing my own skin. This took far longer than the core of the app, but made a world of difference. Now that I think of it, this could be considered my first Flex app.

The downside of the NativeProcess class is it nulls the cross-platform benefit of AIR. The developer must compile a .dmg for Mac, a .exe for Windows, and the choice between a few for Linux. Since I only spent this weekend on the ScreenCapture class and I’m only familiar with the Mac command line, both the class and demo app are Mac-only. Also, the demo won’t work just yet for most of you. It requires a prerelease build of AIR 2.0, but things should be okay once the Beta 2 is out.

Download ScreenCaptureDemo (Mac-only, requires AIR 2.0 prerelease)

Along with adding the ScreenCapture class to DestroyFramework, I created a repository for the ScreenCaptureDemo source and installer on GitHub as well. Check them both out and enjoy!

[note] I’m not quite sure why Vimeo decided to cut out the right audio channel in the screencast…