From 0f1cfe630b45b88ed20a2db1212f7e9b3ee2ca18 Mon Sep 17 00:00:00 2001 From: Syping Date: Thu, 9 Nov 2023 20:17:37 +0100 Subject: [PATCH] libragephoto: add ragephoto Python Package - separate RagePhoto and RagePhoto-Extract sources --- CMakeLists.txt | 106 ++++++---- README.md | 8 +- cmake/wasm.cmake | 2 +- doc/Doxyfile.in | 2 +- src/{ => core}/RagePhoto | 0 src/{ => core}/RagePhoto.c | 0 src/{ => core}/RagePhoto.cpp | 8 +- src/{ => core}/RagePhoto.h | 0 src/{ => core}/RagePhoto.hpp | 0 src/{ => core}/RagePhotoA | 0 src/{ => core}/RagePhotoA.hpp | 0 src/{ => core}/RagePhotoB | 0 src/{ => core}/RagePhotoB.hpp | 0 src/{ => core}/RagePhotoConfig.h.in | 0 src/{ => core}/RagePhotoLibrary.h | 0 src/{ => core}/RagePhotoTypedefs.h | 0 src/{ => core}/ragephoto.pc.in | 0 src/{ => core}/ragephoto.rc.in | 0 src/{ => extract}/RagePhoto-Extract.c | 0 src/{ => extract}/RagePhoto-Extract.cpp | 0 src/{ => extract}/ragephoto-extract.rc.in | 0 src/python/__init__.py | 25 +++ src/python/__version__.py.in | 20 ++ src/python/libragephoto.py | 88 ++++++++ src/python/pyproject.toml.in | 18 ++ src/python/ragephoto.py | 243 ++++++++++++++++++++++ src/python/setup.py.in | 33 +++ 27 files changed, 503 insertions(+), 50 deletions(-) rename src/{ => core}/RagePhoto (100%) rename src/{ => core}/RagePhoto.c (100%) rename src/{ => core}/RagePhoto.cpp (99%) rename src/{ => core}/RagePhoto.h (100%) rename src/{ => core}/RagePhoto.hpp (100%) rename src/{ => core}/RagePhotoA (100%) rename src/{ => core}/RagePhotoA.hpp (100%) rename src/{ => core}/RagePhotoB (100%) rename src/{ => core}/RagePhotoB.hpp (100%) rename src/{ => core}/RagePhotoConfig.h.in (100%) rename src/{ => core}/RagePhotoLibrary.h (100%) rename src/{ => core}/RagePhotoTypedefs.h (100%) rename src/{ => core}/ragephoto.pc.in (100%) rename src/{ => core}/ragephoto.rc.in (100%) rename src/{ => extract}/RagePhoto-Extract.c (100%) rename src/{ => extract}/RagePhoto-Extract.cpp (100%) rename src/{ => extract}/ragephoto-extract.rc.in (100%) create mode 100644 src/python/__init__.py create mode 100644 src/python/__version__.py.in create mode 100644 src/python/libragephoto.py create mode 100644 src/python/pyproject.toml.in create mode 100644 src/python/ragephoto.py create mode 100644 src/python/setup.py.in diff --git a/CMakeLists.txt b/CMakeLists.txt index 9e3cdd1..30d842d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,7 +24,7 @@ include(GNUInstallDirs) include(cmake/cxxstd.cmake) include(cmake/unicode.cmake) -# RagePhoto Top Level ON +# RagePhoto Top Level if (${CMAKE_PROJECT_NAME} STREQUAL "ragephoto") set(RPTL_ON ON) else() @@ -35,59 +35,53 @@ endif() option(RAGEPHOTO_C_LIBRARY "Build libragephoto as C library" OFF) if (RAGEPHOTO_C_LIBRARY) set(RAGEPHOTO_HEADERS - src/RagePhoto.h - src/RagePhotoA - src/RagePhotoA.hpp - src/RagePhotoB - src/RagePhotoB.hpp - src/RagePhotoLibrary.h - src/RagePhotoTypedefs.h + src/core/RagePhoto.h + src/core/RagePhotoA + src/core/RagePhotoA.hpp + src/core/RagePhotoB + src/core/RagePhotoB.hpp + src/core/RagePhotoLibrary.h + src/core/RagePhotoTypedefs.h ) set(RAGEPHOTO_SOURCES - src/RagePhoto.c + src/core/RagePhoto.c ) else() set(RAGEPHOTO_HEADERS - src/RagePhoto - src/RagePhoto.hpp - src/RagePhotoB - src/RagePhotoB.hpp - src/RagePhotoLibrary.h - src/RagePhotoTypedefs.h + src/core/RagePhoto + src/core/RagePhoto.hpp + src/core/RagePhotoB + src/core/RagePhotoB.hpp + src/core/RagePhotoLibrary.h + src/core/RagePhotoTypedefs.h ) set(RAGEPHOTO_SOURCES - src/RagePhoto.cpp + src/core/RagePhoto.cpp ) endif() # RagePhoto Library Type option(RAGEPHOTO_STATIC "Build libragephoto as static library" OFF) if (RAGEPHOTO_STATIC) - option(RAGEPHOTO_C_API "Build libragephoto with C API support" OFF) set(LIBRAGEPHOTO_LIBTYPE LIBRAGEPHOTO_STATIC) else() - option(RAGEPHOTO_C_API "Build libragephoto with C API support" ON) set(LIBRAGEPHOTO_LIBTYPE LIBRAGEPHOTO_SHARED) endif() # RagePhoto Benchmark option(RAGEPHOTO_BENCHMARK "Build with libragephoto benchmark (C++ only)" OFF) -if (RAGEPHOTO_BENCHMARK) - list(APPEND LIBRAGEPHOTO_DEFINES - RAGEPHOTO_BENCHMARK - ) -endif() -# RagePhoto C API +# RagePhoto API +option(RAGEPHOTO_C_API "Build libragephoto with C API support" ON) if (RAGEPHOTO_C_LIBRARY) set(LIBRAGEPHOTO_API LIBRAGEPHOTO_C_ONLY) else() if (RAGEPHOTO_C_API) set(LIBRAGEPHOTO_API LIBRAGEPHOTO_CXX_C) list(APPEND RAGEPHOTO_HEADERS - src/RagePhoto.h - src/RagePhotoA - src/RagePhotoA.hpp + src/core/RagePhoto.h + src/core/RagePhotoA + src/core/RagePhotoA.hpp ) else() set(LIBRAGEPHOTO_API LIBRAGEPHOTO_CXX_ONLY) @@ -97,15 +91,15 @@ endif() # RagePhoto Win32 Shared Resources if (WIN32) string(TIMESTAMP ragephoto_BUILD_YEAR "%Y" UTC) - configure_file(src/ragephoto.rc.in "${ragephoto_BINARY_DIR}/resources/ragephoto.rc" @ONLY) + configure_file(src/core/ragephoto.rc.in "${ragephoto_BINARY_DIR}/resources/ragephoto.rc" @ONLY) list(APPEND RAGEPHOTO_SHARED_RESOURCES "${ragephoto_BINARY_DIR}/resources/ragephoto.rc" ) endif() # RagePhoto Configures + Target + Installs -configure_file(src/ragephoto.pc.in "${ragephoto_BINARY_DIR}/pkgconfig/ragephoto.pc" @ONLY) -configure_file(src/RagePhotoConfig.h.in "${ragephoto_BINARY_DIR}/include/RagePhotoConfig.h" @ONLY) +configure_file(src/core/ragephoto.pc.in "${ragephoto_BINARY_DIR}/pkgconfig/ragephoto.pc" @ONLY) +configure_file(src/core/RagePhotoConfig.h.in "${ragephoto_BINARY_DIR}/include/RagePhotoConfig.h" @ONLY) list(APPEND RAGEPHOTO_HEADERS "${ragephoto_BINARY_DIR}/include/RagePhotoConfig.h" ) @@ -122,13 +116,14 @@ endif() target_compile_definitions(ragephoto PRIVATE LIBRAGEPHOTO_LIBRARY ${LIBRAGEPHOTO_DEFINES} + $<$:RAGEPHOTO_BENCHMARK> ) -if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914 AND NOT RAGEPHOTO_C_LIBRARY) - target_compile_options(ragephoto PRIVATE "/Zc:__cplusplus") +if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) + target_compile_options(ragephoto PRIVATE $<$:/Zc:__cplusplus>) endif() target_include_directories(ragephoto PUBLIC "${ragephoto_BINARY_DIR}/include" - "${ragephoto_SOURCE_DIR}/src" + "${ragephoto_SOURCE_DIR}/src/core" ) install(TARGETS ragephoto ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}" @@ -167,14 +162,14 @@ option(RAGEPHOTO_EXTRACT "Build libragephoto with ragephoto-extract" ${RPTL_ON}) if (RAGEPHOTO_EXTRACT) # RagePhoto-Extract Source files if (RAGEPHOTO_C_API) - set(EXTRACT_SOURCES src/RagePhoto-Extract.c) + set(EXTRACT_SOURCES src/extract/RagePhoto-Extract.c) else() - set(EXTRACT_SOURCES src/RagePhoto-Extract.cpp) + set(EXTRACT_SOURCES src/extract/RagePhoto-Extract.cpp) endif() # RagePhoto-Extract Win32 Shared Resources if (WIN32) string(TIMESTAMP ragephoto_BUILD_YEAR "%Y" UTC) - configure_file(src/ragephoto-extract.rc.in "${ragephoto_BINARY_DIR}/resources/ragephoto-extract.rc" @ONLY) + configure_file(src/extract/ragephoto-extract.rc.in "${ragephoto_BINARY_DIR}/resources/ragephoto-extract.rc" @ONLY) list(APPEND EXTRACT_RESOURCES "${ragephoto_BINARY_DIR}/resources/ragephoto-extract.rc" ) @@ -184,13 +179,48 @@ if (RAGEPHOTO_EXTRACT) set_target_properties(ragephoto-extract PROPERTIES INSTALL_RPATH "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" ) - if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914 AND NOT RAGEPHOTO_C_API) - target_compile_options(ragephoto-extract PRIVATE "/Zc:__cplusplus") + if (MSVC AND MSVC_VERSION GREATER_EQUAL 1914) + target_compile_options(ragephoto-extract PRIVATE $<$:/Zc:__cplusplus>) endif() target_link_libraries(ragephoto-extract PRIVATE ragephoto) install(TARGETS ragephoto-extract DESTINATION "${CMAKE_INSTALL_BINDIR}") endif() +# RagePhoto Python Package +option(RAGEPHOTO_PYTHON "Create ragephoto Python Package" OFF) +if (RAGEPHOTO_PYTHON) + # Python Package Library file + if (WIN32) + set(PYRAGEPHOTO_LIBRARY "libragephoto.dll") + else() + set(PYRAGEPHOTO_LIBRARY "libragephoto.so") + endif() + # Generate Python Package Project files + configure_file(src/python/setup.py.in "${ragephoto_BINARY_DIR}/pyragephoto/setup.py" @ONLY) + configure_file(src/python/pyproject.toml.in "${ragephoto_BINARY_DIR}/pyragephoto/pyproject.toml" @ONLY) + configure_file(src/python/__version__.py.in "${ragephoto_BINARY_DIR}/pyragephoto/ragephoto/__version__.py" @ONLY) + # Python Package Source files + Target + set(PYRAGEPHOTO_SOURCES + "src/python/__init__.py" + "src/python/libragephoto.py" + "src/python/ragephoto.py" + ) + add_custom_target(pyragephoto SOURCES ${PYRAGEPHOTO_SOURCES}) + # Copy Python Package to build directory + file(COPY ${PYRAGEPHOTO_SOURCES} DESTINATION "${ragephoto_BINARY_DIR}/pyragephoto/ragephoto") + # Python Package Bundle Settings + option(RAGEPHOTO_PYTHON_BUNDLE_LIBRARY "Bundle libragephoto with ragephoto Python Package" OFF) + if (RAGEPHOTO_PYTHON_BUNDLE_LIBRARY) + add_custom_command( + TARGET ragephoto + POST_BUILD + COMMAND "${CMAKE_COMMAND}" -E copy "$" "${ragephoto_BINARY_DIR}/pyragephoto/ragephoto/${PYRAGEPHOTO_LIBRARY}" + BYPRODUCTS "${ragephoto_BINARY_DIR}/pyragephoto/ragephoto/${PYRAGEPHOTO_LIBRARY}" + VERBATIM + ) + endif() +endif() + # CPack Package Generation if (RPTL_ON) include(InstallRequiredSystemLibraries) diff --git a/README.md b/README.md index f439b17..7858009 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@ ## libragephoto Open Source RAGE Photo Parser for GTA V and RDR 2 -- Read/Write RAGE Photos error free and correct -- Support for metadata stored in RAGE Photos -- Export RAGE Photos to jpeg with ragephoto-extract -- High Efficient and Simple C/C++ API + - Read/Write RAGE Photos error free and correct + - Support for metadata stored in RAGE Photos + - Export RAGE Photos to jpeg with ragephoto-extract + - High Efficient and Simple C/C++ API #### Build libragephoto diff --git a/cmake/wasm.cmake b/cmake/wasm.cmake index 5da54dd..ad3e1d6 100644 --- a/cmake/wasm.cmake +++ b/cmake/wasm.cmake @@ -40,7 +40,7 @@ if (CMAKE_VERSION VERSION_GREATER_EQUAL "3.13.0") ) target_include_directories(ragephoto-wasm PUBLIC "${ragephoto_BINARY_DIR}/include" - "${ragephoto_SOURCE_DIR}/src" + "${ragephoto_SOURCE_DIR}/src/core" ) else() message(WARNING "A useable WebAssembly build needs at least CMake 3.13.0 or newer") diff --git a/doc/Doxyfile.in b/doc/Doxyfile.in index c846f9e..2e37135 100644 --- a/doc/Doxyfile.in +++ b/doc/Doxyfile.in @@ -3,7 +3,7 @@ PROJECT_NUMBER = "Version: @ragephoto_VERSION@" INPUT = "@CMAKE_CURRENT_SOURCE_DIR@/index.doc" \ "@CMAKE_CURRENT_SOURCE_DIR@/build.doc" \ "@CMAKE_CURRENT_SOURCE_DIR@/usage.doc" \ - "src" + "src/core" OUTPUT_DIRECTORY = "@CMAKE_CURRENT_BINARY_DIR@" EXTRACT_PRIVATE = NO ENABLE_PREPROCESSING = YES diff --git a/src/RagePhoto b/src/core/RagePhoto similarity index 100% rename from src/RagePhoto rename to src/core/RagePhoto diff --git a/src/RagePhoto.c b/src/core/RagePhoto.c similarity index 100% rename from src/RagePhoto.c rename to src/core/RagePhoto.c diff --git a/src/RagePhoto.cpp b/src/core/RagePhoto.cpp similarity index 99% rename from src/RagePhoto.cpp rename to src/core/RagePhoto.cpp index 0bf72ed..8f17faf 100644 --- a/src/RagePhoto.cpp +++ b/src/core/RagePhoto.cpp @@ -157,16 +157,12 @@ inline uint32_t joaatFromInitial(const char *data, size_t size, uint32_t init_va RagePhoto::RagePhoto() { m_data = static_cast(malloc(sizeof(RagePhotoData))); - if (!m_data) { + if (!m_data) throw std::runtime_error("RagePhotoData data struct can't be allocated"); - return; - } memset(m_data, 0, sizeof(RagePhotoData)); m_parser = static_cast(malloc(sizeof(RagePhotoFormatParser))); - if (!m_parser) { + if (!m_parser) throw std::runtime_error("RagePhotoFormatParser parser struct can't be allocated"); - return; - } memset(m_parser, 0, sizeof(RagePhotoFormatParser)); setBufferDefault(m_data); } diff --git a/src/RagePhoto.h b/src/core/RagePhoto.h similarity index 100% rename from src/RagePhoto.h rename to src/core/RagePhoto.h diff --git a/src/RagePhoto.hpp b/src/core/RagePhoto.hpp similarity index 100% rename from src/RagePhoto.hpp rename to src/core/RagePhoto.hpp diff --git a/src/RagePhotoA b/src/core/RagePhotoA similarity index 100% rename from src/RagePhotoA rename to src/core/RagePhotoA diff --git a/src/RagePhotoA.hpp b/src/core/RagePhotoA.hpp similarity index 100% rename from src/RagePhotoA.hpp rename to src/core/RagePhotoA.hpp diff --git a/src/RagePhotoB b/src/core/RagePhotoB similarity index 100% rename from src/RagePhotoB rename to src/core/RagePhotoB diff --git a/src/RagePhotoB.hpp b/src/core/RagePhotoB.hpp similarity index 100% rename from src/RagePhotoB.hpp rename to src/core/RagePhotoB.hpp diff --git a/src/RagePhotoConfig.h.in b/src/core/RagePhotoConfig.h.in similarity index 100% rename from src/RagePhotoConfig.h.in rename to src/core/RagePhotoConfig.h.in diff --git a/src/RagePhotoLibrary.h b/src/core/RagePhotoLibrary.h similarity index 100% rename from src/RagePhotoLibrary.h rename to src/core/RagePhotoLibrary.h diff --git a/src/RagePhotoTypedefs.h b/src/core/RagePhotoTypedefs.h similarity index 100% rename from src/RagePhotoTypedefs.h rename to src/core/RagePhotoTypedefs.h diff --git a/src/ragephoto.pc.in b/src/core/ragephoto.pc.in similarity index 100% rename from src/ragephoto.pc.in rename to src/core/ragephoto.pc.in diff --git a/src/ragephoto.rc.in b/src/core/ragephoto.rc.in similarity index 100% rename from src/ragephoto.rc.in rename to src/core/ragephoto.rc.in diff --git a/src/RagePhoto-Extract.c b/src/extract/RagePhoto-Extract.c similarity index 100% rename from src/RagePhoto-Extract.c rename to src/extract/RagePhoto-Extract.c diff --git a/src/RagePhoto-Extract.cpp b/src/extract/RagePhoto-Extract.cpp similarity index 100% rename from src/RagePhoto-Extract.cpp rename to src/extract/RagePhoto-Extract.cpp diff --git a/src/ragephoto-extract.rc.in b/src/extract/ragephoto-extract.rc.in similarity index 100% rename from src/ragephoto-extract.rc.in rename to src/extract/ragephoto-extract.rc.in diff --git a/src/python/__init__.py b/src/python/__init__.py new file mode 100644 index 0000000..b01d1a8 --- /dev/null +++ b/src/python/__init__.py @@ -0,0 +1,25 @@ +############################################################################## +# libragephoto for Python +# Copyright (C) 2023 Syping +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# This software is provided as-is, no warranties are given to you, we are not +# responsible for anything with use of the software, you are self responsible. +############################################################################## + +from .ragephoto import RagePhoto + +__all__ = [ + "libragephoto", # libragephoto Loader Module + "ragephoto", # RagePhoto Module + "RagePhoto" # RagePhoto API +] diff --git a/src/python/__version__.py.in b/src/python/__version__.py.in new file mode 100644 index 0000000..0168254 --- /dev/null +++ b/src/python/__version__.py.in @@ -0,0 +1,20 @@ +############################################################################## +# libragephoto for Python +# Copyright (C) 2023 Syping +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# This software is provided as-is, no warranties are given to you, we are not +# responsible for anything with use of the software, you are self responsible. +############################################################################## + +VERSION = (@ragephoto_VERSION_MAJOR@, @ragephoto_VERSION_MINOR@, @ragephoto_VERSION_PATCH@) +__version__ = "@ragephoto_VERSION@" diff --git a/src/python/libragephoto.py b/src/python/libragephoto.py new file mode 100644 index 0000000..e129293 --- /dev/null +++ b/src/python/libragephoto.py @@ -0,0 +1,88 @@ +############################################################################## +# libragephoto for Python +# Copyright (C) 2023 Syping +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# This software is provided as-is, no warranties are given to you, we are not +# responsible for anything with use of the software, you are self responsible. +############################################################################## + +from ctypes import * +from ctypes.util import find_library +from pathlib import Path +from platform import system + +if system() == "Windows": + bundle_library_path = Path(__file__).parent.resolve() / "libragephoto.dll" + if bundle_library_path.is_file(): + library_path = str(bundle_library_path) +else: + bundle_library_path = Path(__file__).parent.resolve() / "libragephoto.so" + if bundle_library_path.is_file(): + library_path = str(bundle_library_path) + else: + library_path = find_library("ragephoto") + +if not library_path: + raise ImportError("libragephoto is required.") + +libragephoto = cdll.LoadLibrary(library_path) +libragephoto.ragephoto_open.restype = c_void_p +libragephoto.ragephoto_clear.argtypes = [c_void_p] +libragephoto.ragephoto_close.argtypes = [c_void_p] +libragephoto.ragephoto_load.argtypes = [c_void_p, POINTER(c_char), c_size_t] +libragephoto.ragephoto_load.restype = c_bool +libragephoto.ragephoto_loadfile.argtypes = [c_void_p, c_char_p] +libragephoto.ragephoto_loadfile.restype = c_bool +libragephoto.ragephoto_error.argtypes = [c_void_p] +libragephoto.ragephoto_error.restype = c_int32 +libragephoto.ragephoto_getphotodesc.argtypes = [c_void_p] +libragephoto.ragephoto_getphotodesc.restype = c_char_p +libragephoto.ragephoto_getphotoformat.argtypes = [c_void_p] +libragephoto.ragephoto_getphotoformat.restype = c_uint32 +libragephoto.ragephoto_getphotojpeg.argtypes = [c_void_p] +libragephoto.ragephoto_getphotojpeg.restype = POINTER(c_char) +libragephoto.ragephoto_getphotojson.argtypes = [c_void_p] +libragephoto.ragephoto_getphotojson.restype = c_char_p +libragephoto.ragephoto_getphotoheader.argtypes = [c_void_p] +libragephoto.ragephoto_getphotoheader.restype = c_char_p +libragephoto.ragephoto_getphotosign.argtypes = [c_void_p] +libragephoto.ragephoto_getphotosign.restype = c_uint64 +libragephoto.ragephoto_getphotosignf.argtypes = [c_void_p, c_uint32] +libragephoto.ragephoto_getphotosignf.restype = c_uint64 +libragephoto.ragephoto_getphotosize.argtypes = [c_void_p] +libragephoto.ragephoto_getphotosize.restype = c_uint32 +libragephoto.ragephoto_getphototitle.argtypes = [c_void_p] +libragephoto.ragephoto_getphototitle.restype = c_char_p +libragephoto.ragephoto_getsavesize.argtypes = [c_void_p] +libragephoto.ragephoto_getsavesize.restype = c_size_t +libragephoto.ragephoto_getsavesizef.argtypes = [c_void_p, c_uint32] +libragephoto.ragephoto_getsavesizef.restype = c_size_t +libragephoto.ragephoto_save.argtypes = [c_void_p, POINTER(c_char)] +libragephoto.ragephoto_save.restype = c_bool +libragephoto.ragephoto_savef.argtypes = [c_void_p, POINTER(c_char), c_uint32] +libragephoto.ragephoto_savef.restype = c_bool +libragephoto.ragephoto_savefile.argtypes = [c_void_p, c_char_p] +libragephoto.ragephoto_savefile.restype = c_bool +libragephoto.ragephoto_savefilef.argtypes = [c_void_p, c_char_p, c_uint32] +libragephoto.ragephoto_savefilef.restype = c_bool +libragephoto.ragephoto_setbufferdefault.argtypes = [c_void_p] +libragephoto.ragephoto_setbufferoffsets.argtypes = [c_void_p] +libragephoto.ragephoto_setphotodesc.argtypes = [c_void_p, c_char_p, c_uint32] +libragephoto.ragephoto_setphotoformat.argtypes = [c_void_p, c_uint32] +libragephoto.ragephoto_setphotojpeg.argtypes = [c_void_p, POINTER(c_char), c_uint32, c_uint32] +libragephoto.ragephoto_setphotojpeg.restype = c_bool +libragephoto.ragephoto_setphotojson.argtypes = [c_void_p, c_char_p, c_uint32] +libragephoto.ragephoto_setphotoheader.argtypes = [c_void_p, c_char_p, c_uint32] +libragephoto.ragephoto_setphotoheader2.argtypes = [c_void_p, c_char_p, c_uint32, c_uint32] +libragephoto.ragephoto_setphototitle.argtypes = [c_void_p, c_char_p, c_uint32] +libragephoto.ragephoto_version.restype = c_char_p diff --git a/src/python/pyproject.toml.in b/src/python/pyproject.toml.in new file mode 100644 index 0000000..97a882e --- /dev/null +++ b/src/python/pyproject.toml.in @@ -0,0 +1,18 @@ +[project] +name = "ragephoto" +version = "@ragephoto_VERSION@" +authors = [ + { name = "Syping" }, +] +description = "libragephoto for Python" +requires-python = ">=3.6" +classifiers = [ + "License :: OSI Approved :: BSD-2-Clause", +] + +[build-system] +requires = ["setuptools", "wheel"] +build-backend = "setuptools.build_meta" + +[project.urls] +"Homepage" = "https://libragephoto.syping.de/" diff --git a/src/python/ragephoto.py b/src/python/ragephoto.py new file mode 100644 index 0000000..0ceaaa5 --- /dev/null +++ b/src/python/ragephoto.py @@ -0,0 +1,243 @@ +############################################################################## +# libragephoto for Python +# Copyright (C) 2023 Syping +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# This software is provided as-is, no warranties are given to you, we are not +# responsible for anything with use of the software, you are self responsible. +############################################################################## + +from .libragephoto import * +from enum import IntEnum +from json import loads as parseJson +from json import dumps as serializeJson + +class RagePhoto: + class DefaultSize(IntEnum): + DEFAULT_GTA5_PHOTOBUFFER = 524288 + DEFAULT_RDR2_PHOTOBUFFER = 1048576 + DEFAULT_DESCBUFFER = 256 + DEFAULT_JSONBUFFER = 3072 + DEFAULT_TITLBUFFER = 256 + + class Error(IntEnum): + DescBufferTight = 39 + DescMallocError = 31 + DescReadError = 32 + HeaderBufferTight = 35 + HeaderMallocError = 4 + IncompatibleFormat = 2 + IncompleteChecksum = 7 + IncompleteDescBuffer = 30 + IncompleteDescMarker = 28 + IncompleteDescOffset = 11 + IncompleteEOF = 8 + IncompleteHeader = 3 + IncompleteJendMarker = 33 + IncompleteJpegMarker = 12 + IncompleteJsonBuffer = 20 + IncompleteJsonMarker = 18 + IncompleteJsonOffset = 9 + IncompletePhotoBuffer = 14 + IncompletePhotoSize = 15 + IncompleteTitleBuffer = 25 + IncompleteTitleMarker = 23 + IncompleteTitleOffset = 10 + IncorrectDescMarker = 29 + IncorrectJendMarker = 34 + IncorrectJpegMarker = 13 + IncorrectJsonMarker = 19 + IncorrectTitleMarker = 24 + JsonBufferTight = 37 + JsonMallocError = 21 + JsonReadError = 22 + NoError = 255 + NoFormatIdentifier = 1 + PhotoBufferTight = 36 + PhotoMallocError = 16 + PhotoReadError = 17 + TitleBufferTight = 38 + TitleMallocError = 26 + TitleReadError = 27 + UnicodeInitError = 5 + UnicodeHeaderError = 6 + Uninitialised = 0 + + class PhotoFormat(IntEnum): + GTA5 = 0x01000000 + RDR2 = 0x04000000 + + def __init__(self): + self.__instance = libragephoto.ragephoto_open() + + def __del__(self): + libragephoto.ragephoto_close(self.__instance) + + def clear(self): + libragephoto.ragephoto_clear(self.__instance) + + def load(self, data): + return libragephoto.ragephoto_load(self.__instance, data, len(data)) + + def loadFile(self, file): + if isinstance(file, str): + return libragephoto.ragephoto_loadfile(self.__instance, file.encode()) + else: + return libragephoto.ragephoto_loadfile(self.__instance, file) + + def error(self): + return libragephoto.ragephoto_error(self.__instance) + + def description(self): + _desc = libragephoto.ragephoto_getphotodesc(self.__instance) + if _desc: + return _desc + else: + return b"" + + def format(self): + return libragephoto.ragephoto_getphotoformat(self.__instance) + + def jpeg(self): + _jpeg = libragephoto.ragephoto_getphotojpeg(self.__instance) + if _jpeg: + return _jpeg[:self.jpegSize()] + else: + return b"" + + def jpegSign(self, format = None): + if format is None: + return libragephoto.ragephoto_getphotosign(self.__instance) + else: + return libragephoto.ragephoto_getphotosignf(self.__instance, format) + + def jpegSize(self): + return libragephoto.ragephoto_getphotosize(self.__instance) + + def json(self): + _json = libragephoto.ragephoto_getphotojson(self.__instance) + if _json: + return _json + else: + return b"" + + def header(self): + _header = libragephoto.ragephoto_getphotoheader(self.__instance) + if _header: + return _header + else: + return b"" + + def save(self, format = None): + _data = bytearray(self.saveSize(format)) + _ptr = (c_char * len(_data)).from_buffer(_data) + if format is None: + _ret = libragephoto.ragephoto_save(self.__instance, _ptr) + else: + _ret = libragephoto.ragephoto_savef(self.__instance, _ptr, format) + if _ret: + return _data + else: + return None + + def saveFile(self, file, format = None): + if isinstance(file, str): + _file = file.encode() + else: + _file = file + if format is None: + return libragephoto.ragephoto_savefile(self.__instance, _file) + else: + return libragephoto.ragephoto_savefilef(self.__instance, _file, format) + + def saveSize(self, format = None): + if format is None: + return libragephoto.ragephoto_getsavesize(self.__instance) + else: + return libragephoto.ragephoto_getsavesizef(self.__instance, format) + + def setBufferDefault(self): + return libragephoto.ragephoto_setbufferdefault(self.__instance) + + def setBufferOffsets(self): + return libragephoto.ragephoto_setbufferoffsets(self.__instance) + + def setDescription(self, desc, buffer = None): + if isinstance(desc, str): + _desc = desc.encode() + else: + _desc = desc + if buffer is None: + libragephoto.ragephoto_setphotodesc(self.__instance, _desc, self.DefaultSize.DEFAULT_DESCBUFFER) + else: + libragephoto.ragephoto_setphotodesc(self.__instance, _desc, buffer) + + def setFormat(self, format): + libragephoto.ragephoto_setphotoformat(self.__instance, format) + + def setJpeg(self, jpeg, buffer = None): + _buffer = 0 + if buffer is None: + _format = self.format() + if _format == self.PhotoFormat.GTA5: + _buffer = self.DefaultSize.DEFAULT_GTA5_PHOTOBUFFER + elif _format == self.PhotoFormat.RDR2: + _buffer = self.DefaultSize.DEFAULT_RDR2_PHOTOBUFFER + if _buffer < len(jpeg): + _buffer = len(jpeg) + return libragephoto.ragephoto_setphotojpeg(self.__instance, jpeg, len(jpeg), _buffer) + + def setJson(self, json, buffer = None): + if isinstance(json, str): + _json = json.encode() + else: + _json = json + if buffer is None: + libragephoto.ragephoto_setphotojson(self.__instance, _json, self.DefaultSize.DEFAULT_JSONBUFFER) + else: + libragephoto.ragephoto_setphotojson(self.__instance, _json, buffer) + + def setHeader(self, header, headerSum1, headerSum2 = 0): + if isinstance(header, str): + _header = header.encode() + else: + _header = header + libragephoto.ragephoto_setphotoheader2(self.__instance, _header, headerSum1, headerSum2) + + def setTitle(self, title, buffer = None): + if isinstance(title, str): + _title = title.encode() + else: + _title = title + if buffer is None: + libragephoto.ragephoto_setphototitle(self.__instance, _title, self.DefaultSize.DEFAULT_TITLBUFFER) + else: + libragephoto.ragephoto_setphototitle(self.__instance, _title, buffer) + + def title(self): + _title = libragephoto.ragephoto_getphototitle(self.__instance) + if _title: + return _title + else: + return b"" + + def updateSign(self): + try: + _json = parseJson(self.json()) + except JSONDecodeError: + return False + _json["sign"] = self.jpegSign() + self.setJson(serializeJson(_json, separators=(',', ':'))) + return True + + def version(self): + return libragephoto.ragephoto_version() diff --git a/src/python/setup.py.in b/src/python/setup.py.in new file mode 100644 index 0000000..b996135 --- /dev/null +++ b/src/python/setup.py.in @@ -0,0 +1,33 @@ +#!/usr/bin/env python3 + +############################################################################## +# libragephoto for Python +# Copyright (C) 2023 Syping +# +# Redistribution and use in source and binary forms, with or without modification, +# are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright notice, +# this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright notice, +# this list of conditions and the following disclaimer in the documentation +# and/or other materials provided with the distribution. +# +# This software is provided as-is, no warranties are given to you, we are not +# responsible for anything with use of the software, you are self responsible. +############################################################################## + +from setuptools import setup, find_packages + +setup( + name = "ragephoto", + version = "@ragephoto_VERSION@", + author = "Syping", + packages = ["ragephoto"], + url = "https://libragephoto.syping.de/", + description = "libragephoto for Python", + classifiers = [ + "License :: OSI Approved :: BSD-2-Clause", + ] +)