4.數位相框-freetype多行顯示,居中顯示

来源:https://www.cnblogs.com/lifexy/archive/2018/03/06/8514154.html
-Advertisement-
Play Games

本章主要內容如下: 1)多行顯示 2)居中顯示 在上章3.數位相框-通過freetype庫實現矢量顯示里,我們使用矢量坐標時,該坐標僅僅在原點位置處,所以文字有可能會超出坐標,如下圖所示: 既然超出了坐標,會不會被下一行的文字覆蓋掉? 答:對於幾行同樣大的文字而言,不會的. 以 24*24的韋字為例 ...


本章主要內容如下:

  • 1)多行顯示
  • 2)居中顯示

 

在上章3.數位相框-通過freetype庫實現矢量顯示里,我們使用矢量坐標時,該坐標僅僅在原點位置處,所以文字有可能會超出坐標,如下圖所示:

 

既然超出了坐標,會不會被下一行的文字覆蓋掉?

答:對於幾行同樣大的文字而言,不會的.

以 24*24的韋字為例,讓它顯示在(0,40)處,所以文字的y範圍在17~40,如下圖所示,發現該文字超過了原點,而上方數據又會空出來一段,就不會覆蓋到上一行數據.

 

 對於幾行規格大小不同的文字,則有可能會被覆蓋.以20*20的韋字為例,如下圖,可以發現空出的數據比24*24的少1行,若上一行的規格很大時(超出原點很大一部分), 那麼這個20*20的韋字,就會覆蓋掉上一行文字底部的數據.

 

 

1.從左顯示多行24*24文字

內容如下:

定義一個兩個標誌變數line_box_ymaxline_box_ymin.

通過FT_Glyph_Get_CBox()測量字形圖像,獲取一行文字的yMax,Min最大值,最小值.

顯示第一行時:

pen.x = 0* 64;
pen.y = ( fb_var.yres-24 ) * 64;   // fb_var.yres:LCD總高度,   原點為(0,24)

顯示第2~n行時:

pen.x = 0* 64;
pen.y-= (line_box_ymax - line_box_ymin )* 64;   //在上行的pen.y基礎上,減去上行的邊框高

  

代碼如下:

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/ioctl.h>
#include <string.h>
#include <linux/fb.h>
#include <math.h>
#include<wchar.h>
#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H

unsigned char *fbmem;
unsigned char *hzkmem;

struct fb_var_screeninfo fb_var;
struct fb_fix_screeninfo  fb_fix;

unsigned int screensize;
#define FONTDATAMAX 4096

/*rgb565*/
void pixel_show(int x,int y, unsigned int color)
{
       unsigned int red,green,blue;
       switch(fb_var.bits_per_pixel)        //rgb   像素
       {
            case 32:
            {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;   
                 break;
            }
            case 24:
           {
                unsigned int  *addr=(unsigned int  *)fbmem+(fb_var.xres*y+x);
                *addr=color;
                 break;
           }
           case 16:            //將RGB888 轉為RGB565
           {
                unsigned short  *addr=(unsigned short  *)fbmem+(fb_var.xres*y+x);
                red   = (color >> 16) & 0xff;
                green = (color >> 8) & 0xff;
                blue  = (color >> 0) & 0xff;
                color = ((red >> 3) << 11) | ((green >> 2) << 5) | (blue >> 3);
                *addr = color;
                break;
           }
           case 8:
          {
               unsigned char  *addr=(unsigned char  *)fbmem+(fb_var.xres*y+x);     
               *addr = (unsigned char)color;
               break;
          }
          default:
         {
            printf("can't  surport %dbpp \n",fb_var.bits_per_pixel);
            break;
         }
       }
}

