Крестики-нолики на HTML CSS и прокрастинация

Есть такое понятие — прокрастинация, это про «никогда не откладывай на завтра то, что можно сделать послезавтра». В тяжёлых проектах есть соблазн отложить принятие трудных решений «на потом» или не делать
Я
У меня с моими «
Вчера ночью меня осенило, открыл ноут перед сном и исправил последнюю ошибку (их там оказалось две — в выводе данных из программы моделирующей игру и в самом конверторе,
Багов быть не должно, могут быть шероховатости. Я сам знаю пару неаккуратных вещей — кнопка «Restart» работает не во всех браузерах и на ничьей следующий ход уже не сделать (хотя он и не нужен
Картинка на чистом CSS

Сейчас CSS позволяет делать всё более интересные вещи. Раз уж сегодня короткий день, за 20 минут из «сэкономленного» часа накидал программу, которая конвертирует любую картинку (в форматах PNG, JPEG или GIF) в чистый CSS (без использования dataURI). Каждая точка кодируется через одну конструкцию
Если заморачиваться серьёзно, то можно выявлять в картинке области с градиентом (так делается в формате PNG для упаковки) и покрывать их целиком одной конструкцией, а так же оптимизировать наложением линейных градиентных областей с прозрачностью (через rgba или hsla). Достаточно интересная программисткая задача, кстати.
Самую очевидную оптимизацию я сделал в пробке по работе домой — выделил самый частый цвет и пустил его на фон, выиграл примерно 11,5КБ на картинке в примере.
За 20 минут я только успел сделать небольшой конвертор (результат работы можно посмотреть в разделе «Храню», только для «Хрома»). Так как синтаксис завязан на префиксы, то я в генераторе сделал указание браузера под который нужно сгенерировать код (поддерживаются: IE, Opera, Firefox и Chrome). Всё это весьма расточительно, картинка 75×75 занимает 164КБ.
У меня заработало для «Хрома» и «Файэрфокса», под «Оперой» не завелось, лень проверять что она не поддерживает, IE попробовать не могу — его не бывает на «Маках». Код конвертора
// Конвертор картинки в чистый CSS, / ноябрь 2011
<?
// ffccbb → fcb
// ff0000 → red
// abcdef → abcdef
function Bo_shortcolor($color) {
static $shortnames = array(
"#000080" => "navy",
"#008000" => "green",
"#008080" => "teal",
"#4b0082" => "indigo",
"#800000" => "maroon",
"#800080" => "purple",
"#808000" => "olive",
//"#808080" => "gray",
"#808080" => "grey",
"#a0522d" => "sienna",
"#a52a2a" => "brown",
"#c0c0c0" => "silver",
"#cd853f" => "peru",
"#d2b48c" => "tan",
"#da70d6" => "orchid",
"#dda0dd" => "plum",
"#ee82ee" => "violet",
"#f0e68c" => "khaki",
"#f0ffff" => "azure",
"#f5deb3" => "wheat",
"#f5f5dc" => "beige",
"#fa8072" => "salmon",
"#faf0e6" => "linen",
"#ff0000" => "red",
"#ff6347" => "tomato",
"#ff7f50" => "coral",
"#ffa500" => "orange",
"#ffc0cb" => "pink",
"#ffd700" => "gold",
"#ffe4c4" => "bisque",
"#fffafa" => "snow",
"#fffff0" => "ivory",
);
$c = strtolower($color);
if (isset($shortnames[$c])) {
return $shortnames[$c];
}
if ($c[0] == $c[1] && $c[2] == $c[3] && $c[4] == $c[5]) {
return '#' . $c[1] . $c[3] . $c[5];
}
return '#' . $c;
}
function Bo_convert($filename, $prefix = '') {
if (!file_exists($filename) && !is_readable($filename)) {
throw new Exception('File not found.');
}
$types = array(
IMAGETYPE_JPG => 'jpeg',
IMAGETYPE_PNG => 'png',
IMAGETYPE_GIF => 'gif',
);
$imagedata = @getimagesize($filename);
if (!is_array($imagedata) || !isset($imagedata[2]) || !isset($types[$imagedata[2]])) {
throw new Exception('Unknown image format');
}
$im = call_user_func("imagecreatefrom" . $types[$imagedata[2]], $filename);
$w = imagesx($im);
$h = imagesy($im);
// Самый частый цвет идёт на background-color
$colorfreq = array();
for ($x = 0; $x<$w; $x++) for ($y = 0; $y<$h; $y++) @$colorfreq[imagecolorat($im, $x, $y)]++;
$bg = array_search(max($colorfreq), $colorfreq);
for ($x = 0; $x<$w; $x++)
for ($y = 0; $y<$h; $y++) {
$pixel = imagecolorat($im, $x, $y);
if ($pixel != $bg) {
$color = Bo_shortcolor(sprintf('%06x', $pixel));
$dots[] = "{$prefix}radial-gradient($color,$color) {$x}px {$y}px";
}
}
$dots = join(',', $dots);
$bg = Bo_shortcolor(sprintf('%06x', $bg));
return <<<HTML
<head>
<title>$filename converted in background by Evgeny Stepanischev //bolknote.ru</title>
<style text="text/css">
div {
background: $dots;
background-repeat: no-repeat;
{$prefix}background-size: 1px 1px;
background-color: $bg;
background-size: 1px 1px;
width: {$w}; height: {$h};
}
</style>
<body>
<div></div>
</body>
HTML;
}
if ($_SERVER['argc'] < 2) {
echo <<<HELP
Image to background CSS convertor by Evgeny Stepanischev. //bolknote.ru Nov 2011
Usage: {$_SERVER['argv'][0]} filename [prefix]
filename - image file name (PNG, JPEG or GIF)
prefix - your browser name (Opera, IE, FF, Safari, Chrome)
HELP;
exit;
}
$browsers = array(
'ie' => '-ms-',
'opera' => '-o-',
'safari' => '-webkit-',
'chrome' => '-webkit-',
'chromium' => '-webkit-',
'ff' => '-moz-',
'firefox' => '-moz-',
);
if (isset($_SERVER['argv'][2])) {
$type = strtolower($_SERVER['argv'][2]);
$prefix = isset($browsers[$type]) ? $browsers[$type] : '-' . $type . '-';
} else {
$prefix = '';
}
try {
echo Bo_convert($_SERVER['argv'][1], $prefix);
} catch (Exception $e) {
echo "Error: ", $e->getMessage(), "\n";
};
Цвета из CSS, названия которых короче их номеров
Кстати, если вдруг
Например, «silver» короче своего числового эквивалента «#c0c0c0» на один символ, а «tan» короче «#d2b48c» на четыре.