Linux

PDFium 라이브러리 삽질기 - 5

respiro 2019. 12. 16. 17:14

PDFium 라이브러리 삽질기 - 5

v8 과 xfa 지원 및 skia 테스트


작성 일자: 2019년 12월 16일

최종 수정: 2020년 02월 05일

작성자: N3


 

이번 삽질은 지난 삽질과정에서 제외한 v8 과 xfa 지원 및 skia에 대해 삽질을 해 보도록 한다.


# Build arguments go here.

# See "gn args <out_dir> --list" for available build arguments.

pdf_is_standalone   = true                 # Set for a non-embedded build.

pdf_is_complete_lib = true                 # Static Library - libpdfium.a

pdf_enable_xfa      = false                # XFA support enabled.

pdf_enable_v8       = false                # Javascript support enabled.

pdf_use_skia        = false                 # Avoid skia backend experiment.

pdf_use_skia_paths  = false               # Avoid other skia backend experiment.


pdf_bundle_freetype = true

use_system_freetype = false


clang_use_chrome_plugins = false


use_goma            = false

use_custom_libcxx   = false

use_sysroot         = false


is_component_build  = false                # Dynamic Library - libpdfium.so

is_debug            = false                # Enable debugging features.

is_clang            = false                # Avoid dependency hell.


use_system_zlib     = true

use_system_libpng   = true

use_system_lcms2    = true

use_system_libjpeg  = true

use_libjpeg_turbo   = true

use_system_libopenjpeg2 = true

1. v8 지원

 v8 이란? 구글에서 개발하고 있는 C++ 로 작성된 오픈소스로, 고성능의 자바스크립트 와 웹 어셈블리 엔진이다. 크롬, Node.js 등에서 사용되며,  ECMAScript(ECMA-262) 와 웹어셈블리를 구현한다. Windows 7 이상, macOS 10.12 이상, Linux 시스템에서 동작한다.


 CentOS 7 에서 다음과 같이 설치할 수 있다.

$ sudo yum install v8 v8-devel


pdfium 소스에  v8 소스가 포함되어 함께 빌드되기 때문에, 따로 설치할 필요는 없다.


앞의 삽질들에서 C++14 지원 등의 컴파일러 문제로  v8 지원 기능을 끄고 테스트했으나, 컴파일러 제한을 없앤 지금 이제 이 옵션을 다시 켜고 컴파일해 본다.


args.gn

pdf_enable_v8       = true


PDF 파일을 만들 때, 자바스크립트를 쓰겠다는 것으로 추정되는데, 일단 빌드가 잘 되므로 해당 기능을 켠다.



v8 동적 라이브러리 유의!!!

v8 지원을 위한 shared library 로 빌드하게 되면, 

libv8.so libv8_libbase.so libv8_libplatform.so 등 3개의 v8 동적 라이브러리가 함께 생성된다.

이 라이브러리는 CentOS의 패키지중 v8-devel 에 포함된 libv8.so 와 이름이 같다.

주의가 필요하다.

2. xfa 지원

 xfa(XFA Form) 란? XML 포맷 아키텍처로 웹 폼 처리를 위해 JetForm 에 의해 개발된 독점적 XML 포맷이었다. 향후, PDF 1.5 표준에 사용될 수 있게 되었다. PDF 1.7 (ISO 32000-1) 의 완전한 응용에 필요한 외부 명세서로 참조된다.  XML 폼 아키텍처는 ISO 표준으로 표준화되지 않았으며, PDF 2.0 에서 사양권고 되었다.


주로 PDF 1.7 포맷의 Adobe 확장 포맷에서 사용된 것으로 보인다. 별로 중요하지 않은 기능으로 보인다.


pdf_enable_xfa 가 활성화되면 아래의 옵션이 영향을 받게 된다.

pdf_enable_xfa         = true

pdf_enable_xfa_bmp  = true

pdf_enable_xfa_gif    = true

pdf_enable_xfa_png   = true

pdf_enable_xfa_tiff     = true


해당 옵션을 모두 켜고 빌드해도 오류없이 잘 된다.


앞에서 만든 libpdfium 패키지에 위 옵션을 추가하고, 릴리스 버전을 2로 올리고, 빌드하고, 설치한다.

3. skia 

 Skia 는 2D 그래픽 라이브러리로, 구글의 크롬 또는 크롬 OS, 안드로이드등에서 그래픽 엔진을 위해 이용된다.  

 pdfium 은 디폴트로 Skia 를 사용하지 한고, Mapnik 등에서 검증(AGG 예전 버전을 고쳐서 사용하고 있다.) 된 AGG 라이브러리를 사용한다.


 아직 pdfium 에서의 skia 지원은 실험적이라 하니, 여기서는 실험적으로 테스트만 해 본다.


