izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg-sequences.h
Go to the documentation of this file.
1// -*- mode: C++ -*-
2
3// Copyright (C) 2014-2020 Benjamin De Kosnik <b.dekosnik@gmail.com>
4
5// This file is part of the alpha60-MiL SVG library. This library is
6// free software; you can redistribute it and/or modify it under the
7// terms of the GNU General Public License as published by the Free
8// Software Foundation; either version 3, or (at your option) any
9// later version.
10
11// This library is distributed in the hope that it will be useful, but
12// WITHOUT ANY WARRANTY; without even the implied warranty of
13// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14// General Public License for more details.
15
16#ifndef a60_SVG_SEQUENCES_H
17#define a60_SVG_SEQUENCES_H 1
18
19#include <fstream>
20#include <random>
21#include <unistd.h>
22
23#include "a60-svg.h"
24
25
26namespace svg {
27
28/**
29 Fade rectangle fill from transparent to color, of duration sec, given fps
30 starts on white (klr), fades to klr color in sec
31 can use with image behind
32*/
35 size_t fps = 30, double sec = 1.0, double maxopac = 1.0)
36{
37 // Calc number of frames needed.
38 size_t framesn = fps * sec;
39 double step = maxopac / framesn;
40
41 // Start rectangle as transparent, fade to color.
42 strings ret;
43 style sty = { klr, 0.0, klr, 0.0, 0 };
44 for (size_t i = 0; i < framesn; ++i)
45 {
46 // Foreground rectangle.
47 rect_element rsvg;
48
49 double opacity = i * step;
50 sty._M_fill_opacity = opacity;
51
52 rsvg.start_element();
53 rsvg.add_data(dr);
54 rsvg.add_style(sty);
55 rsvg.finish_element();
56 ret.push_back(rsvg.str());
57 }
58
59 return ret;
60}
61
62
63/// Start rectangle as transparent, fade to color.
66 size_t fps = 30, double sec = 1.0, double minopac = 0)
67{
68 strings ret = fade_to_color_seq(dr, klr, fps, sec, minopac);
69 std::reverse(ret.begin(), ret.end());
70 return ret;
71}
72
73
74/// blink sequence of duration sec, given fps
75/// starts on background (backgf)
76/// at duration twhen
77/// blinks specific frame (blinkf) times (nblinks) for seconds (blinksec)
78/// can use with image behind
81 size_t fps, double sec,
82 double twhen, size_t nblinks, double blinksec)
83{
84 // Calc number of frames needed.
85 size_t framesn = fps * sec;
86 size_t startn = fps * twhen;
87 size_t blinkframesn = (fps * blinksec) + 1; // End with backgf.
88 size_t blinkn = blinkframesn * nblinks;
89
90 if (startn + blinkn > framesn)
91 throw std::logic_error("blink:: desired frames exceed total duration");
92
93 strings ret;
94 double opaque(1.0);
95 double transparent(0.0);
96 style sty = { klr, 0.0, klr, 0.0, 0 };
97
98 // Generate intro.
99 for (size_t i = 0; i < startn; ++i)
100 {
101 sty._M_fill_opacity = transparent;
102 rect_element rsvg;
103 rsvg.start_element();
104 rsvg.add_data(dr);
105 rsvg.add_style(sty);
106 rsvg.finish_element();
107 ret.push_back(rsvg.str());
108 }
109
110 // Blink.
111 for (size_t i = 0; i < nblinks; ++i)
112 {
113 for (size_t j = 0; j < blinkframesn - 1; ++j)
114 {
115 sty._M_fill_opacity = opaque;
116 rect_element rsvg;
117 rsvg.start_element();
118 rsvg.add_data(dr);
119 rsvg.add_style(sty);
120 rsvg.finish_element();
121 ret.push_back(rsvg.str());
122 }
123
124 sty._M_fill_opacity = transparent;
125 rect_element rsvg;
126 rsvg.start_element();
127 rsvg.add_data(dr);
128 rsvg.add_style(sty);
129 rsvg.finish_element();
130 ret.push_back(rsvg.str());
131 }
132
133 // Generate outtro.
134 for (size_t i = startn + blinkn; i < framesn; ++i)
135 {
136 sty._M_fill_opacity = opaque;
137 rect_element rsvg;
138 rsvg.start_element();
139 rsvg.add_data(dr);
140 rsvg.add_style(sty);
141 rsvg.finish_element();
142 ret.push_back(rsvg.str());
143 }
144
145 return ret;
146}
147
148
149/// wink sequence of duration sec, given fps to color klr
150/// starts on background transparent, so can use with an image behind.
151/// at duration twhen
152/// winks specific rectangle (r) this much (maxclose) for seconds (winksec)
155 size_t fps, double sec,
156 double twhen, double maxclose, double winksec)
157{
158 const int rows = dr._M_height;
159
160 // Calc number of frames needed.
161 size_t framesn = fps * sec;
162 size_t startn = fps * twhen;
163 size_t winkframesn = (fps * winksec) + 1;
164 size_t winkframeshalfn = winkframesn / 2;
165
166 // End with backgf.
167 if (startn + winkframesn >= framesn)
168 throw std::logic_error("wink:: desired frames exceed total duration");
169
170 strings ret;
171 double opaque(1.0);
172 double transparent(0.0);
173 style sty = { klr, 0.0, klr, 0.0, 0 };
174
175 // Generate intro.
176 for (size_t i = 0; i < startn; ++i)
177 {
178 sty._M_fill_opacity = transparent;
179 rect_element rsvg;
180 rsvg.start_element();
181 rsvg.add_data(dr);
182 rsvg.add_style(sty);
183 rsvg.finish_element();
184 ret.push_back(rsvg.str());
185 }
186
187 // Make two "eyelid" rectangles, one upper and the other lower.
188 double ymid = dr._M_height / 2;
189 double ymax = ymid * maxclose;
190
191 // grow down
192 rect_element::data dhi = { dr._M_x_origin, dr._M_y_origin, dr._M_width, 0 };
193
194 // grow up
195 rect_element::data dlo = { dr._M_x_origin, dr._M_y_origin + rows,
196 dr._M_width, 0 };
197
198 // Wink.
199 // Step is ammount to move from eyes open to closed and back again.
200 const double step = 2 * ymax / winkframesn;
201
202 // Wink down.
203 for (size_t j = 0; j < winkframeshalfn; ++j)
204 {
205 sty._M_fill_opacity = opaque;
206 double offsetn = j * step;
207
208 // Double rainbow, y'all.
209 rect_element r1;
210 r1.start_element();
211 dhi._M_height = offsetn;
212 r1.add_data(dhi);
213 r1.add_style(sty);
214 r1.finish_element();
215
216 rect_element r2;
217 r2.start_element();
218 dlo._M_y_origin = dr._M_y_origin + rows - offsetn;
219 dlo._M_height = offsetn;
220 r2.add_data(dlo);
221 r2.add_style(sty);
222 r2.finish_element();
223
224 ret.push_back(r1.str() + r2.str());
225 }
226
227 // Wink up.
228 for (size_t j = 0; j < winkframeshalfn; ++j)
229 {
230 sty._M_fill_opacity = opaque;
231 double offsetn = (winkframeshalfn - j) * step;
232
233 // Double rainbow, y'all.
234 rect_element r1;
235 r1.start_element();
236 dhi._M_height = offsetn;
237 r1.add_data(dhi);
238 r1.add_style(sty);
239 r1.finish_element();
240
241 rect_element r2;
242 r2.start_element();
243 dlo._M_y_origin = dr._M_y_origin + rows - offsetn;
244 dlo._M_height = offsetn;
245 r2.add_data(dlo);
246 r2.add_style(sty);
247 r2.finish_element();
248
249 ret.push_back(r1.str() + r2.str());
250 }
251
252 // Generate outtro.
253 for (size_t i = startn + winkframesn; i < framesn; ++i)
254 {
255 sty._M_fill_opacity = transparent;
256 rect_element rsvg;
257 rsvg.start_element();
258 rsvg.add_data(dr);
259 rsvg.add_style(sty);
260 rsvg.finish_element();
261 ret.push_back(rsvg.str());
262 }
263
264 return ret;
265}
266
267
268/// Simulated vertical roll, with fades.
269/// r == frame size
272 size_t /*fps = 30*/, double step = 10,
273 int blursz = 200, int solidsz = 133, double opac = 0.6)
274{
275 // Composition of two rectangular elements:
276 // (background) 60 pixel wide rectangular blur 10 pixels, 60% opacity
277 // (foreground) 20 pixels wide centered solid color overlay
278 const int blurr = 20; // blur radius
279 // const int blursz = 200; // 60, 100, 160, 200
280 // const int solidsz = 133; // 20, 40, 80, 133
281 const double vblursz = blursz / 2;
282 const double vsolidsz = solidsz / 2;
283
284 // One full sweep is half-bottom to offscreen top.
285 double x = (drin._M_height + (2 * blursz) + (3 * blurr)) / step;
286 size_t framesn = static_cast<size_t>(x);
287
288 style sty = { klr, 1.0, klr, 0.0, 0 };
289
290 // rect_elementangles start at bottom off-screen and sweep up.
291 // SVG rect area is rect 00 top left
292 // SVG rect is drawn down and left from starting position.
293
294 // Blur rectangles. The SVG gaussian blur gives a hard edge on the
295 // top corner. So, to have an even fade, double it and center under
296 // the solid rectangle.
297 rect_element::data drblurb(drin);
298 drblurb._M_y_origin = drin._M_y_origin + drin._M_height;
299 drblurb._M_height = blursz;
300
301 rect_element::data drblurt(drin);
302 drblurt._M_y_origin = drin._M_y_origin + drin._M_height - blursz;
303 drblurt._M_height = blursz;
304
305 // Solid rectangle.
306 rect_element::data drs(drin);
307 drs._M_y_origin = drin._M_y_origin + drin._M_height - vsolidsz;
308 drs._M_height = solidsz;
309
310 strings ret;
311 for (size_t i = 0; i < framesn; ++i)
312 {
313 double stepn = i * step;
314
315 // Dual blur.
316 sty._M_fill_opacity = opac;
317
318 rect_element rsvg1;
319 ssize_type yblurb = static_cast<int>(drblurb._M_y_origin - stepn);
320 rsvg1.start_element();
321 rsvg1.add_data(drblurb);
322 rsvg1.add_filter("20y");
323 rsvg1.add_style(sty);
324 rsvg1.finish_element();
325
326 rect_element rsvg3;
327 // ssize_type yblurt = static_cast<int>(drblurt._M_y_origin - stepn);
328 rsvg3.start_element();
329 rsvg3.add_data(drblurt);
330 rsvg3.add_filter("20y");
331
332 std::ostringstream ostrt;
333 ostrt << "rotate(180, 960, " << yblurb - vblursz << ")";
334 rsvg3.add_transform(ostrt.str());
335 rsvg3.add_style(sty);
336 rsvg3.finish_element();
337
338 string scene(rsvg1.str() + rsvg3.str());
339
340 // Foreground rectangle.
341 sty._M_fill_opacity = opac + 0.20;
342 rect_element rsvgfg;
343 // ssize_type y = static_cast<int>(drs._M_y_origin - stepn);
344 rsvgfg.start_element();
345 rsvgfg.add_data(drs);
346 rsvgfg.add_style(sty);
347 rsvgfg.finish_element();
348
349 ret.push_back(scene + rsvgfg.str());
350 }
351
352 return ret;
353}
354
355
356/// Randomly create grid of [maxwidth] x [maxheight] grid, and fill with dots.
357string
358dot_grid_seq(const rect_element::data& drin, const color klr,
359 const rect_element::atype radius = 80,
360 const int maxwidth = 8, const int maxheight = 4,
361 const rect_element::atype xstart = 40,
362 const rect_element::atype ystart = 100)
363{
364 // 1920x1080 landscape baselines.
365 // 8 wide, 4 high
366 // 160 pixel diameter, start at x 40, y 100, move 240.
367
368 static std::mt19937_64 rg(std::random_device{}());
369 auto distw = std::uniform_int_distribution<>(0, maxwidth);
370 auto disth = std::uniform_int_distribution<>(0, maxheight);
371 auto distb = std::uniform_int_distribution<>(0, 1);
372 const int gwidth = distw(rg);
373 const int gheight = disth(rg);
374
375 // Start at bottom off-screen and go up.
376 // These should all be arguments if this were to be parameterized.
377 ssize_type negspace = 2 * radius * 1.5;
378 ssize_type yinit = drin._M_height - radius - ystart;
379
380 // style sty = { klr, 1.0, klr, 0.0, 0 };
381 style sty = { klr, .9, klr, 0.0, 0 };
382
383 string ret;
384 for (auto iheight = 0; iheight < gheight; iheight++)
385 {
386 for (auto iwidth = 0; iwidth < gwidth; iwidth++)
387 {
388 const bool b = distb(rg);
389 if (b)
390 {
391 circle_element csvg;
392 circle_element::atype x = radius + xstart + (iwidth * negspace);
393 circle_element::atype y = yinit - (iheight * negspace);
394 circle_element::data dc = { x, y, radius };
395 csvg.start_element();
396 csvg.add_data(dc);
397 csvg.add_style(sty);
398 csvg.finish_element();
399 ret += csvg.str();
400 }
401 }
402 }
403
404 return ret;
405}
406
407
408/**
409 Simulated optical sound dots, or film processing punches,
410 an experimental film stylistic.
411
412 "The conclusion of a Warhol film is usually announced by the
413 appearance of a flurry of white dots—an artifact of the
414 identification number punched into the last few feet of the roll
415 at the lab." Kyle Westphal, Andy Warhol's Magic Trick
416
417 Analyzing Warhol's Outer and Inner Space frame-by-frame, assume:
418 1920 x 1080 frame size
419 160 pixel diameter circles, with 240 pixel horiz/vert spacing
420 100 pixel from edge
421
422 At 30fps, sequence is:
423 - 2 frames dot pattern 1
424 - 2 frames dot pattern 2
425 - 17 frames nothing
426 - 2 frames dot pattern 3
427 - 2 frames dot pattern 4
428
429 Simplify to:
430 - 2 frames dot pattern 1
431 - 2 frames dot pattern 2
432 - 20 frames blank
433
434 compositions are no more than four across, and sometimes go off the frame
435
436 r == frame size
437*/
440 size_t fps = 30, double sec = 1.0,
441 const int radius = 80,
442 const int maxw = 8, const int maxh = 4,
443 const int xstart = 40, const int ystart = 100)
444{
445 strings ret;
446 size_t framesn = fps * sec; // Calc number of frames needed.
447 size_t step_size = 4 + 17 + 4;
448 for (size_t i = 1; i + step_size < framesn; i += step_size)
449 {
450 string dotpattern1 = dot_grid_seq(drin, klr, radius, maxw, maxh,
451 xstart, ystart);
452 ret.push_back(dotpattern1);
453 string dotpattern2 = dot_grid_seq(drin, klr, radius, maxw, maxh,
454 xstart, ystart);
455 ret.push_back(dotpattern2);
456
457 string empty;
458 ret.insert(ret.end(), 17, empty);
459
460 string dotpattern3 = dot_grid_seq(drin, klr, radius, maxw, maxh,
461 xstart, ystart);
462 ret.push_back(dotpattern3);
463 string dotpattern4 = dot_grid_seq(drin, klr, radius, maxw, maxh,
464 xstart, ystart);
465 ret.push_back(dotpattern4);
466 }
467
468 return ret;
469}
470
471
472/// 1 channel
473/// start with image, background color is klr
474/// each "frame" == string in returned strings has an image and a background
476swipe_left_seq(const rect_element::data& drin, const string imgf,
477 const color klr = color::white, size_t fps = 30, double sec = 9)
478{
479 using atype = rect_element::atype;
480
481 // Watch for horizontal tearing, tricky.
482 // double sec = 5; // swipesec implies 384 pix/sec landscape
483 // double sec = 8; // swipesec implies 240 pix/sec landscape
484 // double sec = 9; // swipesec implies ~640 pix/sec landscape ie 21 pix/frame
485 const style styl = { klr, 1.0, klr, 0.0, 0 };
486 const size_t framesn = fps * sec;
487 const auto width = drin._M_width;
488 const auto offset(width / framesn);
489
490 strings ret;
491 for (size_t i = 0; i < framesn; ++i)
492 {
493 rect_element r;
494 r.start_element();
495 r.add_data(drin);
496 r.add_style(styl);
497 r.finish_element();
498
499 image_element::atype x = 0 - (i * offset);
500 image_element img;
501 image_element::data di = { imgf, x, 0,
502 atype(width), atype(drin._M_height) };
503 img.start_element();
504 img.add_data(di);
505 img.finish_element();
506
507 ret.push_back(r.str() + img.str());
508 }
509 return ret;
510}
511
512} // namespace svg
513
514#endif
void add_filter(const string id)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
void add_style(const style &sty)
void add_data(const data &d, string trans="")
void add_transform(const string s)
Common transforms include rotate(180)
void add_data(const data &d)
Either serialize immediately (as below), or create data structure that adds data to data_vec and then...
string str() const
void start_element(const string &id)
string dot_grid_seq(const rect_element::data &drin, const color klr, const rect_element::atype radius=80, const int maxwidth=8, const int maxheight=4, const rect_element::atype xstart=40, const rect_element::atype ystart=100)
Randomly create grid of [maxwidth] x [maxheight] grid, and fill with dots.
strings swipe_left_seq(const rect_element::data &drin, const string imgf, const color klr=color::white, size_t fps=30, double sec=9)
1 channel start with image, background color is klr each "frame" == string in returned strings has an...
color
Color enumerated as types.
strings fade_to_color_seq(const rect_element::data &dr, const color klr, size_t fps=30, double sec=1.0, double maxopac=1.0)
int ssize_type
Definition a60-svg.h:59
strings wink_to_color_seq(const rect_element::data &dr, const color klr, size_t fps, double sec, double twhen, double maxclose, double winksec)
wink sequence of duration sec, given fps to color klr starts on background transparent,...
strings fade_from_color_seq(const rect_element::data &dr, const color klr, size_t fps=30, double sec=1.0, double minopac=0)
Start rectangle as transparent, fade to color.
strings vertical_sync_roll_seq(const rect_element::data &drin, const color klr, size_t, double step=10, int blursz=200, int solidsz=133, double opac=0.6)
Simulated vertical roll, with fades. r == frame size.
strings blink_to_color_seq(const rect_element::data &dr, const color klr, size_t fps, double sec, double twhen, size_t nblinks, double blinksec)
blink sequence of duration sec, given fps starts on background (backgf) at duration twhen blinks spec...
strings optical_sound_dots_seq(const rect_element::data &drin, const color klr, size_t fps=30, double sec=1.0, const int radius=80, const int maxw=8, const int maxh=4, const int xstart=40, const int ystart=100)
std::vector< string > strings
Definition a60-svg.h:37
Datum consolidating style preferences.