#pragma once #include "Document/ImageAdjustments.h" #include #include #include #include // 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 maps; std::vector 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; };