Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions .github/workflows/gui.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
name: GUI

permissions:
contents: read

on:
push:
pull_request:

jobs:
gui-ubuntu:
name: "GUI Ubuntu"
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Dependencies
run: |
sudo apt-get update
sudo apt-get -q install -y \
libceres-dev \
nlohmann-json3-dev \
libopencv-dev \
openimageio-tools libopenimageio-dev \
exiftool \
liblensfun-dev \
liblensfun-data-v1 \
libglib2.0-dev \
qt6-base-dev \
qt6-base-dev-tools

- name: Configure
run: >
cmake -S . -B build
-D CMAKE_BUILD_TYPE=Release
-D RTA_BUILD_GUI=ON
-D RTA_BUILD_TESTS=ON
-D RTA_BUILD_PYTHON_BINDINGS=OFF

- name: Build
run: cmake --build build --config Release

- name: Binary smoke
run: test -x build/src/rawtoaces_gui/rawtoaces_gui

gui-macos:
name: "GUI macOS"
runs-on: macos-latest
steps:
- uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4

- name: Dependencies
run: |
brew install cmake ceres-solver nlohmann-json openimageio nanobind robin-map qt@6 exiftool lensfun
python3 -m pip install --break-system-packages pytest || python3 -m pip install pytest

- name: Configure
run: |
QT_PREFIX="$(brew --prefix qt@6)"
cmake -S . -B build \
-D CMAKE_BUILD_TYPE=Release \
-D RTA_BUILD_GUI=ON \
-D RTA_BUILD_TESTS=ON \
-D CMAKE_PREFIX_PATH="$QT_PREFIX"

- name: Build
run: cmake --build build --config Release

- name: Binary smoke
run: test -x "build/src/rawtoaces_gui/Raw to ACES.app/Contents/MacOS/Raw to ACES"
12 changes: 10 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.16)
project( RAWTOACES )

if( NOT DEFINED CMAKE_CXX_STANDARD )
Expand Down Expand Up @@ -78,6 +78,7 @@ option( RTA_BUILD_TESTS "Build unit tests" ON )
option( RTA_INSTALL_DATABASE "Download and install the spectral measurements database" ON )
option( ENABLE_COVERAGE "Enable code coverage reporting" OFF )
option( RTA_ENABLE_LENSFUN "Use lensfun for lens correction" ON )
option( RTA_BUILD_GUI "Build Qt 6 GUI application (rawtoaces_gui)" OFF )
set ( RTA_SANITISER_MODE "none" CACHE STRING "Dynamic analysis sanitiser mode ('none', 'address', 'memory', or 'thread')" )

if ( ENABLE_SHARED )
Expand All @@ -102,12 +103,19 @@ add_subdirectory("src/${RAWTOACES_CORE_LIB}")
add_subdirectory("src/${RAWTOACES_UTIL_LIB}")
add_subdirectory("src/rawtoaces")

if ( RTA_BUILD_TESTS )
enable_testing()
endif()

if ( RTA_BUILD_GUI )
add_subdirectory("src/rawtoaces_gui")
endif()

if ( RTA_BUILD_PYTHON_BINDINGS )
add_subdirectory(src/bindings)
endif ( RTA_BUILD_PYTHON_BINDINGS )

if ( RTA_BUILD_TESTS )
enable_testing()
add_subdirectory(tests)
endif ( RTA_BUILD_TESTS )

Expand Down
18 changes: 16 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
</p>

