• 一新建项目
  • 二封装pdfium库
  • 三使用封装好的pdf动态库
    • 1在vs中使用
    • 2在qt中使用
  • 四结语

 承接上篇,pdfium的lib文件是已经编译出来了,理论上已经可以开始直接用了,官方提供的测试demo中基本上介绍了用法的整套流程,你可以选择导出一页页的(图片)文件,也可以直接取出Buffer丢给支持图形库去渲染。

但是需要注意的是,他在实际使用中依旧有很多不便:
1、我们能够编译出来的只有vs2015或以上版本的lib,如果我们需要在别的ide中引用,那么就可能不行。
2、编译出来的lib一共24个,所以确定要在项目中,光pdf库就引用这么多个吗= =。

解决方式:基于这些lib的基础上,再包一层,把他编译成动态库,接口用纯C语言,不仅简洁,而且理论上说是跨平台的。

 关于动态库,只简单说几句,不了解可以自己查:静态链接库(.lib)cpp里所有代码被被编译成2进制文件,使用时直接会连接到你的项目中,而动态链接库,里面是你项目的代码,也不会编译进你的程序中。

开发环境:windows7+vs2015

一、新建项目:

 打开vs2015,新建一个c++的win32项目,当然,你也可以直接新建成空项目,然后在设置里手动修改输出方式为dll。这里我的项目叫pdf

二、封装pdfium库:

1、把上篇编译出来的pdfium库的lib和头文件整理好,并添加到刚才新建的项目中去:


2、在项目中新建PdfManager.h,PdfManager.cpp。开始写代码:
PdfManager.h:

#ifndef _PDF_MANAGER_H_
#define _PDF_MANAGER_H_
//filename是文件名,需要唯一,dat是打开的pdf的内容(可以用fstream打开,以二进制形式),length是pdf长度
extern "C" _declspec(dllexport) bool __stdcall PDFMANAGER_Loadpdf(const char* filename, char* dat, int length); //加载pdf(即加载已经打开的pdf)
//filename是文件名,关闭该pdf
extern "C" _declspec(dllexport) bool __stdcall PDFMANAGER_Closepdf(const char* filename); //关闭pdf
//filename是文件名,关闭该pdf,page是需要显示页数,width是宽,height是高,size是当前页的大小,outBmp是是否导出bmp文件,返回该页buffer
extern "C" _declspec(dllexport) char* __stdcall PDFMANAGER_LoadPage(const char* filename, int page, float& width, float& height, int& size, bool OutBmp);//加载页面
//filename是文件名,关闭该页面,打开后需要关闭,否则会内存泄漏
extern "C" _declspec(dllexport) void __stdcall PDFMANAGER_ClosePage(const char* filename, int page); //关闭页面
//获取总页数
extern "C" _declspec(dllexport) int __stdcall PDFMANAGER_GetPageCount(const char* filename);
//获取下一页该渲染的页
extern "C" _declspec(dllexport) int __stdcall PDFMANAGER_GetCurrentPage(const char* filename);
#endif

PdfManager.cpp:

#include "PdfManager.h"#include "fpdfview.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <memory>
#include <map>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
#include "fpdf_dataavail.h"
#include "fpdf_edit.h"
#include "fpdf_ext.h"
#include "fpdf_formfill.h"
#include "fpdf_text.h"#include <functional>
#include <fstream>enum OutputFormat
{OUTPUT_STR,OUTPUT_BMP,
};struct Options
{Options() :pages(false), output_format(OUTPUT_BMP) {}bool pages; //是否指定范围OutputFormat output_format;int first_page = 0; //起始页数int last_page = 0; //终止页数int currentpage = 0; //要打印的页面float width = 0; //目标宽度float height = 0; //目标高度
};FPDF_BOOL Is_Data_Avail(FX_FILEAVAIL* avail, size_t offset, size_t size)
{return true;
}class PDFManager
{static std::string WriteBmp(int num,const void* buffer,int stride,int width,int height){if (stride < 0 || width < 0 || height < 0)return false;if (height > 0 && width > INT_MAX / height)return false;int out_len = stride * height;if (out_len > INT_MAX / 3)return "";char filename[256];snprintf(filename, sizeof(filename), "%d.bmp", num);FILE* fp = fopen(filename, "wb");if (!fp)return "";BITMAPINFO bmi = {};bmi.bmiHeader.biSize = sizeof(bmi) - sizeof(RGBQUAD);bmi.bmiHeader.biWidth = width;bmi.bmiHeader.biHeight = -height;  // top-down imagebmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 32;bmi.bmiHeader.biCompression = BI_RGB;bmi.bmiHeader.biSizeImage = 0;BITMAPFILEHEADER file_header = {};file_header.bfType = 0x4d42;file_header.bfSize = sizeof(file_header) + bmi.bmiHeader.biSize + out_len;file_header.bfOffBits = file_header.bfSize - out_len;fwrite(&file_header, sizeof(file_header), 1, fp);fwrite(&bmi, bmi.bmiHeader.biSize, 1, fp);fwrite(buffer, out_len, 1, fp);fclose(fp);return std::string(filename);}struct FPDF_FORMFILLINFO_PDFiumTest : public FPDF_FORMFILLINFO{// Hold a map of the currently loaded pages in order to avoid them// to get loaded twice.std::map<int, FPDF_PAGE> loaded_pages;// Hold a pointer of FPDF_FORMHANDLE so that PDFium app hooks can// make use of it.FPDF_FORMHANDLE form_handle;};struct AvailDeleter{inline void operator()(FPDF_AVAIL avail) const{FPDFAvail_Destroy(avail);}};static FPDF_FORMFILLINFO_PDFiumTest* ToPDFiumTestFormFillInfo(FPDF_FORMFILLINFO* form_fill_info){return static_cast<FPDF_FORMFILLINFO_PDFiumTest*>(form_fill_info);}FPDF_PAGE GetPageForIndex(FPDF_FORMFILLINFO* param,FPDF_DOCUMENT& doc,int index){FPDF_FORMFILLINFO_PDFiumTest* form_fill_info =ToPDFiumTestFormFillInfo(param);auto& loaded_pages = form_fill_info->loaded_pages;auto iter = loaded_pages.find(index);if (iter != loaded_pages.end())return iter->second;FPDF_PAGE page = FPDF_LoadPage(doc, index);if (!page)return nullptr;FPDF_FORMHANDLE& form_handle = form_fill_info->form_handle;FORM_OnAfterLoadPage(page, form_handle);FORM_DoPageAAction(page, form_handle, FPDFPAGE_AACTION_OPEN);loaded_pages[index] = page;return page;}char* RenderPage(FPDF_DOCUMENT& doc,FPDF_FORMFILLINFO_PDFiumTest& form_fill_info, float& width, float& height,const Options& options,int& size){FPDF_PAGE page = GetPageForIndex(&form_fill_info, doc, options.currentpage);if (!page){return nullptr;}FPDF_TEXTPAGE text_page = FPDFText_LoadPage(page);double scale = 1.0;int widthdraw = static_cast<int>(FPDF_GetPageWidth(page) * scale);int heightdraw = static_cast<int>(FPDF_GetPageHeight(page) * scale);if (options.width > 0 && options.height > 0){if (options.width > options.height){double scalewidth = (double)options.height / (double)heightdraw;heightdraw = options.height;widthdraw = scalewidth * widthdraw;}else{double scaleheight = (double)options.width / (double)widthdraw;widthdraw = options.width;heightdraw = scaleheight * heightdraw;}}//else//{//  widthdraw = static_cast<int>(FPDF_GetPageWidth(page) * scale);//  heightdraw = static_cast<int>(FPDF_GetPageHeight(page) * scale);//}int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;FPDF_BITMAP bitmap = FPDFBitmap_Create(widthdraw, heightdraw, alpha);const char* buffer = nullptr;char* rtnBuffer = nullptr;int out_len = 0;if (bitmap){FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;FPDFBitmap_FillRect(bitmap, 0, 0, widthdraw, heightdraw, fill_color);FPDF_RenderPageBitmap(bitmap, page, 0, 0, widthdraw, heightdraw, 0, FPDF_ANNOT | FPDF_REVERSE_BYTE_ORDER);//FPDF_FFLDraw(form, bitmap, page, 0, 0, width, height, 0, FPDF_ANNOT | FPDF_REVERSE_BYTE_ORDER);int stride = FPDFBitmap_GetStride(bitmap);int strheight = FPDFBitmap_GetHeight(bitmap);buffer = reinterpret_cast<const char*>(FPDFBitmap_GetBuffer(bitmap));//开辟新内存size = stride * strheight;rtnBuffer = new char[size];memset(rtnBuffer, 0, size);memcpy(rtnBuffer, buffer, size);width = FPDFBitmap_GetWidth(bitmap);height = FPDFBitmap_GetHeight(bitmap);Pages_.insert(std::make_pair(options.currentpage, rtnBuffer));switch (options.output_format){case OUTPUT_BMP:WriteBmp(options.currentpage, buffer, stride, widthdraw, heightdraw);break;default:break;}FPDFBitmap_Destroy(bitmap);}/*elsefprintf(stderr, "Page was too large to be rendered.\n");*/form_fill_info.loaded_pages.erase(options.currentpage);/*FORM_DoPageAAction(page, form, FPDFPAGE_AACTION_CLOSE);FORM_OnBeforeClosePage(page, form);*/FPDFText_ClosePage(text_page);FPDF_ClosePage(page);return rtnBuffer;}class TestLoader{public:TestLoader(const char* buff, size_t len){m_pBuf = new char[len];memcpy(m_pBuf, buff, len);m_Len = len;}~TestLoader(){delete[]m_pBuf;}static int GetBlock(void* param,unsigned long pos,unsigned char* pBuf,unsigned long size){TestLoader* pLoader = static_cast<TestLoader*>(param);if (pos + size < pos || pos + size > pLoader->m_Len)return 0;memcpy(pBuf, pLoader->m_pBuf + pos, size);return 1;}private:char* m_pBuf;size_t m_Len;};void RenderPdf(const char* pBuf, size_t len, const Options& options){memset(&platform_callbacks_, '\0', sizeof(platform_callbacks_));platform_callbacks_.version = 3;form_callbacks_.version = 1;form_callbacks_.m_pJsPlatform = &platform_callbacks_;Loader_ = std::move(std::unique_ptr<TestLoader>(new TestLoader(pBuf, len)));File_access_ = std::make_unique<FPDF_FILEACCESS>();memset(File_access_.get(), '\0', sizeof(File_access_.get()));File_access_->m_FileLen = static_cast<unsigned long>(len);File_access_->m_GetBlock = TestLoader::GetBlock;File_access_->m_Param = Loader_.get();memset(&File_avail_, '\0', sizeof(File_avail_));File_avail_.version = 1;File_avail_.IsDataAvail = Is_Data_Avail;memset(&Hints_, '\0', sizeof(Hints_));Hints_.version = 1;int nRet = PDF_DATA_NOTAVAIL;Pdf_avail_ = FPDFAvail_Create(&File_avail_, File_access_.get());std::unique_ptr<void, PDFManager::AvailDeleter> scoped_pdf_avail_deleter(Pdf_avail_);if (FPDFAvail_IsLinearized(Pdf_avail_) == PDF_LINEARIZED){this->PdfDoc_ = FPDFAvail_GetDocument(Pdf_avail_, nullptr);if (this->PdfDoc_){while (nRet == PDF_DATA_NOTAVAIL)nRet = FPDFAvail_IsDocAvail(Pdf_avail_, &Hints_);if (nRet == PDF_DATA_ERROR){fprintf(stderr, "Unknown error in checking if doc was available.\n");FPDF_CloseDocument(this->PdfDoc_);return;}nRet = FPDFAvail_IsFormAvail(Pdf_avail_, &Hints_);if (nRet == PDF_FORM_ERROR || nRet == PDF_FORM_NOTAVAIL){fprintf(stderr,"Error %d was returned in checking if form was available.\n",nRet);FPDF_CloseDocument(this->PdfDoc_);return;}this->bIsLinearized_ = true;}}else{this->PdfDoc_ = FPDF_LoadCustomDocument(File_access_.get(), nullptr);}if (!this->PdfDoc_){unsigned long err = FPDF_GetLastError();return;}(void)FPDF_GetDocPermissions(this->PdfDoc_);PageCount = FPDF_GetPageCount(this->PdfDoc_);}public:PDFManager();~PDFManager();void Init(char *dat, int length);void Close();char* GetPdfPage(int page, float& width, float& height, int& size, bool OutBmp = false);//返回长度void ClosePdfPage(int page);int PageCount = 0;int PageCurrent = 0;int PageBad = 0;
private:FPDF_DOCUMENT PdfDoc_ = nullptr;//文档//FPDF_FORMHANDLE Form_ = nullptr;bool bIsLinearized_ = false; //是否线性化FPDF_FORMFILLINFO_PDFiumTest form_callbacks_;IPDF_JSPLATFORM platform_callbacks_;FX_DOWNLOADHINTS Hints_;//FX_FILEAVAIL File_avail_;std::unique_ptr<FPDF_FILEACCESS> File_access_;FPDF_AVAIL Pdf_avail_;std::unique_ptr<TestLoader> Loader_;char* File_contents_ = nullptr;int File_length_ = 0;std::map<int, char*> Pages_; //保存页面数据};PDFManager::PDFManager()
{}PDFManager::~PDFManager()
{for (auto &buffer : Pages_){delete[]buffer.second;}Pages_.clear();this->Close();
}void PDFManager::Init(char *dat, int length)
{File_contents_ = dat;File_length_ = length;Options options;options.output_format = OutputFormat::OUTPUT_BMP;if (!File_contents_)return;RenderPdf(File_contents_, File_length_, options);
}char* PDFManager::GetPdfPage(int page, float& width, float& height, int& size, bool OutBmp)
{if (this->bIsLinearized_){this->Close();return 0;}if (page < 0)return 0;Options options;options.currentpage = page;options.width = width;options.height = height;if (!OutBmp)options.output_format = OUTPUT_STR;PageCurrent = page;PageCurrent++;return RenderPage(this->PdfDoc_, form_callbacks_, width, height, options, size);
}void PDFManager::ClosePdfPage(int page)
{std::map<int, char*>::iterator itor = Pages_.find(page);if (itor != Pages_.end()){delete[]itor->second;Pages_.erase(page);}
}void PDFManager::Close()
{if (!this->PdfDoc_)return;FPDF_CloseDocument(this->PdfDoc_);
}//接口函数
std::map<std::string, PDFManager*> g_pdfmanagersmap;
bool __stdcall PDFMANAGER_Loadpdf(const char* filename, char* dat, int length)
{if (!filename){return false;}if (g_pdfmanagersmap.size() == 0){FPDF_LIBRARY_CONFIG config;config.version = 2;config.m_pUserFontPaths = nullptr;config.m_pIsolate = nullptr;config.m_v8EmbedderSlot = 0;FPDF_InitLibraryWithConfig(&config);}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){itor->second->Init(dat, length);}else{PDFManager* pdfmanager = new PDFManager();g_pdfmanagersmap.insert(std::make_pair(file, pdfmanager));pdfmanager->Init(dat, length);}return true;
}bool __stdcall PDFMANAGER_Closepdf(const char* filename)
{if (!filename){return false;}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){delete itor->second;g_pdfmanagersmap.erase(file);if (g_pdfmanagersmap.size() == 0){FPDF_DestroyLibrary();}}return true;
}char* __stdcall PDFMANAGER_LoadPage(const char* filename, int page, float& width, float& height, int& size, bool OutBmp)
{if (!filename){return nullptr;}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){return itor->second->GetPdfPage(page, width, height, size, OutBmp);}return nullptr;
}void __stdcall PDFMANAGER_ClosePage(const char* filename, int page)
{if (!filename){return;}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){itor->second->ClosePdfPage(page);}
}int __stdcall PDFMANAGER_GetPageCount(const char* filename)
{if (!filename){return 0;}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){return itor->second->PageCount;}return 0;
}int __stdcall PDFMANAGER_GetCurrentPage(const char* filename)
{if (!filename){return 0;}std::string file = filename;std::map<std::string, PDFManager*>::iterator itor = g_pdfmanagersmap.find(file);if (itor != g_pdfmanagersmap.end()){return itor->second->PageCurrent;}return 0;
}

注释说的比较清楚,就不解释了。

3、添加模块文件:


我取名为PdfManager.def,在里面添加如下代码:

LIBRARY "Pdf"
EXPORTS
PDFMANAGER_Loadpdf @ 1
PDFMANAGER_Closepdf @ 2
PDFMANAGER_LoadPage @ 3
PDFMANAGER_ClosePage @ 4
PDFMANAGER_GetPageCount @ 5
PDFMANAGER_GetCurrentPage @ 6

即指定要编译成dll的接口函数。

4、编译,最后整理成pdf库:


直接编译release版本就可以了,通用。

三、使用封装好的pdf动态库:

1、在vs中使用:

1.1 先新建测试项目
1.2 添加pdf库
1.2 添加代码:
main.cpp:

#include <iostream>
#include <fstream>
#include "PdfManager.h"
#include <memory>#include <windows.h>
char* GetFileContents(const char* filename, size_t *size)
{std::fstream instream;instream.open(filename, std::ios::_Nocreate | std::ios::binary);if (!instream.is_open()){std::printf("open file Failed!\n");std::printf("%s\n", filename);instream.close();return nullptr;}instream.seekg(0, std::ios::end);*size = instream.tellg();instream.seekg(0, std::ios::beg);char *buffer = new char[*size];instream.read(buffer, *size);instream.close();return buffer;
}int main()
{char* name = "test.pdf";size_t length;std::unique_ptr<char>  filecontents(GetFileContents(name, &length));PDFMANAGER_Loadpdf(name, filecontents.get(), length);int counts = PDFMANAGER_GetPageCount(name);for (int i = 0; i < counts; ++i){if (GetAsyncKeyState(VK_F2) & 0x8000)break;float width, height = 0;int length = 0;PDFMANAGER_LoadPage(name, i, width, height, length, true);PDFMANAGER_ClosePage(name, i);}PDFMANAGER_Closepdf(name);system("pause");return 0;
}

