PDFium is Chromium's PDF rendering engine, the license agreement is BSD 3-Clause. Unlike Mozilla's PDF.js based on HTML5, PDFium is based on the rendering code of Foxit Software, which is open sourced by Google in cooperation with it.
In addition, the Qt PDF module also selects PDFium, see QtWebEngine / QtPdf .
This article will introduce how to use PDFium to implement a simple PDF reader. For the code, see: https://github.com/ikuokuo/pdfium-reader .
Compile PDFium
Use precompiled library: https://github.com/bblanchon/pdfium-binaries
Otherwise, refer to 161a9dca415b70 PDFium / README to compile by yourself. The practical steps are as follows:
# get depot_tools, contains: gclient, ninja, gn, ...
git clone --depth 1 https://chromium.googlesource.com/chromium/tools/depot_tools.git
export PATH="$PATH:$HOME/Codes/Star/depot_tools"
# get pdfium
cd pdfium-reader/
mkdir -p third_party/chromium
cd third_party/chromium
gclient config --unmanaged https://pdfium.googlesource.com/pdfium.git
gclient sync
cd pdfium
# get deps
# on linux, install additional build dependencies
./build/install-build-deps.sh
# gn config
# args see the following `out/Release/args.gn`
gn args out/Release
# ninja build
# pdfium
ninja -C out/Release pdfium
# pdfium_test
ninja -C out/Release pdfium_test
# run sample: pdf > ppm
./out/Release/pdfium_test --ppm path/to/myfile.pdf
out/Release/args.gn
during the period are as follows:
use_goma = false # Googlers only. Make sure goma is installed and running first.
is_debug = false # Enable debugging features.
# Set true to enable experimental Skia backend.
pdf_use_skia = false
# Set true to enable experimental Skia backend (paths only).
pdf_use_skia_paths = false
pdf_enable_xfa = false # Set false to remove XFA support (implies JS support).
pdf_enable_v8 = false # Set false to remove Javascript support.
pdf_is_standalone = true # Set for a non-embedded build.
pdf_is_complete_lib = true # Set for a static library build.
is_component_build = false # Disable component build (Though it should work)
Use PDFium
Read PDFium / Getting Started to learn how to initialize PDFium and load documents. The steps are as follows, or see pdfium_start.c :
#include <fpdfview.h>
#include <stdio.h>
int main(int argc, char const *argv[]) {
FPDF_STRING test_doc = "test_doc.pdf";
if (argc >= 2) {
test_doc = argv[1];
}
printf("test_doc: %s\n", test_doc);
FPDF_InitLibrary();
FPDF_DOCUMENT doc = FPDF_LoadDocument(test_doc, NULL);
if (!doc) {
unsigned long err = FPDF_GetLastError();
// Load pdf docs unsuccessful: ...
goto EXIT;
}
FPDF_CloseDocument(doc);
EXIT:
FPDF_DestroyLibrary();
return 0;
}
getting information
For examples, see pdf_info.cc , which can print PDF metadata, page information, etc.
Such as FPDF_GetMetaText
obtain metadata ( UTF-16LE
code):
void PrintPdfMetaData(FPDF_DOCUMENT doc) {
static constexpr const char *kMetaTags[] = {
"Title", "Author", "Subject", "Keywords",
"Creator", "Producer", "CreationDate", "ModDate"};
for (const char *meta_tag : kMetaTags) {
const unsigned long len = FPDF_GetMetaText(doc, meta_tag, nullptr, 0);
if (!len)
continue;
std::vector<char16_t> buf(len);
FPDF_GetMetaText(doc, meta_tag, buf.data(), buf.size());
auto text = strings::FromUtf16(std::u16string(buf.data()));
if (strcmp(meta_tag, "CreationDate") == 0 ||
strcmp(meta_tag, "ModDate") == 0) {
text = fpdf::DateToRFC3399(text);
}
std::cout << " " << meta_tag << ": " << text << std::endl;
}
}
Render the page
For examples, see pdf_render.cc , which can render PDF pages and save them as PNG.
FPDF_RenderPageBitmap
render a page:
void PdfRenderPage(const std::string &pdf_name, FPDF_DOCUMENT doc, int index) {
Timer t;
FPDF_PAGE page = FPDF_LoadPage(doc, index);
double scale = 1.0;
// double scale = 2.0;
int width = static_cast<int>(FPDF_GetPageWidth(page) * scale);
int height = static_cast<int>(FPDF_GetPageHeight(page) * scale);
int alpha = FPDFPage_HasTransparency(page) ? 1 : 0;
ScopedFPDFBitmap bitmap(FPDFBitmap_Create(width, height, alpha)); // BGRx
if (bitmap) {
FPDF_DWORD fill_color = alpha ? 0x00000000 : 0xFFFFFFFF;
FPDFBitmap_FillRect(bitmap.get(), 0, 0, width, height, fill_color);
int rotation = 0;
int flags = FPDF_ANNOT;
FPDF_RenderPageBitmap(bitmap.get(), page, 0, 0, width, height,
rotation, flags);
auto t_render = t.Elapsed();
int stride = FPDFBitmap_GetStride(bitmap.get());
void *buffer = FPDFBitmap_GetBuffer(bitmap.get());
char img_name[256];
int chars_formatted = snprintf(
img_name, sizeof(img_name), "%s.%d.png", pdf_name.c_str(), index);
if (chars_formatted < 0 ||
static_cast<size_t>(chars_formatted) >= sizeof(img_name)) {
fprintf(stderr, "Filename is too long: %s\n", img_name);
exit(EXIT_FAILURE);
}
auto ok = PdfWritePng(img_name, buffer, width, height, stride);
if (!ok) {
fprintf(stderr, "Write png failed: %s\n", img_name);
exit(EXIT_FAILURE);
}
auto t_write = t.Elapsed();
fprintf(stdout, "%s\n", img_name);
fprintf(stdout, " %02d: %dx%d, render=%lldms, write=%lldms\n",
index, width, height, t_render, t_write);
} else {
fprintf(stderr, "Page was too large to be rendered.\n");
exit(EXIT_FAILURE);
}
FPDF_ClosePage(page);
}
stb_image_write.h saved as PNG:
bool PdfWritePng(const std::string &img_name, void *buffer,
int width, int height, int stride) {
// BGRA > RGBA
auto buf = reinterpret_cast<uint8_t *>(buffer);
for (int r = 0; r < height; ++r) {
for (int c = 0; c < width; ++c) {
auto pixel = buf + (r*stride) + (c*4);
auto b = pixel[0];
pixel[0] = pixel[2]; // b = r
pixel[2] = b; // r = b
}
}
return stbi_write_png(img_name.c_str(), width, height, 4, buf, stride) != 0;
}
Implement the UI
PDFium Reader code given in this article, using ImGui + GLFW + OpenGL3 can realize the UI across the three major desktop systems.
If you want to know more, you can directly look at the code, compile and run according to README.
GoCoding personal practice experience sharing, please follow the official account!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。