当前位置: 首页 > 工具软件 > libgd > 使用案例 >

C语言字符串生成图片(libgd)学习3

凌波峻
2023-12-01

       最近跟着导师做项目,要求使用C语言编程,达到的目标是将字符串转为jpg格式的图片,在网上翻帖子的时候看到libgd这个库正好可以满足我的使用需求,先将其使用学习过程记录如下。

       参考内容博客地址:http://elkpi.com/topics/libgd-notes.html

        libgd官网网址:https://libgd.github.io/

        今天终于将中文字符串转图片输出图片buffer内容的模块完成了,开心一下,但是在这个过程中也暴露了许多问题,先记录如下。

        先上代码:

/*
 * 动态水印管理接口
 * 作者:beastsam
 * 日期:2018.9.18
 * 功能:根据用户名,终端机器特征码,文件标题,当前时间等信息将字符串生成图片
 * 参数:
 *     pcUserName[in]    用户名
 *     aucDevcode[in]    终端机器特征码
 *     pcTitle[in]       文件标题
 *     pcCurtime[in]     当前时间
 *     pucPic[out]       图片形式水印缓冲区
 *     uisize[out]       记录图片形式水印缓冲区大小
 * 返回值:
 *       如成功执行返回0
 *       若执行失败返回错误代码  
 * 备注:
 *       引用第三方库libgd 
 *       官网:https://libgd.github.io
 */
 
#include <stdio.h>
#include <string.h>
#include "gd.h"
#include "water_mark_manage.h"
 
int water_mark_manage(char *pcUserName, char *aucDevcode, char *pcTitle, 
							char *pcCurtime, char *pucPic, int *uisize)
{
    /* 输入参数长度检查 */
    if(strlen(pcUserName)>MAX_USERNAME || strlen(aucDevcode)>MAX_DEVCODE ||strlen(strlen)>MAX_TITLE ||strlen(pcCurtime)>MAX_TIME ){
        return ERROR_PARAM;
    }
    
    gdImagePtr pstImg = NULL;            //声明图像结构体指针,结构体具体内容见gd.h文件
    
    int black = 0;                       //声明颜色索引
    int white = 0;
    double udFontHig = 50.0;             //字体高度
    char *pcErr = NULL;                  //gdImageStringFT()函数错误内容,若函数正常执行,函数返回NULL  
    int uiFontLen = 0;                   //存储图片生成高度
    int uiFontwid = 0;                   //存储图片生成宽度
    char pcMsg[MAX_BUFFER];              //参数集和字符串
    char pcJpegName[MAX_BUFFER];         //生成图片名称
    char *pcTmp = NULL;                    //gdimg存储缓存
    //linux中文字体为文泉驿微米黑,系统路径为/usr/share/fonts/wqy-microhei.ttc
    char *pcFont = "/usr/share/fonts/wqy-zenhei/wqy-zenhei.ttc";
    
    //计算单个字体宽度,按照左上,右上,右下,左下顺序,利用(X,Y)坐标表示,因此brect共有8个值
    int brect[8];          
       
    FILE *pfJpeg = NULL;                 //声明输出文件格式  正式代码删除

    
    
    /*  拼接输入参数,将参数整合到pcMsg中 */
   strncpy(pcMsg, pcUserName, strlen(pcUserName));
   strcat(pcMsg,aucDevcode);
   strcat(pcMsg,pcTitle);
   strcat(pcMsg,pcCurtime);  
   
    /* 获取brect用以测量图片大小 */
    pcErr = gdImageStringFT(NULL, &brect[0], 0, pcFont, 
                            udFontHig, 0.0, 0, 0, pcMsg);
    if(pcErr){
    return ERROR_GET_FONT_SIZE;
    }
    
    /* 创建对字符串来讲一个足够大尺寸的图片,并且有一些留白 */
    uiFontLen = brect[2]-brect[6]+6;
    uiFontwid = brect[3]-brect[7]+6;
    
    //创建uiFontLen*uiFontwid的图像,如果需要使用真彩色,换成gdImageCreatTrueColor接口
    pstImg = gdImageCreate(uiFontLen,uiFontwid);
    
    /* 指定背景色,因为是图中首个被定义的颜色所以为背景色.颜色为红绿蓝三原色组成 */
    white = gdImageColorResolve(pstImg, 255, 255, 255);
    black = gdImageColorResolve(pstImg, 0, 0, 0);
    
    /* 设置打印字符串左下角基准点 */
    uiFontLen = 3-brect[6];
    uiFontwid = 3-brect[7];
    
    /* 将字符串打印至gd image */
    pcErr = gdImageStringFT(pstImg, &brect[0], black, pcFont, 
                            udFontHig, 0.0, uiFontLen, uiFontwid, pcMsg);
     if(pcErr){
    return ERROR_RENDER_IMAGE;
    }
    
    /* 测试用代码段,生成图片名称,正式代码可删  91-96 */
    strncpy(pcJpegName, pcMsg, strlen(pcMsg));
    strcat(pcJpegName,".jpg");   
    //打开一个文件作为写入,"wb"意思是写二进制,对MSDOS很重要,对Unix来说影响较小
    pfJpeg = fopen(pcJpegName, "wb");
    //将图片输出到硬盘存储以jpg格式,第三个参数为按照默认图片质量(0-95)
    gdImageJpeg(pstImg, pfJpeg, -1);
    
    /* 将生成的图片buffer传入参数pucPic中 */
    int uiTempSize;
    pcTmp = (char*)gdImageJpegPtr(pstImg,&uiTempSize,-1); 
    memcpy(pucPic, pcTmp, uiTempSize);
    *uisize = uiTempSize;

    fclose(pfJpeg);    
    free(pcTmp);
    gdImageDestroy(pstImg);
    
    return 0;

}

         下面来具体罗列一下我遇到的新手常见问题。