Cairo 와 같은 벡터 그래픽 엔진으로 보인다. Skia 는 Shadow 를 뜻하는 그리스어라 한다.


 Cairo 가 C 로 작성된것과 다르게 Skia 는 C++ 로 작성되었다.

 

Skia 를 빌드하기 위해서는 C++17 을 지원하는 툴체인이 있어야 한다.\


pdfium 과 마찬가지로 ninja 로 빌드한다.

$ git clone 'https://chromium.googlesource.com/chromium/tools/depot_tools.git'

$ export PATH="${PWD}/depot_tools:${PATH}"


$ git clone https://skia.googlesource.com/skia.git

$ cd skia

$ python2 tools/git-sync-deps

Skipping "../src".

buildtools                           > 505de88083136eefd056e5ee4ca0f01fe9b33de8

common                               > 9737551d7a52c3db3262db5856e6bcd62c462b92

third_party/externals/piex           > bb217acdca1cc0c16b704669dd6f91a1b509c406

third_party/externals/microhttpd     > 748945ec6f1c67b7efc934ab0808e1d32f2fb98d

third_party/externals/egl-registry   > a0bca08de07c7d7651047bedc0b653cfaaa4f2ae

third_party/externals/dng_sdk        > c8d0c9b1d16bfda56f15165d39e0ffa360a11123

third_party/externals/opencl-lib     > 4e6d30e406d2e5a65e1d65e404fe6df5f772a32b

third_party/externals/spirv-tools    > 0c4feb643b89d1792b02f7cbef315e9d95633bd7

third_party/externals/libjpeg-turbo  > 574f3a772c96dc9db2c98ef24706feb3f6dbda9a

third_party/externals/wuffs          > 4080840928c0b05a80cda0d14ac2e2615f679f1a

third_party/externals/zlib           > 47af7c547f8551bd25424e56354a2ae1e9062859

third_party/externals/dawn           > 3c086a0c2e1dc3e2e14aaa3d78c052c7e07274b4

...


$ mkdir -p out/static

$ mkdir -p out/shared


skia 는 pdfium 과 달리 args.gn  파일이 아니라, --args 로 설정값을 전달한다.

args 옵션이 추가되면, args.gn  파일이 생성된다.


일단, 해당 아규먼트 목록을 출력한다.

$ gn gen out/static

$ gn args out/static --list

ar

    Current value (from the default) = "ar"

      From //gn/BUILDCONFIG.gn:20


cc

    Current value (from the default) = "cc"

      From //gn/BUILDCONFIG.gn:21


cc_wrapper

    Current value (from the default) = ""

      From //gn/toolchain/BUILD.gn:35


clang_win

    Current value (from the default) = ""

      From //gn/BUILDCONFIG.gn:30


current_cpu

    Current value (from the default) = ""

      (Internally set; try `gn help current_cpu`.)


current_os

    Current value (from the default) = ""

      (Internally set; try `gn help current_os`.)


cxx

    Current value (from the default) = "c++"

      From //gn/BUILDCONFIG.gn:22


dlsymutil_pool_depth

    Current value (from the default) = 24

      From //gn/toolchain/BUILD.gn:42


    dsymutil seems to kill the machine when too many processes are run in

    parallel, so we need to use a pool to limit the concurrency when passing

    large -j to Ninja (e.g. Goma build). Unfortunately this is also one of the

    slowest steps in a build, so we don't want to limit too much. Use the number

    of CPUs as a default.


extra_asmflags
    Current value (from the default) = []
      From //gn/BUILD.gn:11

extra_cflags
    Current value (from the default) = []
      From //gn/BUILD.gn:12

extra_cflags_c
    Current value (from the default) = []
      From //gn/BUILD.gn:13

extra_cflags_cc
    Current value (from the default) = []
      From //gn/BUILD.gn:14

extra_ldflags
    Current value (from the default) = []
      From //gn/BUILD.gn:15

host_ar
    Current value (from the default) = "ar"
      From //gn/toolchain/BUILD.gn:6

host_cc
    Current value (from the default) = "cc"
      From //gn/toolchain/BUILD.gn:7

host_cpu
    Current value (from the default) = "x64"
      (Internally set; try `gn help host_cpu`.)

host_cxx
    Current value (from the default) = "c++"
      From //gn/toolchain/BUILD.gn:8

