From 6bd49ac82a9606ec394c52b1a8f583915c9bd8b5 Mon Sep 17 00:00:00 2001 From: "Javier S. Pedro" Date: Thu, 30 Jun 2011 22:48:35 +0200 Subject: initial import --- index.php | 390 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 390 insertions(+) create mode 100644 index.php (limited to 'index.php') diff --git a/index.php b/index.php new file mode 100644 index 0000000..79a4428 --- /dev/null +++ b/index.php @@ -0,0 +1,390 @@ + + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . +*/ + +define('SVGNS', 'http://www.w3.org/2000/svg'); + +define('COLOR_EXTRACT_RENDER_SIZE', 128); +define('HARMATTAN_ICON_SIZE', 80); +define('HARMATTAN_FOCAL_SIZE', 54); + +function svg2png($svg, $w, $h, $png) +{ + $output = array(); + $exitcode = -1; + exec(sprintf("~/bin/qsvg %s %d %d %s", escapeshellarg($svg), $w, $h, escapeshellarg($png)),$output,$exitcode); + return $exitcode == 0; +} + +function multiarray($d, $k, $n = 0) +{ + return array_fill(0, $k, $d == 1 ? $n : multiarray($d - 1, $k, $n)); +} + +function warn($s) +{ + global $warnings; + $warnings[] = $s; +} + +function colfilter_none($c) +{ + return false; +} + +function colfilter_pure($c) +{ + return ($c['red'] == 0 && $c['green'] == 0 && $c['blue'] == 0) || + ($c['red'] == 255 && $c['green'] == 255 && $c['blue'] == 255); +} + +function colfilter_grey($c) +{ + return ($c['red'] == $c['green']) && ($c['green'] == $c['blue']); +} + +function colfilter_grey5($c) +{ + $r = $c['red'] >> 3; + $g = $c['green'] >> 3; + $b = $c['blue'] >> 3; + return ($r == $g) && ($g == $b); +} + +function domcolor_mean($img, $flt) +{ + $w = imagesx($img); + $h = imagesy($img); + $t = $w * $h; + $r = 0; $g = 0; $b = 0; + for ($y = 0; $y < $h; $y++) { + for ($x = 0; $x < $w; $x++) { + $c = imagecolorsforindex($img, imagecolorat($img, $x, $y)); + if (call_user_func($flt, $c)) continue; + $r += $c['red']; + $g += $c['green']; + $b += $c['blue']; + } + } + $r /= $t; $g /= $t; $b /= $t; + return array($r, $g, $b); +} + +function domcolor_mode($img, $flt) +{ + $w = imagesx($img); + $h = imagesy($img); + $t = $w * $h; + $f = multiarray(3, 256, 0); + $max_c = false; + $max_f = 0; + for ($y = 0; $y < $h; $y++) { + for ($x = 0; $x < $w; $x++) { + $c = imagecolorsforindex($img, imagecolorat($img, $x, $y)); + if (call_user_func($flt, $c)) continue; + $this_f = $f[$c['red']][$c['green']][$c['blue']] += 1; + if ($this_f > $max_f) { + $max_c = $c; + $max_f = $this_f; + } + } + } + if ($max_c) + return array($max_c['red'], $max_c['green'], $max_c['blue']); + else + return false; +} + +$domalgos = array('mean', 'mode'); +$colfilters = array('none', 'pure', 'grey', 'grey5'); + +function extract_dominant_color($svg, $algo = 'average', $filter = 'grey') +{ + global $domalgos, $colfilters; + $png = '/tmp/hicg-icon.png'; + if (!in_array($algo, $domalgos)) { + return false; + } + if (!in_array($filter, $colfilters)) { + return false; + } + if (!svg2png($svg, COLOR_EXTRACT_RENDER_SIZE, COLOR_EXTRACT_RENDER_SIZE, $png)) { + return false; + } + $img = imagecreatefrompng($png); + if (!$img) { + return false; + } + $color = call_user_func('domcolor_'. $algo, $img, 'colfilter_'.$filter); + imagedestroy($img); + return $color; +} + +function clip_color_value($c) +{ + if ($c < 0) return 0; + else if ($c > 255) return 255; + return $c; +} + +function clip_color($c) +{ + return array_map('clip_color_value', $c); +} + +function greyscale_color($c) +{ + return .299*$c[0] + .587*$c[1] + .114*$c[2]; +} + +function color2hex($c) +{ + return sprintf("%02x%02x%02x", $c[0], $c[1], $c[2]); +} + +function get_disabled_color($c) +{ + /* Clear and desature a bit. */ + $nc = array_map(create_function('$x', 'return $x + 90;'), $c); + $grey = greyscale_color($nc); + $nc = array_map(create_function('$x', 'return $x * 0.8 + ('.$grey.') * 0.2;'), $nc); + return clip_color($nc); +} + +function get_pressed_color($c) +{ + /* Desaturate and darken. */ + $grey = greyscale_color($c); + $nc = array_map(create_function('$x', 'return $x * 0.5 + ('.$grey.') * 0.5;'), $c); + $nc = array_map(create_function('$x', 'return $x - 40;'), $nc); + + return clip_color($nc); +} + +function get_icon_light_color($c) +{ + $nc = array_map(create_function('$x', 'return $x + 60;'), $c); + return clip_color($nc); +} + +function get_icon_dark_color($c) +{ + $nc = array_map(create_function('$x', 'return $x - 50;'), $c); + return clip_color($nc); +} + +function get_svg_attribute($node, $attrib) +{ + $v = $node->getAttributeNS(SVGNS, 'svg:' . $attrib); + if (empty($v)) { + $v = $node->getAttribute('svg:' . $attrib); + if (empty($v)) { + $v = $node->getAttribute($attrib); + } + } + + return $v; +} + +function calc_scale_ratios($w, $h, &$s, &$tx, &$ty) +{ + if ($w > $h) { + $s = HARMATTAN_FOCAL_SIZE / $w; + $sw = HARMATTAN_FOCAL_SIZE; + $sh = $s * $h; + } else { + $s = HARMATTAN_FOCAL_SIZE / $h; + $sw = $s * $w; + $sh = HARMATTAN_FOCAL_SIZE; + } + $tx = HARMATTAN_ICON_SIZE / 2 - $sw / 2; + $ty = HARMATTAN_ICON_SIZE / 2 - $sh / 2; +} + +function make_icon($src, $template, $dst, $color) +{ + $srcDoc = new DOMDocument(); + $srcDoc->load($src); + $doc = new DOMDocument(); + $doc->load($template); + + /* Get scaling ratios from source SVG. */ + $srcNode = $srcDoc->documentElement; + $w = intval(get_svg_attribute($srcNode, 'width')); + $h = intval(get_svg_attribute($srcNode, 'height')); + calc_scale_ratios($w, $h, $s, $tx, $ty); + + /* Fix gradient colors. */ + $grd = $doc->getElementsByTagName('stop'); + $grd->item(0)->setAttribute('style', 'stop-color:#' . color2hex(get_icon_light_color($color)) . ';stop-opacity:1'); + $grd->item(1)->setAttribute('style', 'stop-color:#' . color2hex(get_icon_dark_color($color)) . ';stop-opacity:1'); + + /* Create the scaling & centering transform. */ + $g = $doc->createElement('g'); + $g->setAttribute('transform', "translate($tx, $ty) scale($s)"); + + foreach ($srcNode->childNodes as $node) { + $n = $doc->importNode($node, TRUE); + $g->appendChild($n); + } + + $doc->documentElement->appendChild($g); + + $doc->save($dst); +} + +function make_png($src, $dst) +{ + if (!svg2png($src, HARMATTAN_ICON_SIZE, HARMATTAN_ICON_SIZE, $dst)) { + warn("I failed to generate a 80x80 PNG."); + } +} + +$warnings = array(); + +if (@isset($_POST['send'])) { + $prefix = './files/' . uniqid() . '_'; + $srcfile = $prefix . 'src.svg'; + if (!move_uploaded_file($_FILES['iconfile']['tmp_name'], $srcfile)) { + die('Upload failed.'); + } + $domalgo = $_POST['domalgo']; + $colfilter = $_POST['colfilter']; + $iconfile = $prefix . 'icon.svg'; + $pngfile = $prefix . 'icon.png'; + + $domcolor = extract_dominant_color($srcfile, $domalgo, $colfilter); + if (!$domcolor) { + warn("I failed to get a dominant color. Your icon might be too greyish."); + $domcolor = array(0, 0, 0); + $discolor = array(0, 0, 0); + $prscolor = array(0, 0, 0); + } else { + $discolor = get_disabled_color($domcolor); + $prscolor = get_pressed_color($domcolor); + } + + make_icon($srcfile, 'template.svg', $iconfile, $domcolor); + make_png($iconfile, $pngfile); + + $srcurl = $srcfile; + $iconurl = $iconfile; + $pngurl = $pngfile; +} else { + /* Load some sample data. */ + $srcfile = 'samplesrc.svg'; + $domalgo = 'mode'; + $colfilter = 'grey5'; + $iconfile = 'sampleicon.svg'; + $pngfile = 'sampleicon.png'; + + $domcolor = extract_dominant_color($srcfile, $domalgo, $colfilter); + $discolor = get_disabled_color($domcolor); + $prscolor = get_pressed_color($domcolor); + + /* This should not get into production. ;) */ + make_icon($srcfile, 'template.svg', $iconfile, $domcolor); + make_png($iconfile, $pngfile); + + $srcurl = $srcfile; + $iconurl = $iconfile; + $pngurl = $pngfile; +} + +echo ''; +?> + + + +Harmattan Icon Generator + + + + +

Warnings

+ +

Warning:

+ + +

Upload your icon

+
+
+ Your application's current icon file + +
+
+ Algorithm for dominant color extraction + + +
+
+ Colors to ignore + + + + +
+
+ Drop shadow + + +
+
+ +
+
+

Results

+
+

You uploaded:

+ +
+
+
+

Your icon's dominant color is #

+
+
+
+

A suggested disabled color is #

+
+
+
+

A suggested pressed color is #

+
+
+
+

Harmattan style icon:

+
+
+ +

YourApp

+
+
+
+

Download SVG file. Or a 80x80 PNG file.

+
+

Suggested reading

+ + + -- cgit v1.2.3