add Qt example, GTK example fixes, README update
This commit is contained in:
parent
350916588f
commit
33c3dcb512
9 changed files with 181 additions and 31 deletions
|
@ -1,5 +1,5 @@
|
||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
enable_language(CXX)
|
project(ragephoto LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
@ -60,12 +60,17 @@ target_compile_definitions(ragephoto PRIVATE
|
||||||
install(TARGETS ragephoto DESTINATION lib)
|
install(TARGETS ragephoto DESTINATION lib)
|
||||||
install(FILES ${RAGEPHOTO_HEADERS} DESTINATION include)
|
install(FILES ${RAGEPHOTO_HEADERS} DESTINATION include)
|
||||||
|
|
||||||
option(WITH_EXAMPLES "Build ragephoto examples" OFF)
|
option(WITH_GTK_EXAMPLE "Build libragephoto with GTK Photo Viewer" OFF)
|
||||||
if (WITH_EXAMPLES)
|
if (WITH_GTK_EXAMPLE)
|
||||||
add_subdirectory(examples/ragephoto-gtkviewer)
|
add_subdirectory(examples/ragephoto-gtkviewer)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(WITH_EXTRACT "Build ragephoto-extract" ON)
|
option(WITH_QT_EXAMPLE "Build libragephoto with Qt Photo Viewer" OFF)
|
||||||
|
if (WITH_QT_EXAMPLE)
|
||||||
|
add_subdirectory(examples/ragephoto-qtviewer)
|
||||||
|
endif()
|
||||||
|
|
||||||
|
option(WITH_EXTRACT "Build libragephoto with ragephoto-extract" ON)
|
||||||
if (WITH_EXTRACT)
|
if (WITH_EXTRACT)
|
||||||
project(ragephoto-extract LANGUAGES CXX)
|
project(ragephoto-extract LANGUAGES CXX)
|
||||||
set(EXTRACT_SOURCES
|
set(EXTRACT_SOURCES
|
||||||
|
|
|
@ -6,7 +6,7 @@ Open Source RAGE Photo Parser for GTA V
|
||||||
- Export RAGE Photos to jpeg with ragephoto-extract
|
- Export RAGE Photos to jpeg with ragephoto-extract
|
||||||
- High Efficient and Simple C++ API
|
- High Efficient and Simple C++ API
|
||||||
|
|
||||||
#### Build libragephoto & ragephoto-extract
|
#### Build libragephoto
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone https://gitlab.com/Syping/libragephoto && cd libragephoto
|
git clone https://gitlab.com/Syping/libragephoto && cd libragephoto
|
||||||
|
@ -16,6 +16,9 @@ make -j $(nproc --all)
|
||||||
sudo make install
|
sudo make install
|
||||||
```
|
```
|
||||||
|
|
||||||
|
##### Optional CMake flags
|
||||||
|
`-DWITH_EXTRACT=OFF` `-DWITH_GTK_EXAMPLE=ON` `-DWITH_QT_EXAMPLE=ON` `-DBUILD_SHARED=OFF`
|
||||||
|
|
||||||
#### How to Use libragephoto
|
#### How to Use libragephoto
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
|
|
|
@ -1,12 +1,12 @@
|
||||||
cmake_minimum_required(VERSION 3.7)
|
cmake_minimum_required(VERSION 3.7)
|
||||||
enable_language(CXX)
|
project(ragephoto-gtkviewer LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
set(CMAKE_CXX_STANDARD 11)
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
find_package(PkgConfig REQUIRED)
|
find_package(PkgConfig REQUIRED)
|
||||||
pkg_check_modules(gtkmm REQUIRED gtkmm-3.0)
|
pkg_check_modules(GTKMM REQUIRED gtkmm-3.0)
|
||||||
|
|
||||||
project(ragephoto-gtkviewer LANGUAGES CXX)
|
project(ragephoto-gtkviewer LANGUAGES CXX)
|
||||||
|
|
||||||
|
@ -22,9 +22,9 @@ set(GTKVIEWER_SOURCES
|
||||||
if(TARGET ragephoto)
|
if(TARGET ragephoto)
|
||||||
set(RAGEPHOTO_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src)
|
set(RAGEPHOTO_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src)
|
||||||
add_executable(ragephoto-gtkviewer ${GTKVIEWER_HEADERS} ${GTKVIEWER_SOURCES})
|
add_executable(ragephoto-gtkviewer ${GTKVIEWER_HEADERS} ${GTKVIEWER_SOURCES})
|
||||||
target_link_libraries(ragephoto-gtkviewer ${gtkmm_LIBRARIES} ragephoto)
|
target_link_libraries(ragephoto-gtkviewer ${GTKMM_LIBRARIES} ragephoto)
|
||||||
target_link_directories(ragephoto-gtkviewer PRIVATE ${gtkmm_LIBRARY_DIRS})
|
target_link_directories(ragephoto-gtkviewer PRIVATE ${GTKMM_LIBRARY_DIRS})
|
||||||
target_include_directories(ragephoto-gtkviewer PRIVATE ${gtkmm_INCLUDE_DIRS} ${RAGEPHOTO_INCLUDE_DIRS})
|
target_include_directories(ragephoto-gtkviewer PRIVATE ${GTKMM_INCLUDE_DIRS} ${RAGEPHOTO_INCLUDE_DIRS})
|
||||||
install(TARGETS ragephoto-gtkviewer DESTINATION bin)
|
install(TARGETS ragephoto-gtkviewer DESTINATION bin)
|
||||||
else()
|
else()
|
||||||
message("ragephoto-gtkviewer need to be build with libragephoto together")
|
message("ragephoto-gtkviewer need to be build with libragephoto together")
|
||||||
|
|
|
@ -22,7 +22,7 @@
|
||||||
#include <RagePhoto.h>
|
#include <RagePhoto.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
PhotoViewer::PhotoViewer(Gtk::Label *title_label, Gtk::Label *json_label) : p_title_label(title_label), p_json_label(json_label)
|
PhotoViewer::PhotoViewer(Gtk::Window *win) : p_win(win)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -75,10 +75,7 @@ void PhotoViewer::open_file(const char *filename)
|
||||||
GdkPixbuf *c_pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
|
GdkPixbuf *c_pixbuf = gdk_pixbuf_loader_get_pixbuf(loader);
|
||||||
p_image = Glib::wrap(c_pixbuf);
|
p_image = Glib::wrap(c_pixbuf);
|
||||||
|
|
||||||
p_title_label->set_text("Title: " + ragePhoto.title());
|
p_win->set_title("RagePhoto GTK Photo Viewer - " + ragePhoto.title());
|
||||||
// p_title_label->show();
|
|
||||||
|
|
||||||
get_parent_window()->set_title("RagePhoto GTK Photo Viewer - " + ragePhoto.title());
|
|
||||||
|
|
||||||
free(photoData);
|
free(photoData);
|
||||||
|
|
||||||
|
|
|
@ -19,21 +19,20 @@
|
||||||
#ifndef PHOTOVIEWER_H
|
#ifndef PHOTOVIEWER_H
|
||||||
#define PHOTOVIEWER_H
|
#define PHOTOVIEWER_H
|
||||||
|
|
||||||
#include <gtkmm/drawingarea.h>
|
|
||||||
#include <gtkmm/label.h>
|
|
||||||
#include <gdkmm/pixbuf.h>
|
#include <gdkmm/pixbuf.h>
|
||||||
|
#include <gtkmm/drawingarea.h>
|
||||||
|
#include <gtkmm/window.h>
|
||||||
|
|
||||||
class PhotoViewer : public Gtk::DrawingArea
|
class PhotoViewer : public Gtk::DrawingArea
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
PhotoViewer(Gtk::Label *title_label, Gtk::Label *json_label);
|
PhotoViewer(Gtk::Window *win);
|
||||||
void open_file(const char *filename);
|
void open_file(const char *filename);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
|
bool on_draw(const Cairo::RefPtr<Cairo::Context>& cr) override;
|
||||||
Glib::RefPtr<Gdk::Pixbuf> p_image;
|
Glib::RefPtr<Gdk::Pixbuf> p_image;
|
||||||
Gtk::Label *p_title_label;
|
Gtk::Window *p_win;
|
||||||
Gtk::Label *p_json_label;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PHOTOVIEWER_H
|
#endif // PHOTOVIEWER_H
|
||||||
|
|
|
@ -36,24 +36,25 @@ int main(int argc, char *argv[])
|
||||||
win.set_resizable(false);
|
win.set_resizable(false);
|
||||||
|
|
||||||
Gtk::Box vertical_box(Gtk::ORIENTATION_VERTICAL);
|
Gtk::Box vertical_box(Gtk::ORIENTATION_VERTICAL);
|
||||||
|
vertical_box.set_margin_bottom(6);
|
||||||
|
vertical_box.set_spacing(6);
|
||||||
|
|
||||||
Gtk::Label title_label;
|
PhotoViewer photo_viewer(&win);
|
||||||
Gtk::Label json_label;
|
|
||||||
PhotoViewer photo_viewer(&title_label, &json_label);
|
|
||||||
vertical_box.add(photo_viewer);
|
vertical_box.add(photo_viewer);
|
||||||
vertical_box.add(title_label);
|
|
||||||
vertical_box.add(json_label);
|
|
||||||
photo_viewer.show();
|
photo_viewer.show();
|
||||||
|
|
||||||
Gtk::Box horizontal_box(Gtk::ORIENTATION_HORIZONTAL);
|
Gtk::Box horizontal_box(Gtk::ORIENTATION_HORIZONTAL);
|
||||||
|
horizontal_box.set_margin_left(6);
|
||||||
|
horizontal_box.set_margin_right(6);
|
||||||
|
horizontal_box.set_spacing(6);
|
||||||
vertical_box.add(horizontal_box);
|
vertical_box.add(horizontal_box);
|
||||||
|
|
||||||
Gtk::Button open_button;
|
Gtk::Button open_button;
|
||||||
open_button.set_label("Open");
|
open_button.set_label("Open");
|
||||||
open_button.set_hexpand(true);
|
open_button.set_hexpand(true);
|
||||||
open_button.set_can_default(false);
|
open_button.set_size_request(100);
|
||||||
open_button.signal_clicked().connect([&](){
|
open_button.signal_clicked().connect([&](){
|
||||||
Gtk::FileChooserDialog dialog("Open Photo", Gtk::FILE_CHOOSER_ACTION_OPEN);
|
Gtk::FileChooserDialog dialog("Open Photo...", Gtk::FILE_CHOOSER_ACTION_OPEN);
|
||||||
dialog.set_transient_for(win);
|
dialog.set_transient_for(win);
|
||||||
|
|
||||||
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
|
dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL);
|
||||||
|
@ -62,6 +63,7 @@ int main(int argc, char *argv[])
|
||||||
Glib::RefPtr<Gtk::FileFilter> filter_photo = Gtk::FileFilter::create();
|
Glib::RefPtr<Gtk::FileFilter> filter_photo = Gtk::FileFilter::create();
|
||||||
filter_photo->set_name("GTA V Photo");
|
filter_photo->set_name("GTA V Photo");
|
||||||
filter_photo->add_pattern("PGTA5*");
|
filter_photo->add_pattern("PGTA5*");
|
||||||
|
dialog.add_filter(filter_photo);
|
||||||
|
|
||||||
int result = dialog.run();
|
int result = dialog.run();
|
||||||
|
|
||||||
|
@ -81,7 +83,7 @@ int main(int argc, char *argv[])
|
||||||
Gtk::Button close_button;
|
Gtk::Button close_button;
|
||||||
close_button.set_label("Close");
|
close_button.set_label("Close");
|
||||||
close_button.set_hexpand(true);
|
close_button.set_hexpand(true);
|
||||||
close_button.set_can_default(false);
|
close_button.set_size_request(100);
|
||||||
close_button.signal_clicked().connect([&](){
|
close_button.signal_clicked().connect([&](){
|
||||||
win.close();
|
win.close();
|
||||||
});
|
});
|
||||||
|
|
26
examples/ragephoto-qtviewer/CMakeLists.txt
Normal file
26
examples/ragephoto-qtviewer/CMakeLists.txt
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
cmake_minimum_required(VERSION 3.7)
|
||||||
|
project(ragephoto-qtviewer LANGUAGES CXX)
|
||||||
|
|
||||||
|
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||||
|
set(CMAKE_CXX_STANDARD 11)
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
|
||||||
|
set(FORCE_QT_VERSION "" CACHE STRING "Force Qt Version")
|
||||||
|
if(FORCE_QT_VERSION)
|
||||||
|
set(QT_VERSION_MAJOR ${FORCE_QT_VERSION})
|
||||||
|
else()
|
||||||
|
find_package(QT NAMES Qt6 Qt5 COMPONENTS Core REQUIRED)
|
||||||
|
endif()
|
||||||
|
find_package(Qt${QT_VERSION_MAJOR} COMPONENTS Widgets REQUIRED)
|
||||||
|
|
||||||
|
set(QTVIEWER_SOURCES
|
||||||
|
src/main.cpp
|
||||||
|
)
|
||||||
|
|
||||||
|
if(TARGET ragephoto)
|
||||||
|
add_executable(ragephoto-qtviewer ${QTVIEWER_SOURCES})
|
||||||
|
target_link_libraries(ragephoto-qtviewer Qt${QT_VERSION_MAJOR}::Widgets ragephoto)
|
||||||
|
target_include_directories(ragephoto-qtviewer PRIVATE ${RAGEPHOTO_INCLUDE_DIRS})
|
||||||
|
else()
|
||||||
|
message("ragephoto-qtviewer need to be build with libragephoto together")
|
||||||
|
endif()
|
120
examples/ragephoto-qtviewer/src/main.cpp
Normal file
120
examples/ragephoto-qtviewer/src/main.cpp
Normal file
|
@ -0,0 +1,120 @@
|
||||||
|
/*****************************************************************************
|
||||||
|
* libragephoto RAGE Photo Parser
|
||||||
|
* Copyright (C) 2021 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.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
#include <RagePhoto.h>
|
||||||
|
#include <QApplication>
|
||||||
|
#include <QHBoxLayout>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <QFile>
|
||||||
|
#include <QFileDialog>
|
||||||
|
#include <QImage>
|
||||||
|
#include <QLabel>
|
||||||
|
#include <QMainWindow>
|
||||||
|
#include <QMessageBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QTimer>
|
||||||
|
|
||||||
|
bool readPhotoFile(const QString &filename, QMainWindow *mainWindow, QLabel *photoLabel)
|
||||||
|
{
|
||||||
|
QFile file(filename);
|
||||||
|
if (file.open(QIODevice::ReadOnly)) {
|
||||||
|
const QByteArray fileData = file.readAll();
|
||||||
|
RagePhoto ragePhoto;
|
||||||
|
const bool loaded = ragePhoto.load(fileData.data(), static_cast<size_t>(fileData.size()));
|
||||||
|
if (!loaded) {
|
||||||
|
const RagePhoto::Error error = ragePhoto.error();
|
||||||
|
if (error <= RagePhoto::Error::PhotoReadError) {
|
||||||
|
QMessageBox::warning(mainWindow, "Open Photo", "Failed to read photo: " + filename);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const QByteArray photoData = QByteArray::fromRawData(ragePhoto.photoData(), ragePhoto.photoSize());
|
||||||
|
const QImage image = QImage::fromData(photoData, "JPEG");
|
||||||
|
photoLabel->setPixmap(QPixmap::fromImage(image));
|
||||||
|
mainWindow->setWindowTitle("RagePhoto Qt Photo Viewer - " + QString::fromStdString(ragePhoto.title()));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
QMessageBox::warning(mainWindow, "Open Photo", "Failed to read file: " + filename);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
#if QT_VERSION >= 0x050600
|
||||||
|
#if QT_VERSION < 0x060000
|
||||||
|
QApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
|
||||||
|
QApplication::setAttribute(Qt::AA_UseHighDpiPixmaps, true);
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
QApplication app(argc, argv);
|
||||||
|
app.setApplicationName("ragephoto-qtviewer");
|
||||||
|
|
||||||
|
QMainWindow mainWindow;
|
||||||
|
mainWindow.setWindowTitle("RagePhoto Qt Photo Viewer");
|
||||||
|
mainWindow.setFixedSize(400, 100);
|
||||||
|
|
||||||
|
QWidget centralWidget(&mainWindow);
|
||||||
|
mainWindow.setCentralWidget(¢ralWidget);
|
||||||
|
|
||||||
|
QVBoxLayout verticalLayout(&mainWindow);
|
||||||
|
verticalLayout.setContentsMargins(0, 0, 0, 0);
|
||||||
|
verticalLayout.setSpacing(6);
|
||||||
|
centralWidget.setLayout(&verticalLayout);
|
||||||
|
|
||||||
|
QLabel photoLabel(&mainWindow);
|
||||||
|
verticalLayout.addWidget(&photoLabel);
|
||||||
|
|
||||||
|
QHBoxLayout horizontalLayout(&mainWindow);
|
||||||
|
horizontalLayout.setContentsMargins(6, 0, 6, 6);
|
||||||
|
horizontalLayout.setSpacing(6);
|
||||||
|
verticalLayout.addLayout(&horizontalLayout);
|
||||||
|
|
||||||
|
QPushButton openButton("Open", &mainWindow);
|
||||||
|
QObject::connect(&openButton, &QPushButton::clicked, &mainWindow, [&](){
|
||||||
|
const QString filename = QFileDialog::getOpenFileName(&mainWindow, "Open Photo...", QString(), "GTA V Photo (PGTA5*)");
|
||||||
|
if (readPhotoFile(filename, &mainWindow, &photoLabel)) {
|
||||||
|
QTimer::singleShot(0, &mainWindow, [&](){
|
||||||
|
mainWindow.setFixedSize(mainWindow.sizeHint());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
horizontalLayout.addWidget(&openButton);
|
||||||
|
|
||||||
|
QPushButton closeButton("Close", &mainWindow);
|
||||||
|
QObject::connect(&closeButton, &QPushButton::clicked, &mainWindow, &QMainWindow::close);
|
||||||
|
horizontalLayout.addWidget(&closeButton);
|
||||||
|
|
||||||
|
const QStringList args = app.arguments();
|
||||||
|
if (args.length() == 2) {
|
||||||
|
const QString filename = args.at(1);
|
||||||
|
if (readPhotoFile(filename, &mainWindow, &photoLabel)) {
|
||||||
|
QTimer::singleShot(0, &mainWindow, [&](){
|
||||||
|
mainWindow.setFixedSize(mainWindow.sizeHint());
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (args.length() > 2) {
|
||||||
|
QMessageBox::warning(&mainWindow, "RagePhoto Qt Photo Viewer", "Can't open multiple photos at once!");
|
||||||
|
}
|
||||||
|
|
||||||
|
mainWindow.show();
|
||||||
|
|
||||||
|
return app.exec();
|
||||||
|
}
|
|
@ -85,10 +85,8 @@ bool RagePhoto::load(const char *data, size_t length)
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CODECVT_COMPATIBLE
|
#ifdef CODECVT_COMPATIBLE
|
||||||
char16_t photoHeader16[128];
|
|
||||||
memcpy(photoHeader16, photoHeader, 256);
|
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
std::wstring_convert<std::codecvt_utf8_utf16<char16_t>,char16_t> convert;
|
||||||
p_photoString = convert.to_bytes(photoHeader16);
|
p_photoString = convert.to_bytes(reinterpret_cast<char16_t*>(photoHeader));
|
||||||
#elif defined ICONV_COMPATIBLE
|
#elif defined ICONV_COMPATIBLE
|
||||||
iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
|
iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE");
|
||||||
if (iconv_in == (iconv_t)-1) {
|
if (iconv_in == (iconv_t)-1) {
|
||||||
|
|
Loading…
Reference in a new issue