#pragma once #include "Document/BrushStroke.h" #include "Document/LayerMask.h" #include "Rendering/LayerRenderer.h" #include // Shared by the brush tests: strokes, previews, pixels. inline BrushSettings brush(double diameter, double hardness, double red, double green, double blue, double opacity = 1) { return BrushSettings{.diameter = diameter, .hardness = hardness, .red = red, .green = green, .blue = blue, .opacity = opacity}; } // A document-pixel clone, copied from `offset` away. inline BrushStroke::Clone documentClone(const QImage &image, QSizeF offset = QSizeF(0, 0)) { return {image, QRectF(-offset.width(), -offset.height(), image.width(), image.height()), false, {}}; } inline ImageLayer blankLayer(int width, int height) { return ImageLayer(QStringLiteral("Layer 1"), QSizeF(width, height)); } // The stroke as the canvas shows it, canvas-sized. inline QImage preview(const BrushStroke &stroke, QSizeF canvas) { QImage context = BrushRaster::context(int(canvas.width()), int(canvas.height()), false); QPainter painter(&context); const ImageLayer &layer = stroke.layer; const std::optional &asset = layer.asset; const QImage image = asset && !asset->raster ? asset->image() : QImage(); LayerRenderer::drawBrushPreview(image, stroke.paintTransform, stroke.paintTransform.center(), painter, {.opacity = layer.opacity, .blendMode = layer.blendMode, .mask = layer.mask ? layer.mask->enabledImage().value_or(QImage()) : QImage()}, {.patches = stroke.patches(), .pixelWidth = stroke.width, .pixelHeight = stroke.height, .paintingMask = stroke.isMask, .sourceRect = stroke.sourceRect, .raster = asset ? asset->raster : nullptr}); painter.end(); return context; } inline std::vector pixel(const QImage &image, int x, int y) { const QImage bytes = image.convertToFormat(QImage::Format_RGBA8888_Premultiplied); const uchar *at = bytes.constScanLine(y) + x * 4; return {at[0], at[1], at[2], at[3]}; } inline int alpha(const QImage &image, int x, int y) { return pixel(image, x, y)[3]; } // A red hard 20 px brush, Swift's default session settings. inline BrushSettings red(double diameter = 20, double hardness = 1) { return brush(diameter, hardness, 1, 0, 0); } inline std::unique_ptr stroke(int width, int height, const BrushSettings &settings) { return std::make_unique(blankLayer(width, height), false, settings, QSizeF(width, height)); } // A committed asset as the canvas shows it. inline QImage render(const ImportedImage &asset, const LayerTransform &transform, QSizeF canvas) { QImage context = BrushRaster::context(int(canvas.width()), int(canvas.height()), false); QPainter painter(&context); LayerRenderer::draw(asset.image(), transform, transform.center(), painter, {}); return context; } inline ImportedImage gray(uchar value) { QImage image = BrushRaster::context(1, 1, true); image.fill(value); return LayerMask::assetFrom(image); }