From 33c3dcb5122ac5d244b7e168c3393072cc46906e Mon Sep 17 00:00:00 2001 From: Syping Date: Fri, 27 Aug 2021 20:07:14 +0200 Subject: [PATCH] add Qt example, GTK example fixes, README update --- CMakeLists.txt | 13 +- README.md | 5 +- examples/ragephoto-gtkviewer/CMakeLists.txt | 10 +- .../ragephoto-gtkviewer/src/PhotoViewer.cpp | 7 +- .../ragephoto-gtkviewer/src/PhotoViewer.h | 9 +- examples/ragephoto-gtkviewer/src/main.cpp | 18 +-- examples/ragephoto-qtviewer/CMakeLists.txt | 26 ++++ examples/ragephoto-qtviewer/src/main.cpp | 120 ++++++++++++++++++ src/RagePhoto.cpp | 4 +- 9 files changed, 181 insertions(+), 31 deletions(-) create mode 100644 examples/ragephoto-qtviewer/CMakeLists.txt create mode 100644 examples/ragephoto-qtviewer/src/main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index a3bd9bd..cdd589b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,5 @@ cmake_minimum_required(VERSION 3.7) -enable_language(CXX) +project(ragephoto LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) @@ -60,12 +60,17 @@ target_compile_definitions(ragephoto PRIVATE install(TARGETS ragephoto DESTINATION lib) install(FILES ${RAGEPHOTO_HEADERS} DESTINATION include) -option(WITH_EXAMPLES "Build ragephoto examples" OFF) -if (WITH_EXAMPLES) +option(WITH_GTK_EXAMPLE "Build libragephoto with GTK Photo Viewer" OFF) +if (WITH_GTK_EXAMPLE) add_subdirectory(examples/ragephoto-gtkviewer) 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) project(ragephoto-extract LANGUAGES CXX) set(EXTRACT_SOURCES diff --git a/README.md b/README.md index 6abfa6e..2ada516 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ Open Source RAGE Photo Parser for GTA V - Export RAGE Photos to jpeg with ragephoto-extract - High Efficient and Simple C++ API -#### Build libragephoto & ragephoto-extract +#### Build libragephoto ```bash git clone https://gitlab.com/Syping/libragephoto && cd libragephoto @@ -16,6 +16,9 @@ make -j $(nproc --all) sudo make install ``` +##### Optional CMake flags +`-DWITH_EXTRACT=OFF` `-DWITH_GTK_EXAMPLE=ON` `-DWITH_QT_EXAMPLE=ON` `-DBUILD_SHARED=OFF` + #### How to Use libragephoto ```cpp diff --git a/examples/ragephoto-gtkviewer/CMakeLists.txt b/examples/ragephoto-gtkviewer/CMakeLists.txt index 0304260..5e7c109 100644 --- a/examples/ragephoto-gtkviewer/CMakeLists.txt +++ b/examples/ragephoto-gtkviewer/CMakeLists.txt @@ -1,12 +1,12 @@ cmake_minimum_required(VERSION 3.7) -enable_language(CXX) +project(ragephoto-gtkviewer LANGUAGES CXX) set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_CXX_STANDARD 11) set(CMAKE_CXX_STANDARD_REQUIRED ON) 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) @@ -22,9 +22,9 @@ set(GTKVIEWER_SOURCES if(TARGET ragephoto) set(RAGEPHOTO_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/src) add_executable(ragephoto-gtkviewer ${GTKVIEWER_HEADERS} ${GTKVIEWER_SOURCES}) - target_link_libraries(ragephoto-gtkviewer ${gtkmm_LIBRARIES} ragephoto) - target_link_directories(ragephoto-gtkviewer PRIVATE ${gtkmm_LIBRARY_DIRS}) - target_include_directories(ragephoto-gtkviewer PRIVATE ${gtkmm_INCLUDE_DIRS} ${RAGEPHOTO_INCLUDE_DIRS}) + target_link_libraries(ragephoto-gtkviewer ${GTKMM_LIBRARIES} ragephoto) + target_link_directories(ragephoto-gtkviewer PRIVATE ${GTKMM_LIBRARY_DIRS}) + target_include_directories(ragephoto-gtkviewer PRIVATE ${GTKMM_INCLUDE_DIRS} ${RAGEPHOTO_INCLUDE_DIRS}) install(TARGETS ragephoto-gtkviewer DESTINATION bin) else() message("ragephoto-gtkviewer need to be build with libragephoto together") diff --git a/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp b/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp index 00adf60..d37d740 100644 --- a/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp +++ b/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp @@ -22,7 +22,7 @@ #include #include -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); p_image = Glib::wrap(c_pixbuf); - p_title_label->set_text("Title: " + ragePhoto.title()); - // p_title_label->show(); - - get_parent_window()->set_title("RagePhoto GTK Photo Viewer - " + ragePhoto.title()); + p_win->set_title("RagePhoto GTK Photo Viewer - " + ragePhoto.title()); free(photoData); diff --git a/examples/ragephoto-gtkviewer/src/PhotoViewer.h b/examples/ragephoto-gtkviewer/src/PhotoViewer.h index bf1dcea..5c1a122 100644 --- a/examples/ragephoto-gtkviewer/src/PhotoViewer.h +++ b/examples/ragephoto-gtkviewer/src/PhotoViewer.h @@ -19,21 +19,20 @@ #ifndef PHOTOVIEWER_H #define PHOTOVIEWER_H -#include -#include #include +#include +#include class PhotoViewer : public Gtk::DrawingArea { public: - PhotoViewer(Gtk::Label *title_label, Gtk::Label *json_label); + PhotoViewer(Gtk::Window *win); void open_file(const char *filename); protected: bool on_draw(const Cairo::RefPtr& cr) override; Glib::RefPtr p_image; - Gtk::Label *p_title_label; - Gtk::Label *p_json_label; + Gtk::Window *p_win; }; #endif // PHOTOVIEWER_H diff --git a/examples/ragephoto-gtkviewer/src/main.cpp b/examples/ragephoto-gtkviewer/src/main.cpp index 3b2eb48..1caf428 100644 --- a/examples/ragephoto-gtkviewer/src/main.cpp +++ b/examples/ragephoto-gtkviewer/src/main.cpp @@ -36,24 +36,25 @@ int main(int argc, char *argv[]) win.set_resizable(false); Gtk::Box vertical_box(Gtk::ORIENTATION_VERTICAL); + vertical_box.set_margin_bottom(6); + vertical_box.set_spacing(6); - Gtk::Label title_label; - Gtk::Label json_label; - PhotoViewer photo_viewer(&title_label, &json_label); + PhotoViewer photo_viewer(&win); vertical_box.add(photo_viewer); - vertical_box.add(title_label); - vertical_box.add(json_label); photo_viewer.show(); 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); Gtk::Button open_button; open_button.set_label("Open"); open_button.set_hexpand(true); - open_button.set_can_default(false); + open_button.set_size_request(100); 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.add_button("_Cancel", Gtk::RESPONSE_CANCEL); @@ -62,6 +63,7 @@ int main(int argc, char *argv[]) Glib::RefPtr filter_photo = Gtk::FileFilter::create(); filter_photo->set_name("GTA V Photo"); filter_photo->add_pattern("PGTA5*"); + dialog.add_filter(filter_photo); int result = dialog.run(); @@ -81,7 +83,7 @@ int main(int argc, char *argv[]) Gtk::Button close_button; close_button.set_label("Close"); close_button.set_hexpand(true); - close_button.set_can_default(false); + close_button.set_size_request(100); close_button.signal_clicked().connect([&](){ win.close(); }); diff --git a/examples/ragephoto-qtviewer/CMakeLists.txt b/examples/ragephoto-qtviewer/CMakeLists.txt new file mode 100644 index 0000000..5a2e193 --- /dev/null +++ b/examples/ragephoto-qtviewer/CMakeLists.txt @@ -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() diff --git a/examples/ragephoto-qtviewer/src/main.cpp b/examples/ragephoto-qtviewer/src/main.cpp new file mode 100644 index 0000000..a1f57bb --- /dev/null +++ b/examples/ragephoto-qtviewer/src/main.cpp @@ -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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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(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(); +} diff --git a/src/RagePhoto.cpp b/src/RagePhoto.cpp index ed74a7b..0f471c0 100644 --- a/src/RagePhoto.cpp +++ b/src/RagePhoto.cpp @@ -85,10 +85,8 @@ bool RagePhoto::load(const char *data, size_t length) } #ifdef CODECVT_COMPATIBLE - char16_t photoHeader16[128]; - memcpy(photoHeader16, photoHeader, 256); std::wstring_convert,char16_t> convert; - p_photoString = convert.to_bytes(photoHeader16); + p_photoString = convert.to_bytes(reinterpret_cast(photoHeader)); #elif defined ICONV_COMPATIBLE iconv_t iconv_in = iconv_open("UTF-8", "UTF-16LE"); if (iconv_in == (iconv_t)-1) {