mirror of
https://github.com/RetroDECK/ES-DE.git
synced 2024-11-25 07:35:38 +00:00
Added a PDF viewer
Also added the PoDoFo and Poppler libraries as dependencies
This commit is contained in:
parent
177dd23b7c
commit
bd2c229476
66
CMake/Packages/FindPoDoFo.cmake
Normal file
66
CMake/Packages/FindPoDoFo.cmake
Normal file
|
@ -0,0 +1,66 @@
|
||||||
|
# - Try to find the PoDoFo library
|
||||||
|
#
|
||||||
|
# Windows users MUST set when building:
|
||||||
|
#
|
||||||
|
# PoDoFo_USE_SHARED - whether use PoDoFo as shared library
|
||||||
|
#
|
||||||
|
# Once done this will define:
|
||||||
|
#
|
||||||
|
# PoDoFo_FOUND - system has the PoDoFo library
|
||||||
|
# PoDoFo_INCLUDE_DIRS - the PoDoFo include directory
|
||||||
|
# PoDoFo_LIBRARIES - the libraries needed to use PoDoFo
|
||||||
|
# PoDoFo_DEFINITIONS - the definitions needed to use PoDoFo
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
# SPDX-FileCopyrightText: 2016 Pino Toscano <pino@kde.org>
|
||||||
|
|
||||||
|
|
||||||
|
find_path(PoDoFo_INCLUDE_DIRS
|
||||||
|
NAMES podofo/podofo.h
|
||||||
|
)
|
||||||
|
find_library(PoDoFo_LIBRARIES
|
||||||
|
NAMES libpodofo podofo
|
||||||
|
)
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(PoDoFo DEFAULT_MSG PoDoFo_LIBRARIES PoDoFo_INCLUDE_DIRS)
|
||||||
|
|
||||||
|
set(PoDoFo_DEFINITIONS)
|
||||||
|
if(PoDoFo_FOUND)
|
||||||
|
if(WIN32)
|
||||||
|
if(NOT DEFINED PoDoFo_USE_SHARED)
|
||||||
|
message(SEND_ERROR "Win32 users MUST set PoDoFo_USE_SHARED")
|
||||||
|
message(SEND_ERROR "Set -DPoDoFo_USE_SHARED=0 if linking to a static library PoDoFo")
|
||||||
|
message(SEND_ERROR "or -DPoDoFo_USE_SHARED=1 if linking to a DLL build of PoDoFo")
|
||||||
|
message(FATAL_ERROR "PoDoFo_USE_SHARED unset on win32 build")
|
||||||
|
else()
|
||||||
|
if(PoDoFo_USE_SHARED)
|
||||||
|
set(PoDoFo_DEFINITIONS "${PoDoFo_DEFINITIONS} -DUSING_SHARED_PODOFO")
|
||||||
|
endif(PoDoFo_USE_SHARED)
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# PoDoFo-0.9.5 unconditionally includes openssl/opensslconf.h in a public
|
||||||
|
# header. The fix is in https://sourceforge.net/p/podofo/code/1830/ and will
|
||||||
|
# hopefully be released soon with 0.9.6. Note that krename doesn't use
|
||||||
|
# OpenSSL in any way.
|
||||||
|
file(STRINGS "${PoDoFo_INCLUDE_DIRS}/podofo/base/podofo_config.h" PoDoFo_MAJOR_VER_LINE REGEX "^#define[ \t]+PODOFO_VERSION_MAJOR[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${PoDoFo_INCLUDE_DIRS}/podofo/base/podofo_config.h" PoDoFo_MINOR_VER_LINE REGEX "^#define[ \t]+PODOFO_VERSION_MINOR[ \t]+[0-9]+$")
|
||||||
|
file(STRINGS "${PoDoFo_INCLUDE_DIRS}/podofo/base/podofo_config.h" PoDoFo_PATCH_VER_LINE REGEX "^#define[ \t]+PODOFO_VERSION_PATCH[ \t]+[0-9]+$")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+PODOFO_VERSION_MAJOR[ \t]+([0-9]+)$" "\\1" PoDoFo_MAJOR_VER "${PoDoFo_MAJOR_VER_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+PODOFO_VERSION_MINOR[ \t]+([0-9]+)$" "\\1" PoDoFo_MINOR_VER "${PoDoFo_MINOR_VER_LINE}")
|
||||||
|
string(REGEX REPLACE "^#define[ \t]+PODOFO_VERSION_PATCH[ \t]+([0-9]+)$" "\\1" PoDoFo_PATCH_VER "${PoDoFo_PATCH_VER_LINE}")
|
||||||
|
set(PoDoFo_VERSION "${PoDoFo_MAJOR_VER}.${PoDoFo_MINOR_VER}.${PoDoFo_PATCH_VER}")
|
||||||
|
if(PoDoFo_VERSION VERSION_EQUAL "0.9.5")
|
||||||
|
find_package(OpenSSL)
|
||||||
|
if (OpenSSL_FOUND)
|
||||||
|
message("OpenSSL found, which is required for this version of PoDofo (0.9.5)")
|
||||||
|
set(PoDoFo_INCLUDE_DIRS ${PoDoFo_INCLUDE_DIRS} ${OPENSSL_INCLUDE_DIR})
|
||||||
|
else()
|
||||||
|
unset(PoDoFo_FOUND)
|
||||||
|
message("OpenSSL NOT found, which is required for this version of PoDofo (0.9.5)")
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
mark_as_advanced(PoDoFo_INCLUDE_DIRS PoDoFo_LIBRARIES PoDoFo_DEFINITIONS)
|
178
CMake/Packages/FindPoppler.cmake
Normal file
178
CMake/Packages/FindPoppler.cmake
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
# - Try to find Poppler and specified components: {cpp, Qt4, Qt5}
|
||||||
|
# Once done this will define:
|
||||||
|
#
|
||||||
|
# POPPLER_FOUND - system has Poppler and specified components
|
||||||
|
# POPPLER_INCLUDE_DIRS - The include directories for Poppler headers
|
||||||
|
# POPPLER_LIBRARIES - Link these to use Poppler
|
||||||
|
# POPPLER_NEEDS_FONTCONFIG - A boolean indicating if libpoppler depends on libfontconfig
|
||||||
|
# POPPLER_HAS_XPDF - A boolean indicating if libpoppler headers are available
|
||||||
|
# POPPLER_INCLUDE_DIR - the include directory for libpoppler XPDF headers
|
||||||
|
#
|
||||||
|
# Redistribution and use of this file is allowed according to the terms of the
|
||||||
|
# MIT license. For details see the file COPYING-CMAKE-MODULES.
|
||||||
|
|
||||||
|
if( POPPLER_LIBRARIES )
|
||||||
|
# in cache already
|
||||||
|
set( Poppler_FIND_QUIETLY TRUE )
|
||||||
|
endif( POPPLER_LIBRARIES )
|
||||||
|
|
||||||
|
# Check which components we need to find
|
||||||
|
list(FIND Poppler_FIND_COMPONENTS "cpp" FIND_POS)
|
||||||
|
if(${FIND_POS} EQUAL -1)
|
||||||
|
set(FIND_CPP FALSE)
|
||||||
|
else()
|
||||||
|
set(FIND_CPP TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(FIND Poppler_FIND_COMPONENTS "Qt4" FIND_POS)
|
||||||
|
if(${FIND_POS} EQUAL -1)
|
||||||
|
set(FIND_QT4 FALSE)
|
||||||
|
else()
|
||||||
|
set(FIND_QT4 TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
list(FIND Poppler_FIND_COMPONENTS "Qt5" FIND_POS)
|
||||||
|
if(${FIND_POS} EQUAL -1)
|
||||||
|
set(FIND_QT5 FALSE)
|
||||||
|
else()
|
||||||
|
set(FIND_QT5 TRUE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Default values
|
||||||
|
set(POPPLER_FOUND FALSE)
|
||||||
|
set(POPPLER_INCLUDE_DIRS)
|
||||||
|
set(POPPLER_LIBRARIES)
|
||||||
|
set(POPPLER_REQUIRED "POPPLER_LIBRARY")
|
||||||
|
|
||||||
|
# use pkg-config to get the directories and then use these values
|
||||||
|
# in the find_path() and find_library() calls
|
||||||
|
if( NOT WIN32 )
|
||||||
|
find_package(PkgConfig)
|
||||||
|
|
||||||
|
pkg_check_modules(POPPLER_PKG QUIET poppler)
|
||||||
|
if( FIND_CPP )
|
||||||
|
pkg_check_modules(POPPLER_CPP_PKG QUIET poppler-cpp)
|
||||||
|
endif()
|
||||||
|
if( FIND_QT4 )
|
||||||
|
pkg_check_modules(POPPLER_QT4_PKG QUIET poppler-qt4)
|
||||||
|
endif()
|
||||||
|
if( FIND_QT5 )
|
||||||
|
pkg_check_modules(POPPLER_QT5_PKG QUIET poppler-qt5)
|
||||||
|
endif()
|
||||||
|
endif( NOT WIN32 )
|
||||||
|
|
||||||
|
# Check for Poppler headers (optional)
|
||||||
|
find_path( POPPLER_INCLUDE_DIR NAMES poppler-config.h PATH_SUFFIXES poppler )
|
||||||
|
if( NOT( POPPLER_INCLUDE_DIR ) )
|
||||||
|
#if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
# message( STATUS "Could not find poppler-config.h, recompile Poppler with "
|
||||||
|
# "ENABLE_XPDF_HEADERS to link against libpoppler directly." )
|
||||||
|
#endif()
|
||||||
|
set( POPPLER_HAS_XPDF FALSE )
|
||||||
|
else()
|
||||||
|
set( POPPLER_HAS_XPDF TRUE )
|
||||||
|
list(APPEND POPPLER_INCLUDE_DIRS ${POPPLER_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Find libpoppler (Required)
|
||||||
|
find_library( POPPLER_LIBRARY NAMES poppler ${POPPLER_CPP_PKG_LIBRARIES}
|
||||||
|
HINTS ${POPPLER_PKG_LIBDIR} ${POPPLER_CPP_PKG_LIBDIR} )
|
||||||
|
if( NOT(POPPLER_LIBRARY) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find libpoppler." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else( NOT(POPPLER_LIBRARY) )
|
||||||
|
list(APPEND POPPLER_LIBRARIES ${POPPLER_LIBRARY})
|
||||||
|
|
||||||
|
# Scan poppler libraries for dependencies on Fontconfig
|
||||||
|
include(GetPrerequisites)
|
||||||
|
mark_as_advanced(gp_cmd)
|
||||||
|
GET_PREREQUISITES("${POPPLER_LIBRARY}" POPPLER_PREREQS 1 0 "" "")
|
||||||
|
if("${POPPLER_PREREQS}" MATCHES "fontconfig")
|
||||||
|
set(POPPLER_NEEDS_FONTCONFIG TRUE)
|
||||||
|
else()
|
||||||
|
set(POPPLER_NEEDS_FONTCONFIG FALSE)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# cpp Component
|
||||||
|
if( FIND_CPP )
|
||||||
|
list(APPEND POPPLER_REQUIRED POPPLER_CPP_INCLUDE_DIR POPPLER_CPP_LIBRARY)
|
||||||
|
find_path( POPPLER_CPP_INCLUDE_DIR NAMES poppler-version.h
|
||||||
|
HINTS ${POPPLER_PKG_INCLUDEDIR} ${POPPLER_CPP_PKG_INCLUDEDIR}
|
||||||
|
PATH_SUFFIXES cpp poppler/cpp )
|
||||||
|
if( NOT(POPPLER_CPP_INCLUDE_DIR) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find Poppler cpp wrapper headers." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_INCLUDE_DIRS ${POPPLER_CPP_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
find_library(
|
||||||
|
POPPLER_CPP_LIBRARY NAMES poppler-cpp ${POPPLER_CPP_PKG_LIBRARIES}
|
||||||
|
HINTS ${POPPLER_PKG_LIBDIR} ${POPPLER_CPP_PKG_LIBDIR} )
|
||||||
|
if( NOT(POPPLER_CPP_LIBRARY) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find libpoppler-cpp." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_LIBRARIES ${POPPLER_CPP_LIBRARY})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Qt4 Component
|
||||||
|
if( FIND_QT4 )
|
||||||
|
list(APPEND POPPLER_REQUIRED POPPLER_QT4_INCLUDE_DIR POPPLER_QT4_LIBRARY)
|
||||||
|
find_path(POPPLER_QT4_INCLUDE_DIR NAMES poppler-qt4.h poppler-link.h
|
||||||
|
HINTS ${POPPLER_PKG_INCLUDEDIR} ${POPPLER_CPP_QT4_INCLUDEDIR}
|
||||||
|
PATH_SUFFIXES qt4 poppler/qt4 )
|
||||||
|
if( NOT(POPPLER_QT4_INCLUDE_DIR) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find Poppler-Qt4 headers." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_INCLUDE_DIRS ${POPPLER_QT4_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
find_library(
|
||||||
|
POPPLER_QT4_LIBRARY NAMES poppler-qt4 ${POPPLER_QT4_PKG_LIBRARIES}
|
||||||
|
HINTS ${POPPLER_PKG_LIBDIR} ${POPPLER_QT4_PKG_LIBDIR} )
|
||||||
|
if( NOT(POPPLER_QT4_LIBRARY) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find libpoppler-qt4." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_LIBRARIES ${POPPLER_QT4_LIBRARY})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
|
# Qt5 Component
|
||||||
|
if( FIND_QT5 )
|
||||||
|
list(APPEND POPPLER_REQUIRED POPPLER_QT5_INCLUDE_DIR POPPLER_QT5_LIBRARY)
|
||||||
|
find_path(POPPLER_QT5_INCLUDE_DIR NAMES poppler-qt5.h poppler-link.h
|
||||||
|
HINTS ${POPPLER_QT5_INCLUDEDIR} ${POPPLER_QT5_PKG_INCLUDEDIR}
|
||||||
|
PATH_SUFFIXES qt5 poppler/qt5 )
|
||||||
|
if( NOT(POPPLER_QT5_INCLUDE_DIR) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message( STATUS "Could not find Poppler-Qt5 headers." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_INCLUDE_DIRS ${POPPLER_QT5_INCLUDE_DIR})
|
||||||
|
endif()
|
||||||
|
find_library(
|
||||||
|
POPPLER_QT5_LIBRARY NAMES poppler-qt5 ${POPPLER_QT5_PKG_LIBRARIES}
|
||||||
|
HINTS ${POPPLER_PKG_LIBDIR} ${POPPLER_QT5_PKG_LIBDIR} )
|
||||||
|
if( NOT(POPPLER_QT5_LIBRARY) )
|
||||||
|
if( NOT Poppler_FIND_QUIETLY )
|
||||||
|
message(STATUS "Could not find libpoppler-qt5." )
|
||||||
|
endif( NOT Poppler_FIND_QUIETLY )
|
||||||
|
else()
|
||||||
|
list(APPEND POPPLER_LIBRARIES ${POPPLER_QT5_LIBRARY})
|
||||||
|
endif()
|
||||||
|
endif()
|
||||||
|
endif( NOT(POPPLER_LIBRARY) )
|
||||||
|
|
||||||
|
include(FindPackageHandleStandardArgs)
|
||||||
|
find_package_handle_standard_args(Poppler DEFAULT_MSG ${POPPLER_REQUIRED})
|
||||||
|
|
||||||
|
mark_as_advanced(POPPLER_CPP_INCLUDE_DIR POPPLER_QT4_INCLUDE_DIR
|
||||||
|
POPPLER_QT5_INCLUDE_DIR POPPLER_LIBRARIES POPPLER_CPP_LIBRARY
|
||||||
|
POPPLER_QT4_LIBRARY POPPLER_QT5_LIBRARY)
|
|
@ -135,6 +135,7 @@ elseif(NOT EMSCRIPTEN)
|
||||||
find_package(FreeImage REQUIRED)
|
find_package(FreeImage REQUIRED)
|
||||||
find_package(Freetype REQUIRED)
|
find_package(Freetype REQUIRED)
|
||||||
find_package(Libgit2 REQUIRED)
|
find_package(Libgit2 REQUIRED)
|
||||||
|
find_package(PoDoFo REQUIRED)
|
||||||
find_package(Pugixml REQUIRED)
|
find_package(Pugixml REQUIRED)
|
||||||
find_package(SDL2 REQUIRED)
|
find_package(SDL2 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
@ -455,6 +456,7 @@ else()
|
||||||
${FreeImage_INCLUDE_DIRS}
|
${FreeImage_INCLUDE_DIRS}
|
||||||
${FREETYPE_INCLUDE_DIRS}
|
${FREETYPE_INCLUDE_DIRS}
|
||||||
${GIT2_INCLUDE_PATH}
|
${GIT2_INCLUDE_PATH}
|
||||||
|
${PoDoFo_INCLUDE_DIRS}
|
||||||
${PUGIXML_INCLUDE_DIRS}
|
${PUGIXML_INCLUDE_DIRS}
|
||||||
${SDL2_INCLUDE_DIR})
|
${SDL2_INCLUDE_DIR})
|
||||||
endif()
|
endif()
|
||||||
|
@ -571,6 +573,7 @@ else()
|
||||||
${FreeImage_LIBRARIES}
|
${FreeImage_LIBRARIES}
|
||||||
${FREETYPE_LIBRARIES}
|
${FREETYPE_LIBRARIES}
|
||||||
${GIT2_LIBRARY}
|
${GIT2_LIBRARY}
|
||||||
|
${PoDoFo_LIBRARIES}
|
||||||
${PUGIXML_LIBRARIES}
|
${PUGIXML_LIBRARIES}
|
||||||
${SDL2_LIBRARY})
|
${SDL2_LIBRARY})
|
||||||
endif()
|
endif()
|
||||||
|
@ -626,10 +629,13 @@ set(EXECUTABLE_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
|
||||||
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
|
set(LIBRARY_OUTPUT_PATH ${dir} CACHE PATH "Build directory" FORCE)
|
||||||
|
|
||||||
# Add each component.
|
# Add each component.
|
||||||
|
add_subdirectory(es-pdf-converter)
|
||||||
add_subdirectory(external)
|
add_subdirectory(external)
|
||||||
add_subdirectory(es-core)
|
add_subdirectory(es-core)
|
||||||
add_subdirectory(es-app)
|
add_subdirectory(es-app)
|
||||||
|
|
||||||
# Make sure rlottie is built before es-core and set lottie2gif to not be built.
|
# Make sure that es-pdf-convert is built first, and then that rlottie is built before es-core.
|
||||||
|
# Also set lottie2gif to not be built.
|
||||||
|
add_dependencies(lunasvg es-pdf-convert)
|
||||||
add_dependencies(es-core rlottie)
|
add_dependencies(es-core rlottie)
|
||||||
set_target_properties(lottie2gif PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
set_target_properties(lottie2gif PROPERTIES EXCLUDE_FROM_ALL 1 EXCLUDE_FROM_DEFAULT_BUILD 1)
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# EmulationStation Desktop Edition
|
# EmulationStation Desktop Edition
|
||||||
# CMakeLists.txt (es-app)
|
# CMakeLists.txt (es-app)
|
||||||
#
|
#
|
||||||
# CMake configuration for es-app.
|
# CMake configuration for es-app
|
||||||
# Also contains the application packaging configuration.
|
# Also contains the application packaging configuration.
|
||||||
#
|
#
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ set(ES_HEADERS
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MiximageGenerator.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MiximageGenerator.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.h
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/PDFViewer.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Screensaver.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Screensaver.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.h
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UIModeController.h
|
${CMAKE_CURRENT_SOURCE_DIR}/src/UIModeController.h
|
||||||
|
@ -70,6 +71,7 @@ set(ES_SOURCES
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MetaData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/MiximageGenerator.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/MiximageGenerator.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/PlatformId.cpp
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/src/PDFViewer.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/Screensaver.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/Screensaver.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/SystemData.cpp
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/src/UIModeController.cpp
|
${CMAKE_CURRENT_SOURCE_DIR}/src/UIModeController.cpp
|
||||||
|
@ -228,6 +230,7 @@ elseif(APPLE)
|
||||||
install(DIRECTORY ${CMAKE_SOURCE_DIR}/licenses DESTINATION ../Resources)
|
install(DIRECTORY ${CMAKE_SOURCE_DIR}/licenses DESTINATION ../Resources)
|
||||||
else()
|
else()
|
||||||
install(TARGETS emulationstation RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
install(TARGETS emulationstation RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
|
install(TARGETS es-pdf-convert RUNTIME DESTINATION ${CMAKE_INSTALL_PREFIX}/bin)
|
||||||
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
if(CMAKE_SYSTEM_NAME MATCHES Linux)
|
||||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/emulationstation.6.gz
|
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/assets/emulationstation.6.gz
|
||||||
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man6)
|
DESTINATION ${CMAKE_INSTALL_PREFIX}/share/man/man6)
|
||||||
|
|
|
@ -47,6 +47,14 @@ void MediaViewer::stopMediaViewer()
|
||||||
mImages.clear();
|
mImages.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MediaViewer::launchPDFViewer()
|
||||||
|
{
|
||||||
|
if (mGame->getManualPath() != "") {
|
||||||
|
Window::getInstance()->stopMediaViewer();
|
||||||
|
Window::getInstance()->startPDFViewer(mGame);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void MediaViewer::update(int deltaTime)
|
void MediaViewer::update(int deltaTime)
|
||||||
{
|
{
|
||||||
if (mVideo)
|
if (mVideo)
|
||||||
|
|
|
@ -21,6 +21,7 @@ public:
|
||||||
|
|
||||||
bool startMediaViewer(FileData* game) override;
|
bool startMediaViewer(FileData* game) override;
|
||||||
void stopMediaViewer() override;
|
void stopMediaViewer() override;
|
||||||
|
void launchPDFViewer() override;
|
||||||
|
|
||||||
void update(int deltaTime) override;
|
void update(int deltaTime) override;
|
||||||
void render(const glm::mat4& parentTrans) override;
|
void render(const glm::mat4& parentTrans) override;
|
||||||
|
|
268
es-app/src/PDFViewer.cpp
Normal file
268
es-app/src/PDFViewer.cpp
Normal file
|
@ -0,0 +1,268 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// PDFViewer.cpp
|
||||||
|
//
|
||||||
|
// Parses PDF documents using the PoDoFo library and renders pages using the Poppler
|
||||||
|
// library via the external es-pdf-convert binary.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "PDFViewer.h"
|
||||||
|
|
||||||
|
#include "Log.h"
|
||||||
|
#include "Sound.h"
|
||||||
|
#include "utils/FileSystemUtil.h"
|
||||||
|
|
||||||
|
#define DEBUG_PDF_CONVERSION false
|
||||||
|
|
||||||
|
PDFViewer::PDFViewer()
|
||||||
|
: mRenderer {Renderer::getInstance()}
|
||||||
|
{
|
||||||
|
Window::getInstance()->setPDFViewer(this);
|
||||||
|
mTexture = TextureResource::get("");
|
||||||
|
mPages.clear();
|
||||||
|
mPageImage.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PDFViewer::startPDFViewer(FileData* game)
|
||||||
|
{
|
||||||
|
mManualPath = game->getManualPath();
|
||||||
|
|
||||||
|
if (!Utils::FileSystem::exists(mManualPath)) {
|
||||||
|
LOG(LogError) << "No PDF manual found for game \"" << game->getName() << "\"";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
LOG(LogDebug) << "PDFViewer::startPDFViewer(): Opening document \"" << mManualPath << "\"";
|
||||||
|
|
||||||
|
PoDoFo::PdfMemDocument pdf;
|
||||||
|
mPages.clear();
|
||||||
|
mPageCount = 0;
|
||||||
|
mCurrentPage = 0;
|
||||||
|
mScaleFactor = 1.0f;
|
||||||
|
|
||||||
|
try {
|
||||||
|
pdf.Load(mManualPath.c_str());
|
||||||
|
}
|
||||||
|
catch (PoDoFo::PdfError& e) {
|
||||||
|
LOG(LogError) << "PDFViewer: Couldn't load file \"" << mManualPath << "\", PoDoFo error \""
|
||||||
|
<< e.what() << ": " << e.ErrorMessage(e.GetError()) << "\"";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if (DEBUG_PDF_CONVERSION)
|
||||||
|
PoDoFo::EPdfVersion versionEPdf {pdf.GetPdfVersion()};
|
||||||
|
std::string version {"unknown"};
|
||||||
|
|
||||||
|
switch (versionEPdf) {
|
||||||
|
case 0:
|
||||||
|
version = "1.0";
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
version = "1.1";
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
version = "1.2";
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
version = "1.3";
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
version = "1.4";
|
||||||
|
break;
|
||||||
|
case 5:
|
||||||
|
version = "1.5";
|
||||||
|
break;
|
||||||
|
case 6:
|
||||||
|
version = "1.6";
|
||||||
|
break;
|
||||||
|
case 7:
|
||||||
|
version = "1.7";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
version = "unknown";
|
||||||
|
};
|
||||||
|
|
||||||
|
LOG(LogDebug) << "PDF version: " << version;
|
||||||
|
LOG(LogDebug) << "Page count: " << pdf.GetPageCount();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mPageCount = static_cast<int>(pdf.GetPageCount());
|
||||||
|
|
||||||
|
for (int i {0}; i < mPageCount; ++i) {
|
||||||
|
const int rotation {pdf.GetPage(i)->GetRotation()};
|
||||||
|
const PoDoFo::PdfRect cropBox {pdf.GetPage(i)->GetCropBox()};
|
||||||
|
float width {static_cast<float>(cropBox.GetWidth())};
|
||||||
|
float height {static_cast<float>(cropBox.GetHeight())};
|
||||||
|
|
||||||
|
if (rotation != 0 && rotation != 180)
|
||||||
|
std::swap(width, height);
|
||||||
|
|
||||||
|
// Maintain page aspect ratio.
|
||||||
|
glm::vec2 textureSize {glm::vec2 {width, height}};
|
||||||
|
const glm::vec2 targetSize {glm::vec2 {mRenderer->getScreenWidth() * mScaleFactor,
|
||||||
|
mRenderer->getScreenHeight() * mScaleFactor}};
|
||||||
|
glm::vec2 resizeScale {targetSize.x / textureSize.x, targetSize.y / textureSize.y};
|
||||||
|
|
||||||
|
if (resizeScale.x < resizeScale.y) {
|
||||||
|
textureSize.x *= resizeScale.x;
|
||||||
|
textureSize.y = std::min(textureSize.y * resizeScale.x, targetSize.y);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
textureSize.y *= resizeScale.y;
|
||||||
|
textureSize.x = std::min((textureSize.y / height) * width, targetSize.x);
|
||||||
|
}
|
||||||
|
|
||||||
|
const int textureWidth {static_cast<int>(std::round(textureSize.x))};
|
||||||
|
const int textureHeight {static_cast<int>(std::round(textureSize.y))};
|
||||||
|
|
||||||
|
#if (DEBUG_PDF_CONVERSION)
|
||||||
|
LOG(LogDebug) << "Page " << i + 1 << ": Rotation: " << rotation << " degrees / "
|
||||||
|
<< "Crop box width: " << width << " / "
|
||||||
|
<< "Crop box height: " << height << " / "
|
||||||
|
<< "Size ratio: " << width / height << " / "
|
||||||
|
<< "Texture size: " << textureWidth << "x" << textureHeight;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mPages[i + 1] = PageEntry {textureWidth, textureHeight, {}};
|
||||||
|
}
|
||||||
|
|
||||||
|
mCurrentPage = 1;
|
||||||
|
convertPage(mCurrentPage);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::stopPDFViewer()
|
||||||
|
{
|
||||||
|
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
mPages.clear();
|
||||||
|
mPageImage.reset();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::convertPage(int pageNum)
|
||||||
|
{
|
||||||
|
assert(pageNum <= static_cast<int>(mPages.size()));
|
||||||
|
|
||||||
|
const std::string esConvertPath {Utils::FileSystem::getExePath() + "/es-pdf-convert"};
|
||||||
|
if (!Utils::FileSystem::exists(esConvertPath)) {
|
||||||
|
LOG(LogError) << "Couldn't find PDF conversion binary es-pdf-convert";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string command {Utils::FileSystem::getEscapedPath(esConvertPath)};
|
||||||
|
command.append(" ")
|
||||||
|
.append(Utils::FileSystem::getEscapedPath(mManualPath))
|
||||||
|
.append(" ")
|
||||||
|
.append(std::to_string(pageNum))
|
||||||
|
.append(" ")
|
||||||
|
.append(std::to_string(mPages[pageNum].width))
|
||||||
|
.append(" ")
|
||||||
|
.append(std::to_string(mPages[pageNum].height));
|
||||||
|
|
||||||
|
if (mPages[pageNum].imageData.empty()) {
|
||||||
|
#if (DEBUG_PDF_CONVERSION)
|
||||||
|
LOG(LogDebug) << "Converting page: " << mCurrentPage;
|
||||||
|
LOG(LogDebug) << command;
|
||||||
|
#endif
|
||||||
|
FILE* commandPipe;
|
||||||
|
std::array<char, 512> buffer {};
|
||||||
|
std::string imageData;
|
||||||
|
int returnValue;
|
||||||
|
|
||||||
|
if (!(commandPipe = reinterpret_cast<FILE*>(popen(command.c_str(), "r")))) {
|
||||||
|
LOG(LogError) << "Couldn't open pipe to es-pdf-convert";
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (fread(buffer.data(), 1, 512, commandPipe)) {
|
||||||
|
mPages[pageNum].imageData.insert(mPages[pageNum].imageData.end(),
|
||||||
|
std::make_move_iterator(buffer.begin()),
|
||||||
|
std::make_move_iterator(buffer.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
returnValue = pclose(commandPipe);
|
||||||
|
size_t imageDataSize {mPages[pageNum].imageData.size()};
|
||||||
|
|
||||||
|
if (returnValue != 0 || (static_cast<int>(imageDataSize) <
|
||||||
|
mPages[pageNum].width * mPages[pageNum].height * 4)) {
|
||||||
|
LOG(LogError) << "Error reading PDF file";
|
||||||
|
mPages[pageNum].imageData.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
#if (DEBUG_PDF_CONVERSION)
|
||||||
|
LOG(LogDebug) << "Using cached texture for page: " << mCurrentPage;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
mPageImage.reset();
|
||||||
|
mPageImage = std::make_unique<ImageComponent>(false, false);
|
||||||
|
mPageImage->setOrigin(0.5f, 0.5f);
|
||||||
|
mPageImage->setPosition(mRenderer->getScreenWidth() / 2.0f,
|
||||||
|
mRenderer->getScreenHeight() / 2.0f);
|
||||||
|
|
||||||
|
mPageImage->setFlipY(true);
|
||||||
|
mPageImage->setMaxSize(
|
||||||
|
glm::vec2 {mPages[pageNum].width / mScaleFactor, mPages[pageNum].height / mScaleFactor});
|
||||||
|
mPageImage->setRawImage(reinterpret_cast<const unsigned char*>(&mPages[pageNum].imageData[0]),
|
||||||
|
mPages[pageNum].width, mPages[pageNum].height);
|
||||||
|
|
||||||
|
#if (DEBUG_PDF_CONVERSION)
|
||||||
|
LOG(LogDebug) << "ABGR32 data stream size: " << mPages[pageNum].imageData.size();
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::render(const glm::mat4& /*parentTrans*/)
|
||||||
|
{
|
||||||
|
glm::mat4 trans {Renderer::getIdentity()};
|
||||||
|
mRenderer->setMatrix(trans);
|
||||||
|
|
||||||
|
// Render a black background below the document.
|
||||||
|
mRenderer->drawRect(0.0f, 0.0f, Renderer::getScreenWidth(), Renderer::getScreenHeight(),
|
||||||
|
0x000000FF, 0x000000FF);
|
||||||
|
|
||||||
|
if (mPageImage != nullptr) {
|
||||||
|
mPageImage->render(trans);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::showNextPage()
|
||||||
|
{
|
||||||
|
if (mCurrentPage == mPageCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
++mCurrentPage;
|
||||||
|
convertPage(mCurrentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::showPreviousPage()
|
||||||
|
{
|
||||||
|
if (mCurrentPage == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
--mCurrentPage;
|
||||||
|
convertPage(mCurrentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::showFirstPage()
|
||||||
|
{
|
||||||
|
if (mCurrentPage == 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
mCurrentPage = 1;
|
||||||
|
convertPage(mCurrentPage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PDFViewer::showLastPage()
|
||||||
|
{
|
||||||
|
if (mCurrentPage == mPageCount)
|
||||||
|
return;
|
||||||
|
|
||||||
|
NavigationSounds::getInstance().playThemeNavigationSound(SCROLLSOUND);
|
||||||
|
mCurrentPage = mPageCount;
|
||||||
|
convertPage(mCurrentPage);
|
||||||
|
}
|
56
es-app/src/PDFViewer.h
Normal file
56
es-app/src/PDFViewer.h
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
// SPDX-License-Identifier: MIT
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition
|
||||||
|
// PDFViewer.h
|
||||||
|
//
|
||||||
|
// Parses PDF documents using the PoDoFo library and renders pages using the Poppler
|
||||||
|
// library via the external es-pdf-convert binary.
|
||||||
|
//
|
||||||
|
|
||||||
|
#ifndef ES_APP_PDF_VIEWER_H
|
||||||
|
#define ES_APP_PDF_VIEWER_H
|
||||||
|
|
||||||
|
#include "FileData.h"
|
||||||
|
#include "Window.h"
|
||||||
|
#include "components/ImageComponent.h"
|
||||||
|
|
||||||
|
#include <podofo/podofo.h>
|
||||||
|
|
||||||
|
class PDFViewer : public Window::PDFViewer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PDFViewer();
|
||||||
|
~PDFViewer() { stopPDFViewer(); }
|
||||||
|
|
||||||
|
bool startPDFViewer(FileData* game) override;
|
||||||
|
void stopPDFViewer() override;
|
||||||
|
|
||||||
|
void convertPage(int pageNum);
|
||||||
|
|
||||||
|
void render(const glm::mat4& parentTrans) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void showNextPage() override;
|
||||||
|
void showPreviousPage() override;
|
||||||
|
void showFirstPage() override;
|
||||||
|
void showLastPage() override;
|
||||||
|
|
||||||
|
struct PageEntry {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
std::vector<char> imageData;
|
||||||
|
};
|
||||||
|
|
||||||
|
Renderer* mRenderer;
|
||||||
|
std::shared_ptr<TextureResource> mTexture;
|
||||||
|
std::unique_ptr<ImageComponent> mPageImage;
|
||||||
|
std::map<int, PageEntry> mPages;
|
||||||
|
|
||||||
|
float mScaleFactor;
|
||||||
|
int mCurrentPage;
|
||||||
|
int mPageCount;
|
||||||
|
|
||||||
|
std::string mManualPath;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // ES_APP_PDF_VIEWER_H
|
|
@ -25,6 +25,7 @@
|
||||||
#include "Log.h"
|
#include "Log.h"
|
||||||
#include "MameNames.h"
|
#include "MameNames.h"
|
||||||
#include "MediaViewer.h"
|
#include "MediaViewer.h"
|
||||||
|
#include "PDFViewer.h"
|
||||||
#include "Screensaver.h"
|
#include "Screensaver.h"
|
||||||
#include "Scripting.h"
|
#include "Scripting.h"
|
||||||
#include "Settings.h"
|
#include "Settings.h"
|
||||||
|
@ -725,6 +726,7 @@ int main(int argc, char* argv[])
|
||||||
CollectionSystemsManager::getInstance();
|
CollectionSystemsManager::getInstance();
|
||||||
Screensaver screensaver;
|
Screensaver screensaver;
|
||||||
MediaViewer mediaViewer;
|
MediaViewer mediaViewer;
|
||||||
|
PDFViewer pdfViewer;
|
||||||
GuiLaunchScreen guiLaunchScreen;
|
GuiLaunchScreen guiLaunchScreen;
|
||||||
|
|
||||||
if (!window->init()) {
|
if (!window->init()) {
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
# EmulationStation Desktop Edition
|
# EmulationStation Desktop Edition
|
||||||
# CMakeLists.txt (es-core)
|
# CMakeLists.txt (es-core)
|
||||||
#
|
#
|
||||||
# CMake configuration for es-core.
|
# CMake configuration for es-core
|
||||||
#
|
#
|
||||||
|
|
||||||
project(core)
|
project(core)
|
||||||
|
|
|
@ -29,6 +29,7 @@ Window::Window() noexcept
|
||||||
, mBackgroundOverlayOpacity {1.0f}
|
, mBackgroundOverlayOpacity {1.0f}
|
||||||
, mScreensaver {nullptr}
|
, mScreensaver {nullptr}
|
||||||
, mMediaViewer {nullptr}
|
, mMediaViewer {nullptr}
|
||||||
|
, mPDFViewer {nullptr}
|
||||||
, mLaunchScreen {nullptr}
|
, mLaunchScreen {nullptr}
|
||||||
, mInfoPopup {nullptr}
|
, mInfoPopup {nullptr}
|
||||||
, mListScrollOpacity {0.0f}
|
, mListScrollOpacity {0.0f}
|
||||||
|
@ -40,6 +41,7 @@ Window::Window() noexcept
|
||||||
, mRenderScreensaver {false}
|
, mRenderScreensaver {false}
|
||||||
, mRenderMediaViewer {false}
|
, mRenderMediaViewer {false}
|
||||||
, mRenderLaunchScreen {false}
|
, mRenderLaunchScreen {false}
|
||||||
|
, mRenderPDFViewer {false}
|
||||||
, mGameLaunchedState {false}
|
, mGameLaunchedState {false}
|
||||||
, mAllowTextScrolling {true}
|
, mAllowTextScrolling {true}
|
||||||
, mAllowFileAnimation {true}
|
, mAllowFileAnimation {true}
|
||||||
|
@ -219,16 +221,35 @@ void Window::input(InputConfig* config, Input input)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mMediaViewer && mRenderMediaViewer) {
|
if (mMediaViewer && mRenderMediaViewer) {
|
||||||
if (config->isMappedLike("right", input) && input.value != 0)
|
if (config->isMappedLike("y", input) && input.value != 0) {
|
||||||
|
mMediaViewer->launchPDFViewer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (config->isMappedLike("right", input) && input.value != 0)
|
||||||
mMediaViewer->showNext();
|
mMediaViewer->showNext();
|
||||||
else if (config->isMappedLike("left", input) && input.value != 0)
|
else if (config->isMappedLike("left", input) && input.value != 0)
|
||||||
mMediaViewer->showPrevious();
|
mMediaViewer->showPrevious();
|
||||||
else if (input.value != 0)
|
else if (input.value != 0)
|
||||||
// Any other input than left or right stops the media viewer.
|
// Any other input stops the media viewer.
|
||||||
stopMediaViewer();
|
stopMediaViewer();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mPDFViewer && mRenderPDFViewer) {
|
||||||
|
if (config->isMappedLike("right", input) && input.value != 0)
|
||||||
|
mPDFViewer->showNextPage();
|
||||||
|
else if (config->isMappedLike("left", input) && input.value != 0)
|
||||||
|
mPDFViewer->showPreviousPage();
|
||||||
|
else if (config->isMappedLike("righttrigger", input) && input.value != 0)
|
||||||
|
mPDFViewer->showLastPage();
|
||||||
|
else if (config->isMappedLike("lefttrigger", input) && input.value != 0)
|
||||||
|
mPDFViewer->showFirstPage();
|
||||||
|
else if (input.value != 0)
|
||||||
|
// Any other input stops the PDF viewer.
|
||||||
|
stopPDFViewer();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (mGameLaunchedState && mLaunchScreen && mRenderLaunchScreen) {
|
if (mGameLaunchedState && mLaunchScreen && mRenderLaunchScreen) {
|
||||||
if (input.value != 0) {
|
if (input.value != 0) {
|
||||||
mLaunchScreen->closeLaunchScreen();
|
mLaunchScreen->closeLaunchScreen();
|
||||||
|
@ -654,6 +675,9 @@ void Window::render()
|
||||||
if (mRenderMediaViewer)
|
if (mRenderMediaViewer)
|
||||||
mMediaViewer->render(trans);
|
mMediaViewer->render(trans);
|
||||||
|
|
||||||
|
if (mRenderPDFViewer)
|
||||||
|
mPDFViewer->render(trans);
|
||||||
|
|
||||||
if (mRenderLaunchScreen)
|
if (mRenderLaunchScreen)
|
||||||
mLaunchScreen->render(trans);
|
mLaunchScreen->render(trans);
|
||||||
|
|
||||||
|
@ -858,6 +882,29 @@ void Window::stopMediaViewer()
|
||||||
mRenderMediaViewer = false;
|
mRenderMediaViewer = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Window::startPDFViewer(FileData* game)
|
||||||
|
{
|
||||||
|
if (mPDFViewer) {
|
||||||
|
if (mPDFViewer->startPDFViewer(game)) {
|
||||||
|
setAllowTextScrolling(false);
|
||||||
|
setAllowFileAnimation(false);
|
||||||
|
|
||||||
|
mRenderPDFViewer = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Window::stopPDFViewer()
|
||||||
|
{
|
||||||
|
if (mPDFViewer) {
|
||||||
|
mPDFViewer->stopPDFViewer();
|
||||||
|
setAllowTextScrolling(true);
|
||||||
|
setAllowFileAnimation(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
mRenderPDFViewer = false;
|
||||||
|
}
|
||||||
|
|
||||||
void Window::displayLaunchScreen(FileData* game)
|
void Window::displayLaunchScreen(FileData* game)
|
||||||
{
|
{
|
||||||
if (mLaunchScreen) {
|
if (mLaunchScreen) {
|
||||||
|
|
|
@ -56,6 +56,7 @@ public:
|
||||||
public:
|
public:
|
||||||
virtual bool startMediaViewer(FileData* game) = 0;
|
virtual bool startMediaViewer(FileData* game) = 0;
|
||||||
virtual void stopMediaViewer() = 0;
|
virtual void stopMediaViewer() = 0;
|
||||||
|
virtual void launchPDFViewer() = 0;
|
||||||
|
|
||||||
virtual void showNext() = 0;
|
virtual void showNext() = 0;
|
||||||
virtual void showPrevious() = 0;
|
virtual void showPrevious() = 0;
|
||||||
|
@ -64,6 +65,20 @@ public:
|
||||||
virtual void render(const glm::mat4& parentTrans) = 0;
|
virtual void render(const glm::mat4& parentTrans) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class PDFViewer
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual bool startPDFViewer(FileData* game) = 0;
|
||||||
|
virtual void stopPDFViewer() = 0;
|
||||||
|
|
||||||
|
virtual void showNextPage() = 0;
|
||||||
|
virtual void showPreviousPage() = 0;
|
||||||
|
virtual void showFirstPage() = 0;
|
||||||
|
virtual void showLastPage() = 0;
|
||||||
|
|
||||||
|
virtual void render(const glm::mat4& parentTrans) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
class GuiLaunchScreen
|
class GuiLaunchScreen
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -124,6 +139,11 @@ public:
|
||||||
void setMediaViewer(MediaViewer* mediaViewer) { mMediaViewer = mediaViewer; }
|
void setMediaViewer(MediaViewer* mediaViewer) { mMediaViewer = mediaViewer; }
|
||||||
bool isMediaViewerActive() { return mRenderMediaViewer; }
|
bool isMediaViewerActive() { return mRenderMediaViewer; }
|
||||||
|
|
||||||
|
void startPDFViewer(FileData* game);
|
||||||
|
void stopPDFViewer();
|
||||||
|
void setPDFViewer(PDFViewer* pdfViewer) { mPDFViewer = pdfViewer; }
|
||||||
|
bool isPDFViewerActive() { return mRenderPDFViewer; }
|
||||||
|
|
||||||
void displayLaunchScreen(FileData* game);
|
void displayLaunchScreen(FileData* game);
|
||||||
void closeLaunchScreen();
|
void closeLaunchScreen();
|
||||||
void setLaunchScreen(GuiLaunchScreen* launchScreen) { mLaunchScreen = launchScreen; }
|
void setLaunchScreen(GuiLaunchScreen* launchScreen) { mLaunchScreen = launchScreen; }
|
||||||
|
@ -180,6 +200,7 @@ private:
|
||||||
|
|
||||||
Screensaver* mScreensaver;
|
Screensaver* mScreensaver;
|
||||||
MediaViewer* mMediaViewer;
|
MediaViewer* mMediaViewer;
|
||||||
|
PDFViewer* mPDFViewer;
|
||||||
GuiLaunchScreen* mLaunchScreen;
|
GuiLaunchScreen* mLaunchScreen;
|
||||||
GuiInfoPopup* mInfoPopup;
|
GuiInfoPopup* mInfoPopup;
|
||||||
|
|
||||||
|
@ -200,6 +221,7 @@ private:
|
||||||
bool mRenderScreensaver;
|
bool mRenderScreensaver;
|
||||||
bool mRenderMediaViewer;
|
bool mRenderMediaViewer;
|
||||||
bool mRenderLaunchScreen;
|
bool mRenderLaunchScreen;
|
||||||
|
bool mRenderPDFViewer;
|
||||||
bool mGameLaunchedState;
|
bool mGameLaunchedState;
|
||||||
bool mAllowTextScrolling;
|
bool mAllowTextScrolling;
|
||||||
bool mAllowFileAnimation;
|
bool mAllowFileAnimation;
|
||||||
|
|
16
es-pdf-converter/CMakeLists.txt
Normal file
16
es-pdf-converter/CMakeLists.txt
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
# SPDX-License-Identifier: MIT
|
||||||
|
#
|
||||||
|
# EmulationStation Desktop Edition
|
||||||
|
# CMakeLists.txt (es-pdf-converter)
|
||||||
|
#
|
||||||
|
# CMake configuration for es-pdf-convert
|
||||||
|
#
|
||||||
|
|
||||||
|
project(es-pdf-convert)
|
||||||
|
|
||||||
|
find_package(Poppler REQUIRED COMPONENTS cpp)
|
||||||
|
|
||||||
|
include_directories(${POPPLER_CPP_INCLUDE_DIR})
|
||||||
|
add_executable(es-pdf-convert ${CMAKE_CURRENT_SOURCE_DIR}/src/main.cpp)
|
||||||
|
target_link_libraries(es-pdf-convert ${POPPLER_CPP_LIBRARY})
|
||||||
|
set_target_properties(es-pdf-convert PROPERTIES INSTALL_RPATH_USE_LINK_PATH TRUE)
|
88
es-pdf-converter/src/main.cpp
Normal file
88
es-pdf-converter/src/main.cpp
Normal file
|
@ -0,0 +1,88 @@
|
||||||
|
// SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
//
|
||||||
|
// EmulationStation Desktop Edition (ES-DE) PDF converter
|
||||||
|
// main.cpp
|
||||||
|
//
|
||||||
|
// Converts PDF document pages to raw ARGB32 image data for maximum performance.
|
||||||
|
// This needs to be separated into its own binary to get around the restrictive GPL
|
||||||
|
// license used by the Poppler PDF rendering library.
|
||||||
|
//
|
||||||
|
// The column limit is 100 characters.
|
||||||
|
// All ES-DE C++ source code is formatted using clang-format.
|
||||||
|
//
|
||||||
|
|
||||||
|
#include "poppler-document.h"
|
||||||
|
#include "poppler-image.h"
|
||||||
|
#include "poppler-page-renderer.h"
|
||||||
|
#include "poppler-page.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if (argc != 5) {
|
||||||
|
std::cout << "Usage: es-pdf-convert <filename> <page number> <horizontal resolution> "
|
||||||
|
"<vertical resolution>"
|
||||||
|
<< std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string path {argv[1]};
|
||||||
|
const int pageNum {atoi(argv[2])};
|
||||||
|
const int width {atoi(argv[3])};
|
||||||
|
const int height {atoi(argv[4])};
|
||||||
|
|
||||||
|
if (width < 1 || width > 7680) {
|
||||||
|
std::cerr << "Invalid horizontal resolution defined: " << argv[3] << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height < 1 || height > 7680) {
|
||||||
|
std::cerr << "Invalid vertical resolution defined: " << argv[4] << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// std::cerr << "Converting file \"" << path << "\", page " << pageNum << " to resolution "
|
||||||
|
// << width << "x" << height << " pixels" << std::endl;
|
||||||
|
|
||||||
|
const poppler::document* document {poppler::document::load_from_file(path)};
|
||||||
|
|
||||||
|
if (document == nullptr)
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
if (pageNum < 1 || pageNum > document->pages()) {
|
||||||
|
std::cerr << "Error: Requested page " << pageNum << " does not exist in document"
|
||||||
|
<< std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const poppler::page* page {document->create_page(pageNum - 1)};
|
||||||
|
poppler::page_renderer pageRenderer;
|
||||||
|
|
||||||
|
pageRenderer.set_render_hint(poppler::page_renderer::text_antialiasing);
|
||||||
|
pageRenderer.set_render_hint(poppler::page_renderer::antialiasing);
|
||||||
|
// pageRenderer.set_render_hint(poppler::page_renderer::text_hinting);
|
||||||
|
|
||||||
|
const poppler::rectf pageRect {page->page_rect()};
|
||||||
|
const bool portraitOrientation {page->orientation() == poppler::page::portrait};
|
||||||
|
const double pageHeight {pageRect.height()};
|
||||||
|
const double sizeFactor {static_cast<double>(portraitOrientation ? height : width) /
|
||||||
|
pageHeight};
|
||||||
|
|
||||||
|
poppler::image image {pageRenderer.render_page(
|
||||||
|
page, static_cast<int>(std::round(72.0 * sizeFactor)),
|
||||||
|
static_cast<int>(std::round(72.0 * sizeFactor)), 0, 0, width, height)};
|
||||||
|
|
||||||
|
if (!image.is_valid()) {
|
||||||
|
std::cerr << "Rendered image is invalid" << std::endl;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Necessary as the image data stream may contain null characters.
|
||||||
|
std::string imageARGB32;
|
||||||
|
imageARGB32.insert(0, std::move(image.data()), width * height * 4);
|
||||||
|
|
||||||
|
std::cout << imageARGB32;
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in a new issue