SeExpr

imageEditor.cpp
Go to the documentation of this file.
1 /*
2 * Copyright Disney Enterprises, Inc. All rights reserved.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License
6 * and the following modification to it: Section 6 Trademarks.
7 * deleted and replaced with:
8 *
9 * 6. Trademarks. This License does not grant permission to use the
10 * trade names, trademarks, service marks, or product names of the
11 * Licensor and its affiliates, except as required for reproducing
12 * the content of the NOTICE file.
13 *
14 * You may obtain a copy of the License at
15 * http://www.apache.org/licenses/LICENSE-2.0
16 */
17
22 #include <iostream>
23 #include <string>
24 #include <png.h>
25
26 #include <QApplication>
27 #include <QDialog>
28 #include <QVBoxLayout>
29 #include <QScrollArea>
30 #include <QLabel>
31 #include <QImage>
32 #include <QPushButton>
33 #include <QMessageBox>
34
35 #include <SeExpr2/Expression.h>
36 #include <SeExpr2/UI/ExprControlCollection.h>
37 #include <SeExpr2/UI/ExprEditor.h>
38 #include <SeExpr2/UI/ExprBrowser.h>
39
40 #include "ImageEditorDialog.h"
41
42 //-- IMAGE SYNTHESIZER CLASSES AND METHODS --//
43
44 double clamp(double x) { return std::max(0., std::min(255., x)); }
45
46 // Simple image synthesizer expression class to support demo image editor
47 class ImageSynthExpression : public SeExpr2::Expression {
48 public:
49 // Constructor that takes the expression to parse
50 ImageSynthExpression(const std::string &expr) : SeExpr2::Expression(expr) {}
51
52 // Simple variable that just returns its internal value
53 struct Var : public SeExpr2::ExprVarRef {
54 Var(const double val) : SeExpr2::ExprVarRef(SeExpr2::ExprType().FP(1).Varying()), val(val) {}
55 Var() : SeExpr2::ExprVarRef(SeExpr2::ExprType().FP(1).Varying()), val(0.0) {}
56 double val; // independent variable
57 void eval(double *result) { result[0] = val; }
58 void eval(const char **result) { assert(false); }
59 };
60 // variable map
61 mutable std::map<std::string, Var> vars;
62
63 // resolve function that only supports one external variable 'x'
64 SeExpr2::ExprVarRef *resolveVar(const std::string &name) const {
65 std::map<std::string, Var>::iterator i = vars.find(name);
66 if (i != vars.end()) return &i->second;
67 return 0;
68 }
69 };
70
71 class ImageSynthesizer {
72 public:
73 ImageSynthesizer();
74 unsigned char *evaluateExpression(const std::string &exprStr);
75
76 private:
77 int _width;
78 int _height;
79 };
80
81 ImageSynthesizer::ImageSynthesizer() {
82 _width = 256;
83 _height = 256;
84 }
85
86 unsigned char *ImageSynthesizer::evaluateExpression(const std::string &exprStr) {
87 ImageSynthExpression expr(exprStr);
88
89 // make variables
90 expr.vars["u"] = ImageSynthExpression::Var(0.);
91 expr.vars["v"] = ImageSynthExpression::Var(0.);
92 expr.vars["w"] = ImageSynthExpression::Var(_width);
93 expr.vars["h"] = ImageSynthExpression::Var(_height);
94
95 // check if expression is valid
96 bool valid = expr.isValid();
97 if (!valid) {
98 std::cerr << "Invalid expression " << std::endl;
99 std::cerr << expr.parseError() << std::endl;
100 return NULL;
101 }
102
103 // evaluate expression
104 std::cerr << "Evaluating expression..." << std::endl;
105 unsigned char *image = new unsigned char[_width * _height * 4];
106 double one_over_width = 1. / _width, one_over_height = 1. / _height;
107 double &u = expr.vars["u"].val;
108 double &v = expr.vars["v"].val;
109 unsigned char *pixel = image;
110 for (int row = 0; row < _height; row++) {
111 for (int col = 0; col < _width; col++) {
112 u = one_over_width * (col + .5);
113 v = one_over_height * (row + .5);
114 SeExpr2::Vec3d result = SeExpr2::Vec3dConstRef(expr.evalFP());
115 pixel[0] = clamp(result[2] * 256.);
116 pixel[1] = clamp(result[1] * 256.);
117 pixel[2] = clamp(result[0] * 256.);
118 pixel[3] = 255;
119 pixel += 4;
120 }
121 }
122
123 return image;
124 }
125
126 //-- IMAGE EDITOR DIALOG METHODS --//
127
128 ImageEditorDialog::ImageEditorDialog(QWidget *parent) : QDialog(parent) {
129 _imageSynthesizer = new ImageSynthesizer();
130
131 this->setWindowTitle("Image Synthesis Editor");
132
133 // Image Previewer
134 _imageLabel = new QLabel();
135 _imageLabel->setFixedSize(256, 256);
136 _imageLabel->setAlignment(Qt::AlignHCenter | Qt::AlignVCenter);
137
138 // Locate logo image relative to location of the app itself
139 QString imageFile = QCoreApplication::applicationDirPath() + "/../share/doc/SeExpr2/seexprlogo.png";
140 QImage image(imageFile); // just a fun default
141
142 QPixmap imagePixmap = QPixmap::fromImage(image);
143 imagePixmap = imagePixmap.scaled(256, 256, Qt::KeepAspectRatio);
144 _imageLabel->setPixmap(imagePixmap);
145 QWidget *imagePreviewWidget = new QWidget();
146 QHBoxLayout *imagePreviewLayout = new QHBoxLayout(imagePreviewWidget);
147 imagePreviewLayout->addStretch();
148 imagePreviewLayout->addWidget(_imageLabel);
149 imagePreviewLayout->addStretch();
150
151 // Expression controls
152 ExprControlCollection *controls = new ExprControlCollection();
153 QScrollArea *scrollArea = new QScrollArea();
154 scrollArea->setMinimumHeight(100);
155 scrollArea->setFixedWidth(450);
156 scrollArea->setWidgetResizable(true);
157 scrollArea->setWidget(controls);
158
159 // Expression editor
160 _editor = new ExprEditor(this, controls);
161
162 // Expression browser
163 ExprBrowser *browser = new ExprBrowser(0, _editor);
164
165 // Add user expressions, example expressions to browser list.
166 browser->addUserExpressionPath("imageEditor");
167 #ifdef IMAGE_EDITOR_ROOT
168 std::string exPathStr = IMAGE_EDITOR_ROOT;
169 exPathStr += "/share/SeExpr2/expressions";
170 browser->addPath("Examples", exPathStr);
171 #else
172 browser->addPath("Examples", "./src/demos/imageEditor");
173 #endif
174 browser->update();
175
176 // Create apply button and connect to image preview.
177 QPushButton *applyButton = new QPushButton("Apply");
178 connect(applyButton, SIGNAL(clicked()), (ImageEditorDialog *)this, SLOT(applyExpression()));
179
180 // Layout widgets: Top section contains left side with previewer and
181 // controls, right side with browser. Bottom section contains editor
182 // and apply button.
183 QVBoxLayout *rootLayout = new QVBoxLayout();
184 this->setLayout(rootLayout);
185
186 QWidget *topWidget = new QWidget();
187 QHBoxLayout *topLayout = new QHBoxLayout();
188 topLayout->setContentsMargins(0, 0, 0, 0);
189 topWidget->setLayout(topLayout);
190
191 QWidget *leftWidget = new QWidget();
192 QVBoxLayout *leftLayout = new QVBoxLayout();
193 leftLayout->setContentsMargins(0, 0, 0, 0);
194 leftWidget->setLayout(leftLayout);
195 leftLayout->addWidget(imagePreviewWidget);
196 leftLayout->addWidget(scrollArea, 1);
197
198 QWidget *bottomWidget = new QWidget();
199 QVBoxLayout *bottomLayout = new QVBoxLayout();
200 bottomLayout->setContentsMargins(0, 0, 0, 0);
201 bottomWidget->setLayout(bottomLayout);
202
203 QWidget *buttonWidget = new QWidget();
204 QHBoxLayout *buttonLayout = new QHBoxLayout(0);
205 buttonWidget->setLayout(buttonLayout);
206 buttonLayout->addWidget(applyButton);
207
208 topLayout->addWidget(leftWidget);
209 topLayout->addWidget(browser, 1);
210
211 bottomLayout->addWidget(_editor);
212 bottomLayout->addWidget(buttonWidget);
213
214 rootLayout->addWidget(topWidget);
215 rootLayout->addWidget(bottomWidget);
216 }
217
218 // Apply expression, if any, from the editor contents to the preview image
219 void ImageEditorDialog::applyExpression() {
220 std::string exprStr = _editor->getExpr();
221 if (exprStr.empty()) {
222 QMessageBox msgBox;
223 msgBox.setText("No expression entered in the editor.");
224 msgBox.exec();
225 } else {
226 QImage image(_imageSynthesizer->evaluateExpression(exprStr), 256, 256, QImage::Format_RGB32);
227 if (image.isNull()) {
228 QMessageBox msgBox;
229 msgBox.setText("Error evaluating expression to create preview image.");
230 msgBox.exec();
231 } else {
232 QPixmap imagePixmap = QPixmap::fromImage(image);
233 _imageLabel->setPixmap(imagePixmap);
234 }
235 }
236 }
237
238 //-- MAIN --//
239
240 int main(int argc, char *argv[]) {
241 QApplication app(argc, argv);
242 ImageEditorDialog *dialog = new ImageEditorDialog(0);
243 dialog->show();
244 app.exec();
245 return 0;
246 }
clamp
double clamp(double x)
Definition: imageEditor.cpp:44
SeExpr2::Vec3dConstRef
Vec< const double, 3, true > Vec3dConstRef
Definition: Vec.h:400
ExprEditor
Definition: ExprEditor.h:94
SeExpr2::Vec< double, 3, false >
ExprBrowser
Definition: ExprBrowser.h:43
ExprBrowser::update
void update()
Definition: ExprBrowser.cpp:300
ExprControlCollection
Definition: ExprControlCollection.h:81
SeExpr2::Expression::Expression
Expression(EvaluationStrategy be=Expression::defaultEvaluationStrategy)
Definition: Expression.cpp:90
SeExpr2
Definition: Context.h:22
main
int main(int argc, char *argv[])
Definition: imageEditor.cpp:240
SeExpr2::min
double min(double x, double y)
Definition: ExprBuiltins.h:43
SeExpr2::Expression
main expression class
Definition: Expression.h:76
SeExpr2::max
double max(double x, double y)
Definition: ExprBuiltins.h:42
ExprBrowser.h
SeExpr2::Expression::resolveVar
virtual ExprVarRef * resolveVar(const std::string &name) const
Definition: Expression.h:199
eval
virtual void eval(ArgHandle args)
Definition: ExprBuiltins.cpp:1028
ImageEditorDialog.h
SeExpr2::ExprVarRef::ExprVarRef
ExprVarRef()
Definition: Expression.h:46
SeExpr2::ExprVarRef
abstract class for implementing variable references
Definition: Expression.h:45
ExprEditor.h
ExprBrowser::addPath
void addPath(const std::string &name, const std::string &path)
Definition: ExprBrowser.cpp:274
ExprControlCollection.h
Expression.h
ExprBrowser::addUserExpressionPath
void addUserExpressionPath(const std::string &context)
Definition: ExprBrowser.cpp:399
expr
</pre >< h3 > Binding our variable reference</h3 > If we now tried to use the variable would still not be found by our expressions To make it bindable we need to override the resolveVar() function as follows</pre >< h3 > Variable setting</h3 > Next we need to make a way of setting the variable As the controlling code will use the expression it will repeatedly alternate between setting the independent variables that are used and calling evaluate(). What it has to do depends very much on the application. In this case we only need to set the independent variable x as</pre >< h2 > Evaluating expressions</h2 > Evaluating an expression is pretty easy But before we can do that we need to make an instance< pre > GrapherExpr expr("x+x^2")
x
</pre >< h3 > A simple variable reference</h3 > This is not a very interesting subclass of expression until we add some additional variables Variables on some applications may be very dynamic In this we only need x
Definition: tutorial.txt:108