044_第三代软件开发-保存PDF

头图

第三代软件开发-保存PDF

文章目录

  • 第三代软件开发-保存PDF
    • 项目介绍
    • 保存PDF
      • 头文件
      • 源文件
      • 使用

关键字: QtQmlpdfpainter打印

项目介绍

欢迎来到我们的 QML & C++ 项目!这个项目结合了 QML(Qt Meta-Object Language)和 C++ 的强大功能,旨在开发出色的用户界面和高性能的后端逻辑。

在项目中,我们利用 QML 的声明式语法和可视化设计能力创建出现代化的用户界面。通过直观的编码和可重用的组件,我们能够迅速开发出丰富多样的界面效果和动画效果。同时,我们利用 QML 强大的集成能力,轻松将 C++ 的底层逻辑和数据模型集成到前端界面中。

在后端方面,我们使用 C++ 编写高性能的算法、数据处理和计算逻辑。C++ 是一种强大的编程语言,能够提供卓越的性能和可扩展性。我们的团队致力于优化代码,减少资源消耗,以确保我们的项目在各种平台和设备上都能够高效运行。

无论您是对 QML 和 C++ 开发感兴趣,还是需要我们为您构建复杂的用户界面和后端逻辑,我们都随时准备为您提供支持。请随时联系我们,让我们一同打造现代化、高性能的 QML & C++ 项目!

重要说明☝

☀该专栏在第三代软开发更新完将涨价

保存PDF

这个其实如果是QWidget开发,那就很简单了,直接有现成的打印模块,但是QML下是没有的,这里就需要重新写一下,首先,还是需要我们使用Qt的打印模块,

QT += printsupport 

这里需要说明一下,这个文件不是原创,是在GitHub上找到另一个,完了做了修改。

头文件

