February 21, 2011

Bash script: Harvest email addresses from a directory of files

I had to go through over a year of server logs to rescue newsletter signups that may or may not have been passed to our newsletter service, due to server updates that happened without my knowledge. I wrote a little command to scrape all the log files in my directory, and output a text file with all the addresses it found. Here we go:
# recursively(!) scrapes directories and prints out each email address to a new line
egrep -o -h -r '[a-zA-Z0-9_-\+\.]+@[a-zA-Z0-9_-\+\.]+?\.[a-zA-Z]{2,3}' *.* | sort | uniq > email_addresses.txt
Credit: I started with a command from Linux.com, and customized it until the output was correct, and nicely formatted.

jQuery fadeIn() bug on iPad: element disappears

I'm using jQuery on a new site, and a fadeIn() animation broke, but only on the iPad with iOS 3.2.2. It works fine in every other browser, including the newer iOS (4+) for iPad. To fix the problem, which in my case doesn't affect other browsers, I simply added a callback function that manually sets the width and height of the element:
newSection.fadeIn( 300 , function(){
  newSection.css( { width:320, height:480 } );
});
I tried other css properties first, but width and height are the magic properties that prevent the element from being hidden. Quick, someone tell Steve Jobs :p

February 20, 2011

Actionscript 3: Grabbing and resizing BitmapData