[![CI](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/ci.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/ci.yml)
[![GUI](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/gui.yml/badge.svg)](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/gui.yml)
[![Code scanning – CodeQL](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/github-code-scanning/codeql/badge.svg)](https://github.com/AcademySoftwareFoundation/rawtoaces/actions/workflows/github-code-scanning/codeql)
[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/11185/badge)](https://www.bestpractices.dev/projects/11185)
[![codecov](https://codecov.io/gh/AcademySoftwareFoundation/rawtoaces/branch/main/graph/badge.svg)](https://codecov.io/gh/AcademySoftwareFoundation/rawtoaces)
Expand Down Expand Up @@ -35,16 +36,18 @@ The source code contains the following:
* [`config/`](./config) - CMake configuration files
* [`docs/`](./docs) - Credits and changes information
* [`include/`](./include) - Public header files for the `rawtoaces` library
* [`src/`](./src) - Source code for the core library, utility library, and the command line tool
* [`src/`](./src) - Source code for the core library, utility library, command line tool, and optional Qt GUI (`rawtoaces_gui`)
* [`unittest/`](./unittest) - Unit tests for `rawtoaces`


## Prerequisites

To build `rawtoaces` you would need to satisfy these dependencies:

| Library | Min Version| Purpose | Link to installation instruction |
| ------- | -----------| -------- | -------------------------------- |
| `cmake` | `3.12` | | [CMake download](https://cmake.org/download/)|
| `cmake` | `3.16` | | [CMake download](https://cmake.org/download/)|
| Qt 6 (optional) | `6.4` | Widgets module for `rawtoaces_gui` | [Qt documentation](https://doc.qt.io/qt-6/) |
| `ceres` | `1.12.0` | Ceres Solver is an open source library for solving Non-linear Least Squares problems with bounds constraints and unconstrained optimization problems. It processes non-linear regression for rawtoaces. | [Ceres Solver installation](http://ceres-solver.org/installation.html)|
| `OpenImageIO` | `3.0` | OpenImageIO is an open source library providing vast functionality for image processing. rawtoaces relies on OpenImageIO for reading raw files, saving AcesContainer files, and also all pixel operations. | [OpenImageIO installation](https://github.com/AcademySoftwareFoundation/OpenImageIO/blob/main/INSTALL.md) |
| `nlohmann-json` | `3.6` | nlohmann-json is a simple header-only library for parsing JSON files. | [nlohmann-json integration](https://github.com/nlohmann/json#integration) |
Expand Down Expand Up @@ -116,6 +119,17 @@ $ sudo cmake --install build # Optional if you want it to be accessible system w

The default process will install `librawtoaces_core_${rawtoaces_version}.dylib` and `librawtoaces_util_${rawtoaces_version}.dylib` to `/usr/local/lib`, a few header files to `/usr/local/include/rawtoaces` and a number of data files into `/usr/local/include/rawtoaces/data`.

#### Qt GUI (optional)

Build the desktop application `rawtoaces_gui` with `-DRTA_BUILD_GUI=ON` (requires Qt 6 Widgets). On macOS with Homebrew Qt, point CMake at the prefix, for example:

```sh
$ cmake -S . -B build -DRTA_BUILD_GUI=ON -DCMAKE_PREFIX_PATH="$(brew --prefix qt@6)"
$ cmake --build build
```

After building, start the GUI from `build/src/rawtoaces_gui/`: use the **`rawtoaces_gui`** program on Windows and Linux, or **`Raw to ACES.app`** on macOS (CMake target remains **`rawtoaces_gui`**). The name shown in the window title, menu bar, and About dialog is **Raw to ACES**.

#### Docker

Assuming you have [Docker](https://www.docker.com/) installed, installing and
Expand Down
3 changes: 2 additions & 1 deletion build_scripts/install_deps_ubuntu.bash
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,8 @@ time sudo apt-get -q -f install -y \
openimageio-tools libopenimageio-dev \
exiftool \
liblensfun-dev \
liblensfun-data-v1
liblensfun-data-v1 \
libglib2.0-dev

# Nanobind in apt is still v1.9, we need at least v2.2.
pip3 install pytest nanobind
2 changes: 1 addition & 1 deletion src/bindings/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required ( VERSION 3.12 )
cmake_minimum_required ( VERSION 3.16 )
include_directories ( "${CMAKE_CURRENT_SOURCE_DIR}" )

nanobind_add_module( rawtoaces_bindings
Expand Down
2 changes: 1 addition & 1 deletion src/rawtoaces/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.16)

# Include coverage support if enabled
if( ENABLE_COVERAGE )
Expand Down
2 changes: 1 addition & 1 deletion src/rawtoaces_core/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.12)
cmake_minimum_required(VERSION 3.16)
include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" )

# Include coverage support if enabled
Expand Down
70 changes: 70 additions & 0 deletions src/rawtoaces_gui/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
cmake_minimum_required(VERSION 3.16)

find_package(Qt6 6.4 REQUIRED COMPONENTS Widgets)

set(CMAKE_AUTOMOC ON)

qt_add_library(rawtoaces_gui_lib STATIC
main_window.cpp
conversion_thread.cpp
)

target_link_libraries(rawtoaces_gui_lib PUBLIC
${RAWTOACES_UTIL_LIB}
Qt6::Widgets
)

target_include_directories(rawtoaces_gui_lib PUBLIC
"${CMAKE_CURRENT_SOURCE_DIR}"
)
target_include_directories(rawtoaces_gui_lib PRIVATE
$<$<BOOL:${RTA_ENABLE_LENSFUN}>:${CMAKE_SOURCE_DIR}/src/rawtoaces_util>
)

target_compile_definitions(rawtoaces_gui_lib PUBLIC
$<$<BOOL:${RTA_ENABLE_LENSFUN}>:RTA_GUI_HAS_LENSFUN=1>
)

qt_add_executable(rawtoaces_gui
main.cpp
)

target_link_libraries(rawtoaces_gui PRIVATE rawtoaces_gui_lib)

if(WIN32)
set_target_properties(rawtoaces_gui PROPERTIES WIN32_EXECUTABLE TRUE)
endif()

# macOS: build a real .app so Finder/Dock get bundle metadata; menu bar title
# follows setApplicationDisplayName in main.cpp (e.g. "Raw to ACES").
if(APPLE)
set(RTA_GUI_MACOS_ICON "${CMAKE_CURRENT_SOURCE_DIR}/macos/rawtoaces_gui.icns")
set_target_properties(rawtoaces_gui PROPERTIES
MACOSX_BUNDLE TRUE
# Bundle folder and CFBundleExecutable (Linux/Windows keep target name: rawtoaces_gui).
OUTPUT_NAME "Raw to ACES"
MACOSX_BUNDLE_BUNDLE_NAME "Raw to ACES"
MACOSX_BUNDLE_GUI_IDENTIFIER "org.aswf.rawtoaces.gui"
MACOSX_BUNDLE_INFO_SHORT_VERSION_STRING "${RAWTOACES_VERSION}"
MACOSX_BUNDLE_BUNDLE_VERSION "${RAWTOACES_VERSION}"
)
if(EXISTS "${RTA_GUI_MACOS_ICON}")
target_sources(rawtoaces_gui PRIVATE "${RTA_GUI_MACOS_ICON}")
set_source_files_properties("${RTA_GUI_MACOS_ICON}" PROPERTIES
MACOSX_PACKAGE_LOCATION Resources
)
# Base name (no extension) must match Resources/*.icns; independent of OUTPUT_NAME.
set_target_properties(rawtoaces_gui PROPERTIES
MACOSX_BUNDLE_ICON_FILE "rawtoaces_gui"
)
endif()
endif()

if(APPLE)
install(TARGETS rawtoaces_gui
BUNDLE DESTINATION ${INSTALL_BIN_DIR}
RUNTIME DESTINATION ${INSTALL_BIN_DIR}
)
else()
install(TARGETS rawtoaces_gui DESTINATION ${INSTALL_BIN_DIR})
endif()
50 changes: 50 additions & 0 deletions src/rawtoaces_gui/conversion_thread.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the rawtoaces Project.

#include "conversion_thread.h"

ConversionThread::ConversionThread( QObject *parent ) : QThread( parent )
{}

void ConversionThread::setJob(
rta::util::ImageConverter::Settings settings, QStringList paths )
{
m_settings = std::move( settings );
m_paths = std::move( paths );
m_cancel.store( false );
}

void ConversionThread::requestCancel()
{
m_cancel.store( true );
}

void ConversionThread::run()
{
const int total = static_cast<int>( m_paths.size() );
if ( total <= 0 )
{
emit progress( 0, 0 );
emit batchFinished();
return;
}
for ( int i = 0; i < total; ++i )
{
if ( m_cancel.load() )
{
emit batchFinished();
return;
}

const QString path = m_paths.at( i );
emit fileStarted( i, path );

rta::util::ImageConverter converter;
converter.settings = m_settings;
const bool ok = converter.process_image( path.toStdString() );
emit fileFinished(
i, ok, QString::fromStdString( converter.last_error_message ) );
emit progress( i + 1, total );
}
emit batchFinished();
}
38 changes: 38 additions & 0 deletions src/rawtoaces_gui/conversion_thread.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the rawtoaces Project.

#pragma once

#include <atomic>

#include <QThread>
#include <QStringList>

#include <rawtoaces/image_converter.h>

class ConversionThread final : public QThread
{
Q_OBJECT

public:
explicit ConversionThread( QObject *parent = nullptr );

void
setJob( rta::util::ImageConverter::Settings settings, QStringList paths );

void requestCancel();

signals:
void fileStarted( int index, QString path );
void fileFinished( int index, bool ok, QString message );
void progress( int done, int total );
void batchFinished();

protected:
void run() override;

private:
rta::util::ImageConverter::Settings m_settings{};
QStringList m_paths;
std::atomic_bool m_cancel{ false };
};
Binary file added src/rawtoaces_gui/macos/rawtoaces-icon-1024.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/rawtoaces_gui/macos/rawtoaces-icon-source.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added src/rawtoaces_gui/macos/rawtoaces_gui.icns
Binary file not shown.
42 changes: 42 additions & 0 deletions src/rawtoaces_gui/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright Contributors to the rawtoaces Project.

#include "main_window.h"

#include <QApplication>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QIcon>

#include <cstdlib>

int main( int argc, char *argv[] )
{
#if defined( _WIN32 )
_putenv( const_cast<char *>( "TZ=UTC" ) );
#else
setenv( "TZ", "UTC", 1 );
#endif

QApplication application( argc, argv );
QApplication::setApplicationName( QStringLiteral( "rawtoaces" ) );
// macOS menu bar uses the display name (not the .app / executable basename).
QApplication::setApplicationDisplayName( QStringLiteral( "Raw to ACES" ) );
QApplication::setOrganizationName( QStringLiteral( "rawtoaces" ) );

#if defined( Q_OS_MACOS )
// Qt paints the Dock tile from this pixmap (no system squircle); the .icns carries
// transparent corners (squircle)
const QString icnsPath = QDir{ QCoreApplication::applicationDirPath() }.filePath(
QStringLiteral( "../Resources/rawtoaces_gui.icns" ) );
if ( QFile::exists( icnsPath ) )
{
QApplication::setWindowIcon( QIcon( icnsPath ) );
}
#endif

MainWindow mainWindow;
mainWindow.show();
return application.exec();
}
Loading
Loading