Skip to content
Merged
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
2 changes: 1 addition & 1 deletion dependencies/libexif
Submodule libexif updated 1 files
+19 −102 libexif/exif-data.c
4 changes: 4 additions & 0 deletions include/tev/Common.h
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,10 @@ template <typename... Callable> struct visitor : Callable... {

template <typename T> concept trivially_copyable = std::is_trivially_copyable_v<T>;

template <typename T> std::span<T> toSpan(const std::istringstream& stream) {
return std::span<T>{reinterpret_cast<const T*>(stream.view().data()), stream.view().size()};
}

// Stricter version of from_chars that only returns true if the entire input was consumed and no error occurred.
template <typename T> bool fromChars(const char* begin, const char* end, T& value) {
const auto result = std::from_chars(begin, end, value);
Expand Down
6 changes: 3 additions & 3 deletions include/tev/Image.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,11 @@
#include <array>
#include <atomic>
#include <expected>
#include <istream>
#include <map>
#include <memory>
#include <optional>
#include <span>
#include <sstream>
#include <string>
#include <vector>

Expand Down Expand Up @@ -344,10 +344,10 @@ Task<nanogui::Vector2i> orientToTopLeft(PixelBuffer& data, nanogui::Vector2i siz
using ImageLoadResult = std::expected<std::vector<std::shared_ptr<Image>>, ImageLoadError>;

Task<ImageLoadResult> tryLoadImage(
int imageId, fs::path path, std::istream& iStream, std::string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
int imageId, fs::path path, std::istringstream& iStream, std::string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
);
Task<ImageLoadResult> tryLoadImage(
fs::path path, std::istream& iStream, std::string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
fs::path path, std::istringstream& iStream, std::string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
);
Task<ImageLoadResult>
tryLoadImage(int imageId, fs::path path, std::string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels);
Expand Down
5 changes: 5 additions & 0 deletions include/tev/ThreadPool.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ class ThreadPool {
return pool;
}

static ThreadPool& blockingIo() {
static ThreadPool pool;
return pool;
}

template <std::invocable F> auto enqueueTask(F&& f, int priority, bool stopToken = false) {
using return_type = std::invoke_result_t<F>;

Expand Down
6 changes: 3 additions & 3 deletions include/tev/imageio/BmpImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,15 +21,15 @@
#include <tev/Image.h>
#include <tev/imageio/ImageLoader.h>

#include <istream>
#include <sstream>
#include <optional>

namespace tev {

class BmpImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> loadWithoutFileHeader(
std::istream& iStream,
std::istringstream& iStream,
const fs::path& path,
std::string_view channelSelector,
const ImageLoaderSettings& settings,
Expand All @@ -46,7 +46,7 @@ class BmpImageLoader final : public ImageLoader {
) const;

Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "BMP"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/ClipboardImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class ClipboardImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "clipboard"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/DdsImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class DdsImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "DDS"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/DicomImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class DicomImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "DICOM"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/EmptyImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class EmptyImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "IPC"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/ExrImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class ExrImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "OpenEXR"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/FitsImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class FitsImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "FITS"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/HeifImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class HeifImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "HEIF"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/IcoImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class IcoImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "ICO"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/ImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -217,7 +217,7 @@ class ImageLoader {
virtual ~ImageLoader() {}

virtual Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const = 0;

virtual std::string name() const = 0;
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/Jpeg2000ImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class Jpeg2000ImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

Task<std::vector<ImageData>> load(
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/JpegTurboImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class JpegTurboImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "JPEG Turbo"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/JxlImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace tev {
class JxlImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

Task<std::vector<ImageData>> load(
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/JxrImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class JxrImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "JXR"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/PfmImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class PfmImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "PFM/PAM"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/PngImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class PngImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "PNG"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/QoiImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class QoiImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "QOI"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/RawImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class RawImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "RAW"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/StbiImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class StbiImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "STBI"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/TiffImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class TiffImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "TIFF"; }
Expand Down
2 changes: 1 addition & 1 deletion include/tev/imageio/WebpImageLoader.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace tev {
class WebpImageLoader final : public ImageLoader {
public:
Task<std::vector<ImageData>> load(
std::istream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
std::istringstream& iStream, const fs::path& path, std::string_view channelSelector, const ImageLoaderSettings& settings, int priority
) const override;

std::string name() const override { return "WEBP"; }
Expand Down
3 changes: 2 additions & 1 deletion src/BackgroundImagesLoader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,8 +73,9 @@ void BackgroundImagesLoader::enqueue(const fs::path& path, string_view channelSe
invokeTaskDetached([loadId, path, cs = string{channelSelector}, shallSelect, toReplace, this]() -> Task<void> {
const int taskPriority = -Image::drawId();

co_await ThreadPool::global().enqueueCoroutine(taskPriority);
co_await ThreadPool::blockingIo().enqueueCoroutine(taskPriority);
const auto images = co_await tryLoadImage(taskPriority, path, cs, mImageLoaderSettings, mGroupChannels);
co_await ThreadPool::global().enqueueCoroutine(taskPriority);

{
const lock_guard lock{mPendingLoadedImagesMutex};
Expand Down
27 changes: 22 additions & 5 deletions src/Image.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ Task<nanogui::Vector2i> orientToTopLeft(PixelBuffer& data, nanogui::Vector2i siz
}

Task<ImageLoadResult> tryLoadImage(
int taskPriority, fs::path path, istream& iStream, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
int taskPriority, fs::path path, istringstream& iStream, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels
) {
// No need to keep loading images if tev is already shutting down again.
if (shuttingDown()) {
Expand Down Expand Up @@ -1550,7 +1550,11 @@ Task<ImageLoadResult> tryLoadImage(

vector<shared_ptr<Image>> images = co_await awaitAll(imageTasks) | toVector;
if (images.empty()) {
throw ImageLoadError{fmt::format("No parts/channels match channel selector :{}", channelSelector)};
if (channelSelector.empty()) {
throw ImageLoadError{fmt::format("No parts/channels found in image {}.", path)};
} else {
throw ImageLoadError{fmt::format("No parts/channels match channel selector :{}", channelSelector)};
}
}

const auto end = chrono::system_clock::now();
Expand All @@ -1568,7 +1572,7 @@ Task<ImageLoadResult> tryLoadImage(
}

Task<ImageLoadResult>
tryLoadImage(fs::path path, istream& iStream, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels) {
tryLoadImage(fs::path path, istringstream& iStream, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels) {
co_return co_await tryLoadImage(-Image::drawId(), path, iStream, channelSelector, settings, groupChannels);
}

Expand All @@ -1581,8 +1585,21 @@ Task<ImageLoadResult>
// sure.
}

ifstream fileStream{path, ios_base::binary};
co_return co_await tryLoadImage(taskPriority, path, fileStream, channelSelector, settings, groupChannels);
istringstream iStream;

{
co_await ThreadPool::blockingIo().enqueueCoroutine(taskPriority);

if (!shuttingDown()) {
ostringstream oStream;
ifstream fileStream{path, ios_base::binary};
oStream << fileStream.rdbuf();
iStream = istringstream{std::move(oStream).str()}; // C++20 rvalue .str() overload to avoid a copy of the string
}
}

co_await ThreadPool::global().enqueueCoroutine(taskPriority);
co_return co_await tryLoadImage(taskPriority, path, iStream, channelSelector, settings, groupChannels);
}

Task<ImageLoadResult> tryLoadImage(fs::path path, string_view channelSelector, const ImageLoaderSettings& settings, bool groupChannels) {
Expand Down
18 changes: 11 additions & 7 deletions src/ImageViewer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2591,15 +2591,15 @@ void ImageViewer::copyImageNameToClipboard() const {
}

void ImageViewer::pasteImagesFromClipboard() {
stringstream imageStream;
istringstream imageStream;
if (glfwGetPlatform() == GLFW_PLATFORM_WAYLAND) {
const auto data = waylandGetClipboardPngImage();
if (data.empty()) {
throw runtime_error{"No image data found in clipboard."};
}

// TODO: use spanstream once it is available in C++23 to avoid the copy
imageStream = stringstream{string{data}, ios::in};
imageStream = istringstream{string{data}};
} else if (glfwGetPlatform() == GLFW_PLATFORM_X11) {
clip::lock l;
if (!l.locked()) {
Expand All @@ -2615,16 +2615,18 @@ void ImageViewer::pasteImagesFromClipboard() {
string data(len, '\0');
l.get_data(f, data.data(), len);

imageStream = stringstream{std::move(data), ios::in};
imageStream = istringstream{std::move(data)};
} else {
clip::image clipImage;
if (!clip::get_image(clipImage)) {
throw runtime_error{"No image data found in clipboard."};
}

imageStream << "clip";
imageStream.write(reinterpret_cast<const char*>(&clipImage.spec()), sizeof(clip::image_spec));
imageStream.write(clipImage.data(), clipImage.spec().bytes_per_row * clipImage.spec().height);
ostringstream oss;
oss << "clip";
oss.write(reinterpret_cast<const char*>(&clipImage.spec()), sizeof(clip::image_spec));
oss.write(clipImage.data(), clipImage.spec().bytes_per_row * clipImage.spec().height);
imageStream = istringstream{std::move(oss).str()};
}

tlog::info("Loading image from clipboard...");
Expand All @@ -2646,7 +2648,9 @@ void ImageViewer::showErrorDialog(string_view message, bool logToConsole) {
tlog::error(message);
}

new ErrorDialog(this, MessageDialog::Type::Warning, "Error", message, "OK", "Cancel", false, (int)(m_size.x() * 0.75f), (int)(m_size.y() * 0.75f));
new ErrorDialog(
this, MessageDialog::Type::Warning, "Error", message, "OK", "Cancel", false, (int)(m_size.x() * 0.75f), (int)(m_size.y() * 0.75f)
);
}

chroma_t ImageViewer::inspectionChroma() const {
Expand Down
Loading
Loading