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>
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
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