1. 程式人生 > >使用GDlib在圖片上繪製文字

使用GDlib在圖片上繪製文字

GDlib安裝

在ubuntu 17.04下選擇從原始碼編譯安裝環境準備:

  • libpng,png格式支援; 執行apt install libpng-dev
  • libjpeg
  • libfreetype,字型支援
  • zlib
  • cmake

clone原始碼並切換到目的tag,cd到原始碼根目錄,執行以下命令:

cmake -DBUILD_TEST=1 -DENABLE_FREETYPE=1 -DENABLE_PNG=1 -DENABLE_JPEG=1 -DFREETYPE_INCLUDE_DIRS=/usr/local/include/freetype2/ ./
make
make install

安裝freetype2後cmake未找到,故手到指定了下freetype的路徑-DFREETYPE_INCLUDE_DIRS=/usr/local/include/freetype2/


cmake可指定的部分選項有:

OPTION(ENABLE_PNG "Enable PNG support" 0)
OPTION(ENABLE_LIQ "Enable libimagequant support" 0)
OPTION(ENABLE_JPEG "Enable JPEG support" 0)
OPTION(ENABLE_TIFF "Enable TIFF support" 0)
OPTION(ENABLE_ICONV "Enable ICONV support" 0)
OPTION(ENABLE_XPM "Enable XPM support" 0)
OPTION(ENABLE_FREETYPE "Enable Freetype2 support"
0) OPTION(ENABLE_FONTCONFIG "Enable FontConfig support" 0) OPTION(ENABLE_WEBP "Enable WebP support" 0) if (BUILD_TEST) ENABLE_TESTING() endif(BUILD_TEST)

執行測試可用:ctest

文字繪製函式

繪製文字主要是通過呼叫函式GD庫內gdImageStringFT函式實現,該函式實現如下:

/**
 * Function: gdImageStringFT
 *
 * Render an UTF-8 string onto a gd image.
 *
 * Parameters:
 *  im       - The image to draw onto.
 *  brect    - The bounding rectangle as array of 8 integers where each pair
 *             represents the x- and y-coordinate of a point. The points
 *             specify the lower left, lower right, upper right and upper left
 *             corner.
 *  fg       - The font color.
 *  fontlist - The semicolon delimited list of font filenames to look for.
 *  ptsize   - The height of the font in typographical points (pt).
 *  angle    - The angle in radian to rotate the font counter-clockwise.
 *  x        - The x-coordinate of the basepoint (roughly the lower left corner) of the first letter.
 *  y        - The y-coordinate of the basepoint (roughly the lower left corner) of the first letter.
 *  string   - The string to render.
 *
 * Variant:
 *  - <gdImageStringFTEx>
 *
 * See also:
 *  - <gdImageString>
 */
BGD_DECLARE(char *) gdImageStringFT (gdImage * im, int *brect, int fg, const char *fontlist, double ptsize, double angle, int x, int y, const char *string) { return gdImageStringFTEx (im, brect, fg, fontlist, ptsize, angle, x, y, string, 0); }

從實現可以看出gdImageStringFT只是gdImageStringFTEx的一種特例.
函式傳參中:

  • brect是指向8個元素大小的一維陣列的指標,用來接受繪製文字後文本區域的左下/右下/右上/左上的座標值.
  • fontlist 分號分割的字型檔案(包含路徑)名列表.
  • x/y 文字繪製的起始點座標(左下為起始基準)
  • ptsize文字大小,用文字高度描述
  • string 繪製的文字,注意函式內使用’\0’作為文字結束的標誌,在使用例如ngx_string_t等資料時注意處理轉換;支援utf-8中文字元的渲染,若渲染出席亂碼方塊,檢視下選擇的字型庫是否支援中文.

使用示例

GD庫中的一個使用測試示例:

#include "gd.h"
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include "gdtest.h"

#define PI 3.141592
#define DELTA (PI/8)

