image to terminal color scheme

by wh0
Today on Flash apps for things that obviously don't need a Flash app:

a color scheme maker for PuTTY.

1. Enter the URL of some image and click "remote."
2. Set image points by selecting one of "origin," "row," or "column" and clicking in the image. Nudge with arrow keys.
3. Enter a session name and click "save" to download a registry blob with the color scheme.

update 28 Oct 2013:
use real proxy for remote images
generate linux-style initc strings
♥0 | Line 196 | Modified 2013-10-29 04:49:56 | MIT License
play

ActionScript3 source code

/**
 * Copyright wh0 ( http://wonderfl.net/user/wh0 )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/qd9x
 */

package {
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;
    import flash.net.*;
    import flash.system.*;
    import flash.ui.*;
    
    import com.bit101.components.*;
    
    public class FlashTest extends Sprite {
        
        private static const ROWS:int = 2;
        private static const COLS:int = 8;
        private static const MARQUEE_ANIM:Array = [0, 1, 2, 2, 2, 1, 0, 0, 0, 0, 0, 1, 2, 2, 2, 1];
        
        private var urlField:InputText;
        private var sourceLayer:Sprite;
        private var source:Bitmap;
        private var origin:PointManager;
        private var rowOne:PointManager;
        private var colOne:PointManager;
        private var preview:BitmapData;
        private var sessionField:InputText;
        private var tputOut:InputText;
        private var frame:int;
        private var marquee:BitmapData;
        private var dots:Array;
        
        public function FlashTest() {
            loaderInfo.uncaughtErrorEvents.addEventListener(UncaughtErrorEvent.UNCAUGHT_ERROR, function (e:UncaughtErrorEvent):void { Wonderfl.log(e.error); });
            
            urlField = new InputText(this, 0, 0);
            urlField.addEventListener(FocusEvent.FOCUS_IN, onFieldFocus);
            urlField.width = 345;
            urlField.height = 20;
            
            var remoteButton:PushButton = new PushButton(this, 355, 0, 'remote', onRemoteClick);
            remoteButton.width = 50;
            
            var localButton:PushButton = new PushButton(this, 415, 0, 'local', onLocalClick);
            localButton.enabled = false;
            localButton.width = 50;
            
            source = new Bitmap();
            sourceLayer = new Sprite();
            sourceLayer.addEventListener(MouseEvent.CLICK, onSourceClick);
            stage.addEventListener(KeyboardEvent.KEY_DOWN, onSourceKeydown);
            sourceLayer.y = 90;
            sourceLayer.addChild(source);
            addChild(sourceLayer);
            
            origin = new PointManager(this, 0, 30, 'origin');
            rowOne = new PointManager(this, 60, 30, 'row');
            colOne = new PointManager(this, 120, 30, 'column');
            
            preview = new BitmapData(8, 2, false, 0x000000);
            var previewBitmap:Bitmap = new Bitmap(preview);
            previewBitmap.x = 180;
            previewBitmap.y = 30;
            previewBitmap.scaleX = 10;
            previewBitmap.scaleY = 10;
            addChild(previewBitmap);
            
            var saveButton:PushButton = new PushButton(this, 270, 30, 'save', onSaveClick);
            saveButton.width = 50;
            
            sessionField = new InputText(this, 330, 30, 'Default Settings');
            sessionField.addEventListener(FocusEvent.FOCUS_IN, onFieldFocus);
            sessionField.width = 135;
            sessionField.height = 20;
            
            var tputButton:PushButton = new PushButton(this, 0, 60, 'initc', onTputClick);
            tputButton.width = 50;
            
            tputOut = new InputText(this, 60, 60);
            tputOut.width = 405;
            tputOut.height = 20;
            
            frame = 0;
            marquee = new BitmapData(3, 3, true, 0x00000000);
            dots = [];
            for (var i:int = 0; i < ROWS; i++) {
                dots[i] = [];
                for (var j:int = 0; j < COLS; j++) {
                    dots[i][j] = new Bitmap(marquee);
                    sourceLayer.addChild(dots[i][j]);
                }
            }
            addEventListener(Event.ENTER_FRAME, onEnterFrame);
            
            // run an example
            urlField.text = 'http://juan.boxfi.com/wp-content/uploads/2008/11/tango-table.png';
            origin.x = 48;
            origin.y = 33;
            rowOne.x = 73;
            rowOne.y = 46;
            colOne.x = 48;
            colOne.y = 59;
            onRemoteClick(null);
        }
        
        private function onFieldFocus(e:Event):void {
            PointManager.blur();
        }
        
        private function onRemoteClick(e:MouseEvent):void {
            var lc:LoaderContext = new LoaderContext(true);
            var l:Loader = new Loader();
            l.contentLoaderInfo.addEventListener(Event.COMPLETE, function (e:Event):void {
                setBitmap(l.content as Bitmap);
            });
            l.load(new URLRequest('http://p.jsapp.us/proxy/' + urlField.text), lc);
        }
        
        private function onLocalClick(e:MouseEvent):void {
            // didn't need this after all
        }
        
        private function onSaveClick(e:MouseEvent):void {
            var entries:String =
                'Windows Registry Editor Version 5.00\r\n' +
                '\r\n' +
                '[HKEY_CURRENT_USER\\Software\\SimonTatham\\PuTTY\\Sessions\\' + encodeURIComponent(sessionField.text) + ']\r\n';
            var count:int = 6;
            for (var j:int = 0; j < COLS; j++) {
                for (var i:int = 0; i < ROWS; i++) {
                    var color:uint = preview.getPixel(j, i);
                    var r:uint = color >> 16 & 0xff;
                    var g:uint = color >> 8 & 0xff;
                    var b:uint = color & 0xff;
                    entries += '"Colour' + count + '"="' + r + ',' + g + ',' + b + '"\r\n';
                    count++;
                }
            }
            entries += '\r\n';
            new FileReference().save(entries, sessionField.text + '.reg');
        }
        
        private function onTputClick(e:MouseEvent):void {
            var command:String = 'echo -en "';
            var count:int = 0;
            for (var j:int = 0; j < COLS; j++) {
                for (var i:int = 0; i < ROWS; i++) {
                    var color:uint = preview.getPixel(j, i);
                    var indexStr:String = count.toString(16).toUpperCase();
                    var colorStr:String = ('000000' + color.toString(16)).substr(-6, 6);
                    command += '\\e]P' + indexStr + colorStr;
                    count++;
                }
            }
            command += '"';
            tputOut.text = command;
        }
        
        private function onSourceClick(e:MouseEvent):void {
            if (!PointManager.active) return;
            PointManager.active.x = e.localX;
            PointManager.active.y = e.localY;
            refresh();
        }
        
        private function onSourceKeydown(e:KeyboardEvent):void {
            if (!PointManager.active) return;
            if (e.keyCode == Keyboard.UP) PointManager.active.y--;
            else if (e.keyCode == Keyboard.DOWN) PointManager.active.y++;
            else if (e.keyCode == Keyboard.LEFT) PointManager.active.x--;
            else if (e.keyCode == Keyboard.RIGHT) PointManager.active.x++;
            refresh();
        }
        
        private function onEnterFrame(e:Event):void {
            marquee.lock();
            marquee.setPixel32(MARQUEE_ANIM[frame], MARQUEE_ANIM[frame + 8], 0x00000000);
            frame = (frame + 1) % 8;
            marquee.setPixel32(MARQUEE_ANIM[frame], MARQUEE_ANIM[frame + 8], 0x55ffffff);
            var next:int = (frame + 1) % 8;
            marquee.setPixel32(MARQUEE_ANIM[next], MARQUEE_ANIM[next + 8], 0xaaffffff);
            marquee.unlock();
        }
        
        private function setBitmap(b:Bitmap):void {
            source.bitmapData = b.bitmapData;
            refresh();
        }
        
        private function refresh():void {
            for (var i:int = 0; i < ROWS; i++) {
                for (var j:int = 0; j < COLS; j++) {
                    var x:int = origin.x + (rowOne.x - origin.x) * i + (colOne.x - origin.x) * j;
                    var y:int = origin.y + (rowOne.y - origin.y) * i + (colOne.y - origin.y) * j;
                    preview.setPixel(j, i, source.bitmapData.getPixel(x, y));
                    dots[i][j].x = x - 1;
                    dots[i][j].y = y - 1;
                }
            }
        }
        
    }
}

import flash.display.*;
import flash.events.*;
import flash.geom.*;
import com.bit101.components.*;

internal class PointManager {
    
    public static var active:PointManager;
    
    public static function blur():void {
        if (!active) return;
        active.button.selected = false;
        active = null;
    }
    
    private var button:PushButton;
    public var x:int;
    public var y:int;
    
    public function PointManager(parent:DisplayObjectContainer, xpos:Number, ypos:Number, label:String) {
        button = new PushButton(parent, xpos, ypos, label, onButtonClick);
        button.width = 50;
        button.toggle = true;
        x = 0;
        y = 0;
    }
    
    private function onButtonClick(e:MouseEvent):void {
        if (active) active.button.selected = false;
        active = button.selected ? this : null;
    }
    
}