<input id="ohw05"></input>
  • <table id="ohw05"><menu id="ohw05"></menu></table>
  • <var id="ohw05"></var>
  • <code id="ohw05"><cite id="ohw05"></cite></code>
    <label id="ohw05"></label>
    <var id="ohw05"></var>
  • PDFium 渲染

    PDFium 是 Chromium 的 PDF 渲染引擎,許可協議為 BSD 3-Clause。不同于 Mozilla 基于 HTML5 的 PDF.js,PDFium 是基于 Foxit Software (福昕軟件)的渲染代碼,Google 與其合作開源出的。

    此外,Qt PDF 模塊也選用了 PDFium ,可見 QtWebEngine / QtPdf

    本文將介紹如何用 PDFium 實現一個簡單的 PDF 閱讀器,代碼見:https://github.com/ikuokuo/pdfium-reader

    編譯 PDFium

    使用預編譯庫:https://github.com/bblanchon/pdfium-binaries

    不然,參考 PDFium / README 自己編譯,實踐步驟如下:

    # 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 內容如下:

    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)
    

    使用 PDFium

    閱讀 PDFium / Getting Started,了解如何初始化 PDFium 及載入文檔。步驟如下,或見 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;
    }
    

    獲取信息

    樣例見 pdf_info.cc,可打印 PDF 元數據、頁面信息等。

    FPDF_GetMetaText 獲取元數據(UTF-16LE 編碼):

    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;
      }
    }
    

    渲染頁面

    樣例見 pdf_render.cc,可渲染 PDF 頁面并保存為 PNG。

    FPDF_RenderPageBitmap 渲染某一頁:

    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 存為 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;
    }
    

    實現 UI

    本文給出的 PDFium Reader 代碼,用的 ImGui+GLFW+OpenGL3 實現的 UI,可跨三大桌面系統。

    想進一步了解的,可以直接看代碼,編譯運行依照 README。

    GoCoding 個人實踐的經驗分享,可關注公眾號!

    posted @ 2021-12-03 16:50  GoCodingInMyWay  閱讀(169)  評論(0編輯  收藏  舉報
    国产美女a做受大片观看