void draw_bitmap( FT_Bitmap*  bitmap,
             FT_Int      x,
             FT_Int      y)
{
  FT_Int  i, j, p, q;  
  FT_Int  x_max = x + bitmap->width;        //x:當前X位置, bitmap->width:該字寬度
  FT_Int  y_max = y + bitmap->rows;

  for ( i = x, p = 0; i < x_max; i++, p++ )   //i:lcd的x軸
  {
    for ( j = y, q = 0; j < y_max; j++, q++ )  //j:lcd的y軸
    {
      if ( i < 0      || j < 0       ||
           i >= fb_var.xres || j >= fb_var.yres )
        continue;
pixel_show( i, j, bitmap
->buffer[q * bitmap->width + p]); } } } unsigned int line_box_ymax=0; unsigned int line_box_ymin=30000; void lcd_vector_show(char *argv,wchar_t *str[],unsigned int lines) { FT_Glyph glyph; FT_BBox acbox; FT_Library library; FT_Face face; FT_GlyphSlot slot; FT_Vector pen; /* untransformed origin */ unsigned char error; unsigned int line_nums=0; unsigned char n,font_size;
error
= FT_Init_FreeType( &library ); /* initialize library */ if(error) { printf("FT_Init_FreeType ERROR\n"); return ; } error = FT_New_Face( library, argv, 0, &face ); /* create face object */ if(error) { printf("FT_New_Face ERROR\n"); return ; } slot = face->glyph; error = FT_Set_Pixel_Sizes( face, 0,24); /* set character size */ for(line_nums=0;line_nums<lines;line_nums++) { /*設置筆記落下位置*/ /*顯示坐標(從LCD左上方顯示3 行) *x=0 *y=fb_var.yres-24 (減24,是因為笛卡爾坐標以左下方開始計算坐標值的) */ if(line_nums==0) { pen.x = 0* 64; pen.y = ( fb_var.yres-24 ) * 64; } else { pen.x = 0* 64; pen.y-= (line_box_ymax - line_box_ymin )* 64; //在上行的Y值上減去邊框高 /*清空標誌位,因為上一行的ymin永遠當前行小*/ line_box_ymax=0; line_box_ymin=30000; } for ( n = 0; n < wcslen(str[line_nums]); n++ ) { FT_Set_Transform( face, 0, &pen ); error = FT_Load_Char( face,str[line_nums][n], FT_LOAD_RENDER ); if ( error ) { printf("FT_Load_Char ERROR\n"); continue; } FT_Get_Glyph( face->glyph, &glyph ); //獲取字形圖像 的信息 FT_Glyph_Get_CBox( glyph,FT_GLYPH_BBOX_TRUNCATE,&acbox ); //獲取此行文字的box if(acbox.yMax>acbox.yMin) { if(line_box_ymax<acbox.yMax) line_box_ymax=acbox.yMax; if(line_box_ymin>acbox.yMin) line_box_ymin=acbox.yMin; } draw_bitmap( &slot->bitmap, slot->bitmap_left, fb_var.yres- slot->bitmap_top ); pen.x += slot->advance.x; } } FT_Done_Face( face ); FT_Done_FreeType( library ); } int main(int argc,char **argv) { int fd_fb,fd_hzk; struct stat hzk_start; //HZK16文件信息 wchar_t *chinese_str[]={L"韋東山gh",L"abc 中國chinese",L"哈哈哈哈wqe"}; if ( argc != 2 ) { printf ("usage: %s font_file \n", argv[0] ); return 0; } fd_fb=open("/dev/fb0", O_RDWR); if(fd_fb<0) { printf("can't open /dev/fb0 \n"); return 0; } if(ioctl(fd_fb,FBIOGET_VSCREENINFO,&fb_var)<0) { printf("can't get var \n"); return 0; } if(ioctl(fd_fb,FBIOGET_FSCREENINFO,&fb_fix)<0) { printf("can't get fix \n"); return 0; } screensize=fb_var.xres*fb_var.yres*(fb_var.bits_per_pixel/8); //顯存大小 fbmem =(unsigned char *)mmap(NULL,screensize, PROT_READ|PROT_WRITE,MAP_SHARED, fd_fb, 0); //映射fb0 if(!fbmem) { printf("can't map /dev/fb0 \n"); return 0; } memset(fbmem, 0, screensize); //清屏黑色 /*顯示3 行 矢量文字*/ lcd_vector_show(argv[1], chinese_str,3); munmap(fbmem,screensize); return 0; }

 

2.居中顯示

參考第11頁:https://wenku.baidu.com/view/060a0b44f12d2af90342e63a.html?from=search

1)首先定義一個用來存儲一行文字的字形圖像數

#define MAX_GLYPHS  100       //最多存儲一行100個字

TGlyph glyphs[MAX_GLYPHS]; /* glyphs table */

2)首先以坐標(0,0)為基值,獲取每個文字的字形圖像和坐標值,存到glyphs[]里

/*初始化庫,獲取face,設置字體*/
error = FT_Init_FreeType( &library );              /* initialize library */
if(error)
{ //... ...}
error = FT_New_Face( library, argv[1], 0, &face ); /* create face object */
if(error)
{//... ...}
FT_Set_Pixel_Sizes(face, 24, 0);

... ...
int num_glyphs = 0; PGlyph glyph = glyphs; // Pglyph在庫里被定義為Tglyph *, glyph指向glyphs int pen_x = 0; int pen_y = 0; for (n = 0; n < wcslen(wstr); n++) // wstr: wchar_t類型的文字數組 { glyph->index = FT_Get_Char_Index( face, wstr[n]); //存儲每個文字的索引值 glyph->pos.x = pen_x; //記錄每個文字的坐標值,後面會用來設置字形圖像的位置信息 glyph->pos.y = pen_y; error=FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT); //通過索引值,找到face(字體文件)里的字形圖像,並放到face->glyph字元槽里. if ( error ) continue; FT_Get_Glyph(face->glyph, &glyph->image );//然後存儲每個文字的字形圖像 if ( error ) continue; FT_Glyph_Transform(glyph->image, 0, &glyph->pos ); //使用FT_Glyph_Transform(),使glyph->image包含位置信息 pen_x += face->glyph->advance.x; // 以1/64像素點為單位 glyph++; } num_glyphs= glyph- glyphs; //獲取轉換成功的文字個數

3)通過glyphs[]存的一行字形圖像,計算出邊界框

FT_BBox bbox;

bbox.xMin = bbox.yMin = 32000;
bbox.xMax = bbox.yMax = -32000;

       /*判斷一行文字的邊界框範圍*/
       for ( n = 0; n < num_glyphs; n++ )
       {
              FT_BBox glyph_bbox;
              FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox );
                             // FT_GLYPH_BBOX_TRUNCATE:獲取的坐標信息以像素坐標為單位

              if (glyph_bbox.xMin < bbox.xMin)
                     bbox.xMin = glyph_bbox.xMin;

              if (glyph_bbox.yMin < bbox.yMin)
                     bbox.yMin = glyph_bbox.yMin;

              if (glyph_bbox.xMax > bbox.xMax)
                     bbox.xMax = glyph_bbox.xMax;

              if (glyph_bbox.yMax > bbox.yMax)
                     bbox.yMax = glyph_bbox.yMax;
       }

4)通過邊界框,找到居中顯示的坐標信息

       int line_box_width;
       int line_box_height;

       line_box_width  = bbox.xMax - bbox.xMin;              //一行文字的寬度
       line_box_height = bbox.yMax - bbox.yMin;              //一行文字的高度

       pen.x = (var.xres - line_box_width)/2 * 64;          // var.xres:LCD總寬度
       pen.y = (var.yres - line_box_height)/2 * 64;  

