16 std::optional<std::chrono::steady_clock::time_point> deadline) {
17 bool hasImage =
false;
20 std::optional<Color> outputColor;
21 std::optional<Error> failure;
33 std::optional<Image<Color::PALETTE>> indexed;
35 auto ensureImage = [&] {
36 if (hasImage || failure)
return;
37 auto decoded =
Decode(input);
39 failure = decoded.error();
42 image = *std::move(decoded);
46 for (
const auto& token : pipeline.
tokens()) {
47 if (deadline && std::chrono::steady_clock::now() >= *deadline) {
64 if (indexed) indexed =
cropImage(*indexed, token.rect);
72 auto wanted = token.size;
73 if (token.percent != 0) {
74 wanted =
Size{std::max(1, image.
width * token.percent / 100),
75 std::max(1, image.
height * token.percent / 100)};
78 if (indexed) indexed =
resizeImage(*indexed, wanted);
105 failure = colours.error();
110 if (token.limit != 0) {
111 auto fewer =
limitPalette(image, *std::move(colours), token.limit, token.limitHow);
113 failure = fewer.error();
116 colours = *std::move(fewer);
119 auto fitted =
toPalette(image, *std::move(colours), token.dither);
121 failure = fitted.error();
126 failure = expanded.error();
129 image = *std::move(expanded);
130 indexed = *std::move(fitted);
134 outputFormat = token.format;
135 outputColor = token.color;
138 if (failure)
return std::unexpected(*failure);
149 if (!hasImage && !outputColor)
return input;
152 if (failure)
return std::unexpected(*failure);
154 auto pixels = outputColor ?
Convert(image, *outputColor)
156 if (!pixels)
return std::unexpected(pixels.error());
163 if (failure)
return std::unexpected(*failure);
176 "a palette is colours a picture was fitted to, and this one was not; "
177 "name some with -palete"});
180 auto encoded = asIndices ?
Encode(*std::move(indexed), outputFormat)
181 :
Encode(std::move(image), outputFormat, outputColor);
182 if (encoded) encoded->path = input.
path;