I found this handy little class in a Flash project that I just had to jump back into. It's an easy way to take a bitmap snapshot of any DisplayObject, then resize the image data to fit another frame. You can fill the area, letterbox/pillowbox, or just scale to new dimensions. Feel free to use this, and nevermind the warnings that show up in FDT :)
package com.cache.util 
{
 import flash.display.BitmapData;
 import flash.display.DisplayObject;
 import flash.geom.Matrix;
 import flash.geom.Point;
 import flash.geom.Rectangle;
 
 /**
  * @author justin - http://uihacker.blogspot.com/
  */
  
 public class ImageEdit 
 {
  /**
   * Return a snapshot of a DisplayObject
   */
  public static function getBitmapData( vSource:DisplayObject, vW:Number=NaN, vH:Number=NaN, vTransparent:Boolean=true, vColor:int=0xFF00FF, vMatrix:Matrix=null ):BitmapData
  {
   // set defaults.
   var vWidth:int = ( isNaN( vW )) ? vSource.width : vW;
   var vHeight:int = ( isNaN( vH )) ? vSource.height : vH;  
   
   // create BitmapData object.
   var vBmp:BitmapData = new BitmapData( vWidth, vHeight, vTransparent, vColor );
   
   // draw contents of source clip into target.
   if ( vMatrix == null ) vBmp.draw( vSource, null, null, null, null, true );
   else vBmp.draw( vSource, vMatrix, null, null, null, true ); 
   
   return vBmp;
  }
  
  /**
   * Build & return a matrix to use to scale a bitmap
   */
  public static function getScaleMatrix( scale:Number ) : Matrix
  {
   var matrix:Matrix = new Matrix();
   matrix.scale(scale, scale);
   return matrix;
  }
  
  /**
   * Pass these constants into the getResizedBitmapData() function
   */
  public static const RESIZE_SCALE:String = 'ImageEdit.resizeScale';
  public static const RESIZE_LETTERBOX:String = 'ImageEdit.resizeLetterbox';
  public static const RESIZE_CROP:String = 'ImageEdit.resizeCrop';
  
  /**
   * Return a resized BitmapData copy of the original
   */
  public static function getResizedBitmapData( sourceBitmap:BitmapData, targetWidth:Number, targetHeight:Number, resizingMethod:String = '', disposeSourceBmp:Boolean = true ) : BitmapData
  {
   // get current dimensions
   var curW:Number = sourceBitmap.width;
   var curH:Number = sourceBitmap.height;
   
   // get ratios of 2 sides
   var ratio_w:Number = targetWidth / curW;
   var ratio_h:Number = targetHeight / curH;
   var shorterRatio:Number = ( ratio_w > ratio_h ) ? ratio_h : ratio_w;
   var longerRatio:Number = ( ratio_w > ratio_h ) ? ratio_w : ratio_h;
   
   
   // apply sizing
   switch( resizingMethod )
   {
    case RESIZE_CROP :
     // get shorter ratio, so we fill the target area
     var resizedWidth:int = Math.round( curW * longerRatio );
     var resizedHeight:int = Math.round( curH * longerRatio );
     
     // create copy of, and resize the source bitmap
     var resizedSourceBmp:BitmapData = new BitmapData( resizedWidth, resizedHeight, false, 0x00000000 );
     // create scale matrix 
     var matrix:Matrix = new Matrix();
     matrix.scale( longerRatio, longerRatio );
     // take resized snapshot
     resizedSourceBmp.draw( sourceBitmap, matrix );
     
     // draw into destination bitmap, letterbox/pillowbox style
     var destBitmap:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );
     var offset:Point = new Point( targetWidth / 2 - resizedWidth / 2, targetHeight / 2 - resizedHeight / 2 );
     destBitmap.copyPixels( resizedSourceBmp, new Rectangle( -offset.x, -offset.y, resizedSourceBmp.width, resizedSourceBmp.height ), new Point() );
     
     // clean up temp BitmapData
     resizedSourceBmp.dispose();
     if( disposeSourceBmp ) sourceBitmap.dispose();
     
     return destBitmap;
     break;
     
    case RESIZE_LETTERBOX :
     // get shorter ratio, so we fill the target area
     var resizedWidth:int = Math.round( curW * shorterRatio );
     var resizedHeight:int = Math.round( curH * shorterRatio );
     
     // create copy of, and resize the source bitmap
     var resizedSourceBmp:BitmapData = new BitmapData( resizedWidth, resizedHeight, false, 0x00000000 );
     // create scale matrix 
     var matrix:Matrix = new Matrix();
     matrix.scale( shorterRatio, shorterRatio );
     // take resized snapshot
     resizedSourceBmp.draw( sourceBitmap, matrix );
     
     // draw into destination bitmap, letterbox/pillowbox style
     var destBitmap:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );
     var pastePoint:Point = new Point( targetWidth / 2 - resizedWidth / 2, targetHeight / 2 - resizedHeight / 2 );
     destBitmap.copyPixels( resizedSourceBmp, new Rectangle( 0, 0, resizedSourceBmp.width, resizedSourceBmp.height ), pastePoint );
     
     // clean up temp BitmapData
     resizedSourceBmp.dispose();
     if( disposeSourceBmp ) sourceBitmap.dispose();
     
     return destBitmap;
     break;
     
    case RESIZE_SCALE :
    default : 
     // create output bitmap
     var vBmp:BitmapData = new BitmapData( targetWidth, targetHeight, false, 0x00000000 );
     // create scale matrix 
     var matrix:Matrix = new Matrix();
     matrix.scale( ratio_w, ratio_h );
     // snapshot with scale & return
     vBmp.draw( sourceBitmap, matrix );
     
     // clean up temp BitmapData
     if( disposeSourceBmp ) sourceBitmap.dispose();
     
     return vBmp;
     break; 
     
   }
   return null;
  }
 }
}

February 7, 2011

Processing: Shapes disappear when switching from P3D to OPENGL renderer

I was having some issues with my 3d scene in Processing when switching to OPENGL from the P3D rendering mode. At a certain distance, my shapes were disappearing in OPENGL, but they displayed properly in P3D. My good friend (and Processing whiz) Movax gave me the suggestion to adjust my perspective(). Theses we the value that helped my situation:
perspective( 1.0f, 1.5f, 1f, 200000f );
The 200,000 value is the maximum depth that the camera will be able to see in OPENGL mode, which was large enough to view some of my distant objects that had been disappearing.