使用ImageMagick做海报时,如果需要写入用户微信昵称,比如 ‘张三👏’,图片内的文字会变成 ‘张三?’,因为本质上,emoji不是文字,在常规入Pingfang字体中,是不存在对应关系的。查遍24史(github和stackoverflow),都说ImageMagick并不支持emoji表情,php自带的gd库就更不支持了。
说明
首先,emoji对应的unicode码在不同平台解析出的样式不同。所以即使mysql使用字符集UTF8mb4格式将emoji存储起来,拿出来后,发给前端(andr,ios,浏览器),同一个unicode的图并不一样。
思路
所以,想让‘张三👏’完美的在海报上写出来。需要转换思考的方式,将‘张三👏’拆分成‘张三’+‘👏’,前者当成文字,后者当成图片。所以,能找到对应unicode对应的图片素材。就能使用ImageMagick的写入文字和合并图片的方法分治处理了。
emoji素材
https://www.unicode.org/emoji/charts/full-emoji–list.html
以上链接为unicode对应的emoji在各大平台的图像映射关系
分析一下页面源代码,发现,除了绿框内的。其他的都是base64的格式发出的图片数据流,如下:
所以,直接control + s 保存该页面,重命名为emoji.html,同时mkdir 建立emojis文件夹,编写处理图片的php代码,如下:
<?php
$str = file_get_contents('./emoji.html');
$regx = '/<td class=\"code\">.*?<a href=.*?>(.*?)<\/a>.*?<img.*? class=\"imga\" src=\"(.*?)\">.*?<\/td>/is';
preg_match_all($regx, $str, $matches, PREG_PATTERN_ORDER);
$codes = $matches[1];
$stream = $matches[2];
unset($matches);
function get_img_type($str){
$regx = '/^(data:\s*image\/(\w+);base64,)/';
preg_match($regx, $str, $result);
return $result;
}
foreach($codes as $k => $code){
$code = str_replace(' ', '', $code);
$code = str_replace('U+', '', $code);
$info = get_img_type($stream[$k]);
$mime = $info[2];
$prefix = $info[1];
$streamInfo = base64_decode(str_replace($prefix, '', $stream[$k]));
file_put_contents('./emojis/'.$code.'.'.$mime, $streamInfo);
unset($stream[$k]);
}
运行后,拿出所有图片,如下,素材已经取出来了
那么,如何找到‘?’对应的unicode码呢
如下php函数
function utf8ToUnicode($utf8) { $i = 0; $l = strlen($utf8); $out = ''; while ($i < $l) { if ((ord($utf8[$i]) & 0x80) === 0x00) { $n = ord($utf8[$i++]); } elseif ((ord($utf8[$i]) & 0xE0) === 0xC0) { $n = ((ord($utf8[$i++]) & 0x1F) << 6) | ((ord($utf8[$i++]) & 0x3F) << 0); } elseif ((ord($utf8[$i]) & 0xF0) === 0xE0) { $n = ((ord($utf8[$i++]) & 0x0F) << 12) | ((ord($utf8[$i++]) & 0x3F) << 6) | ((ord($utf8[$i++]) & 0x3F) << 0) ; } elseif ((ord($utf8[$i]) & 0xF8) === 0xF0) { $n = ((ord($utf8[$i++]) & 0x07) << 18) | ((ord($utf8[$i++]) & 0x3F) << 12) | ((ord($utf8[$i++]) & 0x3F) << 6) | ((ord($utf8[$i++]) & 0x3F) << 0) ; } elseif ((ord($utf8[$i]) & 0xFC) === 0xF8) { $n = ((ord($utf8[$i++]) & 0x03) << 24) | ((ord($utf8[$i++]) & 0x3F) << 18) | ((ord($utf8[$i++]) & 0x3F) << 12) | ((ord($utf8[$i++]) & 0x3F) << 6) | ((ord($utf8[$i++]) & 0x3F) << 0); } elseif ((ord($utf8[$i]) & 0xFE) === 0xFC) { $n = ((ord($utf8[$i++]) & 0x01) << 30) | ((ord($utf8[$i++]) & 0x3F) << 24) | ((ord($utf8[$i++]) & 0x3F) << 18) | ((ord($utf8[$i++]) & 0x3F) << 12) | ((ord($utf8[$i++]) & 0x3F) << 6) | ((ord($utf8[$i++]) & 0x3F) << 0); } else { throw new \Exception('Invalid utf-8 code point'); } $n = strtoupper(dechex($n)); $pad = strlen($n) <= 4 ? strlen($n) + strlen($n) %2 : 0; $n = str_pad($n, $pad, "0", STR_PAD_LEFT); $out .= $n; //$out .= sprintf("\u%s", $n); } return $out; } echo utf8ToUnicode('👏'); //输出1F44F
从emojis文件夹中可以找到1F44F.png,就是对应的素材。
最后,怎么用ImageMagick插入图片到另一张图片上,这就不在此多做赘述了。
效果图如下: