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 파일을 만들 때, 자바스크립트를 쓰겠다는 것으로 추정되는데, 일단 빌드가 잘 되므로 해당 기능을 켠다.
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
이전 테스트에서 오류가 하나 더 생겼다.