host_os
    Current value (from the default) = "linux"
      (Internally set; try `gn help host_os`.)

is_component_build
    Current value (from the default) = false
      From //gn/BUILDCONFIG.gn:12

is_debug
    Current value (from the default) = true
      From //gn/BUILDCONFIG.gn:36

is_official_build
    Current value (from the default) = false
      From //gn/BUILDCONFIG.gn:11

malloc
    Current value (from the default) = ""
      From //gn/BUILD.gn:17

ndk
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:13

ndk_api
    Current value (from the default) = 21
      From //gn/BUILDCONFIG.gn:16

    Android 5.0, Lollipop

paragraph_bench_enabled
    Current value (from the default) = false
      From //modules/skparagraph/BUILD.gn:8

paragraph_tests_enabled
    Current value (from the default) = true
      From //modules/skparagraph/BUILD.gn:7

sanitize
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:18

skia_android_serial
    Current value (from the default) = ""
      From //gn/skia.gni:12

skia_compile_processors
    Current value (from the default) = false
      From //gn/skia.gni:13

skia_enable_atlas_text
    Current value (from the default) = true
      From //gn/skia.gni:89

skia_enable_ccpr
    Current value (from the default) = true
      From //gn/skia.gni:14

skia_enable_discrete_gpu
    Current value (from the default) = true
      From //gn/skia.gni:15

skia_enable_flutter_defines
    Current value (from the default) = false
      From //gn/skia.gni:16

skia_enable_fontmgr_android
    Current value (from the default) = true
      From //gn/skia.gni:90

skia_enable_fontmgr_custom
    Current value (from the default) = false
      From //gn/skia.gni:92

skia_enable_fontmgr_custom_empty
    Current value (from the default) = false
      From //gn/skia.gni:93

skia_enable_fontmgr_empty
    Current value (from the default) = false
      From //gn/skia.gni:17

skia_enable_fontmgr_fuchsia
    Current value (from the default) = false
      From //gn/skia.gni:18

skia_enable_fontmgr_win
    Current value (from the default) = false
      From //gn/skia.gni:19

skia_enable_fontmgr_win_gdi
    Current value (from the default) = false
      From //gn/skia.gni:20

skia_enable_gpu
    Current value (from the default) = true
      From //gn/skia.gni:21

skia_enable_nvpr
    Current value (from the default) = true
      From //gn/skia.gni:94

skia_enable_particles
    Current value (from the default) = true
      From //modules/particles/BUILD.gn:7

skia_enable_pdf
    Current value (from the default) = true
      From //gn/skia.gni:22

skia_enable_skottie
    Current value (from the default) = true
      From //modules/skottie/BUILD.gn:9

skia_enable_skparagraph
    Current value (from the default) = true
      From //modules/skparagraph/BUILD.gn:6

skia_enable_skshaper
    Current value (from the default) = true
      From //modules/skshaper/BUILD.gn:9

skia_enable_sksl_interpreter
    Current value (from the default) = true
      From //gn/skia.gni:23

skia_enable_skvm_jit
    Current value (from the default) = true
      From //gn/skia.gni:25

skia_enable_spirv_validation
    Current value (from the default) = true
      From //gn/skia.gni:95

skia_enable_tools
    Current value (from the default) = true
      From //gn/skia.gni:27

skia_enable_vulkan_debug_layers
    Current value (from the default) = true
      From //gn/skia.gni:28

skia_generate_workarounds
    Current value (from the default) = false
      From //gn/skia.gni:29

skia_gl_standard
    Current value (from the default) = ""
      From //gn/skia.gni:76

skia_include_multiframe_procs
    Current value (from the default) = false
      From //gn/skia.gni:30

skia_lex
    Current value (from the default) = false
      From //gn/skia.gni:31

skia_libgifcodec_path
    Current value (from the default) = "third_party/externals/libgifcodec"
      From //gn/skia.gni:32

skia_moltenvk_path
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:32

skia_pdf_subset_harfbuzz
    Current value (from the default) = false
      From //gn/skia.gni:33

skia_qt_path
    Current value (from the default) = ""
      From //gn/skia.gni:34

skia_skqp_global_error_tolerance
    Current value (from the default) = 0
      From //gn/skia.gni:35

skia_tools_require_resources
    Current value (from the default) = false
      From //gn/skia.gni:36

skia_update_fuchsia_sdk
    Current value (from the default) = false
      From //gn/skia.gni:37

skia_use_angle
    Current value (from the default) = false
      From //gn/skia.gni:38

skia_use_dawn
    Current value (from the default) = false
      From //gn/skia.gni:39

