Color Effects Chapter 9: Drawing with Pixels 249 21 var invert:ColorTransform = new ColorTransform(); 22 invert.redOffset = 255; 23 invert.greenOffset = 255; 24 invert.blueOffset = 255; 25 invert.redMultiplier = -1; 26 invert.greenMultiplier = -1; 27 invert.blueMultiplier = -1; 28 mc2.transform.colorTransform = invert; The ColorMatrixFilter Class The next color effect uses the ColorMatrixFilter class. This class uses a 4 × 5 matrix to transform red, green, blue, and alpha values of the image, and can be used to create advanced hue, saturation, and contrast changes, among other effects. The following example demonstrates using luminance constants to desaturate an image to create a color grayscale. The identity matrix (the default matrix, as discussed in Chapter 8) for the ColorMatrixFilter class is as follows: Rs, Gs, Bs, As, Os Rnew = 1, 0, 0, 0, 0, Gnew = 0, 1, 0, 0, 0, Bnew = 0, 0, 1, 0, 0, Anew = 0, 0, 0, 1, 0 The rows represent the sum of changes in red, green, blue, and alpha values for each pixel. The first four columns are the multipliers for red, green, blue, and alpha values of the source (s), and the fifth column is the offset value for each row. The identity matrix shows a default multiplier of 1 and offset of 0 for each color channel, and no change to the other source color multiplier or offset values for that channel—that is, Rnew equals Rs, Gnew equals Gs, and so on. By introducing changes to the other color values, the appearance of each pixel will change. A good way to make this clear is to demonstrate the creation of a color grayscale image. When creating the new red value for a pixel, instead of using a multiplier of 1 for red and 0 for green and blue, you can use a partial value of 1 for all colors (with no change in alpha or offset). There will be no change in brightness because the sum of each row will still be 1. The alpha row receives no change to R, G, or B values, and the standard alpha multiplier of 1 is used with no offset. The only question is, what partial values should be used for each color? Knowing that hexadecimal values of gray are created with equal values of each color (0x666666, for example), it’s common to see a value of 0.33 used for each R, G, and B component of every pixel. However, it turns out that unequal values of red, green, and blue combine to create better grayscale images. We can take advantage of prior research to achieve color grayscales that are more pleasing to the eye, using what are known as luminance constants—constant red, green, and blue brightness values used for color calibration. N OT E Luminance is the amount of light that is reflected or emitted by a color. In lay terms, luminance is brightness (which is more of a human perception than a measured quantity). NTSC broadcast luminance constants (TV grayscale) published in 1954 were replaced by val- ues better tuned to CRT monitors and computer displays. For many years, Paul Haeberli’s lumi- nance vectors of 0.3086 for red, 0.6094 for green, and 0.0820 for blue, published in 1993, were used for color grayscale. Recently, these values have been adjust- ed for HDTV standards and are now slightly different. Red has reduced slight- ly, and green and blue have increased slightly, over previous values. The cur- rent standard is 0.2126 for red, 0.7152 for green, and 0.0722 for blue. Experiment to see which combination you prefer. Download from Wow! eBook <www.wowebook.com> Part II: Graphics and Interaction 250 Image Encoding and Saving By applying these constants to the source R, G, and B values, the new red, green, and blue values for each pixel will be optimized for grayscale display (Figure 9-16). The newly created matrix is passed to the filter constructor (line 8), and the result is applied to the filters array of the display object (line 12). The following code is found in the color_matrix_filter.fla source file. 1 //ITU-R BT.709-5 Parameter Values for the HDTV 2 // Standards for Production, 2002 3 var lumRd:Number = .2126; 4 var lumGr:Number = .7152; 5 var lumBl:Number = .0722; 6 7 var grayscale:ColorMatrixFilter = 8 new ColorMatrixFilter([lumRd, lumGr, lumBl, 0, 0, 9 lumRd, lumGr, lumBl, 0, 0, 10 lumRd, lumGr, lumBl, 0, 0, 11 0, 0, 0, 1, 0]); 12 mc1.filters = [grayscale]; The Color Class The last color manipulation is the simplest. It uses the Color class, from the fl.motion package to set the tint of a display object. The tint is set the same way line and fill styles are set using the Graphics class. Two parameters, color and alpha, are used to define the tint. Once the tint is created, it’s applied to the colorTransform property of the display object’s transform object, as in previous examples. The following code is found in the set_tint.fla source file: 1 import fl.motion.Color; 2 3 var blueTint:Color = new Color(); 4 blueTint.setTint(0x0000FF, 1); 5 mc.transform.colorTransform = blueTint; Image Encoding and Saving Now that you know how to create bitmap data, let’s talk about how to save it! We’ll discuss encoding a BitmapData object and saving the image as a JPG. At the end of the chapter, you’ll see how to add encoding and saving to our ongoing painting application, as well as save to PNG format, complete with transparency. The encoding process involves sending the bitmap data to an image encod- ing class. Fortunately, Adobe provides both JPG and PNG encoders as part of Adobe’s AS3 Core Library. At the time of this writing, information can be found at https://github.com/mikechambers/as3corelib, where you can down- load the library. Original Grayscale Figure 9-16. Grayscale created by the ColorMatrixFilter N OT E Discussed in Chapter 8, the Color class was written to support converting time- line animations into ActionScript and is only available to Flash Professional users. However, we have reproduced a subset of these features, to support the material covered in this book, in the com.learningactionscript3.color. ColorUtils class. This will allow users of other ActionScript editors to use the scripts in this book with minor modification. The class is included in the source material for this chapter, and its use in sample source code for Chapter 8 includes notes on its use. Download from Wow! eBook <www.wowebook.com> Image Encoding and Saving Chapter 9: Drawing with Pixels 251 The saving portion of the exercise is accomplished using the FileReference class. This class allows you to upload and download files. Some features, including the save() method for saving to your hard drive, require Flash Player 10. Saving JPG Images The heavy lifting of this exercise is performed during the encoding process by Adobe’s image encoder classes. The inner workings of these classes are a bit outside the scope of this book, but they’re very easy to use. The following script is found in the encode_and_save_jpg.fla source file, and it demonstrates the handy feature of taking a screen capture of everything on the stage. We’ll review Chapter 8 by drawing a button dynamically and adding it to the stage. Clicking that button will copy anything on the stage into a BitmapData instance, and then provide a prompt to save that image as a JPG. Later on, we’ll use a button to save the contents of a preexisting BitmapData instance— namely, the output of the paint program we developed earlier in this chapter. This exercise starts routinely with line 1 importing the JPGEncoder class, and lines 3 through 11 drawing a button and adding it to the display list. Notice that lines 8 and 9 center the button by determining the horizontal and verti- cal center of the stage, and line 10 sets the buttonMode property of the sprite to true to enable hand cursor feedback when rolling over the sprite. 1 import com.adobe.images.JPGEncoder; 2 3 var saveBtn:Sprite = new Sprite(); 4 var g:Graphics = saveBtn.graphics; 5 g.beginFill(0x990000, 1); 6 g.drawCircle(0, 0, 40); 7 g.endFill(); 8 saveBtn.x = stage.stageWidth/2; 9 saveBtn.y = stage.stageHeight/2; 10 saveBtn.buttonMode = true; 11 addChild(saveBtn); Lines 12 and 13 add a mouse click event listener to the button, which calls the function in lines 14 through 24 when the button is clicked. Lines 15 and 16 create a BitmapData object the size of the stage, and line 17 draws into the object everything on the stage, effectively taking a screen shot of the stage. Line 19 creates an instance of the JPGEncoder class, and passes an image qual- ity setting of 100 into the constructor when doing so. If no value is passed into the class during instantiation, a 50-percent quality setting is used. Line 20 encodes the bitmap data into bytes that can be understood as a JPG. It also stores the bytes in a special array called a ByteArray. A ByteArray is a heavily optimized array with its own properties and methods for reading and writing data at the byte level. N OT E An ActionScript 3.0 package called ZaaIL, developed by Aaron Boushley and Nate Beck of ZaaLabs, adds support for 40 additional image formats! See http:// www.zaalabs.com/2010/04/introducing- zaail-40-image-format-support-for-flash/ for more information. N OT E When using a Flash Player 10–specific feature, be sure your file is set to publish to Flash Player 10 in the File →Publish Settings →Flash→Player menu. (Flash Professional CS5 users can get to this setting immediately by clicking the Profile →Edit button in the Publish sec- tion of the Properties panel.) N OT E The companion website includes infor- mation about using a server and PHP to accomplish the same goal in Flash Player 9. See the post “Saving Data in Flash Player 9 Using PHP” for more information. N OT E See Chapter 8 if you need to review drawing vectors with the Graphics class. Download from Wow! eBook <www.wowebook.com> Part II: Graphics and Interaction 252 Adding Functionality to Your Color Picker Finally, line 22 creates an instance of the FileReference class, and line 23 invokes the save() method from this instance. In doing so, it passes in the bytes for the JPG and a default file name. The user’s operating system prompts for a location to save the file and the JPG is written to your local directory of choice. 12 saveBtn.addEventListener(MouseEvent.CLICK, onSaveImage, 13 false, 0, true); 14 function onSaveImage(evt:Event):void { 15 var stageCapture:BitmapData = 16 new BitmapData(stage.stageWidth, stage.stageHeight); 17 stageCapture.draw(stage); 18 19 var jpgEncoder:JPGEncoder = new JPGEncoder(100); 20 var jpgBytes:ByteArray = jpgEncoder.encode(stageCapture); 21 22 var fileRef:FileReference = new FileReference(); 23 fileRef.save(jpgBytes, "stageCapture.jpg"); 24 } Adding Functionality to Your Color Picker Now it’s time to exercise the gray cells and put what you’ve learned into prac- tice. The first example makes the color picker art you created in Chapter 8 functional. In the process, you’ll learn how to get and set pixel color values in a BitmapData instance. Then we’ll end with an exercise that uses many of the skills you’ve developed over the past few chapters. We’ll expand the drawing applica- tion you created by adding the color picker to change the color of your brush. We’ll also use the RoundRectButton class from Chapter 8 to create a button that triggers a save method, saving your artwork to your hard drive in PNG format. Getting and Setting Pixels In Chapter 8, we created the visual component of a color picker (shown in Figure 9-17), but didn’t add any functionality to the exercise. In this chapter, we’ll expand this class-based example and create a ColorPickerCustom class (named as such to differentiate it from the ColorPicker component in Flash Professional). This class will add an instance of the ColorPickerGraphics class you created in Chapter 8 to serve as the color graphic in the picker. We’ll also add a simple text display and a “current color” chip to the picker, and then show you how to get and set pixels using methods of the BitmapData class. The class is found in the book code library, at com/learningactionscript3/ color/ColorPickerCustom.as, and we’ll put it to use in the next section. Lines 1 through 10 define the package and import all the classes required by this class. Lines 12 through 18 declare the class (which extends MovieClip so you can easily treat the picker as a display object) and declare a small number of variables. Lines 14 and 15 contain the picker ( _pickerArt) and a BitmapData instance ( _bmd) that will contain the pixel data from the picker. This will allow us to get the color value of a pixel during the actual color picking process. N OT E Prior to Flash Player 10.1, saving a file using the FileReference class required active involvement, such as a mouse click, from the user. You can’t invoke the save() method from a timer or enter frame event, for example, because that is considered a passive experience from the viewpoint of the user. This has been relaxed in Flash Professional CS5. P u s h Y o u r s e l f ! Figure 9-17. The color picker created in Chapter 8 N OT E ColorPickerGraphics, the display por- tion of the color picker exercise created in Chapter 8, is in the same directory as this class, so your new code will function without importing that class. However, doing so allows you to see all class dependencies at a glance. Download from Wow! eBook <www.wowebook.com> Adding Functionality to Your Color Picker Chapter 9: Drawing with Pixels 253 The _col variable in line 16 will hold the picked color, and the _tf variable in line 17 will contain a text field that we’ll use to display the color value in string hexadecimal notation (#FFFFFF rather than 0xFFFFFF). The final variable, _chip, in line 18, will contain a movie clip that we’ll tint to match the selected color. The text and color chip will provide valuable feedback for the user when picking colors. 1 package com.learningactionscript3.color { 2 3 import flash.display.BitmapData; 4 import flash.display.Graphics; 5 import flash.display.MovieClip; 6 import flash.events.MouseEvent; 7 import flash.text.TextField; 8 import flash.text.TextFieldAutoSize; 9 import fl.motion.Color; 10 import com.learningactionscript3.color.ColorPickerGraphics; 11 12 public class ColorPickerCustom extends MovieClip { 13 14 private var _pickerArt:ColorPickerGraphics; 15 private var _bmd:BitmapData; 16 private var _col:uint = 0x000000; 17 private var _tf:TextField; 18 private var _chip:MovieClip; Lines 20 through 50 make up the class constructor. Lines 21 and 22 create an instance of the ColorPickerGraphics class to create the spectrum artwork, and add it as a child of the new class instance. Lines 23 and 24 add a mouse click event listener to the picker art inside the class. The private method onClick() (lines 52 through 59) will be used for visual feedback inside the picker (setting the text and “current color” chip values) and to populate a class property with the selected color. What we do with that color will be determined outside the ColorPickerCustom class when the picker is put into use by a project. We’ll look at that process later in this section. Lines 26 through 28 create a BitmapData instance the size of the picker art and draw the picker art into the bitmap data. Once we have the color spec- trum in pixel data, we can retrieve the color values of a pixel clicked on by the mouse. Lines 30 through 37 create a text field to display the chosen color’s hexadeci- mal value. It’s the width of the picker art, 14 pixels tall, and positioned just under the picker art. Note its initial content of “#FFFFFF” (white) is in line 34. In a moment, we’ll also apply an initial white color to the selected color chip. In line 35, the field’s background (with a default color of white) is turned on so the picker won’t let the stage color show beneath the field. Also, line 36 disables mouse interaction so that the cursor won’t change into a text cursor upon rolling over the field and the text won’t be selectable. Lines 39 through 45 draw a small movie clip using the Graphics class dis- cussed in Chapter 8, to serve as the selected color chip. It’s white (set in line 41), 100 × 14 pixels (line 42) and is positioned just under the text field (line N OT E In this example, no bitmap is created from the bitmap data or added to the display list. Because the spectrum art has already been stored in the _pic- kerArt property and added to the dis- play list, we need only the BitmapData instance for accessing color data. It need not be a part of the display list. Download from Wow! eBook <www.wowebook.com> Part II: Graphics and Interaction 254 Adding Functionality to Your Color Picker 44). Also, using the Graphics class, lines 47 through 50 draw a 1-pixel black border for the entire picker, as a finishing touch to the picker’s appearance. 19 //class constructor 20 public function ColorPickerCustom() { 21 _pickerArt = new ColorPickerGraphics(); 22 addChild(_pickerArt); 23 _pickerArt.addEventListener(MouseEvent.CLICK, 24 onClick, false, 0, true); 25 26 _bmd = new BitmapData(_pickerArt.width, 27 _pickerArt.height); 28 _bmd.draw(_pickerArt); 29 30 _tf = new TextField(); 31 _tf.width = 100; 32 _tf.height = 14; 33 _tf.y = 100; 34 _tf.text = "#000000"; 35 _tf.background = true; 36 _tf.mouseEnabled = false; 37 addChild(_tf); 38 39 _chip = new MovieClip(); 40 var g:Graphics = _chip.graphics; 41 g.beginFill(0x000000); 42 g.drawRect(0, 0, 100, 14); 43 g.endFill(); 44 _chip.y = 114; 45 addChild(_chip); 46 47 var border:MovieClip = new MovieClip(); 48 border.graphics.lineStyle(1, 0x000000); 49 border.graphics.drawRect(0, 0, 100, 128); 50 addChild(border); 51 } getPixel() Three things happen within the class when the picker is clicked. First, the getPixel() method is used in lines 54 and 55 to retrieve the color value from the pixel at the mouse location. This color is stored in the private property _col. Second, line 56 places the hexadecimal value of the color into the text field, using the prependZeros() method in lines 67 through 75. We’ll cover that method in a moment. Finally, the setTint() method (line 59) is used to apply the selected color to the color chip, as discussed previously in the sec- tion “The Color Class.” 52 //listener function 53 private function onClick(evt:MouseEvent):void { 54 _col = _bmd.getPixel(_pickerArt.mouseX, 55 _pickerArt.mouseY); 56 _tf.text = prependZeros(_col); 57 58 var col:Color = new Color(); 59 col.setTint(_col, 1); 60 _chip.transform.colorTransform = col; 61 } Download from Wow! eBook <www.wowebook.com> Adding Functionality to Your Color Picker Chapter 9: Drawing with Pixels 255 At this point, the color picker is completely functional, but only as a self- contained widget. We can’t yet use the picker for its intended purpose, because the _col property is private, so we can’t retrieve the selected color from outside the class. Therefore, the last functionality we need to put in place is a getter, color, in lines 63 through 65, to provide access to the _col property. 62 //getter for access to _col 63 public function get color():uint { 64 return _col; 65 } Finishing the explanation of this class, the aforementioned prependZeros() method takes a numeric color value and converts it to a string for display in the picker’s text field. However, when converting to a string, leading zeros are dropped. As such, if blue was selected, a string converted from its hexadeci- mal value would read FF instead of the far more typical 0000FF equivalent. So we need to add the number of leading zeros required to fill out the color value. The method starts with an empty string, zeros, in line 68, and then converts the numeric value to a string in line 69 using the toString() method. If we used this method without an argument, it would convert the number to decimal, or base 10. White, therefore, would appear as 16777215, which isn’t very useful for most people. By passing 16 into the method, it will convert the value to hexadecimal, or base 16. Using this argument, the result for white would be ffffff—acceptable, but not ideal. By using the toUpperCase() method, the string will be converted to uppercase and display as FFFFFF. All that remains is adding any necessary leading zeros and the preceding hash mark (#). Because the hexadecimal color string we want has six characters, line 70 determines how many zeros are needed by subtracting the current length of the string from 6. Using blue (0000FF) as an example again, 6 minus 2 (for the two characters in FF) is 4, so we need 4 zeros. Lines 71 through 73 loop the determined number of times and build the zeros string. Finally, the return string is assembled by concatenating the hash mark, leading zeros, and color string. 66 //text formatting for hex string display in picker 67 private function prependZeros(hex:uint):String { 68 var zeros:String = ""; 69 var hexString = hex.toString(16).toUpperCase(); 70 var cnt:int = 6 - hexString.length; 71 for (var i:int = 0; i < cnt; i++) { 72 zeros += "0"; 73 } 74 return "#" + zeros + hexString; 75 } 76 } 77 } Download from Wow! eBook <www.wowebook.com> Part II: Graphics and Interaction 256 Adding Functionality to Your Color Picker Using the picker with setPixel() Now that you know how to get the color values from a pixel, let’s do the reverse. To set the color values of a pixel in a BitmapData object, you need to again provide an x and y coordinate, but you also need to furnish the color you want the pixel to display. In the color_picker_set_pixel.fla source file, we’ll use the picker we just created to set the color of pixels in a small bitmap. Lines 1 through 5 import the ColorPickerCustom class, instantiate the picker, place it at point (10, 10), and add it to the display list. Lines 7 through 12 cre- ate a 100 × 100–pixel black BitmapData object, create a bitmap from that data, position it just to the right of the picker, and add it to the display list. The enter frame event listener in lines 14 through 19 manipulates the bitmap data, which we’ll explain after the code. 1 import com.learningactionscript3.color.ColorPickerCustom; 2 3 var colorPicker:ColorPickerCustom = new ColorPickerCustom(); 4 colorPicker.x = colorPicker.y = 10; 5 addChild(colorPicker); 6 7 var canvasBmd:BitmapData = new BitmapData(100, 100, 8 false, 0xFF000000); 9 var canvasBm:Bitmap = new Bitmap(canvasBmd); 10 canvasBm.x = 120; 11 canvasBm.y = 10; 12 addChild(canvasBm); 13 14 addEventListener(Event.ENTER_FRAME, onLoop, false, 0, true); 15 function onLoop(evt:Event):void { 16 var rndX:int = Math.random() * 100; 17 var rndY:int = Math.random() * 100; 18 canvasBmd.setPixel(rndX, rndY, colorPicker.color); 19 } Lines 16 and 17 of the listener select random pixel locations between 0 and 100, the size of the BitmapData instance. These values are then passed to the setPixel() method, along with the value from the color property of the picker. Figure 9-18 shows the file in action. If you want to get a better view of the pixels changing, add the following bold line to your script after line 11. This will scale the bitmap 300 percent, enlarging the pixels so they are easier to see. The source file already has this line in place, so you can compare your file with the source file, if you prefer. 10 canvasBm.y = 10; 11 canvasBm.scaleX = canvasBm.scaleY = 3; 12 addChild(canvasBm); Expanding Your Paint Program This exercise picks up where our paint tool left off, and can be found in the paint_tool_erase_blur_pick_save_png.fla source file. At this point, the paint program can paint using a blue color and air brush effect, as well as erase what you create. We’re going to add the most recent color picker, to allow you Figure 9-18. Setting pixels in a canvas N OT E The setPixel() method takes integer pixel values but ActionScript will auto- matically truncate a Number (lop off the decimal value) when passed into any object typed as an int. Download from Wow! eBook <www.wowebook.com> Adding Functionality to Your Color Picker Chapter 9: Drawing with Pixels 257 to pick the color for your brush, and a custom button and image encoder to save your artwork as a PNG. Although you may want to reorganize your file later (to consolidate import statements, for example), we’re going to add the new code to the end of the existing script for consistency and simplicity. Lines 56 through 58 import the required classes, including the color picker, button, and image encoder classes. Lines 60 through 62 create and position the color picker, and add it to the display list, as in the setPixel() example. Lines 64 through 68 add a mouse click event listener to the color picker to supplement its functionality. In addition to its self-contained behavior (like populating its text field and tinting its color chip), clicking on the picker widget will also query its color property and recreate the brush tool with the newly selected color. This will change the color of your airbrush. 56 import com.learningactionscript3.color.ColorPickerCustom; 57 import com.learningactionscript3.ui.RoundRectButton; 58 import com.adobe.images.PNGEncoder; 59 60 var colorPicker:ColorPickerCustom = new ColorPickerCustom(); 61 colorPicker.x = colorPicker.y = 10; 62 addChild(colorPicker); 63 64 colorPicker.addEventListener(MouseEvent.CLICK, 65 onPickColor, false, 0, true); 66 function onPickColor(evt:MouseEvent):void { 67 brush = createBrush(colorPicker.color, 1); 68 } The final section of code allows you to save your artwork to a PNG file. Lines 70 through 72 create a single instance of the RoundRectButton class introduced in Chapter 8. The button is 60 × 20 pixels, with a rounded corner radius of 6. A single-pixel border and button color based on a dark blue color theme, offsets the white button label, “Save.” The button is positioned below the picker in lines 73 and 74, and added to the display list in line 75. Lines 77 through 84 add a mouse click event listener to the button, and the three simple lines of code therein are all it takes to save your art as a PNG. Line 80 encodes the bitmap data into bytes, just like the JPGEncoder class that you used in the “Saving JPG Images” section of this chapter, with two small exceptions. The PNGEncoder class requires no quality setting or instantiation. Instead, the encode() method is static and can be called by the class itself, not by an instance of the class. Lines 82 and 83 are essentially the same in both examples, with the very minor change of the default file name. 69 //encode and save 70 var saveBtn:RoundRectButton = 71 new RoundRectButton(60, 20, 6, 1, 0x000066, 72 "Save", 0xFFFFFF); 73 saveBtn.x = 10; 74 saveBtn.y = 150; 75 addChild(saveBtn); 76 Download from Wow! eBook <www.wowebook.com> Part II: Graphics and Interaction 258 What’s Next? 77 saveBtn.addEventListener(MouseEvent.CLICK, onSaveImage, 78 false, 0, true); 79 function onSaveImage(evt:Event):void { 80 var byteArray:ByteArray = PNGEncoder.encode(bmd); 81 82 var fileRef:FileReference = new FileReference(); 83 fileRef.save(byteArray, "myArt.jpg"); 84 } Congratulations! Your modifications are complete. Figure 9-19 shows a detail of the application at work. In this figure, we set the stage color to a pale yellow to emphasize that the erasing is actually removing color, instead of painting over it with white. What’s Next? One of the most surprising things to come to light after each major Flash upgrade is how small the engineering team manages to keep Flash Player. The bitmap manipulation and compositing features discussed in this chapter are by no means an exhaustive look at everything Flash Player can do with pix- els. If you spent some time and effort on the project, you could make a fairly respectable graphics-editing application using only Flash (and, perhaps, a server technology like PHP for file management). The best examples of this that we can think of are the image editing applications available in the Aviary suite at http://www.aviary.com. Yet despite these capabilities, Flash Player still remains small and easy to install and update. Bravo, past and present Flash Professional and Flash Player engineers, and congratulations to the creative and programming team at Aviary! Now it’s time to change direction and focus on the oft-overlooked workhorse of the Flash family: text. Text can be as fruitful a subject for experimentation and eye-candy as vectors and bitmaps, but it also serves a very important utilitarian purpose. Creating, styling, and parsing text are fundamental needs that you’ll frequently encounter. In the next chapter, we’ll look at ways to work with text, including: • Creating text fields on the fly • Initializing basic text field appearance and behavioral attributes • Formatting text, including default formats for text fields, as well as chang- ing formats across entire fields or partial text selections • Using HTML and Cascading Style Sheets (CSS) for limited HTML ren- dering and global styling • Embedding ActionScript triggers in HTML anchor tags • Parsing paragraph, line, and character data from text fields using points and indices Figure 9-19. A detail of the save-capable painting application learningaction- script3 Packages The new packages contributed to the book’s ActionScript 3.0 library for this chapter include ColorPickerCustom , a class for creating a functioning color picker, and ColorEffects , a bonus class that consolidates several preset color effects discussed in the chapter, which you can use with the ConvolutionFilter , ColorTransform , and ColorMatrixFilter classes. Download from Wow! eBook <www.wowebook.com> . _tf.mouseEnabled = false; 37 addChild(_tf); 38 39 _chip = new MovieClip(); 40 var g:Graphics = _chip.graphics; 41 g.beginFill(0x 000 000 ); 42 g.drawRect (0, 0, 100 , 14); 43 g.endFill(); 44 _chip.y = 114; 45. _pickerArt.height); 28 _bmd.draw(_pickerArt); 29 30 _tf = new TextField(); 31 _tf.width = 100 ; 32 _tf.height = 14; 33 _tf.y = 100 ; 34 _tf.text = " #00 000 0"; 35 _tf.background = true; 36 _tf.mouseEnabled. MovieClip { 13 14 private var _pickerArt:ColorPickerGraphics; 15 private var _bmd:BitmapData; 16 private var _col:uint = 0x 000 000 ; 17 private var _tf:TextField; 18 private var _chip:MovieClip; Lines