第三阶段应用层——1.6 数码相册—使用FreeType在LCD上显示多行文字
数码相册——使用FreeType在LCD上显示多行文字
- 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3)
- 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.04_x64 系统
- 参考资料:《嵌入式Linux应用开发手册》、《嵌入式Linux应用开发手册第2版》、【FreeType官方教程—管理字形】、
- 开发环境:Linux 3.4.2内核、arm-linux-gcc 4.3.2工具链
- 源码仓库:https://gitee.com/d_1254436976/Embedded-Linux-Phase-3
目录
- 数码相册——使用FreeType在LCD上显示多行文字
- 一、FreeType的字形指标
- 1、为什么要引用字形指标
- 2、什么是字形指标
- 二、在LCD中从左到右显示多行文字
- 1、先确定该行origin坐标并进行显示,后计算出边框
- 2、代码
- 3、编译与运行
- 三、在LCD中居中显示多行文字
- 1、先计算出该行字体的边框,确定其origin坐标后描绘
- 2、代码
- 3、编译与运行
一、FreeType的字形指标
1、为什么要引用字形指标
- 为了准确的描述每个字形的信息,呈现更好的显示效果。
- 为了更好的兼容各国的文字,呈现更好的显示效果。
2.1 对于汉字,它是方框字,类似于小时候我们在田字格上汉字,给定一个矩形范围,我们可以在这个范围内写出很工整的汉字。
2.2 对于英文,它的字形大小没有固定的大小范围,类似于小时候我们是在四线格中写英文,对于其的高矮宽细无法用一个很好的矩形去总的描绘。
2.3 对于其他国家的文字也存在上述的问题。
2、什么是字形指标
字形指标是与每个字形关联的特定距离,以描述如何使用它来布局文本。
对于单个字形,通常有两组度量:用于在水平文本布局(拉丁,西里尔字母,阿拉伯语,希伯来语等)中设置字形的度量,以及用于在垂直文本布局中对字形进行布局的度量(中文,日语) ,韩文等)。
这里针对水平布局来进行介绍:
- origin自己定义:
FT_Vector pen;pen.x = 10;pen.y = 10;
- height、width获取:
width = bbox.xMax - bbox.xMin;
height = bbox.yMax - bbox.yMin; - advance获取:
FT_Library library;FT_Face face;FT_GlyphSlot slot;FT_Vector pen;error = FT_Init_FreeType( &library ); error = FT_New_Face( library, argv[1], 0, &face ); FT_Set_Pixel_Sizes(face, 24, 0);slot = face->glyph;pen.x += slot->advance.x;pen.y += slot->advance.y;
- xMin、yMin、xMin、yMin存储:
typedef struct FT_BBox_{FT_Pos xMin, yMin;FT_Pos xMin, yMin;; } FT_BBox;
二、在LCD中从左到右显示多行文字
1、先确定该行origin坐标并进行显示,后计算出边框
FreeType所使用的坐标是笛卡尔坐标,与LCD使用的坐标不一样:
在这里,我们需要显示两行文字,具体步骤如下:
- 确定第一行origin的LCD坐标,后根据公式转换为笛卡尔坐标
- 显示该行每个字符的时候origin.x坐标 + 上一个字符的advance;
- 在显示第一行的时候,找寻该行最大的字符的height,即最小的yMin,最大的yMax
- 确定第二行的origin的LCD坐标(其x坐标 == 第一行的origin.lcd_x,其y坐标 == 3步骤中得到的height+ origin.lcd_y == (yMax - yMin)+ origin.lcd_y))
2、代码
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H/* 文件操作 */
static int fd_fb;
static unsigned char *fbmem;/* lcd参数 */
static int screen_size;
static unsigned int line_width;
static unsigned int pixel_width;
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;/* lcd描色 color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{ unsigned char *pen_8;unsigned short *pen_16;unsigned int *pen_32;unsigned int red, green, blue;/* 该坐标在内存中对应像素的位置 */pen_8 = fbmem+y*line_width+x*pixel_width;pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (var.bits_per_pixel) {case 8:*pen_8 = color;break;case 16:/* RGB:565 */red = ((color >> 16) & 0xffff) >> 3;green = ((color >> 8) & 0xffff) >> 2;blue = ((color >> 0) & 0xffff) >> 3;*pen_16 = (red << 11) | (green << 5) | blue;break;case 32:*pen_32 = color;break;default:printf("can not surport &dbpp\n", 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;FT_Int y_max = y + bitmap->rows;//printf("x = %d, y = %d\n", x, y);for (i = x, p = 0; i < x_max; i++, p++) {for (j = y, q = 0; j < y_max; j++, q++) {if (i < 0 || j < 0|| i >= var.xres || j >= var.yres)continue;//image[j][i] |= bitmap->buffer[q * bitmap->width + p];lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);}}
}int main(int argc, char **argv)
{ wchar_t *wstr1 = L"百问网gif";wchar_t *wstr2 = L"www.100ask.com";FT_Library library;FT_Face face;FT_Vector pen;FT_GlyphSlot slot;FT_Matrix matrix;FT_BBox bbox;FT_Glyph glyph;double angle;int error;int line_box_ymin;int line_box_ymax;int i;line_box_ymin = 10000;line_box_ymax = 0;/* 提示信息 */if (argc != 3) {printf("Usage : %s <font_file> <angle>\n", argv[0]);return -1;}/* 打开设备:支持读写 */fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0) {printf("can not open /dev/fb0 , err code :%d\n", fd_fb);return -1;}/* 获得可变信息 */if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) {printf("can not get var\n");return -1;}/* 获得固定信息 */if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) {printf("can not get var\n");return -1;}/* 直接映射到内存的Framebuffer */screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // 屏幕总像素所占的字节数line_width = var.xres * var.bits_per_pixel / 8; // 每行像素所占的字节数pixel_width = var.bits_per_pixel / 8; // 每个像素所占字节数fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fbmem == (unsigned char *)-1) {printf("can not mmap\n");return -1;}/* 清屏 */memset(fbmem, 0, screen_size);/* 显示矢量字 *//* 初始化库 */error = FT_Init_FreeType(&library);/* 装载字体文件 */error = FT_New_Face(library, argv[1], 0, &face);slot = face->glyph;/* 设置大小:24*24 */FT_Set_Pixel_Sizes(face, 24, 0);/* 设置旋转角度 */angle = (1.0 * strtoul(argv[2], NULL, 0) / 360) * 3.14159 * 2; /* use 25 degrees *//* 设置矩阵 */matrix.xx = (FT_Fixed)( cos( angle ) * 0x10000L);matrix.xy = (FT_Fixed)(-sin( angle ) * 0x10000L);matrix.yx = (FT_Fixed)( sin( angle ) * 0x10000L);matrix.yy = (FT_Fixed)( cos( angle ) * 0x10000L);/* 确定座标:* lcd_x = 0* lcd_y = 24* 笛卡尔座标系:* x = lcd_x = 0* y = var.yres - lcd_y = var.yres - 24*/pen.x = 0 * 64;pen.y = (var.yres - 24) * 64;/* 显示第一行文字 */for (i = 0; i < wcslen(wstr1); i++) {/* 设置转换方法 */FT_Set_Transform(face, &matrix, &pen);/* 根据给定的文字信息,加载文字 */error = FT_Load_Char(face, wstr1[i], FT_LOAD_RENDER);if (error) {printf("FT_Load_Char error\n");return -1;}/* 从插槽中取出face->glyph,存到glyph中 */error = FT_Get_Glyph(face->glyph, &glyph); if (error) {printf("FT_Get_Glyph error!\n");return -1;}/* 得到相关字体参数信息 */FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);/* 寻该行最大的字符的height,即最小的yMin,最大的yMax */if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax;if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin;/* 描绘位图信息 */draw_bitmap(&slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top);/* 打印位图信息 */printf("Unicode: 0x%x\n", wstr1[i]);printf("origin.x/64 = %d, origin.y/64 = %d\n", pen.x/64, pen.y/64);printf("xMin = %d, xMax = %d, yMin = %d, yMax = %d\n", bbox.xMin, bbox.xMax, bbox.yMin, bbox.yMax);printf("slot->advance.x/64 = %d, slot->advance.y/64 = %d\n", slot->advance.x/64, slot->advance.y/64);/* 移动笔的位置:同一水平方向 */pen.x += slot->advance.x;}/* 确定座标:* lcd_x = 0* lcd_y = line_box_ymax - line_box_ymin + 24* 笛卡尔座标系:* x = lcd_x = 0* y = var.yres - lcd_y = var.yres - (line_box_ymax - line_box_ymin + 24)*/pen.x = 0 * 64;pen.y = (var.yres - (line_box_ymax - line_box_ymin + 24)) * 64;/* 显示第二行文字 */for (i = 0; i < wcslen(wstr2); i++) { /* 设置转换方法 */FT_Set_Transform(face, &matrix, &pen);/* 根据给定的文字信息,加载文字 */error = FT_Load_Char(face, wstr2[i], FT_LOAD_RENDER);if (error) {printf("FT_Load_Char error\n");return -1;}/* 从插槽中取出face->glyph,存到glyph中 */error = FT_Get_Glyph(face->glyph, &glyph); if (error) {printf("FT_Get_Glyph error!\n");return -1;}/* 得到相关字体参数信息 */FT_Glyph_Get_CBox(glyph, FT_GLYPH_BBOX_TRUNCATE, &bbox);/* 寻该行最大的字符的height,即最小的yMin,最大的yMax */if (line_box_ymax < bbox.yMax) line_box_ymax = bbox.yMax;if (line_box_ymin > bbox.yMin) line_box_ymin = bbox.yMin;/* 描绘位图信息 */draw_bitmap(&slot->bitmap, slot->bitmap_left, var.yres - slot->bitmap_top);/* 打印位图信息 */printf("Unicode: 0x%x\n", wstr1[i]);printf("origin.x/64 = %d, origin.y/64 = %d\n", pen.x/64, pen.y/64);printf("xMin = %d, xMax = %d, yMin = %d, yMax = %d\n", bbox.xMin, bbox.xMax, bbox.yMin, bbox.yMax);printf("slot->advance.x/64 = %d, slot->advance.y/64 = %d\n", slot->advance.x/64, slot->advance.y/64);/* 移动笔的位置:同一水平方向 */pen.x += slot->advance.x;}return 0;
}
3、编译与运行
- 执行
arm-linux-gcc -finput-charset=GBK -o show_line_left show_line_left.c -lfreetype -lm
- 把
show_line_left
可执行文件传到开发板,执行./show_line_left ./simsun.ttc
运行
三、在LCD中居中显示多行文字
1、先计算出该行字体的边框,确定其origin坐标后描绘
在这里,我们需要显示两行文字,具体步骤如下:
- 执行函数
Get_Glyphs_Form_Wstr()
:根据字符串得到每个字符的glyph,并把glyph存储到Glyphs数组中 - 执行函数
compute_string_bbox()
:根据上述得到的Glyphs数组,计算得到该字符串的边框 - 确定第一行字符串的origin坐标,注意此时是笛卡尔坐标。
- 进行描绘
- 描绘第二行的时候重复上述步骤。
2、代码
根据官方文档资料 【5.高级文本渲染:转换,居中和紧缩】进行编写
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <linux/fb.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <wchar.h>#include <ft2build.h>
#include FT_FREETYPE_H
#include FT_GLYPH_H/* FreeType */
#define MAX_GLYPHS 100typedef struct TGlyph_
{FT_UInt index; /* glyph index */FT_Vector pos; /* glyph origin on the baseline */FT_Glyph image; /* glyph image */
} TGlyph, *PGlyph;/* 文件操作 */
static int fd_fb;
static unsigned char *fbmem;/* lcd参数 */
static int screen_size;
static unsigned int line_width;
static unsigned int pixel_width;
static struct fb_var_screeninfo var;
static struct fb_fix_screeninfo fix;/* lcd描色 color : 0x00RRGGBB */
void lcd_put_pixel(int x, int y, unsigned int color)
{ unsigned char *pen_8;unsigned short *pen_16;unsigned int *pen_32;unsigned int red, green, blue;/* 该坐标在内存中对应像素的位置 */pen_8 = fbmem+y*line_width+x*pixel_width;pen_16 = (unsigned short *)pen_8;pen_32 = (unsigned int *)pen_8;switch (var.bits_per_pixel) {case 8:*pen_8 = color;break;case 16:/* RGB:565 */red = ((color >> 16) & 0xffff) >> 3;green = ((color >> 8) & 0xffff) >> 2;blue = ((color >> 0) & 0xffff) >> 3;*pen_16 = (red << 11) | (green << 5) | blue;break;case 32:*pen_32 = color;break;default:printf("can not surport &dbpp\n", 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;FT_Int y_max = y + bitmap->rows;for (i = x, p = 0; i < x_max; i++, p++) {for (j = y, q = 0; j < y_max; j++, q++) {if (i < 0 || j < 0|| i >= var.xres || j >= var.yres)continue;lcd_put_pixel(i, j, bitmap->buffer[q * bitmap->width + p]);}}
}/* 根据字符串得到Glyph,并把Glyph存储到Glyphs数组中 */
int Get_Glyphs_Form_Wstr(FT_Face face, wchar_t *wstr, TGlyph glyphs[])
{int n;int error;int pen_x;int pen_y;PGlyph glyph;FT_GlyphSlot slot;glyph = glyphs;slot = face->glyph;pen_x = 0;pen_y = 0;for (n = 0; n < wcslen(wstr); n++) {/* 根据该字符的Unicode码,获得在face中该字符的索引 */glyph->index = FT_Get_Char_Index(face, wstr[n]);/* 记录描绘坐标 */glyph->pos.x = pen_x;glyph->pos.y = pen_y;/* 从face中根据glyph->index把glyph加载到插槽face->glyph中,不需要转换为位图 */error = FT_Load_Glyph(face, glyph->index, FT_LOAD_DEFAULT);if (error) continue;/* 从插槽face->glyph中把信息加载到glyph->image中 */error = FT_Get_Glyph(face->glyph, &glyph->image);if (error) continue;/* 设置变换方式:使得glyph->image中含有位置信息 */FT_Glyph_Transform(glyph->image, 0, &glyph->pos);/* 下一个字符的原点x坐标 */pen_x += slot->advance.x;glyph++;}/* 返回glyph的个数 */return (glyph - glyphs);
}/* 计算Glyphs数组中的字符串的边框 */
void compute_string_bbox(TGlyph glyphs[], FT_UInt num_glyphs, FT_BBox *abbox)
{FT_BBox bbox;int n;bbox.xMin = bbox.yMin = 32000;bbox.xMax = bbox.yMax = -32000;for (n = 0; n < num_glyphs; n++) {FT_BBox glyph_bbox;/* 以像素为单位从glyphs[n]的数组项取值,得到该字符的边框box */FT_Glyph_Get_CBox(glyphs[n].image, FT_GLYPH_BBOX_TRUNCATE, &glyph_bbox);/* 寻该行最大的字符的height和width,即最小的yMin和xMin,最大的yMax和xMax */if (bbox.xMin > glyph_bbox.xMin) bbox.xMin = glyph_bbox.xMin;if (bbox.xMax < glyph_bbox.xMax) bbox.xMax = glyph_bbox.xMax;if (bbox.yMin > glyph_bbox.yMin) bbox.yMin = glyph_bbox.yMin;if (bbox.yMax < glyph_bbox.yMax) bbox.yMax = glyph_bbox.yMax;}*abbox = bbox;
}/* 描绘Glyphs中的信息——渲染 */
void Draw_Glyphs(TGlyph glyphs[], FT_UInt num_glyphs, FT_Vector pen)
{int n;int error;for (n = 0; n < num_glyphs; n++) {/* 设置变换方式:使得glyph->image中含有位置信息 */FT_Glyph_Transform(glyphs[n].image, 0, &pen);/* 把gylph转换为位图 */error = FT_Glyph_To_Bitmap(&glyphs[n].image, FT_RENDER_MODE_NORMAL, 0, 1); /* destroy copy in "image" */if (!error) {/* 获得位图 */FT_BitmapGlyph bit = (FT_BitmapGlyph)glyphs[n].image;/* 描绘位图 */draw_bitmap(&bit->bitmap, bit->left, var.yres - bit->top);/* 释放空间 */FT_Done_Glyph(glyphs[n].image);}}
}int main(int argc, char **argv)
{ wchar_t *wstr1 = L"百问网gif";wchar_t *wstr2 = L"www.100ask.com";FT_Library library;FT_Face face;FT_Vector pen;FT_GlyphSlot slot;FT_Matrix matrix;FT_BBox bbox;FT_UInt num_glyphs;TGlyph glyphs[MAX_GLYPHS]; //负责存储字符信息的数组PGlyph glyph;double angle;int error;int line_box_ymin;int line_box_ymax;int line_box_height;int line_box_width;int i;int num;line_box_ymin = 10000;line_box_ymax = 0;/* 打开设备:支持读写 */fd_fb = open("/dev/fb0", O_RDWR);if (fd_fb < 0) {printf("can not open /dev/fb0 , err code :%d\n", fd_fb);return -1;}/* 获得可变信息 */if (ioctl(fd_fb, FBIOGET_VSCREENINFO, &var)) {printf("can not get var\n");return -1;}/* 获得固定信息 */if (ioctl(fd_fb, FBIOGET_FSCREENINFO, &fix)) {printf("can not get var\n");return -1;}/* 直接映射到内存的Framebuffer */screen_size = var.xres * var.yres * var.bits_per_pixel / 8; // 屏幕总像素所占的字节数line_width = var.xres * var.bits_per_pixel / 8; // 每行像素所占的字节数pixel_width = var.bits_per_pixel / 8; // 每个像素所占字节数fbmem = (unsigned char *)mmap(NULL, screen_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd_fb, 0);if (fbmem == (unsigned char *)-1) {printf("can not mmap\n");return -1;}/* 清屏 */memset(fbmem, 0, screen_size);/* 显示矢量字 *//* 初始化库 */error = FT_Init_FreeType(&library);/* 装载字体文件 */error = FT_New_Face(library, argv[1], 0, &face);slot = face->glyph;/* 设置像素大小:24*24 */FT_Set_Pixel_Sizes(face, 24, 0);/* 显示第一个字符串 *//* 根据字符串得到字符的glyph,并把glyph存储到Glyphs数组中 */num_glyphs = Get_Glyphs_Form_Wstr(face, wstr1, glyphs); /* 计算Glyphs数组中的字符串的边框 */compute_string_bbox(glyphs, num_glyphs, &bbox);/* 计算一行中最高的高度和最宽的宽度 */line_box_height = bbox.yMax - bbox.yMin;line_box_width = bbox.xMax - bbox.xMin;/* 确定原点坐标 */pen.x = (var.xres - line_box_width)/2 * 64;pen.y = (var.yres - line_box_height)/2 * 64;/* 描绘Glyphs中的信息 */Draw_Glyphs(glyphs, num_glyphs, pen);/* 显示第二个字符串 *//* 根据字符串得到Glyph,并把Glyph存储到Glyphs数组中 */num_glyphs = Get_Glyphs_Form_Wstr(face, wstr2, glyphs); /* 计算Glyphs数组中的字符串的边框 */compute_string_bbox(glyphs, num_glyphs, &bbox);/* 计算一行中最高的高度和最宽的宽度 */line_box_height = bbox.yMax - bbox.yMin;line_box_width = bbox.xMax - bbox.xMin;/* 确定原点坐标 */pen.x = (var.xres - line_box_width)/2 * 64;pen.y = pen.y - 24 * 64;/* 描绘Glyphs中的信息 */Draw_Glyphs(glyphs, num_glyphs, pen);return 0;
}
3、编译与运行
- 执行
arm-linux-gcc -finput-charset=GBK -o show_line_center show_line_center.c -lfreetype -lm
- 把
show_line_center
可执行文件传到开发板,执行./show_line_center ./simsun.ttc
运行
第三阶段应用层——1.6 数码相册—使用FreeType在LCD上显示多行文字相关推荐
- 第三阶段应用层——2.6 视频监控—CMOS摄像头的硬件原理
视频监控-CMOS摄像头的硬件原理 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下UbuntuLTS16.0 ...
- 第三阶段应用层——2.7 视频监控—从零写CMOS摄像头驱动
视频监控-从零写CMOS摄像头驱动 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3),OV7740摄像头 软件平台:运行于VMware Workstation 12 Player下Ubu ...
- 第三阶段应用层——2.4 视频监控—从0写USB摄像头驱动(1)-描述符的分析与打印
视频监控-从0写USB摄像头驱动(1)-描述符的分析与打印 硬件平台:韦东山嵌入式Linxu开发板(S3C2440.v3) 软件平台:运行于VMware Workstation 12 Player下U ...
- java 高并发第三阶段实战_JAVA多线程编程实战视频-第三阶段(共80节)
高并发编程第三阶段01讲 AtomicInteger多线程下测试讲解 高并发编程第三阶段02讲 AtomicInteger API详解,以及CAS算法详细介绍 高并发编程第三阶段03讲 利用CAS构造 ...
- java 高并发第三阶段实战_Java 高并发第三阶段实战---Java并发包深入解析与使用详解...
第三阶段的课程主要围绕着Java并发包的使用,展开详细的介绍,主要内容有1.原子包源码剖析,2.并发包工具类详细介绍,3.线程服务以及Future和callable等详细介绍,4.高并发容器和阻塞容器 ...
- Java 高并发第三阶段实战---Java并发包深入解析与使用详解
第三阶段的课程主要围绕着Java并发包的使用,展开详细的介绍,主要内容有1.原子包源码剖析,2.并发包工具类详细介绍,3.线程服务以及Future和callable等详细介绍,4.高并发容器和阻塞容器 ...
- Linux运维 第三阶段 (一) 网络配置及openssl加密
Linux运维 第三阶段 (一) 网络配置及openssl加密 主机接入网络:IP,netmask,gateway,hostname,DNS1,DNS2,DNS3,route,dhcp(dynamic ...
- 中国石油大学(北京)-《计算机网络应用基础》第三阶段在线作业
第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) 以下关于VPN说法正确的是 A.VPN指的是用户自己租用线路,和公共网络物理上完全隔离的.安全的线路 B.VPN指的是用户通过公用网络 ...
- 中国石油大学《计算机应用基础#》第三阶段在线作业
第三阶段在线作业 单选题 (共20道题) 收起 1.(2.5分) PowerPoint演示文稿的作者必须非常注意幻灯片集的两个要素是(). A.内容和设计 B.内容和模板 C.内容和视觉效果 D.问题 ...
- 自学it18大数据笔记-第三阶段Spark-day04——会持续更新……
笔记为自学时随手记录,如有错误,欢迎指正,不胜感激!现已广州转移至上海,欢迎小伙伴们加qq或微博沟通交流(QQ,微博和博客同名) 笔记分享:自学it18大数据笔记-第三阶段Spark-day04--会 ...
最新文章
- R语言散点图可视化:自定义标题和标签、拟合回归线、lowess为散点图添加平滑拟合线、修改散点图中点颜色和点符号、分组散点图、添加图例、pairs可视化散点图矩阵、ggplt2可视化、lattice
- 综合布线系统设计遵循的标准和条件
- 将多个csv文件导入到pandas中并串联到一个DataFrame中
- MySQL高级 - SQL技巧 -日期函数与聚合函数
- [SpringBoot2]web场景_静态资源规则与定制化
- oracle aq_通过Java 8流使用Oracle AQ
- excel导入到mysql
- 魅族16s Pro跑分曝光:高通骁龙855 Plus+UFS 3.0闪存
- UniLayer集成Chainlink预言机喂价
- 9.数据库服务器部署之------3步实现远程访问
- jetbrains webstorm汉化包
- android 谷歌室内定位,打造室内导航 谷歌发布WifiRttScan App测试室内定位
- 怎么撰写营销策划书?
- 二、Excel大纲—基础篇
- Python 罗德里格矩阵的空间坐标转换——两组公共点求所属坐标系的旋转矩阵与平移矩阵
- 爬虫-模拟点击,实现加载页面全部内容
- 上海亚商投顾:沪指重返3100点
- Shell脚本撰写指南
- 连续时间的马尔可夫链
- PMBOK(第六版) PMP笔记——《第十三章 项目干系人管理》
热门文章
- 完美世界3D格斗手游[格斗宝贝]今日公测
- 大众点评霸王餐自动报名autojs(更新版)
- 贴片电阻封装规格及阻值标注方法
- 解决AssertionError Torch not compiled with CUDA enabled问题
- 常见问题之Golang——verifying github.com/go-playground/assert/v2@v2.0.1/go.mod: checksum mismatch错误...
- go mod tidy 报错:verifying ...: checksum mismatch
- html怎么改默认浏览器,怎样设置默认浏览器?3种更改默认浏览器方法介绍
- 计算机 工具 文件夹 找不到,电脑附件中的“画图工具”找不到了,怎么办?
- 第四代测序技术(纳米孔测序技术)
- 开源人物之九:赖霖枫