skia_use_dng_sdk
    Current value (from the default) = true
      From //gn/skia.gni:96

skia_use_egl
    Current value (from the default) = false
      From //gn/skia.gni:40

skia_use_expat
    Current value (from the default) = true
      From //gn/skia.gni:41

skia_use_experimental_xform
    Current value (from the default) = false
      From //gn/skia.gni:42

skia_use_ffmpeg
    Current value (from the default) = false
      From //gn/skia.gni:43

skia_use_fixed_gamma_text
    Current value (from the default) = false
      From //gn/skia.gni:44

skia_use_fontconfig
    Current value (from the default) = true
      From //gn/skia.gni:45

skia_use_fonthost_mac
    Current value (from the default) = false
      From //gn/skia.gni:46

skia_use_freetype
    Current value (from the default) = true
      From //gn/skia.gni:47

skia_use_gl
    Current value (from the default) = true
      From //gn/skia.gni:49

skia_use_harfbuzz
    Current value (from the default) = true
      From //gn/skia.gni:48

skia_use_icu
    Current value (from the default) = true
      From //gn/skia.gni:50

skia_use_libgifcodec
    Current value (from the default) = true
      From //gn/skia.gni:97

skia_use_libheif
    Current value (from the default) = true
      From //gn/skia.gni:51

skia_use_libjpeg_turbo
    Current value (from the default) = true
      From //gn/skia.gni:52

skia_use_libpng
    Current value (from the default) = true
      From //gn/skia.gni:53

skia_use_libwebp
    Current value (from the default) = true
      From //gn/skia.gni:54

skia_use_lua
    Current value (from the default) = true
      From //gn/skia.gni:55

skia_use_metal
    Current value (from the default) = false
      From //gn/skia.gni:56

skia_use_opencl
    Current value (from the default) = false
      From //gn/skia.gni:57

skia_use_piex
    Current value (from the default) = true
      From //gn/skia.gni:58

skia_use_sfntly
    Current value (from the default) = true
      From //gn/skia.gni:98

skia_use_system_expat
    Current value (from the default) = false
      From //third_party/expat/BUILD.gn:7

skia_use_system_freetype2
    Current value (from the default) = true
      From //third_party/freetype2/BUILD.gn:9

skia_use_system_harfbuzz
    Current value (from the default) = false
      From //third_party/harfbuzz/BUILD.gn:10

skia_use_system_icu
    Current value (from the default) = false
      From //third_party/icu/BUILD.gn:11

skia_use_system_libjpeg_turbo
    Current value (from the default) = false
      From //third_party/libjpeg-turbo/BUILD.gn:7

skia_use_system_libpng
    Current value (from the default) = false
      From //third_party/libpng/BUILD.gn:7

skia_use_system_libwebp
    Current value (from the default) = false
      From //third_party/libwebp/BUILD.gn:7

skia_use_system_lua
    Current value (from the default) = false
      From //third_party/lua/BUILD.gn:7

skia_use_system_zlib
    Current value (from the default) = false
      From //third_party/zlib/BUILD.gn:7

skia_use_vulkan
    Current value (from the default) = false
      From //gn/skia.gni:84

skia_use_wuffs
    Current value (from the default) = false
      From //gn/skia.gni:59

skia_use_x11
    Current value (from the default) = true
      From //gn/skia.gni:60

skia_use_xps
    Current value (from the default) = true
      From //gn/skia.gni:61

skia_use_zlib
    Current value (from the default) = true
      From //gn/skia.gni:62

skia_vtune_path
    Current value (from the default) = ""
      From //gn/skia.gni:64

target_ar
    Current value (from the default) = "ar"
      From //gn/toolchain/BUILD.gn:30

target_cc
    Current value (from the default) = "cc"
      From //gn/toolchain/BUILD.gn:31

target_cpu
    Current value (from the default) = ""
      (Internally set; try `gn help target_cpu`.)

target_cxx
    Current value (from the default) = "c++"
      From //gn/toolchain/BUILD.gn:32

target_os
    Current value (from the default) = ""
      (Internally set; try `gn help target_os`.)

werror
    Current value (from the default) = false
      From //gn/BUILDCONFIG.gn:33

win_sdk
    Current value (from the default) = "C:/Program Files (x86)/Windows Kits/10"
      From //gn/BUILDCONFIG.gn:24

win_sdk_version
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:25

win_toolchain_version
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:28

win_vc
    Current value (from the default) = ""
      From //gn/BUILDCONFIG.gn:27

xcode_sysroot
    Current value (from the default) = ""
      From //gn/BUILD.gn:18


