Skip to content

Instantly share code, notes, and snippets.

@wozozo
Forked from riaf/convert-less.php
Last active August 29, 2015 13:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save wozozo/10106513 to your computer and use it in GitHub Desktop.
Save wozozo/10106513 to your computer and use it in GitHub Desktop.
<?php
$filename = isset($argv[1]) ? realpath($argv[1]) : null;
$mixin = isset($argv[2]) ? $argv[2] : 'sprite-mixin';
$retina = isset($argv[3]) ? true : false;
if (!$filename) {
echo "fail", PHP_EOL;
exit(1);
}
$json = json_decode(file_get_contents($filename), true);
$max_width = 0;
foreach ($json as $defs) {
if ($max_width < $defs['width']) {
$max_width = $defs['width'];
}
}
$output = '';
$background_size = $retina ? sprintf(' background-size: %dpx auto;', $max_width / 2) : '';
$output .= <<<HEAD
// generate code
.{$mixin}(@name) {
background-image: @{$mixin}-background;
{$background_size}
.{$mixin}-position(@name);
.{$mixin}-size(@name);
}
.{$mixin}-position(@name) {
.do () {
}
HEAD;
foreach ($json as $name => $defs) {
$offset_x = $defs['offset_x'] ? '-' . $defs['offset_x'] : 0;
$offset_y = $defs['offset_y'] ? '-' . $defs['offset_y'] : 0;
$width = $defs['width'];
$height = $defs['height'];
if ($retina) {
$width /= 2;
$height /= 2;
$offset_x /= 2;
$offset_y /= 2;
}
$normalize_name = preg_replace('/[^a-z0-9-]/i', '-', $name);
$output .= <<<DEF
.do () when(@name = {$normalize_name}) {
background-position: {$offset_x}px {$offset_y}px;
// width: {$width}px;
// height: {$height}px;
}
DEF;
}
$output .= <<<MID
.do();
}
.{$mixin}-size(@name) {
.do () {
}
MID;
foreach ($json as $name => $defs) {
$offset_x = $defs['offset_x'] ? '-' . $defs['offset_x'] : 0;
$offset_y = $defs['offset_y'] ? '-' . $defs['offset_y'] : 0;
$width = $defs['width'];
$height = $defs['height'];
if ($retina) {
$width /= 2;
$height /= 2;
$offset_x /= 2;
$offset_y /= 2;
}
$normalize_name = preg_replace('/[^a-z0-9-]/i', '-', $name);
$output .= <<<DEF
.do () when(@name = {$normalize_name}) {
// background-position: {$offset_x}px {$offset_y}px;
width: {$width}px;
height: {$height}px;
}
DEF;
}
$output .= <<<FOOT
.do();
}
// generated.
FOOT;
echo $output;
<?php
$src_dir = isset($argv[1]) ? realpath($argv[1]) : __DIR__.'/source';
$NAME = isset($argv[2]) ? $argv[2] : 'sprite';
if (!$src_dir) {
echo "dir not found", PHP_EOL;
exit(1);
}
// ==================================================
// image list
$image_files = array();
foreach(new DirectoryIterator($src_dir) as $fileinfo) {
if (!in_array($fileinfo->getExtension(), array('png'))) {
continue;
}
list($width, $height, $type, $attr) = getimagesize($fileinfo->getPathname());
$image_files[] = array(
'offset_x' => 0,
'offset_y' => 0,
'width' => $width,
'height' => $height + 1,
'filepath' => $fileinfo->getPathname(),
'basename' => $fileinfo->getBasename('.'.$fileinfo->getExtension()),
'calc_status' => 0,
);
}
// ==================================================
// sort
$image_files_width_asc
= $image_files_height_asc
= $image_files_width_desc
= $image_files_height_desc
= $image_files
;
$_width_ = array();
$_height_ = array();
foreach ($image_files as $image_file) {
$_width_[] = $image_file['width'];
$_height_ [] = $image_file['height'];
}
$_width_2 = $_width_;
$_height_2 = $_height_;
array_multisort($_width_, $image_files_width_asc);
array_multisort($_width_2, SORT_DESC, $image_files_width_desc);
array_multisort($_height_, $image_files_height_asc);
array_multisort($_height_2, SORT_DESC, $image_files_height_desc);
// ==================================================
// calc
// max width
$max_width = $image_files_width_desc[0]['width'];
$_ = 0;
$offset_x = 0;
$offset_y = 0;
$image_files = $image_files_width_desc;
while (true) {
// finish?
$fin = true;
foreach ($image_files as $image_file) {
if ($image_file['calc_status'] == 0) {
$fin = false;
}
}
if ($fin) {
break;
}
foreach ($image_files as $key => $image_file) {
$offset_x = 0;
if ($image_file['calc_status'] != 0) {
continue;
}
// head big
if ($image_file['width'] == $max_width) {
$image_files[$key]['offset_y'] = $offset_y;
$image_files[$key]['calc_status'] = 1;
$offset_y += $image_file['height'] + 1;
break;
}
$image_files[$key]['offset_y'] = $offset_y;
$image_files[$key]['calc_status'] = 1;
$offset_x = to_even($image_file['width'] + 1);
$offset_y = to_even($offset_y);
$next_width = $max_width - $offset_x;
$next_height = $image_file['height'];
$next_offset_y = to_even($offset_y);
// 横方向に並べる
$row_width = $max_width;
$row_height = $next_height;
$next_row_width = $next_width;
$next_row_height = $next_height;
$row_offset_x = to_even($offset_x);
$row_offset_y = to_even($next_offset_y);
$row_pointer_x = 0;
$ii = 0;
while (true) {
foreach ($image_files as $row_key => $row_image_file) {
if ($row_image_file['calc_status']) {
continue;
}
if (
$next_row_width >= $row_image_file['width']
&& $next_row_height >= $row_image_file['height']
) {
$image_files[$row_key]['offset_x'] = $row_offset_x;
$image_files[$row_key]['offset_y'] = $row_offset_y;
$image_files[$row_key]['calc_status'] = 1;
$next_row_height -= $row_image_file['height'] + 1;
$row_offset_y += $row_image_file['height'] + 1;
$row_offset_y = to_even($row_offset_y);
$_w = $row_offset_x + $row_image_file['width'] + 1;
if ($_w > $row_pointer_x) {
$row_pointer_x = $_w;
}
}
}
if ($row_pointer_x == 0 || ++$ii > 100) {
break;
}
$next_row_width = $row_width - $row_pointer_x;
$next_row_height = $row_height;
$row_offset_x = to_even($row_pointer_x);
$row_offset_y = to_even($next_offset_y);
}
$offset_y += to_even($image_file['height'] + 1);
break;
}
if (++$_ > 100) {
// fin.
break;
}
}
$width = $max_width;
$height = 0;
foreach ($image_files as $image_file) {
$_h = $image_file['height'] + $image_file['offset_y'] + 1;
if ($_h > $height) {
$height = $_h;
}
}
$image = new Imagick();
$image->newImage($width, $height, new ImagickPixel('transparent'));
$styles = array();
$positions = array();
foreach ($image_files as $image_file) {
$styles[$image_file['basename']] = array(
'width' => $image_file['width'].'px',
'height' => $image_file['height'].'px',
'background-position' => sprintf('%dpx %dpx', - $image_file['offset_x'], - $image_file['offset_y']),
);
$positions[$image_file['basename']] = array(
'width' => $image_file['width'],
'height' => $image_file['height'],
'offset_x' => $image_file['offset_x'],
'offset_y' => $image_file['offset_y'],
);
$image_part = new Imagick($image_file['filepath']);
$image->compositeImage($image_part, Imagick::COMPOSITE_DEFAULT, $image_file['offset_x'], $image_file['offset_y']);
$image_part->clear();
$image_part->destroy();
$image_part = null;
}
$css = '';
foreach ($styles as $class => $defs) {
$css .= ".{$class} {" . PHP_EOL;
foreach ($defs as $key => $value) {
$css .= " {$key}: {$value};" . PHP_EOL;
}
$css .= "}" . PHP_EOL;
}
file_put_contents($NAME . '.css', $css);
file_put_contents($NAME . '.json', json_encode($positions));
$image->writeImages($NAME . '.png', true);
echo "done.\n";
$image->clear();
$image->destroy();
function to_even($number)
{
if ($number % 2 != 0) {
$number += 1;
}
return $number;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment