項目的一些說明:
- 我們在做一個漢字的項目,在這個項目中我們需要使用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
侵權聯繫刪除
作者:小追兵
鏈接:https://www.jianshu.com/p/f339fc8d006c
來源:簡書
簡書著作權歸作者所有,任何形式的轉載都請聯繫作者獲得授權並註明出處。