点阵汉字的字模读取与显示
(1)原理
汉字字模通常以点阵的形式存储,每个点表示一个像素。字模文件中的二进制数据可按照特定格式解析,以获取每个汉字的点阵信息。使用C++的文件操作功能,打开字库文件,读取其中的字模数据。解析文件,提取汉字的点阵信息。 将读取的字模数据转换为可用的数据结构,例如数组或二维数组,表示每个汉字的像素布局。
汉字的区位码是按照汉字内码的顺序存储在16×16的点阵字库中,共有94区,每区94个汉字,总计94×94个汉字。区位码由四个阿拉伯数字组成,前两位为区号,后两位为位号。
机内码与区位码略有不同,为了避免与基本ASCII码冲突,对区码和位码进行处理:先加上20H,再加上80H或A0H。机内码用两个字节表示,高位字节为区码处理后的值,低位字节为位码处理后的值,范围为A1H-FEH。
点阵字库存储汉字的字模信息,每个字节的每个位表示一个汉字的点,横向矩阵字库常用的形式。对于16×16的矩阵,每个汉字需要32个字节来表示,其中每两个字节代表一行的16个点,共16行。在Ubuntu中,可以使用C/C++或Python调用OpenCV库来显示一张图片。
通过汉字的机内码高位字节和低位字节,可以获取对应的区码和位码。具体关系为:
机内码高位字节 = 区码 + 20H + 80H(或区码 + A0H)
机内码低位字节 = 位码 + 20H + 80H(或位码 + AOH)
反过来,如果已知机内码,可以根据以下关系获取区位码:
区码 = 机内码高位字节 - A0H
位码 = 机内码低位字节 - AOH
有了区位码,就可以在汉字库中找到对应的字模。具体方式是计算该汉字的偏移地址:
[ \text{偏移地址} = (\text{区码}-1) \times 94 \times \text{一个字占用的字节数} + \text{位码} \times \text{一个字占用的字节数} ]
这样,就能根据机内码在汉字库中找到相应汉字的字模数据。
在ubuntu下用C++调用OpenCV显示图片文字(这里之前另一门课已经下载过OpenCV,这里就不详细介绍了)
将需要显示的图片和需要的文件存在一个新的文件夹里
在文件夹终端里创建word.cpp文件编写代码并加入
代码如下(logo.txt文件需要改成ANSI)
#include<iostream>
#include<opencv/cv.h>
#include"opencv2/opencv.hpp"
#include<opencv/cxcore.h>
#include<opencv/highgui.h>
#include<math.h>
using namespace cv;
using namespace std;
void paint_chinese(Mat& image,int x_offset,int y_offset,unsigned long offset);
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset);
void put_text_to_image(int x_offset,int y_offset,String image_path,char* logo_path);
int main(){
String image_path="123.jpg";//图片的名字
char* logo_path="logo.txt";//汉字文件的名字
put_text_to_image(200,350,image_path,logo_path);//change txt place
return 0;
}
void paint_ascii(Mat& image,int x_offset,int y_offset,unsigned long offset){
//绘制的起点坐标
Point p;
p.x = x_offset;
p.y = y_offset;
//存放ascii字膜
char buff[16];
//打开ascii字库文件
FILE *ASCII;
if ((ASCII = fopen("Asci0816.zf", "rb")) == NULL){
printf("Can't open ascii.zf,Please check the path!");
//getch();
exit(0);
}
fseek(ASCII, offset, SEEK_SET);
fread(buff, 16, 1, ASCII);
int i, j;
Point p1 = p;
for (i = 0; i<16; i++) //十六个char
{
p.x = x_offset;
for (j = 0; j < 8; j++) //一个char八个bit
{
p1 = p;
if (buff[i] & (0x80 >> j)) /*测试当前位是否为1*/
{
/*
由于原本ascii字膜是8*16的,不够大,
所以原本的一个像素点用4个像素点替换,
替换后就有16*32个像素点
ps:感觉这样写代码多余了,但目前暂时只想到了这种方法
*/
circle(image, p1, 0, Scalar