1.strlen和sizeof

         由于该函数开始需要检测一下参数长度是否超出限制,因此我需要比较参数字符串长度。在这里作为新手的我就遇到了使用sizeof编译报错的经历。

         分析:

       未初始化的情况下,用strlen是不可行的,因为strlen的唯一标准是找‘\0’,记住这个就能明确strlen会执行处什么值。

       初始化与否sizeof()的结果不不变,但是反应的并非真实字符串长度而是所占空间大小,所以memset初始化的时候用sizeof较好。

       char* 类型应特别注意,sizeof()计算出来的是指针大小,32位系统4字节,64位占8字节,与char*的字符串毫无关系,只有char[N]字符数组使用sizeof ()计算大小,结果是数组元素个数,而非指针大小,但是如果将其用于参数传递的话,子函数中获取的将不再是字符串数组类型,而是指针,这个要特别注意。

       系统函数返回值是char *类型的往往会在末尾加上'\0'。

       总归,初始化后strlen计算真实字符串大小不会出错,真实大小的判断方法是找'\0'。sizeof()结果与字符串真实大小无关,与初始化与否无关,计算的是变量所占空间。

2.隐式声明与内建函数

         编译过程中我就遇到了这种类型的报错,原因为忘记include相关头文件了。

3.strncpy

         错误:char *a;  char *b = "hello"; strncpy(a,b,strlen(b));

         正确:char a[x]; char *b = "hello"; strncpy(a,b,strlen(b));

         再说明一下strncpy要比strcpy用着安全一点,因为strcpy只是复制字符串,但不限制复制的数量,很容易造成缓冲溢出。strncpy要安全一些。

4.引用方式调用函数

         在这里我一直由于没有搞懂char*作为参数的真正含义,所以无法将函数内的数值传递到main函数中。之后百度了一下c语言函数,看到了引用方式调用函数,瞬间豁然开朗。我之前的调用方式一直是对形参的操作,形参的数值并未传递到实参。
    

 

 

 

 类似资料: