Files
OmaPhoto/src/Document/Dither.h
T

91 lines
4.0 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/ImageAdjustments.h"
#include <QImage>
#include <QString>
#include <array>
#include <vector>
// Filter › Dither's looks, in the panel's order and DitherPixels.h's.
enum class DitherStyle { atkinson, floydSteinberg, bayer2, bayer4, bayer8, dots, lines, diamonds, patterns, ascii, scanlines };
inline constexpr std::array allDitherStyles{DitherStyle::atkinson, DitherStyle::floydSteinberg, DitherStyle::bayer2, DitherStyle::bayer4,
DitherStyle::bayer8, DitherStyle::dots, DitherStyle::lines, DitherStyle::diamonds,
DitherStyle::patterns, DitherStyle::ascii, DitherStyle::scanlines};
QString rawValue(DitherStyle style);
// Swift's groups: diffusion, ordered, halftone, marks.
int ditherGroup(DitherStyle style);
// Each pixel's rounding error passes to its neighbours.
bool diffuses(DitherStyle style);
// Diffusion and ordered styles have tones; the rest draw marks.
bool hasTones(DitherStyle style);
bool isHalftone(DitherStyle style);
bool drawsMarks(DitherStyle style);
// ASCII and Scanlines draw at full resolution, not chunky.
bool usesPixelSize(DitherStyle style);
// A chunky pixel: a square, or a dot on dark.
enum class DitherPixelShape { square, dot };
inline constexpr std::array allDitherPixelShapes{DitherPixelShape::square, DitherPixelShape::dot};
QString rawValue(DitherPixelShape shape);
enum class DitherColors { blackWhite, twoColors, original };
inline constexpr std::array allDitherColors{DitherColors::blackWhite, DitherColors::twoColors, DitherColors::original};
QString rawValue(DitherColors colors);
// Swift's DitherSettings: the filter's look, in layer pixels.
struct DitherSettings {
static constexpr double pixelSizeLow = 1, pixelSizeHigh = 32;
static constexpr double cellSizeLow = 4, cellSizeHigh = 64;
static constexpr double textSizeLow = 6, textSizeHigh = 64;
static constexpr double levelsLow = 2, levelsHigh = 8;
static constexpr double lineSpacingLow = 2, lineSpacingHigh = 32;
static constexpr double wobbleLow = 0, wobbleHigh = 64;
static QString defaultCharacters() { return QStringLiteral(" .:-=+*#%@"); }
DitherStyle style = DitherStyle::atkinson;
// Each dithered pixel covers this many layer pixels a side.
double pixelSize = 2;
DitherPixelShape pixelShape = DitherPixelShape::square;
// Halftone cells, in dithered pixels.
double cellSize = 8;
// ASCII's line height in layer pixels; letters about 0.6 wide.
double textSize = 14;
// Scanlines: the lines' distance apart, in layer pixels.
double lineSpacing = 4;
// Glow and dots 0–100%; wobble sideways in pixels.
double glow = 35;
double dots = 0;
double wobble = 0;
// The halftone screen's angle, in degrees.
double angle = 45;
// Tones per channel; 2 is 1-bit.
double levels = 2;
// How much error passes on, 0–100%.
double diffusion = 100;
// −100…100: more ink or less, flatter or punchier.
double density = 0;
double contrast = 0;
DitherColors colors = DitherColors::blackWhite;
AdjustmentColor dark = AdjustmentColor(0, 0, 0);
AdjustmentColor light = AdjustmentColor(1, 1, 1);
// Marks stand for the light tones, lit on the dark.
bool lightOnDark = true;
// ASCII's characters, sorted by their ink.
QString characters = defaultCharacters();
DitherSettings normalized() const;
QImage apply(const QImage &image) const;
friend bool operator==(const DitherSettings &, const DitherSettings &) = default;
// Each distinct character's coverage map, least ink first.
struct Glyphs {
std::vector<uint8_t> maps;
std::vector<float> coverage;
int width = 1;
int height = 1;
};
// A monospaced cell: a line tall, a letter wide.
static Glyphs glyphs(const QString &characters, int lineHeight);
private:
QImage dither(const QImage &image) const;
QImage glowing(const QImage &image) const;
};