#ifndef XXXX_PRINT_H
#define XXXX_PRINT_H#include <QObject>
#ifndef QT_NO_PRINTER
#include <QPrinter>
#include <QPrintDialog>
#endif
#include <QQuickItem>
#include <QJSValue>
#include <QDir>class XXXX_Print : public QQuickItem
{Q_OBJECT
//    QML_ELEMENTQ_DISABLE_COPY(XXXX_Print)public:typedef enum { Print, PrintToFile, GrabOnly } GrabMode;Q_ENUMS(GrabMode);private:QSharedPointer<QQuickItemGrabResult> m_result;// 打印的qml组件QQuickItem *m_item;
#ifndef QT_NO_PRINTERQPrintDialog    *m_printDialogue;QPrinter        *m_printer;bool            m_pagePrinted;bool            m_sessionOpen;// 指定调用“print()”将产生多少份副本int             m_copyCount;QPainter        *m_painter;// 启用或禁用抗锯齿bool    m_antialias;// 启用或禁用单色打印(例如,热敏打印机)bool    m_monochrome;// 选择“打印到文件”时要打印到的文件路径(在某些平台上)QString m_filepath;QRectF  m_margins;
#endifGrabMode    m_mode;QString     m_fileDest;QString     m_fileType;int         m_fileQuality;QJSValue    m_callback;Q_PROPERTY(QQuickItem* item READ getItem WRITE setItem NOTIFY itemChanged)
#ifndef QT_NO_PRINTERQ_PROPERTY(QString filepath READ getFilePath WRITE setFilePath NOTIFY filePathChanged)Q_PROPERTY(QString fileDest READ fileDest WRITE setFileDest NOTIFY fileDestChanged)Q_PROPERTY(bool antialias READ getAntialias WRITE setAntialias NOTIFY antialiasChanged)Q_PROPERTY(bool monochrome READ getMonochrome WRITE setMonochrome NOTIFY monochromeChanged)// 打印的 dpi  整数分辨率Q_PROPERTY(int resolution READ getResolution WRITE setResolution NOTIFY resolutionChanged)Q_PROPERTY(int copyCount READ getCopyCount WRITE setCopyCount NOTIFY copyCountChanged)// QRectF 对象,表示以设备像素为单位的页面尺寸Q_PROPERTY(QRectF pageRect READ getPageRect NOTIFY sizeChanged)Q_PROPERTY(QRectF paperRect READ getPaperRect NOTIFY sizeChanged)Q_PROPERTY(QStringList paperSizes READ getPaperSizes)Q_PROPERTY(QString printerName READ getPrinterName WRITE setPrinterName NOTIFY printerNameChanged)Q_PROPERTY(Status status READ getStatus)
#endifpublic:XXXX_Print(QQuickItem *parent = 0);~XXXX_Print();#ifndef QT_NO_PRINTERtypedef enum {Millimeter = QPageSize::Millimeter,Point = QPageSize::Point,Inch = QPageSize::Inch,Pica = QPageSize::Pica,Didot = QPageSize::Didot,Cicero = QPageSize::Cicero,DevicePixel} Unit;Q_ENUMS(Unit)typedef enum {Idle = QPrinter::Idle,Active = QPrinter::Active,Aborted = QPrinter::Aborted,Error = QPrinter::Error,Unknown} Status;Q_ENUMS(Status)
#endifpublic slots:
#ifndef QT_NO_PRINTERbool print(QJSValue callback=QJSValue());bool setup(bool bDialogue = false);bool open();bool close();bool newPage() const;bool abort();
#endifbool grabImage(const QString &fileFormat, int quality=100, QJSValue callback=QJSValue());bool saveImage(const QString &fileName, const QString &fileFormat, int quality, QJSValue callback=QJSValue());// Property Hooks:void setItem( QQuickItem *item );
#ifndef QT_NO_PRINTERvoid setFilePath(const QString &filepath);void setFileDest(const QString &newFileDest);void setMonochrome(bool toggle);void setAntialias(bool toggle);void setMargins(double top, double right, double bottom, double left);bool setPageSize( qreal width, qreal height, Unit unit );bool setPageSize( const QString &paperSize );void setPrinterName(const QString &printerName);void setResolution(int dpi);void setCopyCount(int count);
#endifQQuickItem *getItem() const { return m_item; }
#ifndef QT_NO_PRINTERQString getFilePath() const { return m_filepath; }const QString fileDest() const { return m_fileDest; };bool getMonochrome() const { return m_monochrome; }bool getAntialias() const { return m_antialias; }QRectF getMargins() const { return m_margins; }QRectF getPageRect(Unit unit=DevicePixel) const;QRectF getPaperRect(Unit unit=DevicePixel) const;QStringList getPaperSizes() const;QString getPrinterName() const;int getResolution() const { return m_printer->resolution(); }int getCopyCount() const { return m_printer->copyCount(); }Status getStatus() const;
#endifprivate slots:bool grab();void grabbed();private:bool printGrab(const QImage &img);bool isDirExist(QString fullPath);signals:void itemChanged();void frameGrabbed(const QByteArray &imageData);void sizeChanged();void printComplete();void printError();
#ifndef QT_NO_PRINTERvoid filePathChanged();void monochromeChanged();void antialiasChanged();void marginsChanged();void printerNameChanged();void resolutionChanged();void copyCountChanged();
#endifvoid fileDestChanged();void strTestChanged();
};#endif // XXXX_PRINT_H

源文件