기본 아규먼트로만 테스트해본다.

is_official_build 는 라이브러리 최적화를 수행한다. pdfium  빌드 옵션에도 추가해주는것이 좋다.


$ gn gen out/static --args='is_official_build=true'

$ ninja -C out/static

 float8 Sqrt(float8 x) { return sqrt(x); }

        ^~~~

[3272/3272] link jitter_gms


[respiro@localhost static]$ ls *.a

libdng_sdk.a   libjpeg.a        libpiex.a    libskottie.a      libspvtools.a      libzlib_x86.a

libexpat.a     liblua.a         libpng.a     libskparagraph.a  libspvtools_val.a

libharfbuzz.a  libmicrohttpd.a  libsdl.a     libskresources.a  libwebp.a

libicu.a       libparticles.a   libsfntly.a  libsksg.a         libwebp_sse41.a

libimgui.a     libpathkit.a     libskia.a    libskshaper.a     libzlib.a


동적 라이브러리로 빌드하기

$ gn gen out/shared --args='is_official_build=true is_component_build=true '


$ ninja -C out/shared

..

c++ -MD -MF obj/src/codec/jpeg.SkJpegCodec.o.d -DNDEBUG -DSKIA_DLL -DSK_R32_SHIFT=16 -DSK_GAMMA_APPLY_TO_A8 -DSKIA_IMPLEMENTATION=1 -DSK_HAS_JPEG_LIBRARY -I../.. -fstrict-aliasing -fPIC -fvisibility=hidden -O3 -fdata-sections -ffunction-sections -Wno-unused-parameter -std=c++17 -fvisibility-inlines-hidden -fno-exceptions -fno-rtti -c ../../src/codec/SkJpegCodec.cpp -o obj/src/codec/jpeg.SkJpegCodec.o

../../src/codec/SkJpegCodec.cpp: In member function ‘virtual SkCodec::Result SkJpegCodec::onStartScanlineDecode(const SkImageInfo&, const SkCodec::Options&)’:

../../src/codec/SkJpegCodec.cpp:679:9: error: ‘jpeg_crop_scanline’ was not declared in this scope

         jpeg_crop_scanline(fDecoderMgr->dinfo(), &startX, &width);

         ^~~~~~~~~~~~~~~~~~

..

../../src/codec/SkJpegCodec.cpp: In member function ‘virtual bool SkJpegCodec::conversionSupported(const SkImageInfo&, bool, bool)’:

../../src/codec/SkJpegCodec.cpp:372:57: error: ‘JCS_RGB565’ was not declared in this scope

                 fDecoderMgr->dinfo()->out_color_space = JCS_RGB565;



오류가 발생했다. 시스템의 libjpeg-turbo 헤더를 물고가서 컴파일하고 있다.

임베드된 버전은 2.0 인데, 시스템은 그 전 버전으로 몇 가지 함수와 디파인이 빠져 있다.


....


삽질이 귀챦아졌다.  skia 는 skip 하자.


4. pdfium skia 

pdfium 에 포함된  third_party 의 skia 랑 같이 빌드하는 방법이 더 쉽겠다는 생각을 하게 된다.


args.gn 에 다음을 수정하자.

pdf_use_skia          = true                # Avoid skia backend experiment../

pdf_use_skia_paths  = false             # Avoid other skia backend experiment.


빌드가 오류없이 잘 된다.

$ cd out/static 

$ ninja pdfium_all

$ ./pdfium_embeddertest

...

../../testing/embedder_test.cpp:640: Failure

Expected equality of these values:

  expected_md5sum

    Which is: "b0170c575b65ecb93ebafada0ff0f038"

  HashBitmap(bitmap)

    Which is: "4e7e280c1597222afcb0ee3bb90ec119"

...

Expected equality of these values:

  expected_md5sum

    Which is: "ff6e5c509d1f6984bcdfd18b26a4203a"

  HashBitmap(bitmap)

    Which is: "4e7e280c1597222afcb0ee3bb90ec119"

[  FAILED  ] FPDFViewEmbedderTest.RenderManyRectanglesWithFlags (35 ms)

[ RUN      ] FPDFViewEmbedderTest.RenderHelloWorldWithFlags

../../testing/embedder_test.cpp:640: Failure

Expected equality of these values:

...
[  FAILED  ] 2 tests, listed below:
[  FAILED  ] FPDFViewEmbedderTest.RenderManyRectanglesWithFlags
[  FAILED  ] FPDFViewEmbedderTest.RenderHelloWorldWithFlags


이전 테스트에서 오류가 하나 더 생겼다.