Flag Upload

A script to build a 40X30 flag on legacy-game.net using a given image.

// ==UserScript==
// @name        Flag Upload
// @include     http://*.legacy-game.net/flag.php*
// @version     1.0
// @grant       none
// @namespace https://greasyfork.org/users/4585
// @description A script to build a 40X30 flag on legacy-game.net using a given image.
/*global $,FileReader,pic,HTMLCanvasElement */
// ==/UserScript==

/*****************************************************
                    General Methods                    
/****************************************************/
//
function create(type,attr,text,parent){
    var ele = document.createElement(type);
    for(var x in attr){
        if(x.hasOwnProperty){
            ele.setAttribute(x,attr[x]);
        }
    }
    if(text){ele.innerHTML = text;}
    if(parent){parent.appendChild(ele);}
    return ele;
}

//Method to convert RGB values into hex for flag variables
function toHex(r, g, b) {
    var hex ="0123456789ABCDEF", ans;
    r = hex.charAt((r - (r % 16)) / 16) + hex.charAt(r % 16);
    g = hex.charAt((g - (g % 16)) / 16) + hex.charAt(g % 16);
    b = hex.charAt((b - (b % 16)) / 16) + hex.charAt(b % 16);
    ans = "#" + r + g + b;
    return ans;
}
/*****************************************************
                    CSS Injection                    
/****************************************************/
var custom = ""+
        "#uploadPanel{height:auto; width:auto; background: red none; border: 5px solid darkred; padding: 5px; position:absolute; top:20px; left:20px; max-height:90%; max-width:90%; padding-right:20px; overflow:auto;}\n"+
        "#flagOut{border:1px solid #c3c3c3; display:inline-block;}\n"+
        "#container{position:relative; display:block; height:30px; width:40px; padding:1px;}\n"+
        "#rawImage{position: absolute; display:block; z-index:1;}\n"+
        "#getArea{position:absolute; height:30px; width:40px; top:1px; left:1px; border:1px solid red;z-index:2;}\n"+
        "#imageUpload{display:block;}\n"+
        "#editPanel{display:none;}";

create('link',{rel:'stylesheet',href:'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8/themes/base/jquery-ui.css'},false,document.head);
create('style',{type:'text/css'},custom,document.head);

/*****************************************************
                    Interface Creation & Injection                    
/****************************************************/

var panel = create('div',{id:'uploadPanel'},false,document.body);
create('canvas',{id:'flagOut',width:'40',height:'30'},false,panel);
create('input',{id:'toFlag',type:'button',value:'Send to Flag'},false,panel);
create('span',{},'<br/>Resize Select Box:',panel);
create('input',{id:'resizeToggle',type:'checkbox'},false,panel);
create('span',{},'<br/>Keep Aspect Ratio:',panel);
create('input',{id:'Aratio',type:'checkbox',checked:'checked',disabled:'disabled'},false,panel);
create('span',{},'<br/>',panel);
create('input',{id:'reset',type:'button',value:'Reset to 40X30'},false,panel);
create('input',{id:'rawImgHide',type:'button',value:'Show/Hide Canvas'},false,panel);
create('span',{},'<br/>',panel);
create('span',{id:'edit'},'Editing Tools',panel);
var edit = create('div',{id:'editPanel'},false,panel);
create('input',{id:'greyscale',type:'button',value:'Greyscale'},false,edit);
create('input',{id:'invert',type:'button',value:'Invert'},false,edit);
var container = create('div',{id:'container'},false,panel);
create('canvas',{id:'rawImage',width:'40',height:'30'},false,container);
create('div',{id:'getArea'},false,container);
create('input',{id:'imageUpload',type:'file'},false,panel);

/*****************************************************
                    Canvas Methods                    
/****************************************************/

//Sends image data to 'large' canvas, from which we can select the desired area
function toRawCanvas(imgData){
    var img = new Image() ,
        rawcanvas = document.getElementById('rawImage'), 
        context = rawcanvas.getContext('2d'), 
        area;
    img.src = imgData;
    img.onload = function() {
        var container = document.getElementById('container');
        container.style.height=img.height+2+'px';
        container.style.width=img.width+2+'px';
        rawcanvas.height=img.height+2;
        rawcanvas.width=img.width+2;
        context.drawImage(img, 1, 1);
        area = document.getElementById('getArea');
        area.style.top='1px';
        area.style.left='1px';
    };
}

//Ctrl + V to paste an image to the canvas
//Currently only available with Chrome
function onPasteHandler(e){
    if(e.clipboardData) {
        var items = e.clipboardData.items,
            blob, 
            source;
        if(!items){
            alert("Image Not found");
        }
        for (var i = 0; i < items.length; ++i) {
            if (items[i].type.match('image.*')) {
                blob = items[i].getAsFile();
                source = window.webkitURL.createObjectURL(blob);
                toRawCanvas(source);
            }
        }
    }
}
//Use jQuery UI to allow the capture div inside the raw canvas to move freely when dragging
$(function(){
    $('#getArea').draggable({containment:'parent'});
    window.addEventListener("paste", onPasteHandler);
});
//Show/Hide the Raw Canvas from view 
//Mainly for when the image is larger than the window, or file upload is difficult to see
$('#rawImgHide').click(function(){
    $('#container').slideToggle('slow');
});
//Reset the capture div back to default size
$('#reset').click(function(){
    var area = document.getElementById('getArea');
    area.style.height="30px";
    area.style.width="40px";
});
//Allow the capture div to be resizable (jQuery UI)
//Aspect ratio can only be enabled/disabled when the capture div is resizable            
$('#resizeToggle').click(function(){
    if(this.checked){
        if ($('#Aratio').is(':checked')){
            $('#getArea').resizable({aspectRatio: true, containment:'parent'});
        }
        else{
            $('#getArea').resizable({containment:'parent'});
        }
        $('#Aratio').prop('disabled','');
    }
    else{
        $('#getArea').resizable('destroy');
        $('#Aratio').prop('disabled','disabled');
    }
});
//Enable/Disable aspect ratio on capture div
//Disabling may cause stretching/skewing of output flag
$('#Aratio').click(function(){
    if (this.checked){
        $('#getArea').resizable('destroy');
        $('#getArea').resizable({aspectRatio: true, containment:'parent'});
    }
    else{
        $('#getArea').resizable('destroy');
        $('#getArea').resizable({aspectRatio: false, containment:'parent'});
    }
}); 
//Image upload from local machine to raw canvas
$('#imageUpload').change(function(){
    if (document.getElementById("imageUpload").files.length === 0) {
        return;
    }
    var flag = document.getElementById("imageUpload").files[0],
        reader;
    if (!flag.type.match('image.*')) {
        alert("Not an image");
        return;
    }
    reader = new FileReader();
    reader.onload = (function() {
        return function(e) {
            toRawCanvas(e.target.result);
        };
    }(flag));
    reader.readAsDataURL(flag);
});
//After moving capture div to desired area, send containing image to secondry canvas to preview before sending to legacy page
//Resize to fit 40X30 pixels where needed using native methods
$('#getArea').mouseup(function(){
    var rawcanvas = document.getElementById('rawImage'),
        out = document.getElementById('flagOut'),
        area = document.getElementById('getArea'),
        outctx = out.getContext('2d'),
        x=parseInt(area.style.left,10),
        y=parseInt(area.style.top,10);
    outctx.clearRect (0,0,out.width,out.height);
    outctx.drawImage(rawcanvas, x, y,area.clientWidth,area.clientHeight,0,0,out.width,out.height);
});
//Sent image from preview canvas to legacy page, adjusting page variables and 'pixel' block backgrounds
$('#toFlag').click(function(){
    var canvas=document.getElementById('flagOut'),
        context = canvas.getContext('2d'),
        w = canvas.width,
        h = canvas.height,
        imgd = context.getImageData(0, 0, w, h),
        pix = imgd.data;

    for (var i = 0; i < h; i++) {
        for (var j = 0; j < w; j++) {
            document.getElementsByName("X"+j+"Y"+i)[0].bgColor = pic[j+i*w] = toHex(pix[(j+i*w)*4], pix[(j+i*w)*4 + 1], pix[(j+i*w)*4 + 2]);
        }
    }
});
/*****************************************************
                    Effect Addons                    
/****************************************************/
//Hide/Show effect options
$('#edit').click(function(){
    $('#editPanel').slideToggle();
});
//Perform greyscale effect on output flag
$('#greyscale').click(function(){
    document.getElementById('flagOut').greyscale();
});
//Invert output flag colours
$('#invert').click(function(){
    document.getElementById('flagOut').invert();
});

HTMLCanvasElement.prototype.greyscale = function(){
    var ctx = this.getContext('2d'),
        data = ctx.getImageData(0,0,this.width,this.height),
        d = data.data;
    for(var i=0;i<d.length;i+=4){
         d[i]= d[i+1] = d[i+2] = 0.2126*d[i] + 0.7152*d[i+1] + 0.0722*d[i+2];
    }
    ctx.putImageData(data,0,0);
};

HTMLCanvasElement.prototype.invert = function(){
    var ctx = this.getContext('2d'),
        data = ctx.getImageData(0,0,this.width,this.height),
        d = data.data;
    for(var i=0;i<d.length;i+=4){
        d[i]=255-d[i];
        d[i+1]=255-d[i+1];
        d[i+2]=255-d[i+2];
    }
    ctx.putImageData(data,0,0);
};