目录
1. 基于QWidget的屏幕阅读水印的添加
1.1 平铺
1.1.1 核心代码
1.1.2 构造函数中设置透明度和鼠标穿透
1.1.3 调用
1.1.4 效果展示
1.2 指定位置添加水印
1.2.1 核心代码
1.2.2 设置水印透明度和鼠标穿透
1.2.3 调用
1.2.4 效果展示
2、基于QImage的屏幕水印的添加
2.1 平铺
2.1.1 核心代码
2.1.2 效果展示
2.2 指定位置添加
2.2.1 核心代码
2.2.2 效果展示
3. 附加
最近研究了QT添加水印阅读和打印功能,参考各资源之后,考虑以两种方式实现:
1、平铺
2、指定位置(共九种a、水平位置-【左、中、右】 B、垂直位置-【上、中、下】)
这里分别基于QWidget和QImage添加水印文本。
可支持功能:
(1)支持自定义文本字体、颜色、间距、透明度、旋转角度以及绘制方式。实现个性化定制水印需求。
(2)支持水印文本宽、高自定义,可换行显示。
1. 基于QWidget的屏幕阅读水印的添加
1.1 平铺
1.1.1 核心代码
/* 函数名称:
* ScreenWindowAddMarkByTile 【窗口添加水印-平铺】
* 参数含义:
* vContent:水印的文本
* vFontFamily: 水印字体
* vFontSize: 水印字体大小(100)
* vAlpha: 透明度
* vColor: 水印字体颜色("#ffffff")
* vFontSpceing: 字体间距
* 返回值:
* 添加水印之后的QPixmap
*/
void ScreenWindowAddMarkByTile(const QString &vContent,
const QString &vFontFamily,
const int &vFontSize,
const int &vFontSpceing,
const QString &vColor,
const int &vAlpha,
const qreal &vAngle,
const int &vWindowW,
const int &vWindowH,
const int &vMarkW,
const int &vMarkH)
{
// 设置水印内容
QString content = vContent;
// 当前窗口的宽高(即设置水印的区域)
int width = vWindowW;
int height = vWindowH;
// 设置字体
QFont font;
font.setFamily(vFontFamily);
font.setPointSize(vFontSize);
font.setItalic(true);
font.setLetterSpacing(QFont::AbsoluteSpacing, vFontSpceing);
// 设置画笔
QColor color(vColor);
color.setAlpha(vAlpha); // 0-100之间(数值越小,越透明)
QPen pen;
pen.setColor(color);
// 逆时针旋转角度
int watermark_inclination_angle = vAngle;
qreal angle = -watermark_inclination_angle;
// 计算水印文本的宽高,以及绘制步长(X方向、Y方向)
int watermark_width = vMarkW;
int watermark_height = vMarkH;
int x_step = vMarkW;
int y_step = vMarkH;
QFontMetrics fontMetrics(font);
const int stepSpaceX = 20;
const int stepSpaceY = 30; // 步长间隙
const int textW = fontMetrics.width(vContent);
const int textH = fontMetrics.height();
if(0 == watermark_width && 0 == watermark_height) //1-宽高均未设置
{
x_step = watermark_width = textW + stepSpaceX;
y_step = watermark_height = textH + stepSpaceY;
}
else if(0 == watermark_width) //2-只设置高,未设置宽
{
if(watermark_height < textH)
{
x_step = watermark_width = textW;
}
else
{
int row = watermark_height / textH;
if(row == 0) // 所设置到高度满足字体本身的倍数
{
row = 1; // 默认行数为1
}
x_step = watermark_width = (textW / row);
}
}
else if(0 == watermark_height) //3-只设置宽,未设置高
{
if( watermark_width > textW)
{
y_step = watermark_height = textH + stepSpaceY * 2;
}
else
{
int row = textW / watermark_width;
if(row == 0)
{
row += 1;
}
y_step = watermark_height = (textH * row) + stepSpaceX * 4;
}
x_step += stepSpaceX;
}
y_step = y_step*cos(abs(angle)) + x_step*sin(abs(angle));
x_step = y_step*sin(abs(angle)) + x_step*cos(abs(angle));
// 投影长度(倾斜之后)
// int project_Y = abs(this->width() * sin(angle)) + abs(this->height() * sin(angle)); // 原图像Y坐标在新坐标系Y轴上的投影长度
// int project_X = abs(this->height()*sin(angle)) + abs(this->width()*cos(angle)); // 原图像x坐标在新坐标系x轴上的投影长度
// 计算水印行数、列数
int row_count = height / y_step; //水印写多少行
int col_count = width / x_step + 10; //水印写多少列 因为旋转了,如果不多加会导致水印缺少一块
// 开始绘制
for (int r = 0; r <= row_count; r++)
{
for (int c = 0; c <= col_count; c++)
{
QPainter p(this);
p.setRenderHint(QPainter::Antialiasing, true);
p.setFont(font);
p.setPen(pen);
p.translate(x_step * c, y_step * r);
p.rotate(angle);
p.drawText(QRect(0, 0, x_step, y_step), Qt::TextWordWrap, content);
}
}
}
1.1.2 构造函数中设置透明度和鼠标穿透
setWindowOpacity(0.1);
this->setAttribute(Qt::WA_TransparentForMouseEvents, true);
1.1.3 调用
stackedLayout即可。
1.1.4 效果展示
1.2 指定位置添加水印
可自定义位置共包含9个位置:
a、水平位置-【左、中、右】
B、垂直位置-【上、中、下】
1.2.1 核心代码
void ScreenWindowsAddMarkByPosition(
const QString &v_markContent,
const QString &v_fontFamily,
const int &v_fontSize,
const int &v_alpha,
const qreal &v_angle,
const QString &v_fontColor,
const int &v_fontSpaceing,
const int &v_WindowW,
const int &v_WindowH,
const int &v_markW,
const int &v_markH,
const emMarkPosition &v_posH,
const emMarkPosition &v_posV,
const int &v_padding)
{
int fontSize = v_fontSize;
emMarkPosition posH = v_posH;
emMarkPosition posV = v_posV;
//添加文字水印
QFont font;
font.setFamily(v_fontFamily);
font.setPixelSize(fontSize);
font.setLetterSpacing(QFont::AbsoluteSpacing, v_fontSpaceing);
// 文字颜色
QColor fontColor(v_fontColor);
fontColor.setAlpha(v_alpha);
QFontMetrics fm(font);
int textW = fm.width(v_markContent);
int textH = fm.height();
int textMarkX = 0;
int textMarkY = 0;
int picMarkX = 0;
int picMarkY = 0;
// 计算水印文本的宽高,以及绘制步长(X方向、Y方向)
int watermark_width = v_markW;
int watermark_height = v_markH;
const int stepSpaceX = 20;
const int stepSpaceY = 20;
if(0 == watermark_width && 0 == watermark_height) //1-宽高均未设置
{
watermark_width = textW + stepSpaceX;
watermark_height = textH + stepSpaceY;
}
else if(0 == watermark_width) //2-只设置高,未设置宽
{
if(watermark_height < textH)
{
watermark_width = textW + stepSpaceX;
}
else
{
int row = watermark_height / textH;
if(row == 0) // 所设置到高度满足字体本身的倍数
{
row = 1; // 默认行数为1
}
watermark_width = (textW / row) + stepSpaceX;
}
}
else if(0 == watermark_height) //3-只设置宽,未设置高
{
if( watermark_width > textW)
{
watermark_height = textH + stepSpaceY * 2;
}
else
{
int row = textW / watermark_width;
if(row == 0)
{
row += 1;
}
watermark_height = (textH * row) + stepSpaceX * 4;
}
}
int padding = v_padding;
switch(posH)
{
case emLeft:
picMarkX = padding;
textMarkX = picMarkX + watermark_width + padding;
break;
case emRight:
textMarkX = v_WindowW - /*textW*/watermark_width - padding;
picMarkX = textMarkX;//- watermark_width - padding;
break;
case emHCenter:
picMarkX = v_WindowW / 2 - (watermark_width/* + padding + textW*/) / 2;
textMarkX = picMarkX + watermark_width + padding;
break;
default:
break;
}
switch(posV)
{
case emTop:
if (watermark_height >= textH)
{
picMarkY = padding;
textMarkY = picMarkY + watermark_height / 2 - textH / 2;
}
else
{
textMarkY = padding;
picMarkY = textMarkY + textH / 2 - watermark_height / 2;
}
break;
case emBottom:
if (watermark_height >= textH)
{
picMarkY = v_WindowH - padding - watermark_height;
textMarkY = picMarkY + watermark_height / 2 - textH / 2;
}
else
{
textMarkY = v_WindowH - padding - textH;
picMarkY = textMarkY + textH / 2 - watermark_height / 2;
}
break;
case emVCenter:
picMarkY = v_WindowH / 2 - watermark_height / 2;
textMarkY = v_WindowH / 2 - textH / 2;
break;
default:
break;
}
QPainter painter(this);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setFont(font);
painter.setPen(fontColor);
painter.translate(picMarkX, picMarkY);
painter.rotate(v_angle);
painter.drawText(QRect(0, 0, watermark_width, watermark_height), Qt::TextWordWrap, v_markContent);
}
1.2.2 设置水印透明度和鼠标穿透
setWindowOpacity(0.1);
this->setAttribute(Qt::WA_TransparentForMouseEvents, true);
1.2.3 调用
StackedLayout方式布局即可。
1.2.4 效果展示
2、基于QImage的屏幕水印的添加
2.1 平铺
2.1.1 核心代码
/* 函数名称:
* PixmapAddMarkByTile 【以平铺的方式给pixmap添加水印,平铺】
* 参数含义:
* v_pixmap: 需要添加水印的图片
* v_markContent:水印的文本
* v_markW:水印宽度
* v_markH: 水印高度
* v_fontFamily: 水印字体
* v_fontSize: 水印字体大小(100)
* v_alpha: 透明度
* v_fontColor: 水印字体颜色("#ffffff")
* v_fontSpaceing: 字体间距
* v_angle: 旋转角度
* 返回值:
* 添加水印之后的QPixmap
*/
QPixmap CustomizeMarkImage::PixmapAddMarkByTile(const QPixmap &v_pixmap,
const QString &v_markContent,
const int &v_markW,
const int &v_markH,
const QString &v_fontFamily,
const int &v_fontSize,
const int &v_alpha,
const QString &v_fontColor,
const int &v_fontSpaceing,
const qreal &v_angle)
{
QPixmap pixmap(v_pixmap);
int fontSize = v_fontSize;
int spacing = v_fontSpaceing;
QFont font(v_fontFamily, fontSize, QFont::Thin);
font.setLetterSpacing(QFont::AbsoluteSpacing, spacing);
QColor color(v_fontColor);
color.setAlpha(v_alpha);
qreal angle = -v_angle;
int x_step = v_markW;
int y_step = v_markH;
QFontMetrics fontMetrics(font);
const int textW = fontMetrics.width(v_markContent);
const int textH = fontMetrics.height();
if(0 == v_markW && 0 == v_markH) //1-宽高均未设置
{
x_step = textW;
y_step = textH;
}
else if(0 == v_markW) //2-只设置高,未设置宽
{
if(v_markH < textH)
{
x_step = textW;
}
else
{
int row = v_markH / textH;
if(row == 0) // 所设置到高度满足字体本身的倍数
{
row = 1; // 默认行数为1
}
x_step = (textW / row);
}
}
else if(0 == v_markH) //3-只设置宽,未设置高
{
if(v_markH > textW)
{
y_step = textH;
}
else
{
int row = textW / v_markW;
if(row == 0)
{
row += 1;
}
y_step = (textH * row);
}
}
y_step = y_step*cos(abs(angle)) + x_step*sin(abs(angle));
x_step = y_step*sin(abs(angle)) + x_step*cos(abs(angle));
int col_count = pixmap.width() / y_step; // 水印写多少列 因为旋转了,如果不多加会导致水印缺少一块
int row_count = pixmap.height() / x_step + 10; // 水印写多少行
for (int r = 0; r <= row_count; r++)
{
for (int c = 0; c <= col_count; c++)
{
QPainter painter(&pixmap);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setFont(font);
painter.setPen(QColor(color));
painter.translate(x_step * c, y_step * r);
painter.rotate(angle);
painter.drawText(QRect(0, 0, x_step, y_step), Qt::TextWordWrap, v_markContent);
}
}
return pixmap;
}
2.1.2 效果展示
2.2 指定位置添加
共包含9个位置:
a、水平位置-【左、中、右】
B、垂直位置-【上、中、下】
2.2.1 核心代码
/* 函数名称:
* PixmapAddMarkByPosition 【给pixmap添加水印,通过指定位置】
* 参数含义:
* v_pixmap: 需要添加水印的图片
* v_markContent:水印的文本
* v_markW:水印宽度
* v_markH: 水印高度
* v_fontFamily: 水印字体
* v_fontSize: 水印字体大小(100)
* v_alpha: 透明度
* v_fontColor: 水印字体颜色("#ffffff")
* v_fontSpaceing: 字体间距
* v_posH: 水平位置(左边、右边、水平居中)
* v_posV:垂直位置(顶部、底部、垂直居中)
* 返回值:
* 添加水印之后的QPixmap
*/
QPixmap CustomizeMarkImage::PixmapAddMarkByPosition(const QPixmap &v_pixmap,
const QString &v_markContent,
const int &v_markW,
const int &v_markH,
const QString &v_fontFamily,
const int &v_fontSize,
const int &v_alpha,
const int &v_angle,
const QString &v_fontColor,
const int &v_fontSpaceing,
const emMarkPosition &v_posH,
const emMarkPosition &v_posV,
const int &v_padding)
{
QPixmap picMark(v_pixmap);
int fontSize = v_fontSize;
emMarkPosition posH = v_posH;
emMarkPosition posV = v_posV;
//添加文字水印
QFont font;
font.setFamily(v_fontFamily);
font.setPixelSize(fontSize);
font.setLetterSpacing(QFont::AbsoluteSpacing, v_fontSpaceing);
QColor fontColor(v_fontColor);
fontColor.setAlpha(v_alpha);
QFontMetrics fm(font);
int textW = fm.width(v_markContent);
int textH = fm.height();
int textMarkX = 0;
int textMarkY = 0;
int picMarkX = 0;
int picMarkY = 0;
// 计算水印文本的宽高,以及绘制步长(X方向、Y方向)
int watermark_width = v_markW;
int watermark_height = v_markH;
const int stepSpaceX = 20;
const int stepSpaceY = 20;
if(0 == watermark_width && 0 == watermark_height) //1-宽高均未设置
{
watermark_width = textW + stepSpaceX;
watermark_height = textH + stepSpaceY;
}
else if(0 == watermark_width) //2-只设置高,未设置宽
{
if(watermark_height < textH)
{
watermark_width = textW + stepSpaceX;
}
else
{
int row = watermark_height / textH;
if(row == 0) // 所设置到高度满足字体本身的倍数
{
row = 1; // 默认行数为1
}
watermark_width = (textW / row) + stepSpaceX;
}
}
else if(0 == watermark_height) //3-只设置宽,未设置高
{
if( watermark_width > textW)
{
watermark_height = textH + stepSpaceY * 2;
}
else
{
int row = textW / watermark_width;
if(row == 0)
{
row += 1;
}
watermark_height = (textH * row) + stepSpaceX * 4;
}
}
int padding = v_padding;
switch(posH)
{
case emLeft:
picMarkX = padding;
textMarkX = picMarkX + watermark_width + padding;
break;
case emRight:
textMarkX = picMark.width() - /*textW*/watermark_width - padding;
picMarkX = textMarkX;//- watermark_width - padding;
break;
case emHCenter:
picMarkX = picMark.width() / 2 - (watermark_width/* + padding + textW*/) / 2;
textMarkX = picMarkX + watermark_width + padding;
break;
default:
break;
}
switch(posV)
{
case emTop:
if (watermark_height >= textH)
{
picMarkY = padding;
textMarkY = picMarkY + watermark_height / 2 - textH / 2;
}
else
{
textMarkY = padding;
picMarkY = textMarkY + textH / 2 - watermark_height / 2;
}
break;
case emBottom:
if (watermark_height >= textH)
{
picMarkY = picMark.height() - padding - watermark_height;
textMarkY = picMarkY + watermark_height / 2 - textH / 2;
}
else
{
textMarkY = picMark.height() - padding - textH;
picMarkY = textMarkY + textH / 2 - watermark_height / 2;
}
break;
case emVCenter:
picMarkY = picMark.height() / 2 - watermark_height / 2;
textMarkY = picMark.height() / 2 - textH / 2;
break;
default:
break;
}
QPainter painter(&picMark);
painter.setRenderHint(QPainter::Antialiasing, true);
painter.setFont(font);
painter.setPen(fontColor);
painter.translate(picMarkX, picMarkY);
painter.rotate(v_angle);
painter.drawText(QRect(0, 0, watermark_width, watermark_height), Qt::TextWordWrap, v_markContent);
return picMark;
}
2.2.2 效果展示
3. 附加
修改QPrintPreviewDialog背景色:
QPrintPreviewDialog *pPreviewDlg;
pPreviewDlg->setStyleSheet("QGraphicsView {qproperty-backgroundBrush: #F0F0F0; border:0px}");