/** * Adds a single icon to the stack. * * @param mixed[] $icon Icon (pkmn or etc group). */ function add($icon) { $x = $icon['fit']['x']; $y = $icon['fit']['y']; // Put the other icons underneath the Pokémon icons. if ($icon['section'] != 'pkmn') { $y += $this->sections['pkmn']; } $w = $icon['w']; $h = $icon['h']; $file = $icon['file']; $slug = $icon['slug']; $type = $icon['type']; $indicator = $type == 'pkmn' ? $icon['name_display'] . ' (variation=' . $icon['variation'] . ', subvariation=' . $icon['subvariation'] . ', version=' . $icon['version'] . ')' : $slug; if ($icon['is_duplicate']) { // If this is a duplicate, we don't need to add it. return true; } if (!is_file($file)) { // If the file does not exist, skip this entry. if ($this->verbose) { print I18n::lf('entry_skipped', array($file, $indicator)); } // Image not added. return false; } else { if ($this->verbose) { print I18n::lf('entry_added', array($file, $indicator)); } } // Open the image data. $tmp = @imagecreatefrompng($file); // If we're adding a faux right-facing image, we have to manually // flip the image before copying it to the sprite. if (@$icon['subvariation'] == 'flipped') { $tmp = $this->x_imageflip($tmp, 'v'); } // Copy the image to the sprite. @imagecopy($this->sprite, $tmp, $x, $y, 0, 0, $w, $h); @imagedestroy($tmp); // Image added. return true; }
/** * Displays the program usage. */ public function display_usage() { $this->trim_usage_tpl(); // Retrieve the proper error string in case we've got an error. if ($this->argument_error) { $error_str = I18n::lf('arg_error_tpl', array(I18n::l($this->error_id))); } $usage_vars = array('website' => Settings::get('website'), 'revision' => Settings::get('revision'), 'error' => $error_str, 'copyright' => Settings::get('copyright_str') . "\n" . Settings::get('copyright_gf')); // We'll replace variables and finally format the output // for use in a terminal. $trmfrm = new TerminalFormatter(); $this->render($usage_vars); $usage = $this->get_buffer(); $usage = $trmfrm->format($usage); print $usage; }
} $icon_sprite->output($dir_output . $img_output_tmp, $generate_optimized !== true); $icon_sprite->destroy(); // Use pngcrush to minimize the image. if ($generate_optimized === true) { print I18n::l('pngcrush_start'); if (file_exists($dir_output . $img_output)) { unlink($dir_output . $img_output); } $crush_cmd = $pngcrush_path . ' -l 9 -q -text b author "Pokémon Sprite Generator r' . $revision . '" -text b copyright "' . $copyright_gf . '" ' . $dir_output . $img_output_tmp . ' ' . $dir_output . $img_output; exec($crush_cmd); if (file_exists($dir_output . $img_output)) { // Seems like pngcrush was successful. Let's review the results. $size_before = filesize($dir_output . $img_output_tmp); $size_after = filesize($dir_output . $img_output); print I18n::lf('pngcrush_success', array(format_bytes($size_before), format_bytes($size_after))); // Delete the unoptimized image. print I18n::l('sprite_del_old'); unlink($dir_output . $img_output_tmp); } else { // We couldn't use pngcrush for some reason. print I18n::l('pngcrush_error'); exit; } } else { // If we're not using pngcrush, just rename it to the final filename. rename($dir_output . $img_output_tmp, $dir_output . $img_output); } // 4. Generation of the HTML, SCSS and JS files pertaining to the sprites // --------------------------------------------------------------------------- // We're going to be making a map of positioning values, styling information
/** * Creates an icon stack of the etc sprites. */ private function create_etc_icon_stack() { // This stack will contain icons from all other icon sets. $stack = array(); // Save an array of sets. $sets = array(); $etc_icon_sets = Settings::get('etc_icon_sets'); $dir_base = Settings::get('dir_base'); $file_exts = Settings::get('file_exts'); // Start off where the Pokémon stack ended. $n = count($this->pkmn_stack); if (Settings::get('include_icon_sets')) { foreach ($etc_icon_sets as $set) { $dir = $dir_base . $set . '/'; try { $dir_it = new \DirectoryIterator($dir); } catch (Exception $e) { print I18n::lf('icon_dir_failure', array($dir)); continue; } foreach ($dir_it as $file) { // Some checks to ensure it's a valid image. if ($file->isDot()) { continue; } if ($file->isDir()) { continue; } $fn = $file->getFilename(); $fn_bits = explode('.', $fn); $fn_ext = strtolower(trim(end($fn_bits))); if (!in_array($fn_ext, $file_exts)) { continue; } $size = getimagesize($dir . $fn); $fn_slug = slugify(implode('.', array_slice($fn_bits, 0, -1))); $var = $this->get_icon_var_name($set, $fn_slug); $n += 1; $stack[$n] = array('type' => 'etc', 'var' => $var, 'set' => $set, 'section' => 'other', 'id' => $n, 'slug' => $fn_slug, 'w' => $size[0], 'h' => $size[1], 'file' => $dir . $fn); $sets[$set][] = $n; } } } // Sort icons by size. uasort($stack, array($this, 'etc_max_w_h_sort')); // Deep convert $stack to a StdClass rather than a regular array. // This is in order to be able to use it with the GrowingPacker, which // only accepts a StdClass as input. $stack = json_decode(json_encode($stack), false); // Make sure to pass the width of the Pokémon section as // the initial width. If we're not including Pokémon icons, // set it to a static value. $pkmn_sect_size = $this->get_pkmn_icon_stack_size(); $initial_width = @$pkmn_sect_size['w']; if (!$initial_width) { $initial_width = $this->pkmn_img_width * $this->pkmn_row_count; } // Initialize our packing algorithm and feed the icons. // Permit horizontal growth only if we're not including Pokémon icons. $packer = new GrowingPacker(); $packer->fit($stack, $initial_width, null, false, true); // Convert back to array. $stack = json_decode(json_encode($stack), true); // Remove extraneous data from the stack. foreach ($stack as $n => $icon) { unset($stack[$n]['fit']['right']); unset($stack[$n]['fit']['down']); unset($stack[$n]['fit']['used']); } $this->etc_stack = $stack; $this->etc_sets = $sets; $this->etc_sect_width = intval($packer->root->w); $this->etc_sect_height = intval($packer->root->h); }