[Question]
  [
Your program must take as input a line of characters, like this:
```
@+.0
```
And output the characters sorted by how dark they are, like this:
```
.+0@
```
Requirements:
* You must use a monospaced font for darkness detection.
* You must find out how many pixels each character takes up. You must actually draw the character and count pixels, i.e. you can't just hardcode pixel amounts.
	+ As a more concrete rule: if you switched fonts, your program should still work. Furthermore, your program should be able to switch fonts by simply changing a variable or value or string in the code.
* If you use antialiasing, you must count pixels as percentages of a fully black pixel. For example, an `rgb(32, 32, 32)` pixel will count as 1/8 of a full pixel. Disregard this rule if your characters are not antialiased.
* After counting pixels, you must sort the characters by the amount of pixels, and output them in order.
* This is [code-golf](/questions/tagged/code-golf "show questions tagged 'code-golf'"), so the shortest code in bytes will win.
  
[Answer]
# Bash + ImageMagick: ~~164~~ ~~147~~ 148 characters
```
while read -n1 c
do
o=`convert -size 20x15 xc: +antialias -font cour.ttf -draw "text 0,10 '$c'" xpm:-`
o=${o//[^ ]}
a[${#o}]+=$c
done
echo "${a[@]}"
```
Sample run:
```
bash-4.1$ echo -n '@+.0' | bash graysort.sh
. + 0 @
```
Separators are inserted between grayness groups. Characters with identical grayness level are not separated:
```
bash-4.1$ echo -n 'abcdefghijklmnopqrstuvwxyz' | bash graysort.sh
i cl jortz esv ax u df bgnpq y hk w m
```
[Answer]
## Mathematica, 112 110 108 bytes
This can still likely be golfed further. Assumes the string is in variable s.
And now uses a correct syntax to sort one list by another list.  
Lucky test cases -> "Oh yeah, that works" -> *Facepalm*  
Thanks for the sharp eyes, David Carraher.
**Update:** Replaced OCR A with Menlo because I realized that on OSX the OCR A font family name is actually OCR A Std. So I was sorting a default font instead of the real deal. Menlo is also monospaced with the same byte count, so no net gain or loss.
I've put up a [hosted CDF export of the notebook](http://www.jonathanvanmatre.com/blog/mathematica-notebooks/), so you can see the code in action if you wish. I'm still figuring out how to add some interactivity to web-hosted CDFs, so for now it's just static.
```
c=Characters@s;Last/@Sort[Transpose@{Total[1-#&/@ImageData@Rasterize@Style[#,FontFamily->"Menlo"],3]&/@c,c}]
```
Output for `s = FromCharacterCode /@ Range[33, 135];` with "Courier"
![enter image description here](https://i.stack.imgur.com/ZYOs7.png)
Output for same, but with FontFamily "Monospace":
![enter image description here](https://i.stack.imgur.com/RKTGl.png)
Note that the final results are shown in MM's internal font, not in the font being sorted. Hence, you see the differences in the font chosen reflected in the sort. The CDF link shows both, though, for the completists.
Ungolfed code:
```
s = FromCharacterCode /@ Range[33, 135];
c = Characters@s;
Last /@ Sort[
    Transpose@{Total[1 - # & /@ 
        ImageData@Rasterize@Style[#, FontFamily -> "Menlo"], 3] & /@ c, c}]
```
[Answer]
## QBasic, 259 bytes
```
SCREEN 1
DIM a(255)
FOR i = 32 TO 255
    CLS
    PRINT CHR$(i);
    FOR p = 0 TO 64
        a(i) = a(i) + POINT(p MOD 8, p \ 8)
    NEXT p
NEXT i
FOR p = 0 TO 96
    FOR i = 32 TO 255
        IF a(i) = p THEN PRINT CHR$(i);
    NEXT i
NEXT p
```
I did this for fun, so it's technically non-compliant to the rules in one way. It doesn't take a list of characters, but instead prints all characters from 32-255 and uses that instead. If you really want to see a version which complies with this rule, please tell me.
It also fails another technicality: "Furthermore, your program should be able to switch fonts by simply changing a variable or value or string in the code." There is no easy way to do this from within QBasic. However, the program will of course work fine with any codepage of your choosing.
Lastly, I could squeeze away a few characters (mostly whitespace that the QBasic IDE helpfully inserts,) but it's probably not worth it since this answer stands no chance of winning anyway.
![QBasic sort characters by darkness](https://i.stack.imgur.com/EulXY.png)
[Answer]
# Javascript + Canvas and Browser DOM (280 237 235 bytes)
*Updated version with suggetions from Fors and toothbrush in comments:*
```
function m(x){a=document.createElement('canvas').getContext('2d');a.font='9px Monaco';a.fillText(x,y=i=0,20);for(;i<3600;)y+=a.getImageData(0,0,30,30).data[i++];return y}alert(s.split('').sort(function(a,b){return m(a)-m(b)}).join(''))
```
More readable version:
```
// Scoring function - Calculates darkness for single character
function m(x) {
    a = document.createElement('canvas').getContext('2d');
    a.font = '9px Monaco';
    a.fillText(x, y = i = 0, 20);
    for (; i < 3600;) y += a.getImageData(0, 0, 30, 30).data[i++];
    return y
}
// Assume input is in variable s and alert as output. Comparison function now expression.
alert(s.split('').sort(function (a, b) {
    return m(a) - m(b)
}).join(''))
```
Can maybe be golfed more.
I'm new to this site, so I am unsure how input is normally read for Javascript answers. I assume input is contained in a variable named `s`. If this is not OK, I will update the answer and the char count.
[JSFiddle of updated version.](http://jsfiddle.net/waxwing/ABXEU/4/)
[JSFiddle of first version](http://jsfiddle.net/waxwing/ABXEU/).
[Answer]
# PHP, 298 characters
I've added a few line breaks so you can see it in all its hideousness:
```
<?php
$s=@$_GET[s];$a=array();$v=imagecreate(16,16);$f='imagecolorallocate';
$f($v,0,0,0);for($i=0;$i<strlen($s);$i++){$c=$f($v,$i,0,1);
imagechar($v,5,2,$n=0,$s[$i],$c);for($y=16;$y--;)
for($x=16;$x--;)$n+=($c==imagecolorat($v,$x,$y));
$a[]=ord($s[$i])+($n<<8);}sort($a);foreach($a as $v)echo chr($v);
```
This code uses the GD fonts that come built-in with PHP. The second argument of `imagechar()` selects the font (numbers from 1 to 5 are valid).
**Example:**
```
Input:  !@#$%^&*-=WEIX,./'
Output: '-.,^=!/*IE%X#$&@W
```
If you insert the following on top of the code shown above, then you'll be able to supply the list of characters in your web browser.
```
<?php
define("FONT_SIZE",5);
if(@$_SERVER['PATH_INFO']=='/a.png') {
  $s = $_GET['s'];
  $im = imagecreate(strlen($s)*(FONT_SIZE+4)+4,FONT_SIZE+12);
  imagecolorallocate($im,255,255,128);
  $c = imagecolorallocate($im,0,0,0);
  imagestring($im,FONT_SIZE,2,0,$s,$c);
  header("Content-Type: image/png");
  imagepng($im);
  imagedestroy($im);
  exit();
}
$me = $_SERVER['PHP_SELF'];
$t1 = $img = "";
if ($t1=htmlspecialchars(@$_GET['s'])) {
  $t2=urlencode($_GET['s']);
  $img="<p><img src=\"$me/a.png?s=$t2\" /></p>";
}
echo <<<END_HTML
<html>
<body>
$img
<form action="$me" method="get">
<input type="text" name="s" size="40" value="$t1" />
<input type="submit" value="Go" />
</form>
END_HTML;
if(!isset($_GET['s'])) exit();
?>
```
[Answer]
## [GTB](http://timtechsoftware.com/gtb "GTB")
This has code to be the second hardest code I've ever written for a calculator. No hard-coded pixel values, it actually draws the text on a graph and loops to count each pixel.
```
0→I`_%I<l?_T;1,1,s;_,I,1
C;pT;{0,1,2,3,4,5},{0,1,2}→L1(I
0→I%I<l?_T;1,C;L1(I)>L1,I
```
**Input**
```
,O.i
```
**Output**
```
.,iO
```
[Answer]
## Java - ~~468 450~~ 444
```
public static void main(String[]a){class c implements Comparable<c>{char d;c(char e){d=e;}public int compareTo(c o){return e(d)>e(o.d)?1:-1;}int e(char f){int a=0,x,y;BufferedImage img=new BufferedImage(99,99,1);img.getGraphics().drawString(""+f,9,80);for(y=0;y<99;y++)for(x=0;x<99;x++)a+=img.getRGB(x,y);return a;}}c[]s=new c[a[0].length()];int i=0;for(char d:a[0].toCharArray())s[i++]=new c(d);Arrays.sort(s);for(c d:s)System.out.print(d.d);}
```
`@+.0abcdefghijklmnopqrstuvwxyz`
->
`.irl+jcvtfxyzsuonkheaqpdb0wgm@`
Ungolfed:
```
    public static void main(String[] a) {
    a = new String[]{"@+.0abcdefghijklmnopqrstuvwxyz"};
    class c implements Comparable<c> {
        char    d;
        c(char e) {
            d = e;
        }
        @Override
        public int compareTo(c o) {
            return e(d) > e(o.d)? 1 : -1;
        }
        int e(char f) {
            int a = 0, x, y;
            BufferedImage img = new BufferedImage(99, 99, 1);
            img.getGraphics().drawString("" + f, 9, 80);
            for (y = 0; y < 99; y++)
                for (x = 0; x < 99; x++)
                    a += img.getRGB(x, y);
            return a;
        }
    }
    c[] s = new c[a[0].length()];
    int i = 0;
    for (char d : a[0].toCharArray())
        s[i++] = new c(d);
    Arrays.sort(s);
    for (c d : s)
        System.out.print(d.d);
}
```
[Answer]
## Postscript, 381
Here's something completely different, just for fun. As most fonts are vector anyway, 'counting pixels' is a little odd, isn't it. Calculating glyph shape area, while being correct way, is not that easy. An alternative can be scanning a rectangle and counting 'hits' when a point is inside a glyph shape, and Postscript has operators for this kind of checks. Though, true, scanning and insideness-testing is just a weird way of counting pixels.
```
(%stdin)(r)file token pop/Courier 99 selectfont[1 index length{0}repeat]0 1 99{0 1 99{0 1 5 index length 1 sub{newpath 9 19 moveto 3 copy 7 index exch 1 getinterval false charpath infill{3 index exch 2 copy get 1 add put}{pop}ifelse}for pop}for pop}for 0 1 99 dup mul{0 1 3 index length 1 sub{dup 3 index exch get 2 index eq{3 index exch 1 getinterval print}{pop}ifelse}for pop}for
```
.
```
(%stdin) (r) file token pop
/Courier 99 selectfont
%/DejaVuSansMono 99 selectfont
%/UbuntuMono-Regular 99 selectfont
[ 1 index length {0} repeat ]   % str []
0 1 99 {
    0 1 99 {
        0 1 5 index length 1 sub {
            newpath 
            9 19 moveto
            3 copy              % str [] n m i n m i
            7 index exch        % str [] n m i n m str i
            1 getinterval       % str [] n m i n m s
            false charpath      % str [] n m i n m
            infill              % str [] n m i bool
            {3 index exch 2 copy get 1 add put} {pop} ifelse
        } for
        pop
    } for
    pop
} for
% un-comment next line to print number of 'hits' for each glyph
%
% dup {=} forall
%
% next is 'lazy sort'
0 1 99 dup mul {                % str [] i
    0 1 3 index length 1 sub {  % str [] i j
        dup 3 index exch        % str [] i j [] j
        get 2 index eq          % str [] i j bool
        {3 index exch 1 getinterval print} {pop} ifelse
    } for
    pop
} for
()=
```
And here are results for 3 different fonts (selection of which can be un-commented, above):
```
$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?1z0yA@B
$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?z1yA0B@
$ echo '(.-?@AByz01)' | gs -q -dBATCH d.ps
.-?1zyA0B@
```
[Answer]
# Perl (with GD) (159)
```
use GD;sub i{$i=new GD'Image 5,8;$B=colorExact$i 9,9,9;colorExact$i 0,0,0;char$i gdTinyFont,0,0,@_,1;$_=unpack"B*",wbmp$i 0;y/0//c}print+sort{i($a)-i($b)}@ARGV
```
usage:
```
> perl dark.pl 1 2 3 @ # . , : ~ $ M i I s S
.,~:i13Is2S$M@#
```
edit: shortened to 159 chars
[Answer]
# Java, 584
Wow... This was not a good language to do this in.
```
import java.awt.geom.*;import java.util.*;class F{static void n(final String f,List<Character> s){Collections.sort(s,new Comparator<Character>(){public int compare(Character a,Character b){return d(f,""+a) - d(f,""+b);}});}static int d(String f,String s){int i=0;PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));while(!p.isDone()){i+=p.currentSegment(new double[99])/2;p.next();}return i;}}
```
Usage:
```
import java.awt.geom.*;
import java.util.*;
public class F {
    public static void main(String[]args){
        List<Character> s = new ArrayList<Character>(0);
        s.add('@');
        s.add('+');
        s.add('.');
        s.add('0');
        n("Calibri", s);
        System.out.println(s);
    }
    static void n(final String f,List<Character> s){
        Collections.sort(s,new Comparator<Character>(){
            public int compare(Character a,Character b){
                return d(f,""+a) - d(f,""+b);
            }
        });
    }
    
    static int d(String f,String s){
        int i=0;
        PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));
        while(!p.isDone()){
            i+=p.currentSegment(new double[99])/2;
            p.next();
        }
        return i;
    }
}
```
This setup results in:
```
[., +, 0, @]
```
---
The only line here that needs explanation:
```
PathIterator p=new java.awt.Font(f,0,12).createGlyphVector(((java.awt.Graphics2D)new java.awt.image.BufferedImage(8,8,2).getGraphics()).getFontRenderContext(),s).getGlyphOutline(0).getPathIterator(AffineTransform.getRotateInstance(0.0, 0.0));
```
* Initialize the 12pt font object with the passed font.
* Create a new BufferedImage obejct to create a Graphics2D object linked to a GraphicsContext.
* Get the font rendering context of the 2D graphics context for the string s.
* Get the first glyph (only glyph) in the string.
* Get the path iterator (list of points).
Then this final piece brings it together...
```
while(!p.isDone()){
    i+=p.currentSegment(new double[99])/2;
    p.next();
}
```
By iterating through all points and summing count of points. This density information is passed back up to the comparator and is used for sorting.
[Answer]
### R, 195 characters
```
A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")
```
Indented with comments:
```
A=strsplit(scan(,""),"")[[1]] #Take characters as strings and split into single chars
cat(A[order(sapply(A,function(x){ #Apply the following function to each char and order accordingly
                 png('a',a='none',fa='monospace'); #Open empty png without antialiasing and with monospace font
                 frame(); #create empty plot
                 text(0,0,x); #add the char as text to the plot
                 dev.off(); #close png device
                 sum(apply(png::readPNG('a'), #read it back as rbga 3d matrix
                           c(1,2), #check every layer (R, G, B, A)
                           function(x)any(x!=1))) #if any are not 1, send TRUE
                 }))], #Sum all TRUEs
    sep="") #Prints to output
```
Example:
```
> A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")
1: @+.0
2: 
Read 1 item
.+0@
> A=strsplit(scan(,""),"")[[1]];cat(A[order(sapply(A,function(x){png('a',a='none',fa='monospace');frame();text(0,0,x);dev.off();sum(apply(png::readPNG('a'),c(1,2),function(x)any(x!=1)))}))],sep="")
1: 1234567890
2: 
Read 1 item
1723450689
```
The gestion of fonts in R plots being platform-dependent, I cannot guarantee that it works on PC, but it does on a Mac (OS X 10.7.5, R 2.14.2).
[Answer]
# SmileBASIC, ~~179~~ ~~176~~ 173 bytes
```
INPUT S$DIM Q$[0],A[0],Z[0]WHILE""<S$C$=POP(S$)GCLS
PUSH Q$,C$
GPUTCHR.,0,C$
GSAVE.,0,8,8,A,0S=0FOR I=0TO 63S=S+A[I]NEXT
PUSH Z,S
WEND
RSORT Z,Q$
WHILE LEN(Q$)?POP(Q$);
WEND
```
Uses the currently loaded font.
Fonts can be loaded with `LOAD"GRPF:filename"`.
More readable code:
```
INPUT STRING$
DIM CHARS$[0],PIXELS[0],SIZES[0]
WHILE STRING$>""
 CHAR$=POP(STRING$)
 PUSH CHARS$,CHAR$
 GCLS
 GPUTCHR 0,0,CHAR$
 GSAVE 0,0,8,8,PIXELS
 SIZE=0
 FOR I=0 TO 63
  INC SIZE,PIXELS[I]
 NEXT
 PUSH SIZES,SIZE
WEND
RSORT SIZES,CHARS$
WHILE LEN(CHARS$)
 PRINT POP(CHARS$);
WEND
```
[Answer]
# PHP - 485
Demo:
```
$ php pcg-23362.php "@+.0"
.+0@
```
Code:
```
<?php $f='x.ttf';$d=array();foreach(str_split($argv[1]) as$_){$B=imagettfbbox(50,0,$f,$_);$w=abs($B[4]-$B[0]);$h=abs($B[5]-$B[1]);$im=imagecreate($w,$h);imagecolorallocate($im,255,255,255);imagettftext($im,50,0,0,$h-$B[1],imagecolorallocate($im,0,0,0),$f,$_);$b=$w*$h;for($x=0;$x<$w;$x++)for($y=0;$y<$h;$y++){$z=imagecolorsforindex($im,imagecolorat($im,$x,$y));$color=$z['red']*$z['green']*$z['blue'];$b-=$color/0x1000000;}$d[$_]=$b / ($w * $h);}asort($d);echo implode(array_keys($d));
```
[Answer]
## Python + freetype-py: 147
```
import sys,freetype as F;f=F.Face('m.ttf');f.set_char_size(99);print(sorted([(f.load_char(c)or sum(f.glyph.bitmap.buffer),c)for c in raw_input()]))
```
]