Веб-сайт самохостера Lotigara

summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--source/core/StarAssetPath.cpp4
-rw-r--r--source/core/StarAssetPath.hpp3
-rw-r--r--source/core/StarDirectives.cpp92
-rw-r--r--source/core/StarDirectives.hpp19
-rw-r--r--source/core/StarImageProcessing.cpp386
-rw-r--r--source/core/StarImageProcessing.hpp4
6 files changed, 300 insertions, 208 deletions
diff --git a/source/core/StarAssetPath.cpp b/source/core/StarAssetPath.cpp
index 3a6a83e..2100ee0 100644
--- a/source/core/StarAssetPath.cpp
+++ b/source/core/StarAssetPath.cpp
@@ -147,6 +147,10 @@ bool AssetPath::operator==(AssetPath const& rhs) const {
return tie(basePath, subPath, directives) == tie(rhs.basePath, rhs.subPath, rhs.directives);
}
+AssetPath::AssetPath(String const& path) {
+ *this = move(AssetPath::split(path)); // split code should probably be in here, but whatever
+}
+
std::ostream& operator<<(std::ostream& os, AssetPath const& rhs) {
os << rhs.basePath;
if (rhs.subPath) {
diff --git a/source/core/StarAssetPath.hpp b/source/core/StarAssetPath.hpp
index e51acee..9da30e7 100644
--- a/source/core/StarAssetPath.hpp
+++ b/source/core/StarAssetPath.hpp
@@ -51,6 +51,9 @@ struct AssetPath {
// sourcePath.
static String relativeTo(String const& sourcePath, String const& givenPath);
+ AssetPath() = default;
+ AssetPath(String const& path);
+
String basePath;
Maybe<String> subPath;
NestedDirectives directives;
diff --git a/source/core/StarDirectives.cpp b/source/core/StarDirectives.cpp
index 62a2a49..2394915 100644
--- a/source/core/StarDirectives.cpp
+++ b/source/core/StarDirectives.cpp
@@ -1,6 +1,8 @@
#include "StarImage.hpp"
#include "StarImageProcessing.hpp"
#include "StarDirectives.hpp"
+#include "StarXXHash.hpp"
+#include "StarHash.hpp"
namespace Star {
@@ -16,22 +18,32 @@ NestedDirectives::NestedDirectives(String&& directives) {
void NestedDirectives::parseDirectivesIntoLeaf(String const& directives) {
Leaf leaf;
for (String& op : directives.split('?')) {
- if (!op.empty()) {
- leaf.operations.append(imageOperationFromString(op));
- leaf.strings.append(move(op));
- }
+ if (!op.empty())
+ leaf.entries.emplace_back(imageOperationFromString(op), op);
}
m_root = std::make_shared<Cell>(move(leaf));
}
-bool NestedDirectives::empty() const {
+inline bool NestedDirectives::empty() const {
return (bool)m_root;
}
-void NestedDirectives::append(const NestedDirectives& other) {
+inline bool NestedDirectives::compare(NestedDirectives const& other) const {
+ if (m_root == other.m_root)
+ return true;
+
+ return false;
+}
+
+void NestedDirectives::append(NestedDirectives const& other) {
convertToBranches().emplace_back(other.branch());
}
+NestedDirectives& NestedDirectives::operator+=(NestedDirectives const& other) {
+ append(other);
+ return *this;
+}
+
String NestedDirectives::toString() const {
String string;
addToString(string);
@@ -51,9 +63,8 @@ void NestedDirectives::forEach(LeafCallback callback) const {
void NestedDirectives::forEachPair(LeafPairCallback callback) const {
if (m_root) {
LeafCallback pairCallback = [&](Leaf const& leaf) {
- size_t length = leaf.length();
- for (size_t i = 0; i != length; ++i)
- callback(leaf.operations.at(i), leaf.strings.at(i));
+ for (auto& entry : leaf.entries)
+ callback(entry.operation, entry.string);
};
m_root->forEach(pairCallback);
}
@@ -71,9 +82,8 @@ bool NestedDirectives::forEachPairAbortable(AbortableLeafPairCallback callback)
return false;
else {
AbortableLeafCallback pairCallback = [&](Leaf const& leaf) -> bool {
- size_t length = leaf.length();
- for (size_t i = 0; i != length; ++i) {
- if (!callback(leaf.operations.at(i), leaf.strings.at(i)))
+ for (auto& entry : leaf.entries) {
+ if (!callback(entry.operation, entry.string))
return false;
}
@@ -85,8 +95,8 @@ bool NestedDirectives::forEachPairAbortable(AbortableLeafPairCallback callback)
Image NestedDirectives::apply(Image& image) const {
Image current = image;
- forEach([&](Leaf const& leaf) {
- current = processImageOperations(leaf.operations, current);
+ forEachPair([&](ImageOperation const& operation, String const& string) {
+ processImageOperation(operation, current);
});
return current;
}
@@ -105,11 +115,33 @@ NestedDirectives::Branches& NestedDirectives::convertToBranches() {
return m_root->value.get<Branches>();
}
+bool NestedDirectives::Leaf::Entry::operator==(NestedDirectives::Leaf::Entry const& other) const {
+ return string == other.string;
+}
+
+bool NestedDirectives::Leaf::Entry::operator!=(NestedDirectives::Leaf::Entry const& other) const {
+ return string != other.string;
+}
+
+
size_t NestedDirectives::Leaf::length() const {
- if (operations.size() != strings.size())
- throw DirectivesException("NestedDirectives leaf has mismatching operation/string List sizes");
+ return entries.size();
+}
+
+bool NestedDirectives::Leaf::operator==(NestedDirectives::Leaf const& other) const {
+ size_t len = length();
+ if (len != other.length())
+ return false;
+
+ for (size_t i = 0; i != len; ++i) {
+ if (entries[i] != other.entries[i])
+ return false;
+ }
+ return true;
+}
- return operations.size();
+bool NestedDirectives::Leaf::operator!=(NestedDirectives::Leaf const& other) const {
+ return !(*this == other);
}
NestedDirectives::Cell::Cell() : value(Leaf()) {};
@@ -118,11 +150,33 @@ NestedDirectives::Cell::Cell(Branches&& branches) : value(move(branches)) {};
NestedDirectives::Cell::Cell(const Leaf& leaf) : value(leaf) {};
NestedDirectives::Cell::Cell(const Branches& branches) : value(branches) {};
+/*
+bool NestedDirectives::Cell::operator==(NestedDirectives::Cell const& other) const {
+ if (auto leaf = value.ptr<Leaf>()) {
+ if (auto otherLeaf = other.value.ptr<Leaf>())
+ return *leaf == *otherLeaf;
+ else {
+
+ }
+ }
+ else {
+ for (auto& branch : value.get<Branches>()) {
+
+ }
+ }
+}
+
+
+bool NestedDirectives::Cell::operator!=(NestedDirectives::Cell const& other) const {
+ return !(*this == other);
+}
+//*/
+
void NestedDirectives::Cell::buildString(String& string) const {
if (auto leaf = value.ptr<Leaf>())
- for (auto& leafString : leaf->strings) {
+ for (auto& entry : leaf->entries) {
string += "?";
- string += leafString;
+ string += entry.string;
}
else {
for (auto& branch : value.get<Branches>())
diff --git a/source/core/StarDirectives.hpp b/source/core/StarDirectives.hpp
index bc5b78d..924f295 100644
--- a/source/core/StarDirectives.hpp
+++ b/source/core/StarDirectives.hpp
@@ -12,10 +12,19 @@ STAR_EXCEPTION(DirectivesException, StarException);
class NestedDirectives {
public:
struct Leaf {
- List<ImageOperation> operations;
- List<String> strings;
+ struct Entry {
+ ImageOperation operation;
+ String string;
+
+ bool operator==(Entry const& other) const;
+ bool operator!=(Entry const& other) const;
+ Entry(ImageOperation&& operation, String&& string);
+ };
+ List<Entry> entries;
size_t length() const;
+ bool operator==(NestedDirectives::Leaf const& other) const;
+ bool operator!=(NestedDirectives::Leaf const& other) const;
};
typedef function<void(Leaf const&)> LeafCallback;
@@ -51,7 +60,11 @@ public:
void parseDirectivesIntoLeaf(String const& directives);
bool empty() const;
- void append(const NestedDirectives& other);
+ bool compare(NestedDirectives const& other) const;
+ void append(NestedDirectives const& other);
+ NestedDirectives& operator+=(NestedDirectives const& other);
+ bool operator==(NestedDirectives const& other) const;
+ bool operator!=(NestedDirectives const& other) const;
const ConstBranch& branch() const;
diff --git a/source/core/StarImageProcessing.cpp b/source/core/StarImageProcessing.cpp
index fd07e1c..fc99f69 100644
--- a/source/core/StarImageProcessing.cpp
+++ b/source/core/StarImageProcessing.cpp
@@ -328,12 +328,23 @@ String imageOperationToString(ImageOperation const& operation) {
return "";
}
+void parseImageOperations(String const& params, function<void(ImageOperation&&)> outputter) {
+ for (auto const& op : params.split('?')) {
+ if (!op.empty())
+ outputter(imageOperationFromString(op));
+ }
+}
+
List<ImageOperation> parseImageOperations(String const& params) {
+ auto split = params.split('?');
List<ImageOperation> operations;
- for (auto const& op : params.split('?')) {
+ operations.reserve(split.size());
+
+ for (auto const& op : split) {
if (!op.empty())
operations.append(imageOperationFromString(op));
}
+
return operations;
}
@@ -352,216 +363,219 @@ StringList imageOperationReferences(List<ImageOperation> const& operations) {
return references;
}
-Image processImageOperations(List<ImageOperation> const& operations, Image image, ImageReferenceCallback refCallback) {
- for (auto const& operation : operations) {
- if (auto op = operation.ptr<HueShiftImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- if (pixel[3] != 0)
- pixel = Color::hueShiftVec4B(pixel, op->hueShiftAmount);
- });
- } else if (auto op = operation.ptr<SaturationShiftImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- if (pixel[3] != 0) {
- Color color = Color::rgba(pixel);
- color.setSaturation(clamp(color.saturation() + op->saturationShiftAmount, 0.0f, 1.0f));
- pixel = color.toRgba();
- }
- });
- } else if (auto op = operation.ptr<BrightnessMultiplyImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- if (pixel[3] != 0) {
- Color color = Color::rgba(pixel);
- color.setValue(clamp(color.value() * op->brightnessMultiply, 0.0f, 1.0f));
- pixel = color.toRgba();
- }
- });
- } else if (auto op = operation.ptr<FadeToColorImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- pixel[0] = op->rTable[pixel[0]];
- pixel[1] = op->gTable[pixel[1]];
- pixel[2] = op->bTable[pixel[2]];
- });
- } else if (auto op = operation.ptr<ScanLinesImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned y, Vec4B& pixel) {
- if (y % 2 == 0) {
- pixel[0] = op->fade1.rTable[pixel[0]];
- pixel[1] = op->fade1.gTable[pixel[1]];
- pixel[2] = op->fade1.bTable[pixel[2]];
- } else {
- pixel[0] = op->fade2.rTable[pixel[0]];
- pixel[1] = op->fade2.gTable[pixel[1]];
- pixel[2] = op->fade2.bTable[pixel[2]];
- }
- });
- } else if (auto op = operation.ptr<SetColorImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- pixel[0] = op->color[0];
- pixel[1] = op->color[1];
- pixel[2] = op->color[2];
- });
- } else if (auto op = operation.ptr<ColorReplaceImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- if (auto m = op->colorReplaceMap.maybe(pixel))
- pixel = *m;
- });
-
- } else if (auto op = operation.ptr<AlphaMaskImageOperation>()) {
- if (op->maskImages.empty())
- continue;
-
- if (!refCallback)
- throw StarException("Missing image ref callback during AlphaMaskImageOperation in ImageProcessor::process");
-
- List<Image const*> maskImages;
- for (auto const& reference : op->maskImages)
- maskImages.append(refCallback(reference));
-
- image.forEachPixel([&op, &maskImages](unsigned x, unsigned y, Vec4B& pixel) {
- uint8_t maskAlpha = 0;
- Vec2U pos = Vec2U(Vec2I(x, y) + op->offset);
- for (auto mask : maskImages) {
- if (pos[0] < mask->width() && pos[1] < mask->height()) {
- if (op->mode == AlphaMaskImageOperation::Additive) {
- // We produce our mask alpha from the maximum alpha of any of
- // the
- // mask images.
- maskAlpha = std::max(maskAlpha, mask->get(pos)[3]);
- } else if (op->mode == AlphaMaskImageOperation::Subtractive) {
- // We produce our mask alpha from the minimum alpha of any of
- // the
- // mask images.
- maskAlpha = std::min(maskAlpha, mask->get(pos)[3]);
- }
+void processImageOperation(ImageOperation const& operation, Image& image, ImageReferenceCallback refCallback) {
+ if (auto op = operation.ptr<HueShiftImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ if (pixel[3] != 0)
+ pixel = Color::hueShiftVec4B(pixel, op->hueShiftAmount);
+ });
+ } else if (auto op = operation.ptr<SaturationShiftImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ if (pixel[3] != 0) {
+ Color color = Color::rgba(pixel);
+ color.setSaturation(clamp(color.saturation() + op->saturationShiftAmount, 0.0f, 1.0f));
+ pixel = color.toRgba();
+ }
+ });
+ } else if (auto op = operation.ptr<BrightnessMultiplyImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ if (pixel[3] != 0) {
+ Color color = Color::rgba(pixel);
+ color.setValue(clamp(color.value() * op->brightnessMultiply, 0.0f, 1.0f));
+ pixel = color.toRgba();
+ }
+ });
+ } else if (auto op = operation.ptr<FadeToColorImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ pixel[0] = op->rTable[pixel[0]];
+ pixel[1] = op->gTable[pixel[1]];
+ pixel[2] = op->bTable[pixel[2]];
+ });
+ } else if (auto op = operation.ptr<ScanLinesImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned y, Vec4B& pixel) {
+ if (y % 2 == 0) {
+ pixel[0] = op->fade1.rTable[pixel[0]];
+ pixel[1] = op->fade1.gTable[pixel[1]];
+ pixel[2] = op->fade1.bTable[pixel[2]];
+ } else {
+ pixel[0] = op->fade2.rTable[pixel[0]];
+ pixel[1] = op->fade2.gTable[pixel[1]];
+ pixel[2] = op->fade2.bTable[pixel[2]];
+ }
+ });
+ } else if (auto op = operation.ptr<SetColorImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ pixel[0] = op->color[0];
+ pixel[1] = op->color[1];
+ pixel[2] = op->color[2];
+ });
+ } else if (auto op = operation.ptr<ColorReplaceImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ if (auto m = op->colorReplaceMap.maybe(pixel))
+ pixel = *m;
+ });
+
+ } else if (auto op = operation.ptr<AlphaMaskImageOperation>()) {
+ if (op->maskImages.empty())
+ continue;
+
+ if (!refCallback)
+ throw StarException("Missing image ref callback during AlphaMaskImageOperation in ImageProcessor::process");
+
+ List<Image const*> maskImages;
+ for (auto const& reference : op->maskImages)
+ maskImages.append(refCallback(reference));
+
+ image.forEachPixel([&op, &maskImages](unsigned x, unsigned y, Vec4B& pixel) {
+ uint8_t maskAlpha = 0;
+ Vec2U pos = Vec2U(Vec2I(x, y) + op->offset);
+ for (auto mask : maskImages) {
+ if (pos[0] < mask->width() && pos[1] < mask->height()) {
+ if (op->mode == AlphaMaskImageOperation::Additive) {
+ // We produce our mask alpha from the maximum alpha of any of
+ // the
+ // mask images.
+ maskAlpha = std::max(maskAlpha, mask->get(pos)[3]);
+ } else if (op->mode == AlphaMaskImageOperation::Subtractive) {
+ // We produce our mask alpha from the minimum alpha of any of
+ // the
+ // mask images.
+ maskAlpha = std::min(maskAlpha, mask->get(pos)[3]);
}
}
- pixel[3] = std::min(pixel[3], maskAlpha);
- });
-
- } else if (auto op = operation.ptr<BlendImageOperation>()) {
- if (op->blendImages.empty())
- continue;
-
- if (!refCallback)
- throw StarException("Missing image ref callback during BlendImageOperation in ImageProcessor::process");
-
- List<Image const*> blendImages;
- for (auto const& reference : op->blendImages)
- blendImages.append(refCallback(reference));
-
- image.forEachPixel([&op, &blendImages](unsigned x, unsigned y, Vec4B& pixel) {
- Vec2U pos = Vec2U(Vec2I(x, y) + op->offset);
- Vec4F fpixel = Color::v4bToFloat(pixel);
- for (auto blend : blendImages) {
- if (pos[0] < blend->width() && pos[1] < blend->height()) {
- Vec4F blendPixel = Color::v4bToFloat(blend->get(pos));
- if (op->mode == BlendImageOperation::Multiply)
- fpixel = fpixel.piecewiseMultiply(blendPixel);
- else if (op->mode == BlendImageOperation::Screen)
- fpixel = Vec4F::filled(1.0f) - (Vec4F::filled(1.0f) - fpixel).piecewiseMultiply(Vec4F::filled(1.0f) - blendPixel);
- }
+ }
+ pixel[3] = std::min(pixel[3], maskAlpha);
+ });
+
+ } else if (auto op = operation.ptr<BlendImageOperation>()) {
+ if (op->blendImages.empty())
+ continue;
+
+ if (!refCallback)
+ throw StarException("Missing image ref callback during BlendImageOperation in ImageProcessor::process");
+
+ List<Image const*> blendImages;
+ for (auto const& reference : op->blendImages)
+ blendImages.append(refCallback(reference));
+
+ image.forEachPixel([&op, &blendImages](unsigned x, unsigned y, Vec4B& pixel) {
+ Vec2U pos = Vec2U(Vec2I(x, y) + op->offset);
+ Vec4F fpixel = Color::v4bToFloat(pixel);
+ for (auto blend : blendImages) {
+ if (pos[0] < blend->width() && pos[1] < blend->height()) {
+ Vec4F blendPixel = Color::v4bToFloat(blend->get(pos));
+ if (op->mode == BlendImageOperation::Multiply)
+ fpixel = fpixel.piecewiseMultiply(blendPixel);
+ else if (op->mode == BlendImageOperation::Screen)
+ fpixel = Vec4F::filled(1.0f) - (Vec4F::filled(1.0f) - fpixel).piecewiseMultiply(Vec4F::filled(1.0f) - blendPixel);
}
- pixel = Color::v4fToByte(fpixel);
- });
-
- } else if (auto op = operation.ptr<MultiplyImageOperation>()) {
- image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
- pixel = pixel.combine(op->color, [](uint8_t a, uint8_t b) -> uint8_t {
- return (uint8_t)(((int)a * (int)b) / 255);
- });
- });
-
- } else if (auto op = operation.ptr<BorderImageOperation>()) {
- Image borderImage(image.size() + Vec2U::filled(op->pixels * 2), PixelFormat::RGBA32);
- borderImage.copyInto(Vec2U::filled(op->pixels), image);
- Vec2I borderImageSize = Vec2I(borderImage.size());
-
- borderImage.forEachPixel([&op, &image, &borderImageSize](int x, int y, Vec4B& pixel) {
- int pixels = op->pixels;
- bool includeTransparent = op->includeTransparent;
- if (pixel[3] == 0 || (includeTransparent && pixel[3] != 255)) {
- int dist = std::numeric_limits<int>::max();
- for (int j = -pixels; j < pixels + 1; j++) {
- for (int i = -pixels; i < pixels + 1; i++) {
- if (i + x >= pixels && j + y >= pixels && i + x < borderImageSize[0] - pixels && j + y < borderImageSize[1] - pixels) {
- Vec4B remotePixel = image.get(i + x - pixels, j + y - pixels);
- if (remotePixel[3] != 0) {
- dist = std::min(dist, abs(i) + abs(j));
- if (dist == 1) // Early out, if dist is 1 it ain't getting shorter
- break;
- }
+ }
+ pixel = Color::v4fToByte(fpixel);
+ });
+
+ } else if (auto op = operation.ptr<MultiplyImageOperation>()) {
+ image.forEachPixel([&op](unsigned, unsigned, Vec4B& pixel) {
+ pixel = pixel.combine(op->color, [](uint8_t a, uint8_t b) -> uint8_t {
+ return (uint8_t)(((int)a * (int)b) / 255);
+ });
+ });
+
+ } else if (auto op = operation.ptr<BorderImageOperation>()) {
+ Image borderImage(image.size() + Vec2U::filled(op->pixels * 2), PixelFormat::RGBA32);
+ borderImage.copyInto(Vec2U::filled(op->pixels), image);
+ Vec2I borderImageSize = Vec2I(borderImage.size());
+
+ borderImage.forEachPixel([&op, &image, &borderImageSize](int x, int y, Vec4B& pixel) {
+ int pixels = op->pixels;
+ bool includeTransparent = op->includeTransparent;
+ if (pixel[3] == 0 || (includeTransparent && pixel[3] != 255)) {
+ int dist = std::numeric_limits<int>::max();
+ for (int j = -pixels; j < pixels + 1; j++) {
+ for (int i = -pixels; i < pixels + 1; i++) {
+ if (i + x >= pixels && j + y >= pixels && i + x < borderImageSize[0] - pixels && j + y < borderImageSize[1] - pixels) {
+ Vec4B remotePixel = image.get(i + x - pixels, j + y - pixels);
+ if (remotePixel[3] != 0) {
+ dist = std::min(dist, abs(i) + abs(j));
+ if (dist == 1) // Early out, if dist is 1 it ain't getting shorter
+ break;
}
}
}
+ }
- if (dist < std::numeric_limits<int>::max()) {
- float percent = (dist - 1) / (2.0f * pixels - 1);
- Color color = Color::rgba(op->startColor).mix(Color::rgba(op->endColor), percent);
- if (pixel[3] != 0) {
- if (op->outlineOnly) {
- float pixelA = byteToFloat(pixel[3]);
- color.setAlphaF((1.0f - pixelA) * fminf(pixelA, 0.5f) * 2.0f);
- }
- else {
- Color pixelF = Color::rgba(pixel);
- float pixelA = pixelF.alphaF(), colorA = color.alphaF();
- colorA += pixelA * (1.0f - colorA);
- pixelF.convertToLinear(); //Mix in linear color space as it is more perceptually accurate
- color.convertToLinear();
- color = color.mix(pixelF, pixelA);
- color.convertToSRGB();
- color.setAlphaF(colorA);
- }
+ if (dist < std::numeric_limits<int>::max()) {
+ float percent = (dist - 1) / (2.0f * pixels - 1);
+ Color color = Color::rgba(op->startColor).mix(Color::rgba(op->endColor), percent);
+ if (pixel[3] != 0) {
+ if (op->outlineOnly) {
+ float pixelA = byteToFloat(pixel[3]);
+ color.setAlphaF((1.0f - pixelA) * fminf(pixelA, 0.5f) * 2.0f);
+ }
+ else {
+ Color pixelF = Color::rgba(pixel);
+ float pixelA = pixelF.alphaF(), colorA = color.alphaF();
+ colorA += pixelA * (1.0f - colorA);
+ pixelF.convertToLinear(); //Mix in linear color space as it is more perceptually accurate
+ color.convertToLinear();
+ color = color.mix(pixelF, pixelA);
+ color.convertToSRGB();
+ color.setAlphaF(colorA);
}
- pixel = color.toRgba();
}
- } else if (op->outlineOnly) {
- pixel = Vec4B(0, 0, 0, 0);
+ pixel = color.toRgba();
}
- });
+ } else if (op->outlineOnly) {
+ pixel = Vec4B(0, 0, 0, 0);
+ }
+ });
- image = borderImage;
+ image = borderImage;
- } else if (auto op = operation.ptr<ScaleImageOperation>()) {
- if (op->mode == ScaleImageOperation::Nearest)
- image = scaleNearest(image, op->scale);
- else if (op->mode == ScaleImageOperation::Bilinear)
- image = scaleBilinear(image, op->scale);
- else if (op->mode == ScaleImageOperation::Bicubic)
- image = scaleBicubic(image, op->scale);
+ } else if (auto op = operation.ptr<ScaleImageOperation>()) {
+ if (op->mode == ScaleImageOperation::Nearest)
+ image = scaleNearest(image, op->scale);
+ else if (op->mode == ScaleImageOperation::Bilinear)
+ image = scaleBilinear(image, op->scale);
+ else if (op->mode == ScaleImageOperation::Bicubic)
+ image = scaleBicubic(image, op->scale);
- } else if (auto op = operation.ptr<CropImageOperation>()) {
- image = image.subImage(Vec2U(op->subset.min()), Vec2U(op->subset.size()));
+ } else if (auto op = operation.ptr<CropImageOperation>()) {
+ image = image.subImage(Vec2U(op->subset.min()), Vec2U(op->subset.size()));
- } else if (auto op = operation.ptr<FlipImageOperation>()) {
- if (op->mode == FlipImageOperation::FlipX || op->mode == FlipImageOperation::FlipXY) {
- for (size_t y = 0; y < image.height(); ++y) {
- for (size_t xLeft = 0; xLeft < image.width() / 2; ++xLeft) {
- size_t xRight = image.width() - 1 - xLeft;
+ } else if (auto op = operation.ptr<FlipImageOperation>()) {
+ if (op->mode == FlipImageOperation::FlipX || op->mode == FlipImageOperation::FlipXY) {
+ for (size_t y = 0; y < image.height(); ++y) {
+ for (size_t xLeft = 0; xLeft < image.width() / 2; ++xLeft) {
+ size_t xRight = image.width() - 1 - xLeft;
- auto left = image.get(xLeft, y);
- auto right = image.get(xRight, y);
+ auto left = image.get(xLeft, y);
+ auto right = image.get(xRight, y);
- image.set(xLeft, y, right);
- image.set(xRight, y, left);
- }
+ image.set(xLeft, y, right);
+ image.set(xRight, y, left);
}
}
+ }
- if (op->mode == FlipImageOperation::FlipY || op->mode == FlipImageOperation::FlipXY) {
- for (size_t x = 0; x < image.width(); ++x) {
- for (size_t yTop = 0; yTop < image.height() / 2; ++yTop) {
- size_t yBottom = image.height() - 1 - yTop;
+ if (op->mode == FlipImageOperation::FlipY || op->mode == FlipImageOperation::FlipXY) {
+ for (size_t x = 0; x < image.width(); ++x) {
+ for (size_t yTop = 0; yTop < image.height() / 2; ++yTop) {
+ size_t yBottom = image.height() - 1 - yTop;
- auto top = image.get(x, yTop);
- auto bottom = image.get(x, yBottom);
+ auto top = image.get(x, yTop);
+ auto bottom = image.get(x, yBottom);
- image.set(x, yTop, bottom);
- image.set(x, yBottom, top);
- }
+ image.set(x, yTop, bottom);
+ image.set(x, yBottom, top);
}
}
}
}
+}
+
+Image processImageOperations(List<ImageOperation> const& operations, Image image, ImageReferenceCallback refCallback) {
+ for (auto const& operation : operations)
+ processImageOperation(operation, image, refCallback);
return image;
}
diff --git a/source/core/StarImageProcessing.hpp b/source/core/StarImageProcessing.hpp
index bcb5936..ac6151e 100644
--- a/source/core/StarImageProcessing.hpp
+++ b/source/core/StarImageProcessing.hpp
@@ -136,6 +136,8 @@ typedef Variant<HueShiftImageOperation, SaturationShiftImageOperation, Brightnes
ImageOperation imageOperationFromString(String const& string);
String imageOperationToString(ImageOperation const& operation);
+void parseImageOperations(String const& params, function<void(ImageOperation&&)> outputter);
+
// Each operation is assumed to be separated by '?', with parameters
// separated by ';' or '='
List<ImageOperation> parseImageOperations(String const& params);
@@ -147,6 +149,8 @@ StringList imageOperationReferences(List<ImageOperation> const& operations);
typedef function<Image const*(String const& refName)> ImageReferenceCallback;
+void processImageOperation(ImageOperation const& operation, Image& input, ImageReferenceCallback refCallback = {});
+
Image processImageOperations(List<ImageOperation> const& operations, Image input, ImageReferenceCallback refCallback = {});
}