用PHP的imagettftext绘制文字的换行问题

小追兵专栏

项目的一些说明:
  • 我们在做一个汉字的项目,在这个项目中我们需要使用ps不停的制作一种图片;
  • 而图片样式基本固定。每次制作都需要设计人员重复排版,不停调整图片和文字间隔和大小;
  • 这样的事如果做一两次还是可以忍受的,可是每天都为这个花费大量的时间,就太折磨人了;
  • 精通php的老板一看,觉得这个用php就可以解决,于是他就把这活交给了我,通过php自动生成一张样式统一的卡片,用来减轻设计小女孩的工作量,把她从不停的排版中解除出来(可是我一点不懂php啊,我是做Android的,没关系,不会我们可以学习嘛。哈哈~~);
  • 就这样这个任务落到了公司除老板意外唯一懂技术的我的肩膀上了;
  • 来让我们看看是什么样样子的一个卡片呢?
项目制作的卡片如下图:

[图片上传失败...(image-a2974c-1511782668998)]

由图可以看出,整个大图由小的图片和文字组成。由于文字的多少是不确定的,每次的解释长短不一样,所以我们用程序画图的时候,要动态的根据文字的长短,个数,计算出文字占用的高度。

我们使用imagettftext这个函数把文字绘制在图片上,可是问来了,我们要解决换行问题,还要解决行间距的问题。如果我们单纯的插入\n作为换行符,会发现,行间距几乎为零,很难看。

下面是自己写了一个换行算法,并且可以设置行高同时,可以返回文字占用的高度。也想办法拍出来,标点符号出现在句首的问题。

下面附上“自动换行”和“计算段落高”的算法,执行后悔直接绘制。:
//下面函数方法我是这样调用的,这里是用来测量高度的。

    
     $temp = array("color" => array(99, 99, 99), "fontsize" =>27, "width" => 496, "left" => 100, "top" => 0, "hang_size" => 40);
    //这里我只用它做测量高度,把参数false改为true就是绘制了。
    $str_h=draw_txt_to($im, $temp, $str, false);
    

//----------分割线------------

/**
 * 文字自动换行算法
 * @param $card 画板
 * @param $pos 数组,top距离画板顶端的距离,fontsize文字的大小,width宽度,left距离左边的距离,hang_size行高
 * @param $str 要写的字符串
 * @param $iswrite  是否输出,ture,  花出文字,false只计算占用的高度
 * @return int 返回整个字符所占用的高度
 */

function draw_txt_to($card, $pos, $str, $iswrite)
{

    $_str_h = $pos["top"];
    $fontsize = $pos["fontsize"];
    $width = $pos["width"];
    $margin_lift = $pos["left"];
    $hang_size = $pos["hang_size"];
    $temp_string = "";
    $font_file = "./Fonts/华文细黑.ttf";
    $tp = 0;

    $font_color = imagecolorallocate($card, $pos["color"][0], $pos["color"][1], $pos["color"][2]);
    for ($i = 0; $i < mb_strlen($str); $i++) {

        $box = imagettfbbox($fontsize, 0, $font_file, $temp_string);
        $_string_length = $box[2] - $box[0];
        $temptext = mb_substr($str, $i, 1);

        $temp = imagettfbbox($fontsize, 0, $font_file, $temptext);

        if ($_string_length + $temp[2] - $temp[0] < $width) {//长度不够,字数不够,需要

            //继续拼接字符串。

            $temp_string .= mb_substr($str, $i, 1);

            if ($i == mb_strlen($str) - 1) {//是不是最后半行。不满一行的情况
                $_str_h += $hang_size;//计算整个文字换行后的高度。
                $tp++;//行数
                if ($iswrite) {//是否需要写入,核心绘制函数
                    imagettftext($card, $fontsize, 0, $margin_lift, $_str_h, $font_color, $font_file, $temp_string);
                }

            }
        } else {//一行的字数够了,长度够了。

//            打印输出,对字符串零时字符串置null
            $texts = mb_substr($str, $i, 1);//零时行的开头第一个字。

//            判断默认第一个字符是不是符号;
            $isfuhao = preg_match("/[\\\\pP]/u", $texts) ? true : false;//一行的开头这个字符,是不是标点符号
            if ($isfuhao) {//如果是标点符号,则添加在第一行的结尾
                $temp_string .= $texts;

//                判断如果是连续两个字符出现,并且两个丢失必须放在句末尾的,单独处理
                $f = mb_substr($str, $i + 1, 1);
                $fh = preg_match("/[\\\\pP]/u", $f) ? true : false;
                if ($fh) {
                    $temp_string .= $f;
                    $i++;
                }

            } else {
                $i--;
            }

            $tmp_str_len = mb_strlen($temp_string);
            $s = mb_substr($temp_string, $tmp_str_len-1, 1);//取零时字符串最后一位字符

                if (is_firstfuhao($s)) {//判断零时字符串的最后一个字符是不是可以放在见面
                    //讲最后一个字符用“_”代替。指针前移动一位。重新取被替换的字符。
                    $temp_string=rtrim($temp_string,$s);
                    $i--;
                }
//            }

//            计算行高,和行数。
            $_str_h += $hang_size;
            $tp++;
            if ($iswrite) {

                imagettftext($card, $fontsize, 0, $margin_lift, $_str_h, $font_color, $font_file, $temp_string);
            }
//           写完了改行,置null该行的临时字符串。
            $temp_string = "";
        }
    }

    return $tp * $hang_size;

}


function is_firstfuhao($str)
{
    $fuhaos = array("\\"", "“", "'", "<", "《",);

    return in_array($str, $fuhaos);

}

这样我们的汉字换行绘制输出,和测量高度的问题就解决了。虽然算法不完美,可是时间有限的情况下,基本能满足了我们的需求。

Github地址:https://github.com/SaudM/PhpCard

下篇,我们将实现该图片的图片和卡片的圆角处理。

最后:有需要Shadowsock翻墙账号可以私聊。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,254评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,875评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,682评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,896评论 1 285
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,015评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,152评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,208评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,962评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,388评论 1 304
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,700评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,867评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,551评论 4 335
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,186评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,901评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,142评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,689评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,757评论 2 351

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,900评论 25 707
  • 发现 关注 消息 iOS 第三方库、插件、知名博客总结 作者大灰狼的小绵羊哥哥关注 2017.06.26 09:4...
    肇东周阅读 12,068评论 4 62
  • 愿勤二十载,还尽我恩责。 从此出红尘,一心向自然。
    参度Gfh阅读 212评论 0 0
  • 今天下午考了六级,两点二十摇摇晃晃的起床了,下床穿鞋梳头检查证件急急忙忙的背着书包出去了,跑到楼下看看表都已经四十...
    莻木夏夏爱阅读 244评论 0 1
  • 今年开春,小区的小野猫们多了起来,其中一只小花喵格外让人注意,因为它一丁点儿也不怕人。其他的大小喵们,见到了人总是...
    李淼淼阅读 373评论 0 0