#include "XXXX_print.h"#include <QBuffer>
#include <QFileInfo>
#include <QPainter>
#ifndef QT_NO_PRINTER
# include <QPrintEngine>
#endif
#include <QQuickItemGrabResult>// Just for converting QByteArray:
#include <QQmlEngine>void XXXX_Print::setFileDest(const QString &newFileDest)
{if (m_fileDest == newFileDest)return;m_fileDest = newFileDest;emit fileDestChanged();
}XXXX_Print::XXXX_Print(QQuickItem *parent):QQuickItem(parent)
{
#ifndef QT_NO_PRINTERm_printDialogue = nullptr;m_printer = new QPrinter(QPrinter::ScreenResolution);m_pagePrinted = false;m_sessionOpen = false;m_copyCount = 1;m_painter = nullptr;m_antialias = true;m_monochrome = false;m_margins = QRectF(0, 0, 0, 0);m_filepath.clear();
#endifm_mode = XXXX_Print::GrabOnly;m_item = NULL;m_fileDest.clear();m_fileType.clear();m_fileQuality = 0;
}XXXX_Print::~XXXX_Print()
{
#ifndef QT_NO_PRINTERdelete m_printer;
#endif
}#ifndef QT_NO_PRINTER
/*** @brief XXXX_Print::print  打印/保存PDF(打印 setup至true)* @param callback* @return*/
bool XXXX_Print::print(QJSValue callback)
{m_mode = XXXX_Print::Print;m_callback = callback;return grab();
}
#endif/*** @brief XXXX_Print::grabImage 图片以QByteArray存储* @param fileFormat* @param quality* @param callback* @return*/
bool XXXX_Print::grabImage(const QString &fileFormat, int quality, QJSValue callback)
{m_mode = XXXX_Print::GrabOnly;m_callback = callback;m_fileType = fileFormat;m_fileQuality = quality;return grab();
}/*** @brief XXXX_Print::saveImage   保存图片,不用打开* @param fileName                  图片名称* @param fileFormat                图片类型* @param quality                   图片像素-1 0-100* @param callback* @return*/
bool XXXX_Print::saveImage(const QString &fileName, const QString &fileFormat, int quality, QJSValue callback)
{m_mode = XXXX_Print::PrintToFile;m_callback = callback;m_fileDest = fileName;m_fileType = fileFormat;m_fileQuality = quality;return grab();
}#ifndef QT_NO_PRINTER
/*** @brief XXXX_Print::setup  初始化打印机(true)/存储PDF(false)* @param bDialogue* @return*/
bool XXXX_Print::setup(bool bDialogue)
{m_printer->setOutputFormat(QPrinter::NativeFormat);QMarginsF margins( 0.0, 0.0, 0.0, 0.0);if( !m_printer->setPageMargins( margins, QPageLayout::Millimeter ) ){qWarning() << tr("Printer: Failed to set page margin (in mm) as configured.");return false;}QString strFilePath = QCoreApplication::applicationDirPath();m_printer->setOutputFileName(m_filepath + m_fileDest);   //设置输出路径if(bDialogue){m_printDialogue = new QPrintDialog(m_printer);if( m_printDialogue->exec() == QDialog::Accepted ){m_printDialogue->deleteLater();return true;}qWarning() << "打印机初始化失败";delete m_printDialogue;}else{// HP LaserJet Pro M428f-M429f [453773]m_printer->setOutputFormat(QPrinter::PdfFormat);  //设置输出格式为pdfreturn true;}return false;
}/*** @brief XXXX_Print::open 打开打印机/存储* @return*/
bool XXXX_Print::open()
{if( m_sessionOpen ){qCritical() << tr("Printer::open called while already in a multipage session. (Call 'close' first.)");return false;}m_painter = new QPainter();if( !m_painter ){qCritical() << tr("Printer::open failed to instantiate new QPainter. (Are you out of memory?)");return false;}if(!m_painter->begin(m_printer)){qCritical() << tr("Failed to initialise QPainter to QPrintDevice.");return false;}m_painter->setRenderHint(QPainter::Antialiasing, m_antialias);m_painter->setRenderHint(QPainter::TextAntialiasing, m_antialias);m_painter->setRenderHint(QPainter::SmoothPixmapTransform, m_antialias);m_sessionOpen = true;return true;
}/*** @brief XXXX_Print::close 关闭打印机/存储* @return*/
bool XXXX_Print::close()
{if( !m_sessionOpen ){qCritical() << tr("Printer::close called while not in multipage session.");return false;}delete m_painter;m_painter = nullptr;m_sessionOpen = false;return true;
}/*** @brief XXXX_Print::newPage 下一页* @return*/
bool XXXX_Print::newPage() const
{if( !m_sessionOpen ){qCritical() << tr("Printer::newPage called while not in a multipage session. (Call Printer::open first.)");return false;}return m_printer->newPage();
}/*** @brief XXXX_Print::abort 中止打印机* @return*/
bool XXXX_Print::abort()
{if( m_sessionOpen )close();return m_printer->abort();
}void XXXX_Print::setMonochrome(bool toggle)
{if( m_monochrome == toggle )return;m_monochrome = toggle;emit monochromeChanged();
}void XXXX_Print::setAntialias(bool toggle)
{if( m_antialias == toggle )return;m_antialias = toggle;emit antialiasChanged();
}void XXXX_Print::setFilePath(const QString &filepath)
{if( m_filepath == filepath )return;isDirExist(filepath);m_filepath = filepath;emit filePathChanged();
}
#endifvoid XXXX_Print::setItem(QQuickItem *item)
{if( m_item == item )return;m_item = item;emit itemChanged();
}#ifndef QT_NO_PRINTER
void XXXX_Print::setMargins(double top, double right, double bottom, double left)
{QRectF m( left, top, right-left, bottom-top );if( m_margins == m )return;m_margins = m;emit marginsChanged();
}bool XXXX_Print::setPageSize( const QString &paperSize )
{QPageSize size;// Run through each..for( int x=0; x < QPageSize::LastPageSize; x++ ){size = QPageSize((QPageSize::PageSizeId)x);if( size.name() == paperSize ){bool result = m_printer->setPageSize( size );emit sizeChanged();return result;}}qWarning() << tr("Unknown paper size: ") << paperSize << tr(" (Refer to 'paperSizes()' for valid options.)");return false;
}bool XXXX_Print::setPageSize( qreal width, qreal height, Unit unit )
{QSizeF szf(width, height);QPageSize size;switch( unit ){case DevicePixel:// Fanagle from DPI:szf /= m_printer->resolution();size = QPageSize(szf, QPageSize::Inch);break;default:size = QPageSize(szf, (QPageSize::Unit)unit);break;}bool result = m_printer->setPageSize(size);emit sizeChanged();return result;
}void XXXX_Print::setPrinterName(const QString &printerName)
{if( m_printer->printerName() == printerName )return;m_printer->setPrinterName( printerName );emit printerNameChanged();
}void XXXX_Print::setResolution(int dpi)
{if( m_printer->resolution() == dpi )return;m_printer->setResolution( dpi );emit resolutionChanged();
}void XXXX_Print::setCopyCount(int count)
{if( m_printer->copyCount() == count )return;m_printer->setCopyCount( count );emit copyCountChanged();
}QRectF XXXX_Print::getPageRect(Unit unit) const
{return m_printer->pageRect( (QPrinter::Unit)unit );
}QRectF XXXX_Print::getPaperRect(Unit unit) const
{return m_printer->paperRect( (QPrinter::Unit)unit );
}QStringList XXXX_Print::getPaperSizes() const
{QStringList results;QPageSize size;// Run through each..for( int x=0; x < QPageSize::LastPageSize; x++ ){size = QPageSize((QPageSize::PageSizeId)x);results.append( size.name() );}return results;
}XXXX_Print::Status XXXX_Print::getStatus() const
{QPrinter::PrinterState state = m_printer->printEngine()->printerState();return (XXXX_Print::Status)state;
}
#endifbool XXXX_Print::grab()
{if( !m_item ){qWarning() << tr("Printer::grab: No item source specified. (Set it with the 'item' property.)");return false;}QSharedPointer<QQuickItemGrabResult> res = m_item->grabToImage();if( !res ){qWarning() << tr("Printer::grab: Grab failed for some reason. (Is the item loaded and rendered?)");return false;}connect( res.data(), SIGNAL(ready()), this, SLOT(grabbed()) );m_result = res;return true;
}#ifndef QT_NO_PRINTER
bool XXXX_Print::printGrab(const QImage &img)
{if( !m_sessionOpen ){qCritical() << tr("Printer: Attempt to print without first calling Printer::open(). (This behaviour changed in 1.2)");;return false;}if( m_monochrome )m_painter->drawImage( m_printer->paperRect(QPrinter::DevicePixel), img.convertToFormat(QImage::Format_Mono, Qt::MonoOnly | Qt::ThresholdDither) );elsem_painter->drawImage( m_printer->paperRect(QPrinter::DevicePixel), img );return true;
}/*** @brief XXXX_Print::isDirExist 判断文件夹是否存在,不存在则创建* @param fullPath* @return*/
bool XXXX_Print::isDirExist(QString fullPath)
{
//    QString strFilePath = QCoreApplication::applicationDirPath();QDir dir(fullPath);if(dir.exists()){return true;}else{return dir.mkdir(fullPath);}
}
#endifvoid XXXX_Print::grabbed()
{const QImage img = m_result.data()->image();m_result.clear();QQmlEngine *jse = qmlEngine(this);jse->collectGarbage();bool ret = true;if( m_mode == XXXX_Print::PrintToFile ){ret = img.save(m_fileDest, m_fileType.toStdString().c_str(), m_fileQuality);if( m_callback.isCallable() ){QJSValueList args;args << ret;m_callback.call(args);}}
#ifndef QT_NO_PRINTERelse if( m_mode == XXXX_Print::Print ){ret = printGrab(img);if( m_callback.isCallable() ){QJSValueList args;args << ret;m_callback.call(args);}}
#endifelse if( m_callback.isCallable() ){QImage image;QByteArray ba;QBuffer buffer(&ba);buffer.open(QIODevice::WriteOnly);// 此函数将 QImage 写入给定设备ret = img.save(&buffer, m_fileType.toStdString().c_str(), m_fileQuality);buffer.close();if( ret ){QJSValueList args;args << jse->toScriptValue<QByteArray>(ba);m_callback.call( args );}}//    m_callback = QJSValue();if( ret )emit printComplete();elseemit printError();
}#ifndef QT_NO_PRINTER
QString XXXX_Print::getPrinterName() const
{return m_printer->printerName();
}
#endif

使用

    XXX_Print {id: printPDFfilepath: pdfFilePathfileDest: "/" + UserProfile.userName + dateString +".pdf"antialias: falsemonochrome: falseonPrintComplete: console.log("Print complete.");onPrintError: console.log("Print error!");Component.onCompleted: scanPaperSizes();function scanPaperSizes(){printPDF.setPageSize( 'A4' );printPDF.setMargins(0,0,0,0)}}

博客签名2021

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/132434.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【Windows-软件-FFmpeg】(01)通过CMD运行FFmpeg进行操作,快速上手

前言 通过"cmd"运行"ffmpeg"进行操作&#xff0c;快速上手&#xff1b; 实操 【实操一】 说明 使用"ffmpeg"来合并音频文件和视频文件 &#xff1b; 环境 Windows 11 专业版&#xff08;22621.2428&#xff09;&#xff1b; 代码 &#xf…

Java 性能优化之直接使用成员变量 VS 拷贝副本

背景 刷到一个大佬的 CSDN 博客&#xff0c;仔细看了一下性能优化专栏。联想到我们的日常开发工作&#xff0c;由于业务比较简单&#xff0c;很容就忽略性能问题。但是&#xff0c;性能优化的一下常见思路&#xff0c;也早有耳闻。看了一个 Java 性能优化的方法 「减少操作指令…

Linux进程的优先级

Linux进程的优先级 &#x1f4df;作者主页&#xff1a;慢热的陕西人 &#x1f334;专栏链接&#xff1a;Linux &#x1f4e3;欢迎各位大佬&#x1f44d;点赞&#x1f525;关注&#x1f693;收藏&#xff0c;&#x1f349;留言 本博客主要内容讲解Linux中进程的优先级&#xff0…

安防监控系统EasyCVR视频汇聚平台,如何实现视频汇聚?

关注我们的朋友都知道&#xff0c;EasyCVR平台最初就是以汇聚为核心而进行打造的&#xff0c;那到底什么是汇聚平台呢&#xff1f;又如何进行视频资源汇聚&#xff1f;简单来说&#xff0c;视频汇聚平台是指能够从不同的视频源&#xff08;例如直播、点播等&#xff09;收集、整…

Nginx篇---第二篇

系列文章目录 文章目录 系列文章目录一、请列举Nginx和Apache 之间的不同点二、在Nginx中,如何使用未定义的服务器名称来阻止处理请求?三、请解释Nginx服务器上的Master和Worker进程分别是什么?一、请列举Nginx和Apache 之间的不同点 二、在Nginx中,如何使用未定义的服务器…

[移动通讯]【Carrier Aggregation-13】【Carrier Aggregation】

前言&#xff1a; 前面分享过不同note CA 技术文档 这里主要参考 4G|ShareTechnote 《Carrier Aggregation》 CA SCell 添加的小区的流程&#xff1a; SCell addition and removal&#xff1a; 1 The carrier aggregation additional SCells cannot be activated immediately…

pom.xml详解

我们在开发Java应用程序时&#xff0c;pom.xml文件是项目中的核心配置文件之一&#xff0c;它结合Maven实现对项目依赖的拉取&#xff0c;今天就详细了解一下pom.xml文件的配置 Maven是一种构建工具&#xff0c;它用于构建、管理和发布Java项目pom.xml文件包含了项目的所有重要…

已经不做程序媛4年半了,后悔么?不好说...但再次看到之前写的博客,真的感慨万分。

四年半前&#xff0c;我还在大四实习&#xff0c;做了一年Java开发。四年半后&#xff0c;我是地理信息行业的一名销售经理。 今天&#xff0c;突然点开了CSDN&#xff0c;看到自己的博客有很多人看过&#xff0c;霎时间感慨万千…因为上一次这么认真的对待自己&#xff0c;竟…

Python小试牛刀:GUI(图形界面)实现计算器UI界面(三)

上一篇&#xff1a;Python小试牛刀&#xff1a;GUI&#xff08;图形界面&#xff09;实现计算器UI界面(二)-CSDN博客 回顾前两篇文章&#xff0c;第一篇文章主要实现了计算器UI界面如何布局&#xff0c;以及简单概述Python常用的GUI库。第二篇文章主要实现了计算器UI界面按钮组…

<Vue>使用依赖注入的方式共享数据

什么是vue依赖注入&#xff1f; Vue是一个用于构建用户界面的渐进式框架。 它提供了一种简单而灵活的方式来管理组件之间的数据流&#xff0c;即依赖注入&#xff08;Dependency Injection&#xff0c;DI&#xff09;。 依赖注入是一种设计模式&#xff0c;它允许一个组件从另一…

腾讯云CVM服务器标准型S5、SA3、S6详细介绍

腾讯云CVM服务器标准型实例的各项性能参数平衡&#xff0c;标准型云服务器适用于大多数常规业务&#xff0c;例如&#xff1a;web网站及中间件等&#xff0c;常见的标准型云服务器有CVM标准型S5、S6、SA3、SR1、S5se等规格&#xff0c;腾讯云服务器网txyfwq.com来详细说下云服务…

Synchronized与锁升级

一&#xff1a;java对象内存布局 对象在堆内存的存储布局可以划分为三个部分&#xff1a;对象头&#xff08;Header&#xff09;、实例数据&#xff08;Instance Data&#xff09; 和对齐填充 二&#xff1a;对象在堆内存中的存储布局 1&#xff1a;对象头 &#xff08;在64…

基础课23——设计客服机器人

根据调查数据显示&#xff0c;使用纯机器人完全替代客服的情况并不常见&#xff0c;人机结合模式的使用更为普遍。在这两种模式中&#xff0c;不满意用户的占比都非常低&#xff0c;不到1%。然而&#xff0c;在满意用户方面&#xff0c;人机结合模式的用户满意度明显高于其他模…

Redis02-持久化策略

目录 RDB&#xff08;Redis DataBase Backup file&#xff09; RDB执行原理 AOF&#xff08;Append-Only File&#xff09; RDB和AOF对比 Redis支持多种持久化方式&#xff0c;以确保数据在内存中持久存储&#xff0c;以便在Redis服务器重启时数据不会丢失。Redis中持久化的…

Android Studio(列表视图ListView)

前言 前面在适配器章节&#xff0c;已经介绍了ListView的作用(干什么的)&#xff0c;这节将主要介绍如何去设计ListView页面视图。 思考 列表视图需要些什么&#xff1f; 1. 列表项容器&#xff08;装载各列表项的容器&#xff09;&#xff1a;<ListView/> 2. 列表项布局…

MySQL数据脱敏(Data masking plugin functions)

对于企业而言&#xff0c;数据脱敏可以在数据共享或测试时用于保护敏感数据&#xff08;如信用卡&#xff0c;社保卡&#xff0c;地址等&#xff09;。通过对敏感数据进行脱敏处理&#xff0c;组织可以最大限度地降低数据泄露和未经授权访问的风险&#xff0c;同时仍能够使用真…

AI技术再刷屏!明星集体“说”外语,有何风险?

近日&#xff0c;一段美国歌手泰勒斯威夫特“说”中文的短视频在网络刷屏&#xff0c;引发热议。 视频中&#xff0c;泰勒斯威夫特“说”着流利中文&#xff0c;音色和讲母语时的音色类似&#xff0c;甚至连口型都能对上。 类似的视频还有很多外国人“说”地道中文、很多中国…

figma-如何批量修改字体

一.选择字体 二.批量替换 编辑—>替换相同字体

UI设计工具都哪些常用的,推荐这5款

对于UI设计师来说&#xff0c;日常工作无非是围绕“需求分析”→设计实施→“开发交付”这三个环节来进行。 然而&#xff0c;在每个环节中&#xff0c;设计师使用的工具却完全不同。在这里&#xff0c;我收集整理了UI设计师在日常工作中常用的五种工具&#xff0c;希望能为新…

【ChatOCR】OCR+LLM定制化关键信息抽取(附开源大语言模型汇总整理)

目录 背景技术方案存在的问题及解决思路关键信息提取结果其他解决方案替换文心一言LangChain大型多模态模型&#xff08;Large Multimodal Model, LMM&#xff09; 开源大模型汇总LLaMA —— Meta 大语言模型Stanford Alpaca —— 指令调优的 LLaMA 模型Lit-LLaMA —— 基于 na…