Files
OmaPhoto/src/Document/Filters.h
T

162 lines
6.4 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
#include "Document/CameraRaw.h"
#include "Document/Curves.h"
#include "Document/ImageAdjustments.h"
#include "Document/LayerTransform.h"
#include "Document/Selection.h"
#include "IO/ImageImporter.h"
#include <QImage>
#include <QRandomGenerator>
#include <QTransform>
#include <QUuid>
#include <array>
#include <cmath>
struct ImageLayer;
// The Filter and Image menus' filters.
enum class FilterKind {
gaussianBlur, motionBlur, addNoise, lensCorrection, cameraRaw, removeBackground, contentAwareFill, curves, exposure, gradientMap, grain, blackWhite,
colorBalance
};
// The menu's title, Swift's rawValue.
QString rawValue(FilterKind kind);
// Made without settings: its preview is its result.
bool isAutomatic(FilterKind kind);
// The Image menu's colour adjustments, not under Filter.
bool isImageAdjustment(FilterKind kind);
// Swift's allCases, the menus' order.
inline constexpr std::array allFilterKinds{FilterKind::gaussianBlur, FilterKind::motionBlur, FilterKind::addNoise,
FilterKind::lensCorrection, FilterKind::cameraRaw, FilterKind::removeBackground,
FilterKind::contentAwareFill,
FilterKind::curves, FilterKind::exposure, FilterKind::gradientMap,
FilterKind::grain, FilterKind::blackWhite, FilterKind::colorBalance};
// Remove Background's mask: the model's alone, or refined.
enum class BackgroundQuality { basic, advanced };
QString rawValue(BackgroundQuality quality);
inline constexpr std::array allBackgroundQualities{BackgroundQuality::basic, BackgroundQuality::advanced};
// Every filter's settings; each filter reads only its own.
struct FilterSettings {
// Gaussian Blur's radius in layer pixels: the blur's sigma.
double radius = 1;
// Motion Blur's angle, counterclockwise from horizontal, as Photoshop's.
double angle = 0;
double distance = 10;
// Add Noise's strength, Photoshop's percentage.
double amount = 10;
bool gaussian = false;
// The same noise on every channel: brightness alone.
bool monochromatic = false;
// Positive straightens barrel distortion, negative pincushion.
double distortion = 0;
CurvesSettings curves{};
ExposureSettings exposure{};
GradientMapSettings gradientMap{};
GrainSettings grain{};
BlackWhiteSettings blackWhite{};
ColorBalanceSettings colorBalance{};
CameraRawSettings cameraRaw{};
BackgroundQuality backgroundQuality = BackgroundQuality::basic;
// How far, in pixels, the mask is pulled onto edges.
double refineEdges = 12;
// Pushes the mask's grays apart, 0 to 100, clearing haze.
double matteContrast = 25;
// Contracts (negative) or grows the mask's edge, in pixels.
double shiftEdge = 0;
FilterSettings normalized() const;
friend bool operator==(const FilterSettings &, const FilterSettings &) = default;
};
// What a filter runs on: grid, settings, selection, placement.
struct FilterJob {
FilterKind kind;
QImage image;
FilterSettings settings;
// Pixels in `image` a layer pixel: smaller previews blur less.
double scale;
std::optional<SelectionClip> selection;
QTransform mapping;
// Add Noise's pattern: the same seed, the same grain.
quint32 seed = 0;
// Camera Raw's preview-only views; a commit leaves them off.
std::optional<CameraRawClipping> cameraRawClipping = std::nullopt;
bool showsShadowClipping = false;
bool showsHighlightClipping = false;
// The point colour shown alone, or −1 for the grade.
int visualizesPointColor = -1;
bool showsSharpenMask = false;
// A live adjustment's noise field, fixed in its region's pixels.
QPointF noiseOrigin{};
};
// Swift's PixelFilter.
namespace PixelFilter {
struct Trimmed {
QImage image;
LayerTransform transform;
};
// CIMotionBlur's radius a streak pixel: an even streak's spread.
inline const double motionRadiusPerPixel = 1 / std::sqrt(12.0);
// Remove Distortion at ±100 moves the corners this share.
inline constexpr double lensStrength = 0.35;
// The pixels that are there, placed where they were.
Trimmed trimmed(const QImage &image, const LayerTransform &placed);
// The filter over the job's image, through its selection.
QImage run(const FilterJob &job);
}
// An open filter: the layer's pixels, preview copy, grown grid.
class FilterEdit {
public:
// Previews render from a copy no longer than this.
static constexpr double previewLimit = 2048;
// `area`: a document area the grid must cover (Content-Aware Fill).
FilterEdit(FilterKind kind, const ImageLayer &layer, std::optional<SelectionClip> selection, const FilterSettings &settings,
std::optional<QRectF> area);
// The room a blur needs round the layer, in pixels.
static double blurMargin(FilterKind kind, const FilterSettings &settings);
// Pads the grid for the blur; it only ever grows.
void growForBlur();
std::optional<QImage> previewImage(QUuid id) const;
// The settings as rendered: a hidden Camera Raw group drops.
FilterSettings renderSettings() const;
FilterJob previewJob() const;
// Swift's object identity: a preview lands on its own edit.
const QUuid id = QUuid::createUuid();
const FilterKind kind;
const QUuid layerID;
const ImportedImage original;
const LayerTransform transform;
const std::optional<SelectionClip> selection;
QTransform mapping;
QImage previewSource;
double previewScale = 1;
QTransform previewMapping;
// The layer padded out, and the transform placing it.
std::optional<QImage> grownImage;
std::optional<LayerTransform> grownTransform;
// How far the padding reaches past every side.
double grownMargin = 0;
FilterSettings settings;
bool preview = true;
bool committing = false;
std::optional<QString> previewError;
bool preparing = false;
// Add Noise's grain, fixed while the panel is open.
const quint32 seed = QRandomGenerator::global()->generate();
std::optional<QImage> preparedPreview;
// The settings the prepared preview was made with.
std::optional<FilterSettings> preparedSettings;
std::optional<FilterJob> pending;
CameraRawPanel rawPanel;
private:
void grow(const QRectF &extent);
// Swift's prepared and prepare: mapping and preview copy.
void prepare(const ImportedImage &source, const LayerTransform &placed);
};