结果如图(数字.bmp是渲染出来的每一页,我只渲染完三页就关了):

2、在qt中使用:

2.1新建qt项目
2.2 导入pdf动态库
2.3关键代码(ui逻辑代码就不贴了,其实就是主要讲怎么用,怎么渲染)

PDFForm::PDFForm(const char *filename, QByteArray &bytearray, QWidget *parent) :QWidget(parent),ui(new Ui::PDFForm)
{ui->setupUi(this);FileLength_ = bytearray.length();File_ = new char[FileLength_];std::memcpy(File_, bytearray.toStdString().c_str(), FileLength_);FileName_ = filename;Picture_ = new PictureBox();Picture_->setMode(PictureBox::PB_MODE::FIX_SIZE_CENTRED );this->ui->verticalLayout_2->addWidget(Picture_);
}void PDFForm::InitFile()
{if(HaveLoadPdf_)return;int length = (int)FileLength_;PDFMANAGER_Loadpdf(FileName_.c_str(), File_, length);HaveLoadPdf_ = true;PageCount_ = PDFMANAGER_GetPageCount(FileName_.c_str());this->LoadPage(0);
}void PDFForm::LoadPage(int page)
{if(!HaveLoadPdf_)return;int length = 0;QRect rect = this->ui->verticalLayout_2->geometry();float width = rect.width();float height = rect.height();char* Buffer = PDFMANAGER_LoadPage(FileName_.c_str(),page, width, height, length, false);QImage image((uchar*)Buffer, width, height, QImage::Format_RGBA8888);this->Picture_->setImage(image);PDFMANAGER_ClosePage(FileName_.c_str(),page);//释放页面内存UpdateLabelPage();
}

