diff --git a/CMakeLists.txt b/CMakeLists.txt index caa554b..a3bd9bd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON) message("-- Testing codecvt") try_run(CODECVT_RUN CODECVT_COMPILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/CodecvtTest.cpp) -if (CODECVT_COMPILE) +if (CODECVT_COMPILE AND CODECVT_RUN EQUAL 0) list(APPEND LIBRAGEPHOTO_DEFINES CODECVT_COMPATIBLE ) @@ -18,7 +18,7 @@ endif() message("-- Testing iconv") try_run(ICONV_RUN ICONV_COMPILE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/tests/IconvTest.cpp) -if (ICONV_COMPILE) +if (ICONV_COMPILE AND ICONV_RUN EQUAL 0) list(APPEND LIBRAGEPHOTO_DEFINES ICONV_COMPATIBLE ) @@ -60,6 +60,11 @@ 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) + add_subdirectory(examples/ragephoto-gtkviewer) +endif() + option(WITH_EXTRACT "Build ragephoto-extract" ON) if (WITH_EXTRACT) project(ragephoto-extract LANGUAGES CXX) diff --git a/examples/ragephoto-gtkviewer/CMakeLists.txt b/examples/ragephoto-gtkviewer/CMakeLists.txt new file mode 100644 index 0000000..f49f5cb --- /dev/null +++ b/examples/ragephoto-gtkviewer/CMakeLists.txt @@ -0,0 +1,30 @@ +cmake_minimum_required(VERSION 3.7) +enable_language(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) + +project(ragephoto-gtkviewer LANGUAGES CXX) + +set(GTKVIEWER_HEADERS + src/PhotoViewer.h +) + +set(GTKVIEWER_SOURCES + src/main.cpp + src/PhotoViewer.cpp +) + +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}) +else() + message("ragephoto-gtkviewer need to be build with libragephoto together") +endif() diff --git a/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp b/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp new file mode 100644 index 0000000..00adf60 --- /dev/null +++ b/examples/ragephoto-gtkviewer/src/PhotoViewer.cpp @@ -0,0 +1,102 @@ +/***************************************************************************** +* 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 "PhotoViewer.h" +#include +#include +#include +#include + +PhotoViewer::PhotoViewer(Gtk::Label *title_label, Gtk::Label *json_label) : p_title_label(title_label), p_json_label(json_label) +{ +} + +void PhotoViewer::open_file(const char *filename) +{ + RagePhoto ragePhoto; + // Read file + FILE *file = fopen(filename, "rb"); + if (!file) { + return; + } + const int fseek_end_value = fseek(file, 0, SEEK_END); + if (fseek_end_value == -1) { + fclose(file); + return; + } + const size_t file_size = ftell(file); + if (file_size == -1) { + fclose(file); + return; + } + const int fseek_set_value = fseek(file, 0, SEEK_SET); + if (fseek_set_value == -1) { + fclose(file); + return; + } + char *data = static_cast(malloc(file_size)); + const size_t file_rsize = fread(data, 1, file_size, file); + if (file_size != file_rsize) { + fclose(file); + return; + } + fclose(file); + const bool loaded = ragePhoto.load(data, file_size); + free(data); + if (!loaded) { + const RagePhoto::Error error = ragePhoto.error(); + if (error <= RagePhoto::Error::PhotoReadError) + return; + } + + guchar *photoData = static_cast(malloc(ragePhoto.photoSize())); + if (!photoData) + return; + + memcpy(photoData, ragePhoto.photoData(), ragePhoto.photoSize()); + + GdkPixbufLoader *loader = gdk_pixbuf_loader_new(); + gdk_pixbuf_loader_write(loader, photoData, static_cast(ragePhoto.photoSize()), nullptr); + 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()); + + free(photoData); + + if (p_image) + set_size_request(p_image->get_width(), p_image->get_height()); +} + +bool PhotoViewer::on_draw(const Cairo::RefPtr& cr) +{ + if (!p_image) + return false; + + Gtk::Allocation allocation = get_allocation(); + const int width = allocation.get_width(); + const int height = allocation.get_height(); + + Gdk::Cairo::set_source_pixbuf(cr, p_image, (width - p_image->get_width()) / 2, (height - p_image->get_height()) / 2); + cr->paint(); + + return true; +} diff --git a/examples/ragephoto-gtkviewer/src/PhotoViewer.h b/examples/ragephoto-gtkviewer/src/PhotoViewer.h new file mode 100644 index 0000000..bf1dcea --- /dev/null +++ b/examples/ragephoto-gtkviewer/src/PhotoViewer.h @@ -0,0 +1,39 @@ +/***************************************************************************** +* 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. +*****************************************************************************/ + +#ifndef PHOTOVIEWER_H +#define PHOTOVIEWER_H + +#include +#include +#include + +class PhotoViewer : public Gtk::DrawingArea +{ +public: + PhotoViewer(Gtk::Label *title_label, Gtk::Label *json_label); + 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; +}; + +#endif // PHOTOVIEWER_H diff --git a/examples/ragephoto-gtkviewer/src/main.cpp b/examples/ragephoto-gtkviewer/src/main.cpp new file mode 100644 index 0000000..3b2eb48 --- /dev/null +++ b/examples/ragephoto-gtkviewer/src/main.cpp @@ -0,0 +1,105 @@ +/***************************************************************************** +* 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 "PhotoViewer.h" +#include +#include +#include +#include +#include +#include +#include +#include + +int main(int argc, char *argv[]) +{ + auto app = Gtk::Application::create(argc, argv, "de.syping.ragephoto.gtkviewer", Gio::APPLICATION_HANDLES_OPEN); + + Gtk::Window win; + win.set_title("RagePhoto GTK Photo Viewer"); + win.set_default_size(400, 0); + win.set_resizable(false); + + Gtk::Box vertical_box(Gtk::ORIENTATION_VERTICAL); + + Gtk::Label title_label; + Gtk::Label json_label; + PhotoViewer photo_viewer(&title_label, &json_label); + 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); + 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.signal_clicked().connect([&](){ + Gtk::FileChooserDialog dialog("Open Photo", Gtk::FILE_CHOOSER_ACTION_OPEN); + dialog.set_transient_for(win); + + dialog.add_button("_Cancel", Gtk::RESPONSE_CANCEL); + dialog.add_button("_Open", Gtk::RESPONSE_OK); + + Glib::RefPtr filter_photo = Gtk::FileFilter::create(); + filter_photo->set_name("GTA V Photo"); + filter_photo->add_pattern("PGTA5*"); + + int result = dialog.run(); + + switch(result) { + case Gtk::RESPONSE_OK: { + std::string filename = dialog.get_filename(); + photo_viewer.open_file(filename.c_str()); + break; + } + default: + break; + } + }); + horizontal_box.add(open_button); + open_button.show(); + + Gtk::Button close_button; + close_button.set_label("Close"); + close_button.set_hexpand(true); + close_button.set_can_default(false); + close_button.signal_clicked().connect([&](){ + win.close(); + }); + horizontal_box.add(close_button); + close_button.show(); + + app->signal_open().connect([&](const Gio::Application::type_vec_files &files, const Glib::ustring &hint){ + for (const auto &file : files) { + photo_viewer.open_file(file->get_path().c_str()); + } + app->add_window(win); + win.show(); + }); + + horizontal_box.show(); + vertical_box.show(); + + win.add(vertical_box); + + return app->run(win); +} diff --git a/src/RagePhoto.cpp b/src/RagePhoto.cpp index 16a468e..ed74a7b 100644 --- a/src/RagePhoto.cpp +++ b/src/RagePhoto.cpp @@ -86,7 +86,7 @@ bool RagePhoto::load(const char *data, size_t length) #ifdef CODECVT_COMPATIBLE char16_t photoHeader16[128]; - memcpy(photoHeader16, photoHeader, sizeof(char) * 256); + memcpy(photoHeader16, photoHeader, 256); std::wstring_convert,char16_t> convert; p_photoString = convert.to_bytes(photoHeader16); #elif defined ICONV_COMPATIBLE @@ -352,7 +352,7 @@ size_t RagePhoto::readBuffer(const char *input, char *output, size_t *pos, size_ readLen = inputLen - *pos; if (readLen > len) readLen = len; - memcpy(output, &input[*pos], sizeof(char) * readLen); + memcpy(output, &input[*pos], readLen); *pos = *pos + readLen; return readLen; } diff --git a/tests/CodecvtTest.cpp b/tests/CodecvtTest.cpp index 5e7750e..e20245c 100644 --- a/tests/CodecvtTest.cpp +++ b/tests/CodecvtTest.cpp @@ -58,7 +58,7 @@ int main(int argc, char *argv[]) 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; char16_t photoHeader16[128]; - memcpy(photoHeader16, photoHeader, sizeof(char) * 256); + memcpy(photoHeader16, photoHeader, 256); std::wstring_convert,char16_t> convert; std::string photoString = convert.to_bytes(photoHeader16); std::cout << photoString << std::endl;