13 #include <QApplication>
18 #include <QMessageBox>
19 #include <QPushButton>
20 #include <QScrollArea>
21 #include <QVBoxLayout>
33 constexpr
double clamp(
double x)
43 ImageSynthExpression(
const std::string &expr)
60 void eval(
double *result)
override
64 void eval(
const char **)
override
70 mutable std::map<std::string, Var> vars;
75 auto i = vars.find(name);
82 class ImageSynthesizer
85 using ImageData = std::shared_ptr<std::vector<unsigned char>>;
86 ImageSynthesizer() =
default;
87 ImageData evaluateExpression(
const std::string &exprStr)
const
89 ImageSynthExpression expr(exprStr);
92 expr.vars[
"u"] = ImageSynthExpression::Var(0.);
93 expr.vars[
"v"] = ImageSynthExpression::Var(0.);
94 expr.vars[
"w"] = ImageSynthExpression::Var(_width);
95 expr.vars[
"h"] = ImageSynthExpression::Var(_height);
98 bool valid = expr.isValid();
100 std::cerr <<
"Invalid expression " << std::endl;
102 for (
const auto &arg : expr.parseErrorArgs()) {
103 message = message.arg(QString::fromStdString(arg));
105 std::cerr <<
"Parse error: " << message.toStdString() << std::endl;
106 for (
const auto &occurrence : expr.getErrors()) {
108 for (
const auto &arg : occurrence.ids) {
109 message = message.arg(QString::fromStdString(arg));
111 std::cerr <<
"Prep error: " << message.toStdString() << std::endl;
117 std::cerr <<
"Evaluating expression..." << std::endl;
118 std::vector<unsigned char> image(_width * _height * 4);
119 double one_over_width = 1. / _width;
120 double one_over_height = 1. / _height;
121 double &u = expr.vars[
"u"].val;
122 double &v = expr.vars[
"v"].val;
123 for (
size_t row {}; row < _height; row++) {
124 for (
size_t col {}; col < _width; col++) {
125 auto i = (row * _width + col) * 4;
126 u = one_over_width * (col + .5);
127 v = one_over_height * (row + .5);
129 image[i] =
clamp(result[2] * 256.);
130 image[i + 1] =
clamp(result[1] * 256.);
131 image[i + 2] =
clamp(result[0] * 256.);
136 return std::make_shared<std::vector<unsigned char>>(image);
141 size_t _height {256};
146 ImageEditorDialog::ImageEditorDialog(QWidget *parent)
149 _imageSynthesizer =
new ImageSynthesizer();
151 this->setWindowTitle(
"Image Synthesis Editor");
154 _imageLabel =
new QLabel();
155 _imageLabel->setFixedSize(256, 256);
156 _imageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
158 auto *imagePreviewWidget =
new QWidget();
159 auto *imagePreviewLayout =
new QHBoxLayout(imagePreviewWidget);
160 imagePreviewLayout->addStretch();
161 imagePreviewLayout->addWidget(_imageLabel);
162 imagePreviewLayout->addStretch();
166 auto *scrollArea =
new QScrollArea();
167 scrollArea->setMinimumHeight(100);
168 scrollArea->setFixedWidth(450);
169 scrollArea->setWidgetResizable(
true);
170 scrollArea->setWidget(controls);
174 _editor->setControlCollectionWidget(controls);
180 browser->addUserExpressionPath(
"imageEditor");
181 #ifdef IMAGE_EDITOR_ROOT
182 browser->addPath(
"Examples", QDir::toNativeSeparators(QString(
"%1/share/KSeExpr/expressions").arg(IMAGE_EDITOR_ROOT)).toStdString());
184 browser->addPath(
"Examples",
"./src/demos/imageEditor");
189 auto *applyButton =
new QPushButton(
"Apply");
190 connect(applyButton, SIGNAL(clicked()), (ImageEditorDialog *)
this, SLOT(applyExpression()));
195 auto *rootLayout =
new QVBoxLayout();
196 this->setLayout(rootLayout);
198 auto *topWidget =
new QWidget();
199 auto *topLayout =
new QHBoxLayout();
200 topLayout->setContentsMargins(0, 0, 0, 0);
201 topWidget->setLayout(topLayout);
203 auto *leftWidget =
new QWidget();
204 auto *leftLayout =
new QVBoxLayout();
205 leftLayout->setContentsMargins(0, 0, 0, 0);
206 leftWidget->setLayout(leftLayout);
207 leftLayout->addWidget(imagePreviewWidget);
208 leftLayout->addWidget(scrollArea, 1);
210 auto *bottomWidget =
new QWidget();
211 auto *bottomLayout =
new QVBoxLayout();
212 bottomLayout->setContentsMargins(0, 0, 0, 0);
213 bottomWidget->setLayout(bottomLayout);
215 auto *buttonWidget =
new QWidget();
216 auto *buttonLayout =
new QHBoxLayout(
nullptr);
217 buttonWidget->setLayout(buttonLayout);
218 buttonLayout->addWidget(applyButton);
220 topLayout->addWidget(leftWidget);
221 topLayout->addWidget(browser, 1);
223 bottomLayout->addWidget(_editor);
224 bottomLayout->addWidget(buttonWidget);
226 rootLayout->addWidget(topWidget);
227 rootLayout->addWidget(bottomWidget);
231 void ImageEditorDialog::applyExpression()
233 std::string exprStr = _editor->getExpr().toStdString();
234 if (exprStr.empty()) {
235 QMessageBox::information(
this, this->windowTitle(),
"No expression entered in the editor.");
237 auto data = _imageSynthesizer->evaluateExpression(exprStr);
239 QMessageBox::critical(
this, this->windowTitle(),
"Error evaluating expression to create preview image.");
241 QImage image(data->data(), 256, 256, QImage::Format_RGB32);
242 QPixmap imagePixmap = QPixmap::fromImage(image);
243 _imageLabel->setPixmap(imagePixmap);
252 int main(
int argc,
char *argv[])
254 auto app = std::make_unique<QApplication>(argc, argv);
255 auto dialog = std::make_unique<ImageEditorDialog>(
nullptr);
void eval(ArgHandle args) override
static QString message(KSeExpr::ErrorCode code)
abstract class for implementing variable references
virtual ExprVarRef * resolveVar(const std::string &) const
Expression(EvaluationStrategy be=Expression::defaultEvaluationStrategy)
int main(int argc, char *argv[])
constexpr double clamp(double x)
Vec< const double, 3, true > Vec3dConstRef
double max(double x, double y)
double min(double x, double y)