5)通過坐標信息,將glyphs[]存的一行字形圖像顯示出來

for (n = 0; n < num_glyphs; n++)
{                                                                   
     //再次使用FT_Glyph_Transform(),更新glyphs[n].image里的坐標值
       FT_Glyph_Transform(glyphs[n].image, 0, &pen);

  error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0,1);
                    //轉化為點陣圖,1:轉換後並摧毀glyphs[n].image的內容
  if( !error )
  { 
   FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image;  
   draw_bitmap(&glyphs[n].image->bitmap, bit->left, var.yres - bit->top); //列印點陣圖
   FT_Done_Glyph(glyphs[n].image );       //註銷一個Glyph
  }
}

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 很久沒弄.net的東西,鑒於自己的網站考慮跨平臺,準備利用空閑時間把框架移植成asp.net core,本來.net的東西一般只用3版本以上的,人老了,時間不多了,只好先入坑; 第一件事就是開發環境搭建,按照文檔安裝sdk後,發現iis里的網站直接指向本地源碼不行了,調試要麼f5(從來不喜歡這種方式 ...
  • 用戶登錄與許可權驗證是網站不可缺少的一部分功能,asp.net MVC4框架內置了用於實現該功能的類庫,只需要簡單搭建即可完成該功能. 下麵詳細介紹該功能的完成方法,尾部有實例源碼下載,希望可以給剛開始接觸MVC的朋友做個參考. 第一步:給VS安裝MVC4框架 VS2012自帶MVC4框架,其他版本可 ...
  • 最終效果: ...
  • 在網頁編程時,我們經常需要處理,當session過期時,我們要跳到登陸頁面讓用戶登陸,由於我們可能用到IFrame框架,所以我們我登陸頁面需要顯示在整個頁面,而不是一個IFrame中,大部分的網友是用下麵的代碼進行實現的。 在過濾器中寫如下代碼: 我的實現方式是:跟普通過濾器的寫法一樣,跳到某個ac ...
  • 1.# 表示許可權用戶(如:root),$ 表示普通用戶開機提示:Login:輸入用戶名password:輸入口令 用戶是系統註冊用戶成功登陸後,可以進入相應的用戶環境.退出當前shell,輸入:exit2.useradd netseek 添加一個netseek用戶passwd netseek 給ne ...
  • 一.在Oracle中創建資料庫之前先改一下虛擬機的IP地址,以便訪問 2. 3. 3.1 3.2 3.3 3.4 創建完成:輸入sqlplus sys/123456 as sysdba測試 ...
  • yum解釋:yum是一個Shell前端軟體包管理器,基於RPM包管理。能夠從指定的伺服器自動下載rpm包並且安裝,可以自動處理依賴性關係,並且一次安裝 所有依賴的軟體包,無須繁瑣地一次次下載/安裝,yum提供了查找、安裝、刪除某一個、一組甚至全部軟體包的命令。 ...
  • jdk [root@localhost] tar zxvf jdk 8u144 linux x64.tar.gz [root@localhost] vi /etc/profile 在profile文件中添加下述內容 [root@localhost] source /etc/profile [root ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...