* @license GPLv2 or later */ class Asciify { /** * Plugin specific constants. */ const VERSION = '1.0.0'; const MAIN_MENU_SLUG = 'asciify'; const IMAGE_METAKEY = 'asciify_full'; const SETTINGS_NAME = 'asciify_settings'; const TEXT_DOMAIN = 'asciify'; const DEFAULT_CAPABILITY= 'manage_options'; const CAPABILITY_FILTER = 'asciify_cap'; /** * Image related constants. */ const DEFAULT_IMAGE_WIDTH = 300; const DEFAULT_IMAGE_HEIGHT = 300; /** * Font related constants. */ const FONT_DIR = ASCIIFY_PLUGIN_DIR . DIRECTORY_SEPARATOR . 'fonts'; const DEFAULT_FONT_FILE = 'courier'; const DEFAULT_FONT_SIZE = 10; const DEFAULT_FONT_SPACING = 1; /** * Text related constants. */ const DEFAULT_BLACK_CHAR = '#'; const DEFAULT_WHITE_CHAR = ' '; const DEFAULT_BACKGROUND_COLOR = '0xffffff'; const DEFAULT_FOREGROUND_COLOR = '0x000000'; const REGEXP_HEXADECIMAL = '/0[xX][0-9a-fA-F]+/'; /** * Resize strategy constants. */ const RESIZE_STRATEGY_EXACT = 'exact'; const RESIZE_STRATEGY_CROP = 'crop'; const RESIZE_STRATEGY_PORTRAIT = 'portrait'; const RESIZE_STRATEGY_LANDSCAPE = 'landscape'; const RESIZE_STRATEGY_FIT = 'fit'; const RESIZE_STRATEGY_SQUARE = 'square'; const RESIZE_STRATEGY_FILL = 'fill'; const RESIZE_STRATEGY_AUTO = 'auto'; const DEFAULT_RESIZE_STRATEGY = self::RESIZE_STRATEGY_AUTO; /** * Contains all settings. * * @var \Asciify\config\Settings $settings */ private $settings; /** * Contains all loaded fonts. * * @var array $fonts */ private $fonts = array(); /** * The capabilities used to use the plugin. * * @var string $capabilities */ private $capability = self::DEFAULT_CAPABILITY; /** * Default settings. * * @var array $default_settings */ private $default_settings = array( 'max_width' => self::DEFAULT_IMAGE_WIDTH, 'max_height' => self::DEFAULT_IMAGE_HEIGHT, 'black_char' => self::DEFAULT_BLACK_CHAR, 'white_char' => self::DEFAULT_WHITE_CHAR, 'monochrome' => true, 'font_file' => self::DEFAULT_FONT_FILE, 'font_size' => self::DEFAULT_FONT_SIZE, 'font_spacing' => self::DEFAULT_FONT_SPACING, 'background_color' => self::DEFAULT_BACKGROUND_COLOR, 'foreground_color' => self::DEFAULT_FOREGROUND_COLOR, 'transparent' => false, 'auto_insert' => false, 'scale' => false, 'resize_strategy' => self::DEFAULT_RESIZE_STRATEGY, 'pure_text' => false, 'image_styles' => array( 'original', ), 'version' => self::VERSION, ); /** * Asciify constructor. */ public function __construct() { $this->settings = new Settings(self::SETTINGS_NAME); if (version_compare( $this->settings->version, self::VERSION, '!=' ) ) { // Set defaults. foreach ($this->default_settings as $key => $value) { $this->settings->add($key, $value); } } $this->settings->save(); // Allow people to change what capability is needed. $this->capability = apply_filters(self::CAPABILITY_FILTER, $this->capability); //add_action('wp_head', array($this, 'addStyles'), 100); load_plugin_textdomain( self::TEXT_DOMAIN, false, dirname(plugin_basename(__FILE__)) . DIRECTORY_SEPARATOR . 'languages' ); add_action('admin_menu', array($this, 'addMenu')); $this->setupFilters(); $this->loadFonts(); } /** * @param string $size_name Name of image size. * @param mixed $image_meta Attachment metadata. * * @return bool */ public function getImageSizeFromMeta($size_name, $image_meta) { return (!empty($image_meta['sizes'][$size_name]) ? $image_meta['sizes'][$size_name] : false); } /** * Delete all asciffy image size references from * metadata. Notice that references in post_content will NOT * be removed as this point. */ public function cleanAttachmentMetaData() { global $wpdb; include_once ABSPATH . 'wp-admin/includes/image.php'; $result = $wpdb->get_col("SELECT ID FROM $wpdb->posts WHERE post_type = 'attachment'"); foreach ($result as $attachment_id) { $metadata = get_post_meta($attachment_id, '_wp_attachment_metadata', true); $upload_dir = wp_upload_dir(null, false); $image_size = $this->getImageSizeFromMeta(self::IMAGE_METAKEY, $metadata); if ($image_size) { $filename = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . dirname($metadata['file']) . DIRECTORY_SEPARATOR . $metadata['sizes'][self::IMAGE_METAKEY]['file']; if (file_exists($filename)) { $delete = apply_filters('wp_delete_file', $filename); if (!empty($delete)) { @unlink($delete); } unset($metadata['sizes'][self::IMAGE_METAKEY]); update_post_meta($attachment_id, '_wp_attachment_metadata', $metadata); } } } } /** * Removes all settings. */ public function uninstall() { $this->settings->delete(); $this->cleanAttachmentMetaData(); } /** * Add menu option in administration. */ public function addMenu() { add_management_page( __('Asciify', self::TEXT_DOMAIN), __('Asciify', self::TEXT_DOMAIN), $this->capability, self::MAIN_MENU_SLUG, array($this, 'settingsPage') ); } /** * Load all fonts. */ private function loadFonts() { putenv('GDFONTPATH=' . realpath(self::FONT_DIR)); $fontDir = opendir(self::FONT_DIR); if ($fontDir) { while ($fontFile = readdir($fontDir)) { if ($fontFile[0] != '.') { $this->fonts[] = self::FONT_DIR . DIRECTORY_SEPARATOR . $fontFile; } } closedir($fontDir); } } /** * Register all filters. */ public function setUpFilters() { add_filter('wp_generate_attachment_metadata', array($this, 'onGenerateAttachmentMetaData')); add_action( 'init', function () { add_image_size(self::IMAGE_METAKEY, 9999, 9999); } ); add_filter('image_size_names_choose', array($this, 'onImageSizeNamesChoose')); } /** * @param array $sizes * * @return array */ public function onImageSizeNamesChoose(array $sizes) { return array_merge( $sizes, array( self::IMAGE_METAKEY => __('Ascii Full Size'), ) ); } /** * @param array $metadata * * @return array */ public function onGenerateAttachmentMetaData(array $metadata) { $upload_dir = wp_upload_dir(null, false); $filename = $upload_dir['basedir'] . DIRECTORY_SEPARATOR . $metadata['file']; if ($this->settings->get('pure_text')) { $this->asciifyText($filename); } else { $this->asciifyImage($filename, $metadata); } return $metadata; } /** * Add custom styles for ascii text container. */ public function addStyles() { $foreground_color = $this->settings->get('foreground_color'); $font_size = $this->settings->get('font_size'); $font_file = $this->settings->get('font_file'); echo ''; } /** * @param resource $image * @param int $new_width * @param int $new_height * * @return resource */ public function scaleKeepAspectRatio($image, $new_width, $new_height) { if ($new_width == 0 && $new_height == 0) { return $image; } $old_x = imagesx($image); $old_y = imagesy($image); if ($old_x > $old_y) { $thumb_w = $new_width; $thumb_h = $old_y * ($new_height / $old_x); } elseif ($old_x < $old_y) { $thumb_w = $old_x * ($new_width / $old_y); $thumb_h = $new_height; } else { $thumb_w = $new_width; $thumb_h = $new_height; } $dst_img = imagecreatetruecolor($thumb_w, $thumb_h); imagecopyresampled( $dst_img, $image, 0, 0, 0, 0, $thumb_w, $thumb_h, $old_x, $old_y ); return $dst_img; } /** * @param string $filename */ public function asciifyText($filename) { $image = imagecreatefromstring(file_get_contents($filename)); if ($this->settings->get('max_width') != 0 || $this->settings->get('max_height') != 0) { $scaled = $this->scaleKeepAspectRatio( $image, $this->settings->get('max_width'), $this->settings->get('max_height') ); imagedestroy($image); $image = $scaled; } $width = imagesx($image); $height = imagesy($image); // Convert to grayscale and apply full contrast. if ($this->settings->get('monochrome')) { imagefilter($image, IMG_FILTER_GRAYSCALE); imagefilter($image, IMG_FILTER_CONTRAST, -255); } $font_spacing = $this->settings->get('font_spacing'); $black_char = $this->settings->get('black_char'); $white_char = $this->settings->get('white_char'); $output = ''; for ($i = 0; $i < $height; $i += $font_spacing) { for ($j = 0; $j < $width; $j += $font_spacing) { $rgb = imagecolorat($image, $j, $i); if ($rgb != 0) { if ($white_char != '') { $output .= $white_char; } } else { if ($black_char != '') { $output .= $black_char; } } } $output .= PHP_EOL; } imagedestroy($image); $output = '