如何在没有抗锯齿的情况下将缩放后的文本作为图像
How to get scaled text as image without anti aliasing
我想把像素化的文本(没有抗锯齿)放到HTML画布上。我考虑过使用PHP来使用imagettftext渲染文本,使用负颜色值(禁用抗锯齿),然后将图像放在画布上。这很好,但我也想垂直或水平拉伸文本。有没有办法在PHP中做到这一点?(也可以使用其他脚本语言。)
背景:虽然有一些方法可以在没有抗锯齿的情况下在HTML画布上绘制图像,但我还没有找到任何文本。到目前为止,我已经使用了一个单独的画布,将文本放在画布上,并通过将所有alpha值>128设置为255,将其他所有值设置为0来操作imageData。然后我将该图像复制到目标画布上。这里的问题是,尤其是对于小字体,生成的字符差异很大,字符的线条粗细也不同。示例输出。(示例被放大。请参见"l"的不同厚度和"o"的不同渲染。)因此,任何关于如何在画布上获得清晰的非抗锯齿文本,或者如何创建具有清晰和拉伸文本的图像的想法都是非常受欢迎的。
我正在进行一个类似的项目,该项目涉及使用PHP生成图像并将其绘制到画布上。我注意到,任何透明度都会影响图像的清晰度。如果你在使用透明技术,在画布上绘制图像之前,最好在画布上铺一层平坦的白色。这是我正在学习的一个课程,也许你可以从中获得一些参考。它也可以实现像素化。
你可以这样使用它:
$img = Image::createTextImage($text, $font_size, $color, $ttf_font_file);
$img->pixelate($blocksize);
$img->output('png');
这将向浏览器输出一个图像,您可以将其加载到画布中。
class Image{
public $filepath;
public $width;
public $height;
public $mime;
public $landscape;
public $imageFunct;
public $compression;
// Image resource identifier
private $image;
// Is it a temporary image
private $isTemp;
/**
* constructor
* @param type $fp
* @param type $isTemp - if true, will delete the image file on the destroy call
* @throws Exception
*/
public function __construct($fp, $isTemp = false){
// Make sure file exists
if(!file_exists($fp)) throw new Exception("Image source file does not exist: $fp");
$this->isTemp = $isTemp;
$this->filepath = $fp;
$data = getimagesize($fp);
$this->width = $data[0];
$this->height = $data[1];
$this->landscape = $this->width > $this->height;
$this->mime = $data['mime'];
switch($this->mime){
case("image/png"):
$this->image = imagecreatefrompng($this->filepath);
imagealphablending($this->image, false);
imagesavealpha($this->image, true);
$this->imageFunct = 'imagepng';
$this->compression = 9;
break;
case('image/jpeg'):
case('image/pjpeg'):
case('image/x-jps'):
$this->image = imagecreatefromjpeg($this->filepath);
$this->imageFunct = 'imagejpeg';
$this->compression = 100;
break;
case('image/gif'):
$this->image = imagecreatefromgif($this->filepath);
imagealphablending($this->image, false);
imagesavealpha($this->image, true);
$this->imageFunct = 'imagegif';
break;
default:
throw new Exception("Invalid image type. Only excepts PNG, JPG, and GIF. You entered a {$this->mime} type image.");
}
}
/**
* scales the image to cover the dimensions provided
* @param type $width (of canvas)
* @param type $height (of canvas)
*/
public function scale($width, $height, $cover='fill'){
// Get new dimensions
$imgRatio = $this->height/$this->width;
$canvasRatio = $height/$width;
if(
($canvasRatio > $imgRatio && $cover=='fill') ||
($canvasRatio <= $imgRatio && $cover!='fill')
){
$finalHeight = $height;
$scale = $finalHeight / $this->height;
$finalWidth = $this->width * $scale;
}else{
$finalWidth = $width;
$scale = $finalWidth / $this->width;
$finalHeight = $this->height * $scale;
}
// Resize the image
$thumb = imagecreatetruecolor($finalWidth, $finalHeight);
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
imagecopyresampled($thumb, $this->image, 0, 0, 0, 0, $finalWidth, $finalHeight, $this->width, $this->height);
$this->resize($finalWidth, $finalHeight);
$this->width = $finalWidth;
$this->height = $finalHeight;
}
/**
* scales the image to cover the dimensions provided
* @param type $width (of canvas)
* @param type $height (of canvas)
*/
public function resize($width, $height){
// Resize the image
$thumb = imagecreatetruecolor($width, $height);
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
imagecopyresampled($thumb, $this->image, 0, 0, 0, 0, $width, $height, $this->width, $this->height);
$this->image = $thumb;
$this->width = $width;
$this->height = $height;
}
/**
* tile the image to the provided dimensions
* @param type $width
* @param type $height
* @param type $output_mimetype
*/
public function tile($width, $height){
// Our output image to be created
$out = imagecreatetruecolor($width, $this->height);
imagealphablending($out, false);
imagesavealpha($out, true);
// Tile that shit horiz
$curr_x = 0;
while($curr_x < $width){
imagecopy($out, $this->image, $curr_x, 0, 0, 0, $this->width, $this->height);
$curr_x += $this->width;
}
// our final output image to be created
$thumb = imagecreatetruecolor($width, $height);
imagealphablending($thumb, false);
imagesavealpha($thumb, true);
// Tile that shit vert
$curr_y = 0;
while($curr_y < $height){
imagecopy($thumb, $out, 0, $curr_y, 0, 0, $width, $this->height);
$curr_y += $this->height;
}
imagedestroy($out);
$this->image = $thumb;
}
/**
* Reverse all colors of the image
*/
public function reverseColors(){
return imagefilter($this->image, IMG_FILTER_NEGATE);
}
/**
* Convert image to greyscale
*/
public function greyScale(){
return imagefilter($this->image, IMG_FILTER_GRAYSCALE);
}
/**
* Adjust brightness level. (between 255 and -255)
* @param type $brightness
*/
public function adjustBrightness($brightness){
if($brightness > 255) $brightness = 255;
if($brightness < -255) $brightness = -255;
return imagefilter($this->image, IMG_FILTER_BRIGHTNESS, $brightness);
}
/**
* Adjust the contrast level
* @param int $contrast
*/
public function adjustContrast($contrast){
return imagefilter($this->image, IMG_FILTER_CONTRAST, $contrast);
}
/**
* Turns on edgeDetect Filter
*/
public function edgeDetect(){
return imagefilter($this->image, IMG_FILTER_EDGEDETECT);
}
/**
* Turns on emboss Filter
*/
public function emboss(){
return imagefilter($this->image, IMG_FILTER_EMBOSS);
}
/**
* Turns on gaussianBlur Filter
*/
public function gaussianBlur(){
return imagefilter($this->image, IMG_FILTER_GAUSSIAN_BLUR);
}
/**
* Turns on selectiveBlur Filter
*/
public function selectiveBlur(){
return imagefilter($this->image, IMG_FILTER_SELECTIVE_BLUR);
}
/**
* Turns on sketch Filter
*/
public function sketch(){
return imagefilter($this->image, IMG_FILTER_MEAN_REMOVAL);
}
/**
* Adds a vignette
*/
function vignette(){
for($x = 0; $x < imagesx($this->image); ++$x){
for($y = 0; $y < imagesy($this->image); ++$y){
$index = imagecolorat($this->image, $x, $y);
$rgb = imagecolorsforindex($this->image, $index);
$sharp = 0.4; // 0 - 10 small is sharpnes,
$level = 0.7; // 0 - 1 small is brighter
$l = sin(M_PI / $this->width * $x) * sin(M_PI / $this->height * $y);
$l = pow($l, $sharp);
$l = 1 - $level * (1 - $l);
$rgb['red'] *= $l;
$rgb['green'] *= $l;
$rgb['blue'] *= $l;
$color = imagecolorallocate($this->image, $rgb['red'], $rgb['green'], $rgb['blue']);
imagesetpixel($this->image, $x, $y, $color);
}
}
return true;
}
/**
* Pixelate the image
* @param type $blocksize
* @param type $advanced
*/
public function pixelate($blocksize, $advanced=true){
return imagefilter($this->image, IMG_FILTER_PIXELATE, $blocksize, $advanced);
}
/**
* Adjust smoothness level
* @param type $level
*/
public function adjustSmoothness($level){
return imagefilter($this->image, IMG_FILTER_SMOOTH, $level);
}
/**
* Colorize an image
* @param type $hexColor
*/
public function colorize($hexColor, $alpha){
list($r, $g, $b) = self::convertHexColor($hexColor);
if($alpha < 0) $alpha = 0;
if($alpha > 127) $alpha = 127;
return imagefilter($this->image, IMG_FILTER_COLORIZE, $r, $g, $b, $alpha);
}
/**
* Outputs the image directly to the browser
* @param type $output_mimetype ("png", "jpg", or "gif")
* (defaults to the original image's mimtype)
*/
public function output($output_mimetype = null){
// Get output details
list($mimetype, $funct, $compression) = $this->getOutputDetails($output_mimetype);
// Output and clear memory
header('Content-Type: '.$mimetype);
// Get and call the image creation funtion
$funct($this->image, null, $compression);
}
/**
* Destroys the generated image to free up resources,
* Delete the file if it's a temporary file.
* should be the last method called as the object is unusable after this.
*/
public function destroy(){
imagedestroy($this->image);
if($this->isTemp) unlink($this->filepath);
}
/**
* Crops the image to the given dimensions, at the given starting point
* defaults to the top left
* @param type $width
* @param type $height
* @param type $x
* @param type $y
*/
public function crop($new_width, $new_height, $x = 0, $y = 0){
// Get dimensions
$width = imagesx($this->image);
$height = imagesy($this->image);
// Make the dummy image that will become the new image
$newImg = imagecreatetruecolor($new_width, $new_height);
// Fill with transparent background
imagealphablending($newImg, false);
imagesavealpha($newImg, true);
$transparent = imagecolorallocatealpha($newImg, 255, 255, 255, 127);
imagefilledrectangle($newImg, 0, 0, $new_width, $new_height, $transparent);
// Copy the pixels to the new image
imagecopy($newImg, $this->image, 0, 0, 0, 0, $width, $height);
$this->image = $newImg;
$this->width = $width;
$this->height = $height;
}
/**
* Create an image from a base64 string
* @param type $string
* @return 'Image
*/
public static function createFromBase64($string){
// decode base64 string
$imgData = base64_decode(preg_replace('#^data:image/'w+;base64,#i', '', $string));
// create the image resource
$formImage = imagecreatefromstring($imgData);
// Fill with transparent background
imagealphablending($formImage, false);
imagesavealpha($formImage, true);
$transparent = imagecolorallocatealpha($formImage, 255, 255, 255, 127);
imagefill($formImage, 0, 0, $transparent);
// Save the image to a temp png file to use in our constructor
$tmpname = tempnam('/tmp', 'IMG');
// Generate and save image
imagepng($formImage, $tmpname, 9);
// Return an instance of the class
$img = new Image($tmpname, true);
return $img;
}
/**
* Make an image of text
* @param type $text
* @param type $size
* @param type $color
* @param type $font
*/
public static function createTextImage($text, $font_size, $color, $font_file, $wrap_width = false){
// Make sure font file exists
if(!file_exists($font_file)) throw new Exception("Font file does not exist: {$font_file}");
// Generate wrapping text
if(is_numeric($wrap_width) && $wrap_width != 0)
$text = self::wrapText($font_size, $font_file, $text, $wrap_width);
// Retrieve bounding box:
$type_space = imagettfbbox($font_size, 0, $font_file, $text);
// Determine image width and height, 10 pixels are added for 5 pixels padding:
$image_width = abs($type_space[4] - $type_space[0]) + 10;
$image_height = abs($type_space[5] - $type_space[1]) + 10;
$line_height = self::getLineHeight($font_size, $font_file) +10;
// Create image:
$image = imagecreatetruecolor($image_width, $image_height);
// Allocate text and background colors (RGB format):
$text_color = self::getColor($image, $color);
// Fill with transparent background
imagealphablending($image, false);
imagesavealpha($image, true);
$transparent = imagecolorallocatealpha($image, 255, 255, 255, 127);
imagefill($image, 0, 0, $transparent);
// Fix starting x and y coordinates for the text:
$x = 5; // Padding of 5 pixels.
$y = $line_height - 5; // So that the text is vertically centered.
// Add TrueType text to image:
imagettftext($image, $font_size, 0, $x, $y, $text_color, $font_file, $text);
// Save the image to a temp png file to use in our constructor
$tmpname = tempnam('/tmp', 'IMG');
// Generate and save image
imagepng($image, $tmpname, 9);
// Return an instance of the class
$img = new Image($tmpname, true);
$img->crop($image_width, $image_height);
return $img;
}
/**
* Get output information
* @param type $output_mimetype
* @return array($mimetype, $output_funct, $compression)
*/
private function getOutputDetails($output_mimetype){
switch(strtoupper($output_mimetype)){
case('JPG'):
case('JPEG'):
$mimetype = 'image/jpeg';
$funct = 'imagejpeg';
$compression = 100;
break;
case('PNG'):
$mimetype = 'image/png';
$funct = 'imagepng';
$compression = 9;
break;
case('GIF'):
$mimetype = 'image/gif';
$funct = 'imagegif';
$compression = null;
break;
default:
$mimetype = $this->mime;
$funct = $this->imageFunct;
$compression = $this->compression;
}
return array($mimetype, $funct, $compression);
}
private static function convertHexColor($hex){
// Remove the # if therre is one
$hex = str_replace("#", "", $hex);
// Convert the hex to rgb
if(strlen($hex) == 3){
$r = hexdec(substr($hex, 0, 1) . substr($hex, 0, 1));
$g = hexdec(substr($hex, 1, 1) . substr($hex, 1, 1));
$b = hexdec(substr($hex, 2, 1) . substr($hex, 2, 1));
}else{
$r = hexdec(substr($hex, 0, 2));
$g = hexdec(substr($hex, 2, 2));
$b = hexdec(substr($hex, 4, 2));
}
return array($r, $g, $b);
}
/**
* Convert Hex Colors To RGB
* @param type $image - image identifier
* @param type $hex - the hex color code
* @param type $alpha - 0 for solid - 127 for transparent
* @return type color identifier
* @throws Exception
*/
private static function getColor($image, $hex, $alpha=0){
list($r, $g, $b) = self::convertHexColor($hex);
// The alpha layer seems to make things gritty,
// so let's avoid it if there's no transparency
$return = ($alpha==0) ?
imagecolorallocatealpha($image, $r, $g, $b, $alpha) :
imagecolorallocate($image, $r, $g, $b) ;
// Make sure it worked
if($return === false) throw new Exception("Could not create color $hex.");
return $return;
}
/**
* Inserts linebreaks to wrap text
* @param type $fontSize
* @param type $fontFace
* @param type $string
* @param type $width
* @return string
*/
private static function wrapText($fontSize, $fontFace, $string, $width){
$ret = "";
$arr = explode(" ", $string);
foreach($arr as $word){
$testboxWord = imagettfbbox($fontSize, 0, $fontFace, $word);
// huge word larger than $width, we need to cut it internally until it fits the width
$len = strlen($word);
while($testboxWord[2] > $width && $len > 0){
$word = substr($word, 0, $len);
$len--;
$testboxWord = imagettfbbox($fontSize, 0, $fontFace, $word);
}
$teststring = $ret . ' ' . $word;
$testboxString = imagettfbbox($fontSize, 0, $fontFace, $teststring);
if($testboxString[2] > $width){
$ret.=($ret == "" ? "" : "'n") . $word;
}else{
$ret.=($ret == "" ? "" : ' ') . $word;
}
}
return $ret;
}
/**
* Returns the line height based on the font and font size
* @param type $fontSize
* @param type $fontFace
*/
private static function getLineHeight($fontSize, $fontFace){
// Arbitrary text is drawn, can't be blank or just a space
$type_space = imagettfbbox($fontSize, 0, $fontFace, "Robert is awesome!");
$line_height = abs($type_space[5] - $type_space[1]);
return $line_height;
}
}
编辑
这是一个完全可以工作的脚本,可以做你想做的事情,使用我上面的类:
<?php
error_reporting(E_ALL);
ini_set('display_errors', '1');
// Require the class
require "./Image.php";
// Set the text of your image
$text = "This is a test";
// Hijack a font from the web if you don't have a local .ttf file to use
$ttf_font_file = tempnam('/tmp', 'IMG');
$fh = fopen($ttf_font_file, "w");
fwrite($fh, file_get_contents("https://github.com/todylu/monaco.ttf/blob/master/monaco.ttf?raw=true"));
fclose($fh);
// Set font size to something really big so we can scale it down without losing resolution
$font_size = 100;
// And the font color
$color = "#000";
// Create the image
$img = Image::createTextImage($text, $font_size, $color, $ttf_font_file);
// shrink the image to the desired proportions
$img->resize(200, 25);
// output it as a png
$img->output('png');
// destroy the evidence
$img->destroy();
相关文章:
- 在不移动内部文本的情况下缩放元素的效果
- 自动缩放图像以匹配文本高度
- 基于宽度的文本缩放
- 如何在D3中获得可缩放Icicle布局中文本标签的旋转
- AngularJS:重新缩放文本框
- 如何使用拉斐尔缩放文本.js
- 如何缩放 D3 气泡图中的文本
- 如何在没有抗锯齿的情况下将缩放后的文本作为图像
- 缩放文本以适应Famo.us曲面
- 如何在 html 中缩放文本
- 有没有办法对 jquery 或角度 js 中的文本应用捏合缩放
- 调整大小,移动和缩放图像和文本分区与浏览器调整大小
- 如何在缩放路径时防止缩放文本和边框
- 当您将窗口调整为任何大小时,如何按比例获得此缩放框的图像和文本
- 如何“隐藏”文本在d3的中心可缩放的太阳爆发缩放时
- 无限循环到JS驱动文本缩放动画
- 防止d3缩放将SVG中的文本移动到与SVG其余部分不同的位置
- 如何缩放所有的东西,除了一些路径/文本在svg画布上,而不改变其确切位置
- 更快的方式缩放文本在浏览器?(帮助翻译试题)
- 在html加载时缩放文本,并在同一页面的不同位置淡出