4 * (c) 2018 Martin Mares <mj@ucw.cz>
15 class null_cmd : public cmd_exec {
17 null_cmd(cmd *c UNUSED) { }
18 vector<page *> process(vector<page *> &pages) override { return pages; }
21 static const arg_def no_args[] = {
25 /*** Generic transformed page ***/
27 class xform_page : public page {
31 void render(out_context *out, pdf_matrix xform) override;
32 xform_page(page *p, pdf_matrix xf);
35 xform_page::xform_page(page *p, pdf_matrix xf)
41 BBox media(p->width, p->height);
43 width = media.width();
44 height = media.height();
50 void xform_page::render(out_context *out, pdf_matrix parent_xform)
52 orig_page->render(out, xform * parent_xform);
55 class cmd_exec_simple : public cmd_exec {
56 virtual page *process_page(page *p) = 0;
57 vector<page *> process(vector<page *> &pages) override;
60 vector<page *> cmd_exec_simple::process(vector<page *> &pages)
64 out.push_back(process_page(p));
70 class move_cmd : public cmd_exec_simple {
75 x = c->args.at(0)->as_double(0);
76 y = c->args.at(1)->as_double(0);
78 page *process_page(page *p) override
82 return new xform_page(p, m);
86 static const arg_def move_args[] = {
87 { "x", AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
88 { "y", AT_DIMEN | AT_MANDATORY | AT_POSITIONAL },
94 class scale_cmd : public cmd_exec_simple {
95 double x_factor, y_factor;
99 x_factor = c->args.at(0)->as_double(1);
100 y_factor = c->args.at(1)->as_double(x_factor);
102 page *process_page(page *p) override
105 m.scale(x_factor, y_factor);
106 return new xform_page(p, m);
110 static const arg_def scale_args[] = {
111 { "x", AT_DOUBLE | AT_MANDATORY | AT_POSITIONAL },
112 { "y", AT_DOUBLE | AT_POSITIONAL },
118 class rotate_cmd : public cmd_exec_simple {
123 deg = c->args.at(0)->as_int(0) % 360;
127 die("Rotate requires a multiple of 90 degrees");
129 page *process_page(page *p) override
138 m.shift(0, p->width);
142 m.shift(p->width, p->height);
146 m.shift(p->height, 0);
151 return new xform_page(p, m);
155 static const arg_def rotate_args[] = {
156 { "angle", AT_INT | AT_MANDATORY | AT_POSITIONAL },
162 class flip_cmd : public cmd_exec_simple {
168 horizontal = c->args.at(0)->as_int(0);
169 vertical = c->args.at(1)->as_int(0);
170 if (!horizontal && !vertical)
171 die("Flip has no direction specified");
173 page *process_page(page *p) override
179 m.shift(0, p->height);
184 m.shift(p->width, 0);
186 return new xform_page(p, m);
190 static const arg_def flip_args[] = {
198 class select_cmd : public cmd_exec {
205 vector<page *> process(vector<page *> &pages);
208 static int validate_page_index(vector<page *> &pages, int idx)
210 if (idx >= 1 && idx <= (int) pages.size())
212 if (idx <= -1 && idx >= (int) -pages.size())
213 return idx + pages.size();
214 die("Page index %d out of range", idx);
217 vector<page *> select_cmd::process(vector<page *> &pages)
220 for (auto pb: pipe->branches)
222 vector<page *> selected;
223 for (auto ps: pb->selectors)
225 int f = validate_page_index(pages, ps.from);
226 int t = validate_page_index(pages, ps.to);
227 int step = (f <= t) ? 1 : -1;
228 for (int i=f; f<=t; f += step)
229 selected.push_back(pages[i]);
231 auto processed = run_command_list(pb->commands, selected);
232 for (auto p: processed)
240 class apply_cmd : public cmd_exec {
247 vector<page *> process(vector<page *> &pages);
250 static pipeline_branch *find_branch(pipeline *pipe, vector <page *> &pages, int idx)
252 for (auto pb: pipe->branches)
253 for (auto ps: pb->selectors)
255 int f = validate_page_index(pages, ps.from);
256 int t = validate_page_index(pages, ps.to);
257 if (f <= idx && idx <= t || t <= idx && idx <= f)
263 vector<page *> apply_cmd::process(vector<page *> &pages)
270 pipeline_branch *pb = find_branch(pipe, pages, cnt);
275 auto processed = run_command_list(pb->commands, tmp);
276 for (auto q: processed)
289 class modulo_cmd : public cmd_exec {
295 n = c->args.at(0)->as_int(0);
297 die("Modulo must have n > 0");
300 vector<page *> process(vector<page *> &pages);
303 vector<page *> modulo_cmd::process(vector<page *> &pages)
306 int tuples = ((int) pages.size() + n - 1) / n;
308 for (int tuple=0; tuple < tuples; tuple++)
310 debug("# Tuple %d", tuple);
312 for (auto pb: pipe->branches)
315 for (auto ps: pb->selectors)
319 int step = (f <= t) ? 1 : -1;
320 for (int i=f; i<=t; i += step)
325 else if (i < 0 && i >= -n)
326 j = (tuples-1-tuple)*n + (-i) - 1;
328 die("Modulo: invalid index %d", i);
329 if (j < (int) pages.size())
330 tmp.push_back(pages[j]);
333 page *ref_page = pages[tuple*n];
334 tmp.push_back(new empty_page(ref_page->width, ref_page->height));
338 auto processed = run_command_list(pb->commands, tmp);
339 for (auto q: processed)
348 static const arg_def modulo_args[] = {
349 { "n", AT_INT | AT_MANDATORY | AT_POSITIONAL },
355 class draw_bbox_cmd : public cmd_exec {
357 draw_bbox_cmd(cmd *c UNUSED) { }
358 vector<page *> process(vector<page *> &pages);
361 class draw_bbox_page : public page {
364 void render(out_context *out, pdf_matrix xform);
365 draw_bbox_page(page *p) : page(p) { orig_page = p; }
368 void draw_bbox_page::render(out_context *out, pdf_matrix xform)
370 orig_page->render(out, xform);
373 xform.to_string() + " cm " +
375 bbox.to_rect() + " re S " +
379 vector<page *> draw_bbox_cmd::process(vector<page *> &pages)
383 out.push_back(new draw_bbox_page(p));
387 /*** Command table ***/
389 template<typename T> cmd_exec *ctor(cmd *c) { return new T(c); }
391 const cmd_def cmd_table[] = {
392 { "null", no_args, 0, &ctor<null_cmd> },
393 { "move", move_args, 0, &ctor<move_cmd> },
394 { "scale", scale_args, 0, &ctor<scale_cmd> },
395 { "rotate", rotate_args, 0, &ctor<rotate_cmd> },
396 { "flip", flip_args, 0, &ctor<flip_cmd> },
397 { "select", no_args, 1, &ctor<select_cmd> },
398 { "apply", no_args, 1, &ctor<apply_cmd> },
399 { "modulo", modulo_args, 1, &ctor<modulo_cmd> },
400 { "draw_bbox",no_args, 0, &ctor<draw_bbox_cmd> },
401 { NULL, NULL, 0, NULL }