KSeExpr  4.0.4.0
imageSynth.cpp
Go to the documentation of this file.
1 // SPDX-FileCopyrightText: 2011-2019 Disney Enterprises, Inc.
2 // SPDX-License-Identifier: LicenseRef-Apache-2.0
3 // SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me>
4 // SPDX-License-Identifier: GPL-3.0-or-later
5 
9 #include <cstdio>
10 #include <cstdlib>
11 #include <cstring>
12 #include <fstream>
13 #include <map>
14 #include <png.h>
15 #include <vector>
16 
17 #include <KSeExpr/Expression.h>
18 #include <KSeExpr/Interpreter.h>
20 
21 namespace KSeExpr
22 {
24 class ImageSynthExpr : public Expression
25 {
26 public:
28  ImageSynthExpr(const std::string &expr)
29  : Expression(expr)
30  {
31  }
32 
34  struct Var : public ExprVarRef {
35  Var(const double val)
36  : ExprVarRef(ExprType().FP(1).Varying())
37  , val(val)
38  {
39  }
40 
41  Var()
42  : ExprVarRef(ExprType().FP(1).Varying())
43  {
44  }
45 
46  double val {0.0}; // independent variable
47  void eval(double *result) override
48  {
49  result[0] = val;
50  }
51 
52  void eval(const char **) override
53  {
54  assert(false);
55  }
56  };
58  mutable std::map<std::string, Var> vars;
59 
61  ExprVarRef *resolveVar(const std::string &name) const override
62  {
63  auto i = vars.find(name);
64  if (i != vars.end())
65  return &i->second;
66  return nullptr;
67  }
68 };
69 } // namespace KSeExpr
70 
71 constexpr double clamp(double x)
72 {
73  return std::max(0., std::min(255., x)); // NOLINT readability-magic-numbers
74 }
75 
76 using namespace KSeExpr;
77 
78 int main(int argc, char *argv[])
79 {
80  if (argc != 5) { // NOLINT readability-magic-numbers
81  std::cerr << "Usage: " << argv[0] << " <image file> <width> <height> <exprFile>" << std::endl;
82  return 1;
83  }
84 
85  // parse arguments
86  const char *imageFile = argv[1];
87  const char *exprFile = argv[4];
88  size_t width = std::strtoul(argv[2], nullptr, 10); // NOLINT readability-magic-numbers
89  size_t height = std::strtoul(argv[3], nullptr, 10); // NOLINT readability-magic-numbers
90  if (!width || !height) {
91  std::cerr << "invalid width/height" << std::endl;
92  return 1;
93  }
94 
95  std::ifstream istream(exprFile);
96  if (!istream) {
97  std::cerr << "Cannot read file " << exprFile << std::endl;
98  return 1;
99  }
100  std::string exprStr((std::istreambuf_iterator<char>(istream)), std::istreambuf_iterator<char>());
101  ImageSynthExpr expr(exprStr);
102 
103  // make variables
104  expr.vars["u"] = ImageSynthExpr::Var(0.);
105  expr.vars["v"] = ImageSynthExpr::Var(0.);
106  expr.vars["w"] = ImageSynthExpr::Var(width);
107  expr.vars["h"] = ImageSynthExpr::Var(height);
108 
109  // check if expression is valid
110  bool valid = expr.isValid();
111  if (!valid) {
112  std::cerr << "Invalid expression " << std::endl;
113  std::cerr << expr.parseError() << std::endl;
114  return 1;
115  }
116  if (!expr.returnType().isFP(3)) {
117  std::cerr << "Expected color FP[3] got type " << expr.returnType().toString() << std::endl;
118  return 1;
119  }
120 
121  // evaluate expression
122  std::cerr << "Evaluating expresion...from " << exprFile << std::endl;
123  std::vector<unsigned char> image(width * height * 4);
124 
125  {
126  PerformanceTimer evalTime("eval time");
127  double one_over_width = 1. / width;
128  double one_over_height = 1. / height;
129  double &u = expr.vars["u"].val;
130  double &v = expr.vars["v"].val;
131  for (size_t row {}; row < height; row++) {
132  for (size_t col {}; col < width; col++) {
133  auto i = (row * width + col) * 4;
134  u = one_over_width * (col + .5); // NOLINT readability-magic-numbers
135  v = one_over_height * (row + .5); // NOLINT readability-magic-numbers
136 
137  const double *result = expr.evalFP();
138 
139  // expr._interpreter->print();
140  image[i] = clamp(result[0] * 256.); // NOLINT readability-magic-numbers
141  image[i + 1] = clamp(result[1] * 256.); // NOLINT readability-magic-numbers
142  image[i + 2] = clamp(result[2] * 256.); // NOLINT readability-magic-numbers
143  image[i + 3] = 255; // NOLINT readability-magic-numbers
144  }
145  }
146  } // timer
147 
148  // write image as png
149  std::cerr << "Writing image..." << imageFile << std::endl;
150  std::unique_ptr<std::FILE, decltype(&std::fclose)> fp {fopen(imageFile, "wb"), &std::fclose};
151  if (!fp) {
152  perror("fopen");
153  return 1;
154  }
155  png_structp png_ptr {png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr)};
156  png_infop info_ptr {png_create_info_struct(png_ptr)};
157  png_init_io(png_ptr, fp.get());
158  png_set_IHDR(png_ptr,
159  info_ptr,
160  width,
161  height,
162  8, // NOLINT readability-magic-numbers
163  PNG_COLOR_TYPE_RGBA,
164  PNG_INTERLACE_NONE,
165  PNG_COMPRESSION_TYPE_DEFAULT,
166  PNG_FILTER_TYPE_DEFAULT);
167  std::vector<png_byte *> ptrs(height);
168  for (size_t i {}; i < height; i++) {
169  ptrs[i] = &image[width * i * 4];
170  }
171  png_set_rows(png_ptr, info_ptr, ptrs.data());
172  png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, nullptr);
173 }
void eval(ArgHandle args) override
abstract class for implementing variable references
Definition: Expression.h:36
main expression class
Definition: Expression.h:67
virtual ExprVarRef * resolveVar(const std::string &) const
Definition: Expression.h:201
int main(int argc, char *argv[])
Definition: imageSynth.cpp:78
constexpr double clamp(double x)
Definition: imageSynth.cpp:71
double max(double x, double y)
Definition: ExprBuiltins.h:74
double min(double x, double y)
Definition: ExprBuiltins.h:78
double clamp(double x, double lo, double hi)
Definition: ExprBuiltins.h:66