izzi
SVG SUBSET C++ API
Loading...
Searching...
No Matches
a60-svg-composite-and-layer-basics.h
Go to the documentation of this file.
1// svg composite and layer basics -*- mode: C++ -*-
2
3// Copyright (C) 2014-2020, 2025 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 MiL_SVG_COMPOSITE_AND_LAYER_BASICS_H
17#define MiL_SVG_COMPOSITE_AND_LAYER_BASICS_H 1
18
19
20namespace svg {
21
22/// Take input size and make a one channel (single-image) SVG form.
24make_svg_1_channel(const space_type deltax, const space_type deltay,
25 const string& outbase)
26{
27 using namespace svg;
28 area<> a = { deltax, deltay };
29 return svg_element(outbase, a);
30}
31
32
33void
35{
36 if (!insert1.empty())
37 {
38 rect_element r1;
39 r1.str(insert1);
40 obj.add_element(r1);
41 }
42}
43
44
45/// Take input size and make a two channel (single-image) SVG form.
47make_svg_2_channel(const space_type deltax, const space_type deltay,
48 const string& outbase)
49{
50 using namespace svg;
51 area<> a = { 2 * deltax, deltay };
52 return svg_element(outbase, a);
53}
54
55
56void
57make_2_channel_insert(svg_element& obj, string insert1, string insert2)
58{
59 if (!insert1.empty())
60 {
61 rect_element r1;
62 r1.str(insert1);
63 obj.add_element(r1);
64 }
65
66 if (!insert2.empty())
67 {
68 rect_element r2;
69 r2.str(insert2);
70 obj.add_element(r2);
71 }
72}
73
74
75/// Paint the edges of a physical page.
76/// Assumes page is square.
77////
78/// @param rlen is height of painted rectangle from edge.
79/// NB: 0.125 is a common bleed == 12 pixels.
80/// First attempt was, common bleed plus 2 pixel "on page" -> 14. Not enough.
81void
82paint_edges_with_char_index(svg_element& obj, const area<> a, const char firstc,
84 const double rlen = 24.0)
85{
86 // Paint edges.
87 const std::locale loc("");
88 const bool alphap = std::isalpha(firstc, loc);
89
90 // Position the first character from (a to z + digit } to x values 0 to 26.
91 // Find this index, with numbers and symbols at the end.
92 const uint maxc = 27;
93 uint cidx(maxc - 1);
94 if (alphap)
95 cidx = (static_cast<uint>(firstc) % 65) - 32;
96
97 const double deltac = double(std::min(a._M_width, a._M_height)) / maxc;
98 double deltax(deltac * cidx);
99 double deltay(deltac * cidx);
100
101 style estyl = svg::k::b_style;
102 estyl.set_colors(klr);
103
104 // Top edge, right to left starting outer to inner
105 point_to_rect(obj, { a._M_width - deltax - rlen - deltac, 0 },
106 estyl, deltac, rlen);
107
108 // Bottom edge, left to right starting innner to outer.
109 point_to_rect(obj, { deltax + rlen, a._M_height - rlen },
110 estyl, deltac, rlen);
111
112 // Right side edge, up from bottom to top.
113 point_to_rect(obj,
114 { a._M_width - rlen, a._M_height - deltay - rlen - deltac },
115 estyl, rlen, deltac);
116}
117
118
119/// Import svg file, convert it to svg_element for insertion.
120/// ifile is a plain SVG file with a 1:1 aspect ratio.
121string
122file_to_svg_insert(const string ifile)
123{
124 string isvg;
125
126 // Read SVG to insert.
127 std::ifstream ifs(ifile);
128 if (ifs.good())
129 {
130 // Strip out any XML version line in the SVG file.
131 // Search for and discard lines with "xml version", iff exists
132 string xmlheader;
133 getline(ifs, xmlheader);
134 if (xmlheader.find("xml version") == string::npos)
135 ifs.seekg(0, ifs.beg);
136
137 std::ostringstream oss;
138 oss << ifs.rdbuf();
139 isvg = oss.str();
140 }
141 else
142 {
143 string m("svg_file_to_svg_insert:: insert nested SVG failed ");
144 m += ifile;
145 m += k::newline;
146 throw std::runtime_error(m);
147 }
148 return isvg;
149}
150
151
152/// Import svg file, convert it to svg_element for insertion.
153string
154element_to_svg_insert(const string isvgpre)
155{
156 string isvg;
157
158 // Read SVG to insert, remove anything previous to <svg"
159 auto svgepos = isvgpre.find("<svg version");
160 if (svgepos != string::npos)
161 {
162 // Strip out any XML version line in the SVG file.
163 // Search for and discard lines with "xml version", iff exists
164 isvg = isvgpre.substr(svgepos);
165 }
166 else
167 {
168 string m("element_to_svg_insert:: insert nested SVG failed of size: ");
169 m += std::to_string(isvgpre.size());
170 m += k::newline;
171 m += "of body:";
172 m += k::newline;
173 m += isvgpre;
174 throw std::runtime_error(m);
175 }
176 return isvg;
177}
178
179
180/// Embed svg in group element.
181/// @param obj is containing svg
182/// @param origin is where glyph placement is inside containing svg element.
183/// @param origsize is original file width/height constant
184/// @param isize is final width/height
185/// @param isvg is the raw svg string to insert, assumes _M_lifetime == false.
186/// @param styl is overide style information: defaults to no_style.
187///
188/// NB This only works is the file has no styles set in svg, group, or
189/// individual element definitions (like circle, path, rectangle,
190/// etc.).
191///
192/// See: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/svg
194insert_svg_at(svg_element& obj, const string isvg,
195 const point_2t origin, const double origsize, const double isize,
196 const double angled = 0, const style& styl = k::no_style)
197{
198 // offset
199 auto [ objx, objy ] = origin;
200 const int x = objx - (isize / 2);
201 const int y = objy - (isize / 2);
202 string xformtranslate(transform::translate(x, y));
203
204 // scaled
205 string xformscale;
206 if (isize != origsize)
207 {
208 const double scalex(isize / origsize);
209 xformscale = transform::scale(scalex);
210 }
211
212 // rotated
213 string xformrotate;
214 if (angled != 0)
215 {
216 xformrotate = transform::rotate(90 - angled, objx, objy);
217 }
218
219 // Order of transformations matters...
220 string ts(xformrotate + k::space + xformtranslate + k::space + xformscale);
221
222 group_element gsvg;
223 gsvg.start_element("inset svg", transform(), ts, styl);
224 gsvg.add_raw(isvg);
225 gsvg.finish_element();
226 obj.add_element(gsvg);
227
228 return obj;
229}
230
231
232/// Take @param obj as some kind of svg element or group of elements,
233/// and embed it as a nested svg at a location centered at @param pos
234/// on the main svg.
237{
238 // Find centered position.
239 const auto a = obj._M_area;
240 const auto [ width, height ] = a;
241 const auto [ xo, yo ] = p;
242
243 bool outofbounds(false);
244
245 double x(0);
246 if (xo > (width / 2))
247 x = xo - (width / 2);
248 else
249 outofbounds = true;
250
251 double y(0);
252 if (yo > (height / 2))
253 y = yo - (height / 2);
254 else
255 outofbounds = true;
256
257 if (outofbounds)
258 throw std::runtime_error("nest_inner_svg_element_centered::out of bounds");
259
260 svg_element nested_obj("inner-" + obj._M_name, a, false);
261 nested_obj.start_element({x, y}, a);
262 nested_obj.add_element(obj);
263 nested_obj.finish_element();
264 return nested_obj;
265}
266
267
268/// Composite frame on bleed.
269/// For printed objects with a center gutter, some intra-page
270/// adjustments are necessary.
271/// @param slxt is odd/even (left/right)
272/// @param bleedin is bleed size for one edge in inches. (1/8)
273/// @param bleedxoffset is distance from spine pushed outward.
274void
276 const svg::select slxt, const double bleedin,
277 const double bleedxoffset = 0)
278{
279 const double bleedpx = get_dpi() * bleedin;
280 const double bleedpxo = get_dpi() * (bleedin + (bleedxoffset / 2));
281
282 if (slxt == svg::select::odd)
283 {
284 // LHS
285 // Individual glyph shapes grid.
286 // Left, center vertical and move to right edge horizontal.
287 const point_2t p = { bleedpx, bleedpxo };
288 obj.start_element(p, obj._M_area);
289 }
290 if (slxt == svg::select::even)
291 {
292 // RHS
293 // Radial metadata dimensions grid.
294 // Right, center vertical and move to left edge horizontal
295 const point_2t p = { bleedxoffset * get_dpi(), bleedpxo };
296 obj.start_element(p, obj._M_area);
297 }
298}
299
300} // namespace svg
301
302#endif
void start_element()
SVG element beginning boilerplate for outermost (containing) svg_element. Variable: unit,...
void add_raw(const string &raw)
string str() const
void add_element(const element_base &e)
const style b_style
svg_element insert_svg_at(svg_element &obj, const string isvg, const point_2t origin, const double origsize, const double isize, const double angled=0, const style &styl=k::no_style)
Embed svg in group element.
color
Color enumerated as types.
svg_element make_svg_1_channel(const space_type deltax, const space_type deltay, const string &outbase)
Take input size and make a one channel (single-image) SVG form.
void paint_edges_with_char_index(svg_element &obj, const area<> a, const char firstc, const svg::color klr=color::duboisgreen2, const double rlen=24.0)
Paint the edges of a physical page. Assumes page is square. /.
double space_type
Base floating point type.
Definition a60-svg.h:62
void composite_bleed_areas(svg_element &obj, const svg::select slxt, const double bleedin, const double bleedxoffset=0)
Composite frame on bleed. For printed objects with a center gutter, some intra-page adjustments are n...
void point_to_rect(svg_element &obj, const point_2t origin, style s, double width=4, double height=4, const string filterstr="")
Rectangle at this point.
string file_to_svg_insert(const string ifile)
Import svg file, convert it to svg_element for insertion. ifile is a plain SVG file with a 1:1 aspect...
svg_element make_svg_2_channel(const space_type deltax, const space_type deltay, const string &outbase)
Take input size and make a two channel (single-image) SVG form.
svg_element nest_inner_svg_element_centered(const svg_element &obj, const point_2t &p)
Take.
void make_2_channel_insert(svg_element &obj, string insert1, string insert2)
double & get_dpi()
Resolution of output display device.
Definition a60-svg.h:256
unsigned int uint
Definition a60-svg.h:57
void make_1_channel_insert(svg_element &obj, string insert1)
string element_to_svg_insert(const string isvgpre)
Import svg file, convert it to svg_element for insertion.
std::tuple< space_type, space_type > point_2t
Point (x,y) in 2D space.
Definition a60-svg.h:65
Datum consolidating style preferences.
void set_colors(const svg::color &klr)
Convenience function to set all colors at once.
Datum consolidating transform possibilities. https://developer.mozilla.org/en-US/docs/Web/SVG/Attribu...
static string translate(int x, int y)
static string scale(double factor)
static string rotate(int deg)