Inverting the alpha of a bitmap image

A piece of code and a demo says more than a thousand words :). This code demonstrates inversion of an alpha channel in Flash8/AS2.

  1. /**
  2. * This example demonstrates inverting an alpha channel on an image.
  3. * Since Flash premultiplies the alpha, we need to keep two separate images: one with the color data, and
  4. * one with the alpha data. It demonstrates splitting the alpha from an image, inverting and proves
  5. * premultiplying the alpha destroys color information.
  6. *
  7. * @author J.C. Wichman / Objectpainters.com
  8. */
  9.  
  10. import flash.geom.Rectangle;
  11. import flash.geom.Point;
  12. import flash.display.BitmapData;
  13. import flash.filters.ColorMatrixFilter;
  14.  
  15. //set up some default params for the images
  16. var width:Number = 100;
  17. var height:Number = 100;
  18. var fillColor:Number = 0x000000;
  19.  
  20. /**
  21. * Simple function that checks how many bitmaps have already been shown on stage and
  22. * bases the location for the next one on that information. Never use code like this
  23. * out of context, since its bad programming practice:).
  24. */
  25. function showBitmap (pBitmap:BitmapData, title:String) {
  26. var imageCount:Number = this.getNextHighestDepth();
  27. var row:Number = Math.floor (imageCount/3);
  28. var columns:Number = imageCount%3;
  29.  
  30. var newClip:MovieClip = this.createEmptyMovieClip("image"+imageCount, imageCount);
  31. newClip.attachBitmap(pBitmap, 0);
  32. newClip.createTextField("title", 1, 0, 110, 10,10);
  33. var textClip:TextField = newClip["title"];
  34. textClip.autoSize = true;
  35. textClip.text = "Image "+imageCount+":\n"+title;
  36. var tf:TextFormat = new TextFormat();
  37. tf.font = "Arial";
  38. tf.align ="center";
  39. textClip.setTextFormat(tf);
  40.  
  41. newClip._x = (columns * 150)+10;
  42. newClip._y = (row * 170)+10;
  43. }
  44.  
  45.  
  46. //setting up demo rgb image, this is an image without alpha.
  47. //Since flash uses premultiplied alpha, adding an alpha channel will ruin the image for
  48. //further use when we want to invert the alpha channel, so we keep colours separate from alpha
  49. //(omg pink shirts!)
  50. var colorImage:BitmapData = new BitmapData(width, height, false, fillColor);
  51. for (var x = 0; x < width; x++) {
  52. for (var y = 0; y < height; y++) {
  53. //fiddle with the pixel data to show a dark gradient
  54. colorImage.setPixel( x,y, x<<16|y<<8|x+y);
  55. }
  56. }
  57. showBitmap (colorImage, "Colour w/o alpha");
  58.  
  59. //now we create a demo alpha bitmap. All color info is non existent, only
  60. //alpha data is set. When x<y the alpha value is near opaque, otherwise its near transparent.
  61. //we only use 0xAF and 0x10 instead of 0xFF and 0x00 to show partial alpha values are inverted ok as well
  62. var demoAlpha:BitmapData = new BitmapData(width, height, true, fillColor);
  63. for (var x = 0; x < width; x++) {
  64. for (var y = 0; y < height; y++) {
  65. demoAlpha.setPixel32( x,y, (x<y?0xAF:0x10)<<24);
  66. }
  67. }
  68. showBitmap (demoAlpha, "Alpha only");
  69.  
  70. //now imagine you didnt have a separate alpha bitmap to start with, but a starting image with alpha
  71. //which you needed to extract first:
  72. var alphaSplit:BitmapData = new BitmapData(width, height, true, fillColor);
  73. //copy the alpha channel of one image to another image
  74. alphaSplit.copyChannel(demoAlpha, new Rectangle(0,0, width, height), new Point(0,0), 8,8);
  75. showBitmap (alphaSplit, "Alpha channel copy\n (same as previous)");
  76.  
  77. //now we are going to invert the alpha. This can be done on a pixel by pixel basis, but this might just
  78. //be faster, you'd have to test it
  79. var alphaInvert:BitmapData = alphaSplit.clone();
  80. var matrix:Array = new Array();
  81. matrix = matrix.concat([1, 0, 0, 0, 0]); // red
  82. matrix = matrix.concat([0, 1, 0, 0, 0]); // green
  83. matrix = matrix.concat([0, 0, 1, 0, 0]); // blue
  84. matrix = matrix.concat([0, 0, 0, -1, 0xff]); // alpha, negate the alpha and add 255
  85. alphaInvert.applyFilter(alphaInvert, alphaInvert.rectangle, new Point(0, 0), new ColorMatrixFilter (matrix));
  86. showBitmap (alphaInvert, "Inversion of \nalpha channel");
  87.  
  88. //now the real action, we combine our original color pixels with the inverted alpha channel
  89. var comboImage:BitmapData = new BitmapData(width, height, true, fillColor);
  90. comboImage.copyPixels(colorImage, colorImage.rectangle, new Point(0,0), alphaInvert, new Point(0,0));
  91. showBitmap (comboImage, "Colours + \ninverted alpha");
  92.  
  93. //now to prove premultiplied alpha destroys color information:
  94. var colorImgWithAlpha:BitmapData = new BitmapData(width, height, true, fillColor);
  95. for (var x = 0; x < width; x++) {
  96. for (var y = 0; y < height; y++) {
  97. //fiddle with the pixel data to show a dark gradient
  98. colorImgWithAlpha.setPixel32( x,y, (x<y?0xfe:0x01)<<24|x<<16|y<<8|x+y);
  99. }
  100. }
  101. colorImgWithAlpha.applyFilter(colorImgWithAlpha, colorImgWithAlpha.rectangle, new Point(0, 0), new ColorMatrixFilter (matrix));
  102. showBitmap (colorImgWithAlpha, "Colour with\n premultiplied \n inverted alpha");
  103.  
  104.  
  105.  

Leave a Reply