效果如下图:

到这里就完成了需要在qt中显示或打开pdf的需求,还做了适配,可以直接拉伸缩小,而且最主要的是,因为其本质是位图,放大缩小时重新loadpage可以实现分辨率也不断放大缩小

四、结语:

1、本系列到此结束,其实还有些东西,比如在qt里做显示适配,例如上面的Picture_对象就是自定义的一个image类,在界面上显示时方便居中,要写的话还可以写第五篇,但是我暂时没空,就打住了,以后会不会补需要再看看。

2、本次研究说实话让我提升很多,很多是思维和经验上的改变,独立能力稍微有点加强,希望能早日成为大牛。

17.05.19更新:
代码地址:
传送门

17.07.27更新:
大家不用留邮箱了,我不是经常上这个帐号,下载连接也贴了,也不花积分,直接下载就好了(ps:我自己下了,也叫别人下了,文件没问题,下载下来有问题重新试试,csdn是经常抽风,网络不是很稳定)

17.08.09更新:
鉴于很多人问我要在QT中打开的demo,现在补上(如果觉得不错,不妨点个顶或者关注,你的鼓励是对我最大的支持):
传送门
另外 需要1积分,不知道为啥,现在csdn资源最少1积分,包括我以前的0分资源全部自动调整为1分,特此说明。

