libragephoto: add ragephoto Python Package

- separate RagePhoto and RagePhoto-Extract sources
This commit is contained in:
Syping 2023-11-09 20:17:37 +01:00
parent 9a5bcabf8c
commit 0f1cfe630b
27 changed files with 503 additions and 50 deletions

View file

@ -157,16 +157,12 @@ inline uint32_t joaatFromInitial(const char *data, size_t size, uint32_t init_va
RagePhoto::RagePhoto()
{
m_data = static_cast<RagePhotoData*>(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<RagePhotoFormatParser*>(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);
}

25
src/python/__init__.py Normal file
View file

@ -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
]

View file

@ -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@"

View file

@ -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

View file

@ -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/"

243
src/python/ragephoto.py Normal file
View file

@ -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()

33
src/python/setup.py.in Normal file
View file

@ -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",
]
)