static int EXPECT[16][8] = {
    {498, 401, 630, 401, 630, 374, 498, 374},
    {491, 364, 613, 313, 602, 288, 481, 338},
    {470, 332, 563, 239, 544, 219, 451, 312},
    {438, 310, 488, 189, 463, 178, 412, 300},
    {401, 303, 401, 171, 374, 171, 374, 303},
    {365, 310, 314, 188, 289, 199, 339, 320},
    {334, 331, 241, 238, 221, 257, 314, 350},
    {313, 362, 192, 312, 181, 337, 303, 388},
    {306, 398, 174, 398, 174, 425, 306, 425},
    {313, 433, 191, 484, 202, 509, 323, 459},
    {333, 463, 240, 556, 259, 576, 352, 483},
    {363, 484, 313, 605, 338, 616, 389, 494},
    {398, 490, 398, 622, 425, 622, 425, 490},
    {432, 483, 483, 605, 508, 594, 458, 473},
    {461, 464, 554, 557, 574, 538, 481, 445},
    {481, 435, 602, 485, 613, 460, 491, 409},
};

int main()
{
    char *path;
    gdImagePtr im;
    int black;
    double cos_t, sin_t;
    int x, y, temp;
    int i, j;
    int brect[8];
    int error = 0;
    FILE *fp;

    /* disable subpixel hinting */
    putenv("FREETYPE_PROPERTIES=truetype:interpreter-version=35");

    path = gdTestFilePath("freetype/DejaVuSans.ttf");
    im = gdImageCreate(800, 800);
    gdImageColorAllocate(im, 0xFF, 0xFF, 0xFF); /* allocate white for background color */
    black = gdImageColorAllocate(im, 0, 0, 0);
    cos_t = cos(DELTA);
    sin_t = sin(DELTA);
    x = 100;
    y = 0;
    for (i = 0; i < 16; i++) {
        if (gdImageStringFT(im, brect, black, path, 24, DELTA*i, 400+x, 400+y, "ABCDEF")) {
            error = 1;
            goto done;
        }
        for (j = 0; j < 8; j++) {
            if (brect[j] != EXPECT[i][j]) {
                gdTestErrorMsg("(%d, %d) (%d, %d) (%d, %d) (%d, %d) expected, but (%d, %d) (%d, %d) (%d, %d) (%d, %d)\n",
                       EXPECT[i][0], EXPECT[i][1], EXPECT[i][2], EXPECT[i][3],
                       EXPECT[i][4], EXPECT[i][5], EXPECT[i][6], EXPECT[i][7],
                       brect[0], brect[1], brect[2], brect[3],
                       brect[4], brect[5], brect[6], brect[7]);
                error = 1;
                goto done;
            }
        }
        gdImagePolygon(im, (gdPointPtr)brect, 4, black);
        gdImageFilledEllipse(im, brect[0], brect[1], 8, 8, black);
        temp = (int)(cos_t * x + sin_t * y);
        y = (int)(cos_t * y - sin_t * x);
        x = temp;
    }
    fp = gdTestTempFp();
    //fp = fopen("/tmp/stringft.png","wb");
    gdImagePng(im, fp);
    fclose(fp);
done:
    gdImageDestroy(im);
    gdFontCacheShutdown();
    free(path);
    return error;
}

以上這段測試程式碼實現的功能:

  • 將以(400,400)處為圓心,100為半徑的圓八等分,以等分點為起始點,沿著半徑延長線繪製文字”ABCDEF”.
  • 文字外圍繪製邊框. - 文字繪製起始點處繪製實心橢圓

程式碼中:

  • gdImagePolygon為無填充多邊形繪製函式,這裡繪製了一個四邊形矩形.
  • gdImageFilledEllipse (gdImagePtr im, int mx, int my, int w, int h, int c) 為繪製實心橢圓, 其中mx,my為中心座標(示例中brect[0], brect[1]即文字繪製參考起始點),w為半長軸,h為半短軸(這裡均為8,即繪製圓),c為顏色.

測試示例的繪製的最終效果如下:

文字繪製