Qt显示pdf系列4——封装pdfium库为动态库,显示pdf相关推荐

  1. C++基于QT创建并使用静态库和动态库

    如果这个宇宙里没有你所爱的人,那还算什么宇宙. -- 斯蒂芬 · 威廉 · 霍金 之前写了一篇文章(C++初始动态库和静态库)简单介绍了一下C++静态库和动态库的特点,今天来说一下使用QT这个开发工具 ...

  2. Qt 静态库和动态库

    Qt 静态库和动态库 创建和使用静态库 创建静态库 使用静态库的文件 创建和使用动态库 创建动态库 使用动态库 隐式链接调用共享库 显示调用 创建和使用静态库 创建静态库 1.选择新建文件和项目.=& ...

  3. QT 静态库和动态库的使用方法

    QT 静态库和动态库的使用方法 背景知识:程序在编译成可执行文件时,会有四步过程: 1预处理(头文件和宏定义) g++ -E 1.cpp -o 1.i 2编译 将c代码编译成汇编代码 g++ -S 1 ...

  4. QT添加库(静态库和动态库)

    QT添加库(静态库和动态库) 添加动态库(dll库)的方法:** 就是把所有需要的dll库全部放到exe所在文件夹,和exe处于同一级目录下. 添加静态库(lib库)的方法: 1.右键项目文件,点击添 ...

  5. 【C 语言】动态库封装与设计 ( Windows 动态库简介 | Visual Studio 调用动态库 )

    文章目录 一.Windows 动态库简介 二.Visual Studio 调用动态库 一.Windows 动态库简介 在 C:\Windows\System32 目录中 , 存放着 Windows 中 ...

  6. 极简系列|Makefile工程框架(可执行程序、静态库、动态库)

    作为一名Linux系统下的开发人员,平时工作中会经常用Makefile来构建应用开发框架.如果是特别简单的应用,几行makefile代码就可以搞定.但对于稍微上点规模的应用,其可能会包含若干个模块,复 ...

  7. 用gcc生成静态库和动态库.pdf以及opencv的使用

    一.gcc生成动态库和静态库 1.准备过程 创建hello.h文件并编写hello.h #ifndef HELLO_H #define HELLO_H void hello(const char *n ...

  8. 【C语言】标准库(头文件、静态库、动态库),windows与Linux平台下的常用C语言标准库

    一.Introduction 1.1 C语言标准库 1.2 历代C语言标准 1.3 主流C语言编译器 二.C语言标准库 2.1 常用标准头文件 2.2 常用标准静态库 三.windows平台 四.Li ...

  9. Linux中gcc的编译、静态库和动态库的制作

    欢迎大家关注笔者,你的关注是我持续更博的最大动力 Linux中gcc的编译.静态库.动态库 文章目录: 1 gcc的编译过程 1.1 gcc的编译过程 1.2 gcc的常用参数 2 gcc 静态库的制 ...

最新文章

  1. KubeSphere安装Mysql5.7
  2. 关于大型网站技术演进的思考(一)--存储的瓶颈(上)
  3. 最长单调递增子序列_最长递增子序列(动态规划 + 二分搜索)
  4. Controller层返回字符串
  5. Leetcode18.四数之和
  6. React中的三种类型组件介绍
  7. 视频教程-【深入理解计算机网络】讲师解读计算机网络原理视频课程(上)-计算机网络
  8. 算法:狐狸吃兔子问题(约瑟环)
  9. 第六场问题 B: Bumped!(Dijkstra + 优先队列优化)
  10. 交换机console接口设置密码
  11. Boardcast receiver
  12. Debian服务器更改时区为中国
  13. postcss-pxtorem使用方式
  14. 艾兰岛编辑器-玩家角色
  15. VS2005下error PRJ0003 : Error spawning 'cmd.exe'的解决方法
  16. distribute-list分发列表
  17. 年仅28岁的郭宇宣布从字节退休,财务自由东渡日本
  18. matlab联立两个方程组求解,MATLAB求解联立方程的问题
  19. simulink 双馈风机虚拟同步机VSG控制,风储VSG控制频域SFR模型,对比不同惯量J对一次调频频率的影响
  20. QE01/QE02/QE03屏幕增强

热门文章

  1. 新浪微博开放平台站内应用开发流程直播(二)
  2. 颅脑外伤护理查房PPT模板
  3. python实现socket多客户端连接
  4. 示波器使用的注意事项
  5. 关于嘉立创拼板加工和三种拼板方法
  6. JPA-Hibernate
  7. 【人机交互技术】人脸表情识别技术综述(感觉写的比较简单)
  8. Get https://registry-1.docker.io/v2/: net/http: request canceled while waiting
  9. 渲染用计算机功耗,用了功率计,才发现原来电脑功耗其实并不大,买大功率电源是否浪费?...
  10. 5G与4G到底有什么区别?不仅速度惊人,还有这些优点