通用内容生成图片

236 阅读3分钟

通用文字内容生成图片方案

需求背景

\

为了防止用户很容易的采集到客户的联系方式信息,需要将用户的联系方式用图片显示。

类似于以下情况:

1.公司名片

2.求职招聘

3.旺铺

4.求购

\

\

技术方案

\

整体技术实现方案采用cdn+nginx+lua-gd来实现。利用CDN缓存生成的图片减少服务器的请求次数提高响应速度。

为了提高生成图片服务的灵活性和简单易用好维护,采用lua-gd模块生成图片。

lua-gd官网文档:Lua-GD Reference Manual (ittner.com.br)

\

简单使用lua-gd

im = gd.create(140, 80) -- 创建宽高画布

white = im:colorAllocate(255, 255, 255) -- 白色底

black = im:colorAllocate(0, 0, 0) -- 黑色字

im:string(gd.FONT_TINY, 10, 20, "TINY", black) -- 写入黑色文字指定位置

im:string(gd.FONT_SMALL, 10, 30, "SMALL", black)

im:string(gd.FONT_MEDIUM, 10, 45, "MEDIUM", black)

im:string(gd.FONT_LARGE, 10, 58, "LARGE", black)

im:png("out.png") -- 输出图片

图:out.png

nginx配置lua脚本

nginx接入lua需要按照好对应模块,然后在conf文件中配置写好的lua脚本

\

整体流程

根据输入的参数内容,尺寸,和颜色信息生成Url,请求nginx服务器,由lua解析参数信息lua-gd模块生成图片响应图片信息,相同Url链接地址会被cdn缓存。

流程图:

参数信息主要是三部分:content,size,color

参数说明:

content:自定义文本内容

size:定义高度宽度(WxH)W宽,H高;例子:30x20

color: 颜色为RGB值:如:(255,255,255) 白色

\

URL生成规则

img.hqew.cc/res/gimg/pa…

\

Lua Url编码样例代码:

local function decode(text)
    -- 
    local ts = string.split(text, "@")
    local length = tonumber(ts[2])
    local str = ts[1] .. ""
    -- 固定slat
    local slat = 10
    -- 定长数组4个
    local size = 4
     
    local b64 = require("base64")
    
    local res, err = b64.decode_base64url(str)
    -- 反转字符串提取文本内容
    local content = string.split(string.reverse(res), ",")

    local pl = #content / size;
    
    local m = 0
    if (#content ~= pl * size) then
        m = m + 1
    end

    local chars = {}
    -- 初始化数组
    for i = 1, (pl + m) do
        chars[i] = {}
        for j = 1, size do
            chars[i][j] = -1
        end
    end

    -- 填充内容
    local index = 1;
    for i = 1, #content do
        local x = tonumber(content[i])
        local pi = (index - 1) % (pl + m);
        if (i % size) == 0 then
            index = index + 1
        end
        chars[pi + 1][((i - 1) % (size)) + 1] = x;
    end

    -- 数值转化
    local idx = 0
    for i = 1, (pl + m) do
        for j = 1, size do
            idx = idx + 1
            local value = chars[i][j]
            chars[i][j] = (value - flag + idx);
        end
    end
    
    --位置替换
    for i = 1, (pl + m) do
        if i == (pl + m) then
        else
            if i % 2 == 1 then
                local c1 = chars[i]
                local c2 = chars[i + 1]
                chars[i] = c2
                chars[i + 1] = c1
            end
        end
    end
    
    --解出字符串
    local rs_str = "";
    local ti = 0;
    for i = 1, (pl + m) do
        for j = 1, size do
            ti = ti + 1
            if ti <= length then
                rs_str = rs_str .. toUnicode(chars[i][j])
            end
        end
    end
    return rs_str
end

local request_uri = ngx.var.request_uri
local args = ngx.req.get_uri_args()
local size = args['size']
local color = args['color']
local path = string.match(request_uri, "path/(.*)?")
--高宽
local wh = string.split(size, "x")
--颜色RGB值
local colors = string.split(color, ",")
--内容结果
local dval = decode(path)

--gd 模块
local gd = require "gd"
gd.useFontConfig(true)
im = gd.create(tonumber(wh[1]), tonumber(wh[2]))
white = im:colorAllocate(255, 255, 255)
im:colorTransparent(white)
local black = im:colorAllocate(tonumber(colors[1]), tonumber(colors[2]), tonumber(colors[3]))
--          颜色    字体     字体高度                  x  ,y(底部)
im:stringFT(black, "Arial", tonumber(wh[2])*0.5, 0, 1, tonumber(wh[2])*0.7, dval)
--响应图片
ngx.say(im:pngStr())

\

样例:

pic-test (hqew.cc)

\

\