├── .gitignore ├── Makefile ├── README.md ├── examples ├── example.c ├── hershey_text.c └── urls.txt ├── screenshots └── 0001.png └── svg2pl.c /.gitignore: -------------------------------------------------------------------------------- 1 | tests 2 | .DS_Store 3 | */.DS_Store 4 | **/.DS_Store 5 | svg2pl -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | cmd: 2 | gcc -Wall -O3 examples/example.c -o svg2pl 3 | cmdt: 4 | gcc -Wall -O3 examples/hershey_text.c -o svg2pl 5 | testurl: cmd 6 | curl -s $(FILE) | ./svg2pl > out.svg 7 | test1: cmd 8 | ./svg2pl $(FILE) > $(FILE).o.svg 9 | dltest: 10 | mkdir -p tests;\ 11 | while read -r line; do \ 12 | curl -s https://dev.w3.org/SVG/tools/svgweb/samples/svg-files/$$line > tests/$$line; \ 13 | done < examples/urls.txt; 14 | testfold: cmd 15 | while read -r line; do \ 16 | ./svg2pl tests/$$line > tests/$$line.o.svg; \ 17 | done < examples/urls.txt; -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # svg2pl 2 | 3 | *a tiny library to convert (reasonable subset of) svg to polylines* 4 | 5 | - uses very little memory, 0 dynamic allocations 6 | - single file, no dependencies other than C 7 | - extremely fast 8 | - no error checking -- assumes svg is perfectly valid, otherwise UB 9 | - intended for compact projects or embeded systems 10 | 11 | ![](screenshots/0001.png) 12 | 13 | ## supported svg features: 14 | 15 | - transform attribute on all elements 16 | - all path d= commands (beziers, arcs...) 17 | - elements: g, path, line, polyline, polygon, circle, ellipse, rect, svg 18 | - you can register custom parser functions for other tags (see usage) 19 | 20 | ## limitations: 21 | 22 | - curves and ellipses are discretized 23 | - fills and other styles are ignored, 24 | you can choose whether to skip all elements without "stoke" attribute 25 | - viewBox and nested svg are supported, 26 | but preserveAspectRatio can only be "xMidYMid meet"(default) or "none" 27 | - percentage(%) and physical units are not supported 28 | - JS, CSS and other crazy stuff are obviously not supported 29 | 30 | ## usage: 31 | 1. first define macros `S2P_MOVETO(x,y)` and `S2P_LINETO(x,y)` 32 | - these define what to do when the library has extracted polyline vertices 33 | - you can write to your own data structure, print, or control a machine, etc. 34 | - when not overwritten, these macros by default print the vertices to stdout. 35 | 2. (optional) define macro `S2P_SETDIM(w,h)` 36 | - this define what to do when the width/height of the svg are extracted 37 | - e.g. you might scale all subsequent vertices 38 | 3. `#include "svg2pl.c"` 39 | 4. (optional) call `s2p_def_tag` to register parsers for custom tags (e.g. ` 1){ 7 | s2p_parse_from_file(argv[1]); 8 | }else{ 9 | FILE* fd; 10 | char* buf; 11 | size_t sz; 12 | fd = open_memstream(&buf,&sz); 13 | int c; 14 | while ((c=fgetc(stdin)) != EOF){ 15 | fputc(c, fd); 16 | } 17 | fflush(fd); 18 | fclose(fd); 19 | 20 | fd = fmemopen(buf,sz,"r"); 21 | s2p_parse(fd); 22 | 23 | fclose(fd); 24 | } 25 | printf("\" />"); 26 | 27 | } -------------------------------------------------------------------------------- /examples/hershey_text.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #define S2P_SETDIM(w,h) {printf(" 1){ 641 | s2p_parse_from_file(argv[1]); 642 | }else{ 643 | FILE* fd; 644 | char* buf; 645 | size_t sz; 646 | fd = open_memstream(&buf,&sz); 647 | int c; 648 | while ((c=fgetc(stdin)) != EOF){ 649 | fputc(c, fd); 650 | } 651 | fflush(fd); 652 | fclose(fd); 653 | 654 | fd = fmemopen(buf,sz,"r"); 655 | s2p_parse(fd); 656 | 657 | fclose(fd); 658 | } 659 | printf("\" />"); 660 | 661 | } -------------------------------------------------------------------------------- /examples/urls.txt: -------------------------------------------------------------------------------- 1 | AJ_Digital_Camera.svg 2 | DroidSans-Bold.svg 3 | DroidSans.svg 4 | DroidSansMono.svg 5 | DroidSerif-Bold.svg 6 | DroidSerif-BoldItalic.svg 7 | DroidSerif-Italic.svg 8 | DroidSerif-Regular.svg 9 | Steps.svg 10 | USStates.svg 11 | aa.svg 12 | accessible.svg 13 | acid.svg 14 | adobe.svg 15 | alphachannel.svg 16 | android.svg 17 | anim1.svg 18 | anim2.svg 19 | anim3.svg 20 | atom.svg 21 | basura.svg 22 | beacon.svg 23 | betterplace.svg 24 | blocks_game.svg 25 | bloglines.svg 26 | bozo.svg 27 | bzr.svg 28 | bzrfeed.svg 29 | ca.svg 30 | car.svg 31 | cartman.svg 32 | caution.svg 33 | cc.svg 34 | ch.svg 35 | check.svg 36 | circles1.svg 37 | clippath.svg 38 | compass.svg 39 | compuserver_msn_Ford_Focus.svg 40 | copyleft.svg 41 | copyright.svg 42 | couch.svg 43 | couchdb.svg 44 | cygwin.svg 45 | debian.svg 46 | decimal.svg 47 | dh.svg 48 | digg.svg 49 | displayWebStats.svg 50 | dojo.svg 51 | dst.svg 52 | duck.svg 53 | duke.svg 54 | dukechain.svg 55 | easypeasy.svg 56 | eee.svg 57 | eff.svg 58 | erlang.svg 59 | evol.svg 60 | facebook.svg 61 | faux-art.svg 62 | fb.svg 63 | feed.svg 64 | feedsync.svg 65 | fsm.svg 66 | gallardo.svg 67 | gaussian1.svg 68 | gaussian2.svg 69 | gaussian3.svg 70 | gcheck.svg 71 | genshi.svg 72 | git.svg 73 | gnome2.svg 74 | google.svg 75 | gpg.svg 76 | gump-bench.svg 77 | heart.svg 78 | heliocentric.svg 79 | helloworld.svg 80 | hg0.svg 81 | http.svg 82 | ibm.svg 83 | ie-lock.svg 84 | ielock.svg 85 | ietf.svg 86 | image.svg 87 | instiki.svg 88 | integral.svg 89 | intertwingly.svg 90 | irony.svg 91 | italian-flag.svg 92 | iw.svg 93 | jabber.svg 94 | jquery.svg 95 | json.svg 96 | jsonatom.svg 97 | juanmontoya_lingerie.svg 98 | legal.svg 99 | lineargradient1.svg 100 | lineargradient2.svg 101 | lineargradient3.svg 102 | lineargradient4.svg 103 | m.svg 104 | mac.svg 105 | mail.svg 106 | mars.svg 107 | masking-path-04-b.svg 108 | mememe.svg 109 | microformat.svg 110 | mono.svg 111 | moonlight.svg 112 | mouseEvents.svg 113 | mozilla.svg 114 | msft.svg 115 | msie.svg 116 | mt.svg 117 | mudflap.svg 118 | myspace.svg 119 | mysvg.svg 120 | no.svg 121 | ny1.svg 122 | obama.svg 123 | odf.svg 124 | open-clipart.svg 125 | openid.svg 126 | opensearch.svg 127 | openweb.svg 128 | opera.svg 129 | osa.svg 130 | oscon.svg 131 | osi.svg 132 | padlock.svg 133 | patch.svg 134 | paths-data-08-t.svg 135 | paths-data-09-t.svg 136 | pdftk.svg 137 | pencil.svg 138 | penrose-staircase.svg 139 | penrose-tiling.svg 140 | photos.svg 141 | php.svg 142 | poi.svg 143 | preserveAspectRatio.svg 144 | pservers-grad-03-b-anim.svg 145 | pservers-grad-03-b.svg 146 | pull.svg 147 | python.svg 148 | rack.svg 149 | radialgradient1.svg 150 | radialgradient2.svg 151 | rails.svg 152 | raleigh.svg 153 | rdf.svg 154 | rectangles.svg 155 | rest.svg 156 | rfeed.svg 157 | rg1024_Presentation_with_girl.svg 158 | rg1024_Ufo_in_metalic_style.svg 159 | rg1024_eggs.svg 160 | rg1024_green_grapes.svg 161 | rg1024_metal_effect.svg 162 | ruby.svg 163 | rubyforge.svg 164 | scimitar-anim.svg 165 | scimitar.svg 166 | scion.svg 167 | semweb.svg 168 | shapes-polygon-01-t.svg 169 | shapes-polyline-01-t.svg 170 | smile.svg 171 | snake.svg 172 | star.svg 173 | svg.svg 174 | svg2009.svg 175 | svg_header-clean.svg 176 | sync.svg 177 | tiger.svg 178 | tommek_Car.svg 179 | twitter.svg 180 | ubuntu.svg 181 | unicode-han.svg 182 | unicode.svg 183 | usaf.svg 184 | utensils.svg 185 | venus.svg 186 | video1.svg 187 | videos.svg 188 | vmware.svg 189 | vnu.svg 190 | vote.svg 191 | w3c.svg 192 | whatwg.svg 193 | why.svg 194 | wii.svg 195 | wikimedia.svg 196 | wireless.svg 197 | wp.svg 198 | wso2.svg 199 | x11.svg 200 | yadis.svg 201 | yahoo.svg 202 | yinyang.svg 203 | zillow.svg -------------------------------------------------------------------------------- /screenshots/0001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LingDong-/svg2pl/8297fe26d54237678075b0ebf27f2e2262a6947b/screenshots/0001.png -------------------------------------------------------------------------------- /svg2pl.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------+ 3 | | svg2pl.c | 4 | +----------+ 5 | 6 | convert (reasonable subset of) svg to polylines 7 | 8 | - uses very little memory, 0 dynamic allocations 9 | - single file, no dependencies other than C 10 | - extremely fast 11 | - no error checking -- assumes svg is perfectly valid, otherwise UB 12 | - intended for compact projects or embeded systems 13 | 14 | supported svg features: 15 | - transform attribute on all elements 16 | - all path d= commands (beziers, arcs...) 17 | - elements: g, path, line, polyline, polygon, circle, ellipse, rect, svg 18 | - you can register custom parser functions for other tags (see usage) 19 | 20 | limitations: 21 | - curves and ellipses are discretized 22 | - fills and other styles are ignored, 23 | you can choose whether to skip all elements without "stoke" attribute 24 | - viewBox and nested svg are supported, 25 | but preserveAspectRatio can only be "xMidYMid meet"(default) or "none" 26 | - percentage(%) and physical units are not supported 27 | - JS, CSS and other crazy stuff are obviously not supported 28 | 29 | usage: 30 | 1. first define macros S2P_MOVETO(x,y) and S2P_LINETO(x,y) 31 | - these define what to do when the library has extracted polyline vertices 32 | - you can write to your own data structure, print, or control a machine, etc. 33 | 2. (optional) define macro S2P_SETDIM(w,h) 34 | - this define what to do when the width/height of the svg are extracted 35 | - e.g. you might scale all subsequent vertices 36 | 3. #include this file 37 | 4. (optional) call s2p_def_tag to register parsers for custom tags (e.g. 47 | #include 48 | #include 49 | 50 | #define S2P_TAG_OPEN 0 51 | #define S2P_TAG_SELFCL 1 52 | #define S2P_TAG_CLOSE 2 53 | 54 | #define S2P__ST_OUT 0 55 | #define S2P__ST_OPEN 1 56 | #define S2P__ST_TAG 2 57 | #define S2P__ST_IN 3 58 | #define S2P__ST_AK 4 59 | #define S2P__ST_AKE 5 60 | #define S2P__ST_AVQ 6 61 | #define S2P__ST_AV 7 62 | #define S2P__ST_EXCL 8 63 | #define S2P__ST_CMMT 9 64 | 65 | #define S2P_MAX_ATTR 32 66 | #define S2P_MAX_AK_LEN 7 67 | #define S2P_MAX_TAG_LEN 7 68 | 69 | #define S2P_MAX_MAT 32 70 | 71 | #define S2P_MAX_CUSTFUN 16 72 | 73 | #define S2P__MAX(a,b) ((a) > (b) ? (a) : (b)) 74 | #define S2P__MIN(a,b) ((a) < (b) ? (a) : (b)) 75 | 76 | #ifndef S2P_MOVETO 77 | #define S2P_MOVETO(x,y) {printf("M %f %f\n",(x),(y));} 78 | #endif 79 | 80 | #ifndef S2P_LINETO 81 | #define S2P_LINETO(x,y) {printf("L %f %f\n",x,y);} 82 | #endif 83 | 84 | #ifndef S2P_SETDIM 85 | #define S2P_SETDIM(w,h) {printf("M 0 0 h %f v %f h %f z\n",(w),(h),-(w));} 86 | #endif 87 | 88 | int s2p_reso_curv = 24; 89 | int s2p_reso_circ = 24; 90 | int s2p_skip_nostroke = 0; 91 | 92 | typedef struct s2p_attr_st { 93 | int k_len; 94 | int v_len; 95 | long k; 96 | long v; 97 | } s2p_attr_t; 98 | 99 | typedef void (* s2p_tagdef_funptr_t) (FILE* fd, s2p_attr_t* attrs, int n_attr); 100 | 101 | typedef struct s2p_tagdef_st{ 102 | char type; 103 | char name[S2P_MAX_TAG_LEN]; 104 | s2p_tagdef_funptr_t func; 105 | } s2p_tagdef_t; 106 | 107 | s2p_tagdef_t s2p__tagdefs[S2P_MAX_CUSTFUN]; 108 | int s2p__ntd = 0; 109 | 110 | float s2p__mats[S2P_MAX_MAT][9]; 111 | int s2p__mati = 0; 112 | 113 | #define S2P__MATSET(A,a,b,c,d,e,f) {A[0]=a;A[1]=b;A[2]=c;A[3]=d;A[4]=e;A[5]=f;A[6]=0;A[7]=0;A[8]=1;} 114 | 115 | void s2p__matmul(float* A, float* B, float* C){ 116 | float a = A[0] * B[0] + A[1] * B[3] + A[2] * B[6]; 117 | float b = A[0] * B[1] + A[1] * B[4] + A[2] * B[7]; 118 | float c = A[0] * B[2] + A[1] * B[5] + A[2] * B[8]; 119 | 120 | float d = A[3] * B[0] + A[4] * B[3] + A[5] * B[6]; 121 | float e = A[3] * B[1] + A[4] * B[4] + A[5] * B[7]; 122 | float f = A[3] * B[2] + A[4] * B[5] + A[5] * B[8]; 123 | 124 | float g = A[6] * B[0] + A[7] * B[3] + A[8] * B[6]; 125 | float h = A[6] * B[1] + A[7] * B[4] + A[8] * B[7]; 126 | float i = A[6] * B[2] + A[7] * B[5] + A[8] * B[8]; 127 | 128 | C[0] = a; C[1] = b; C[2] = c; 129 | C[3] = d; C[4] = e; C[5] = f; 130 | C[6] = g; C[7] = h; C[8] = i; 131 | } 132 | 133 | void s2p__m_moveto(float x, float y){ 134 | float* m = s2p__mats[s2p__mati]; 135 | float x1 = m[0] * x + m[1] * y + m[2]; 136 | float y1 = m[3] * x + m[4] * y + m[5]; 137 | float z1 = m[6] * x + m[7] * y + m[8]; 138 | S2P_MOVETO(x1/z1,y1/z1); 139 | } 140 | 141 | void s2p__m_lineto(float x, float y){ 142 | float* m = s2p__mats[s2p__mati]; 143 | float x1 = m[0] * x + m[1] * y + m[2]; 144 | float y1 = m[3] * x + m[4] * y + m[5]; 145 | float z1 = m[6] * x + m[7] * y + m[8]; 146 | S2P_LINETO(x1/z1,y1/z1); 147 | } 148 | 149 | 150 | void s2p_quadratic_bezier( 151 | float x0,float y0,float x1,float y1, 152 | float x2,float y2, 153 | float t, float* xo, float* yo){ 154 | float s = 1-t; 155 | float s2 = s*s; 156 | float t2 = t*t; 157 | (*xo) = s2*x0+2*s*t*x1+t2*x2; 158 | (*yo) = s2*y0+2*s*t*y1+t2*y2; 159 | } 160 | 161 | void s2p_cubic_bezier( 162 | float x0,float y0,float x1,float y1, 163 | float x2,float y2,float x3,float y3, 164 | float t, float* xo, float* yo){ 165 | float s = 1-t; 166 | float s2 = s*s; 167 | float s3 = s*s2; 168 | float t2 = t*t; 169 | float t3 = t2*t; 170 | (*xo) = s3*x0+3*s2*t*x1+3*s*t2*x2+t3*x3; 171 | (*yo) = s3*y0+3*s2*t*y1+3*s*t2*y2+t3*y3; 172 | } 173 | 174 | 175 | float s2p__aang(float ux, float uy, float vx, float vy){ 176 | float dot = ux*vx+uy*vy; 177 | float den = sqrt(ux*ux+uy*uy)*sqrt(vx*vx+vy*vy); 178 | float a = acos(dot/den); 179 | float c = ux*vy-uy*vx; 180 | if (c < 0){ 181 | a *= -1; 182 | } 183 | return a; 184 | } 185 | 186 | void s2p_arc( 187 | float x1, float y1, float x2, float y2, 188 | int fa, int fs, 189 | float rx, float ry, float phi){ 190 | //https://www.w3.org/TR/SVG/implnote.html#ArcImplementationNotes 191 | 192 | float x125 = (x1-x2)*0.5; 193 | float y125 = (y1-y2)*0.5; 194 | float cosph = cos(phi); 195 | float sinph = sin(phi); 196 | 197 | float x1p = cosph*x125+sinph*y125; 198 | float y1p =-sinph*x125+cosph*y125; 199 | float x1p2 = x1p*x1p; 200 | float y1p2 = y1p*y1p; 201 | 202 | if (rx == 0 || ry == 0){ 203 | return s2p__m_lineto(x2,y2); 204 | } 205 | if (rx < 0) rx = -rx; 206 | if (ry < 0) ry = -ry; 207 | 208 | float lam = x1p2/(rx*rx) + y1p2/(ry*ry); 209 | if (lam >= 1.0){ 210 | float sql = sqrt(lam); 211 | rx = sql*rx; 212 | ry = sql*ry; 213 | } 214 | 215 | float rx2 = rx*rx; 216 | float ry2 = ry*ry; 217 | 218 | float rr = (rx2*y1p2+ry2*x1p2); 219 | float rrr = fabs(rx2*ry2-rr); //or fmax(rx2*ry2-rr,0)?? 220 | float sqrrr = sqrt(rrr/rr); 221 | 222 | float cxp = sqrrr * (rx*y1p) / ry; 223 | float cyp =-sqrrr * (ry*x1p) / rx; 224 | if (fa == fs){ 225 | cxp *= -1; 226 | cyp *= -1; 227 | } 228 | 229 | float cx = cosph*cxp - sinph*cyp + (x1+x2)*0.5; 230 | float cy = sinph*cxp + cosph*cyp + (y1+y2)*0.5; 231 | float xpcr = (x1p-cxp)/rx; 232 | float ypcr = (y1p-cyp)/ry; 233 | 234 | float th1 = s2p__aang(1,0, xpcr, ypcr ); 235 | float dth = s2p__aang(xpcr, ypcr, (-x1p-cxp)/rx, (-y1p-cyp)/ry); 236 | dth = fmod(dth+M_PI*4, M_PI*2); 237 | if (fs == 0){ 238 | while (dth > 0){ 239 | dth -= M_PI*2; 240 | } 241 | }else{ 242 | while (dth < 0){ 243 | dth += M_PI*2; 244 | } 245 | } 246 | 247 | for (int i = 0; i < s2p_reso_curv; i++){ 248 | float t = (float)(i+1)/(float)s2p_reso_curv; 249 | float th = th1 + dth * t; 250 | float x0 = cos(th)*rx; 251 | float y0 = sin(th)*ry; 252 | float xx = cx+cosph*x0-sinph*y0; 253 | float yy = cy+sinph*x0+cosph*y0; 254 | s2p__m_lineto(xx,yy); 255 | } 256 | 257 | } 258 | 259 | int s2p__d_next(FILE* fd){ 260 | char c; 261 | while ( c=fgetc(fd), c==','||c<=' '){} 262 | int is_n = '+' <= c && c <= '9'; 263 | ungetc(c,fd); 264 | return is_n; 265 | } 266 | 267 | 268 | void s2p__parse_transf(FILE* fd, long v_pos, int v_len, float* mat){ 269 | fseek(fd, v_pos, SEEK_SET); 270 | 271 | char c; 272 | float x0,x1,x2; 273 | float m [9] = {1,0,0,0,1,0,0,0,1}; 274 | float m1[9] = {1,0,0,0,1,0,0,0,1}; 275 | 276 | while (ftell(fd) < v_pos + v_len){ 277 | s2p__d_next(fd); 278 | c = fgetc(fd); 279 | if (c == 't'){//ranslate 280 | fseek(fd,8,SEEK_CUR); 281 | s2p__d_next(fd); 282 | fgetc(fd); 283 | s2p__d_next(fd); 284 | fscanf(fd, "%f", &x0); 285 | s2p__d_next(fd); 286 | fscanf(fd, "%f", &x1); 287 | s2p__d_next(fd); 288 | fgetc(fd); 289 | 290 | S2P__MATSET(m, 1,0,x0, 0,1,x1); 291 | s2p__matmul(mat,m,mat); 292 | }else if (c == 'r'){//otate 293 | fseek(fd,5,SEEK_CUR); 294 | s2p__d_next(fd); 295 | fgetc(fd); 296 | s2p__d_next(fd); 297 | fscanf(fd, "%f", &x0); 298 | float th = x0 * M_PI / 180.0; 299 | S2P__MATSET(m, cos(th), -sin(th), 0, sin(th), cos(th), 0); 300 | 301 | if (s2p__d_next(fd)){ 302 | fscanf(fd, "%f", &x1); 303 | s2p__d_next(fd); 304 | fscanf(fd, "%f", &x2); 305 | s2p__d_next(fd); 306 | m[2] = x1; 307 | m[5] = x2; 308 | S2P__MATSET(m1, 1,0,-x1, 0,1,-x2); 309 | s2p__matmul(m,m1,m); 310 | } 311 | s2p__matmul(mat,m,mat); 312 | fgetc(fd); 313 | }else if (c == 'm'){//atrix 314 | fseek(fd,5,SEEK_CUR); 315 | s2p__d_next(fd); 316 | fgetc(fd); 317 | s2p__d_next(fd); 318 | 319 | for (int i = 0; i < 6; i++){ 320 | fscanf(fd, "%f", &x0); 321 | m[(i&1)*3+(i>>1)] = x0; //col maj 322 | s2p__d_next(fd); 323 | } 324 | m[6] = 0; m[7] = 0; m[8] = 1; 325 | fgetc(fd); 326 | s2p__matmul(mat,m,mat); 327 | 328 | }else if (c == 's'){ 329 | fseek(fd,3,SEEK_CUR); 330 | c = fgetc(fd); 331 | if (c == 'e'){//scale 332 | s2p__d_next(fd); 333 | fgetc(fd); 334 | s2p__d_next(fd); 335 | fscanf(fd, "%f", &x0); 336 | 337 | S2P__MATSET(m, x0,0,0, 0,x0,0); 338 | 339 | if (s2p__d_next(fd)){ 340 | fscanf(fd, "%f", &x1); 341 | s2p__d_next(fd); 342 | 343 | m[4] = x1; 344 | } 345 | s2p__matmul(mat,m,mat); 346 | fgetc(fd); 347 | }else if (c == 'X'){//skewX 348 | s2p__d_next(fd); 349 | fgetc(fd); 350 | s2p__d_next(fd); 351 | fscanf(fd, "%f", &x0); 352 | s2p__d_next(fd); 353 | fgetc(fd); 354 | 355 | S2P__MATSET(m, 1,tan(x0*M_PI/180.0),0, 0,1,0); 356 | s2p__matmul(mat,m,mat); 357 | 358 | }else if (c == 'Y'){//skewY 359 | s2p__d_next(fd); 360 | fgetc(fd); 361 | s2p__d_next(fd); 362 | fscanf(fd, "%f", &x0); 363 | s2p__d_next(fd); 364 | fgetc(fd); 365 | 366 | S2P__MATSET(m, 1,0,0, tan(x0*M_PI/180.0),1,0); 367 | s2p__matmul(mat,m,mat); 368 | } 369 | 370 | } 371 | } 372 | } 373 | 374 | 375 | 376 | 377 | void s2p__get_transf(FILE* fd, s2p_attr_t* attrs, int n_attr, float* mat){ 378 | for (int i = 0; i < n_attr; i++){ 379 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 380 | fseek(fd, attrs[i].k, SEEK_SET); 381 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 382 | if (!strncmp(keybuf,"tra",3)){ 383 | s2p__parse_transf(fd,attrs[i].v,attrs[i].v_len,mat); 384 | return; 385 | } 386 | } 387 | } 388 | 389 | int s2p__get_stroke(FILE* fd, s2p_attr_t* attrs, int n_attr){ 390 | for (int i = 0; i < n_attr; i++){ 391 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 392 | fseek(fd, attrs[i].k, SEEK_SET); 393 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 394 | 395 | if (!strcmp(keybuf,"stroke")){ 396 | fseek(fd, attrs[i].v, SEEK_SET); 397 | if (fgetc(fd) != 'n' || fgetc(fd) != 'o'){ 398 | return 1; 399 | }else{ 400 | return 0; 401 | } 402 | } 403 | } 404 | return 0; 405 | } 406 | 407 | void s2p__parse_line(FILE* fd, s2p_attr_t* attrs, int n_attr){ 408 | 409 | float x1, y1, x2, y2; 410 | for (int i = 0; i < n_attr; i++){ 411 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 412 | fseek(fd, attrs[i].k, SEEK_SET); 413 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 414 | if (!strcmp(keybuf,"x1")){ 415 | fseek(fd, attrs[i].v, SEEK_SET); 416 | fscanf(fd, "%f", &x1); 417 | }else if (!strcmp(keybuf,"y1")){ 418 | fseek(fd, attrs[i].v, SEEK_SET); 419 | fscanf(fd, "%f", &y1); 420 | }else if (!strcmp(keybuf,"x2")){ 421 | fseek(fd, attrs[i].v, SEEK_SET); 422 | fscanf(fd, "%f", &x2); 423 | }else if (!strcmp(keybuf,"y2")){ 424 | fseek(fd, attrs[i].v, SEEK_SET); 425 | fscanf(fd, "%f", &y2); 426 | } 427 | } 428 | s2p__m_moveto(x1,y1); 429 | s2p__m_lineto(x2,y2); 430 | } 431 | 432 | 433 | void s2p__parse_rect(FILE* fd, s2p_attr_t* attrs, int n_attr){ 434 | float x=0,y=0,w,h,rx=0,ry=0; 435 | for (int i = 0; i < n_attr; i++){ 436 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 437 | fseek(fd, attrs[i].k, SEEK_SET); 438 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 439 | if (!strcmp(keybuf,"x")){ 440 | fseek(fd, attrs[i].v, SEEK_SET); 441 | fscanf(fd, "%f", &x); 442 | }else if (!strcmp(keybuf,"y")){ 443 | fseek(fd, attrs[i].v, SEEK_SET); 444 | fscanf(fd, "%f", &y); 445 | }else if (!strcmp(keybuf,"width")){ 446 | fseek(fd, attrs[i].v, SEEK_SET); 447 | fscanf(fd, "%f", &w); 448 | }else if (!strcmp(keybuf,"height")){ 449 | fseek(fd, attrs[i].v, SEEK_SET); 450 | fscanf(fd, "%f", &h); 451 | }else if (!strcmp(keybuf,"rx")){ 452 | fseek(fd, attrs[i].v, SEEK_SET); 453 | fscanf(fd, "%f", &rx); 454 | }else if (!strcmp(keybuf,"ry")){ 455 | fseek(fd, attrs[i].v, SEEK_SET); 456 | fscanf(fd, "%f", &ry); 457 | } 458 | } 459 | if (rx && !ry){ 460 | ry = rx; 461 | } 462 | if (!rx || !ry){ 463 | s2p__m_moveto(x,y); 464 | s2p__m_lineto(x+w,y); 465 | s2p__m_lineto(x+w,y+h); 466 | s2p__m_lineto(x,y+h); 467 | s2p__m_lineto(x,y); 468 | }else{ 469 | rx = fabs(rx); 470 | ry = fabs(ry); 471 | if (rx > w/2) rx = w/2; 472 | if (ry > h/2) ry = h/2; 473 | s2p__m_moveto(x,y+ry); 474 | s2p_arc(x,y+ry, x+rx,y, 0,1, rx,ry,0); 475 | s2p__m_lineto(x+w-rx,y); 476 | s2p_arc(x+w-rx,y, x+w,y+ry, 0,1, rx,ry,0); 477 | s2p__m_lineto(x+w,y+h-ry); 478 | s2p_arc(x+w,y+h-ry, x+w-rx,y+h, 0,1, rx,ry,0); 479 | s2p__m_lineto(x+rx,y+h); 480 | s2p_arc(x+rx,y+h, x,y+h-ry, 0,1, rx,ry,0); 481 | s2p__m_lineto(x,y+ry); 482 | } 483 | } 484 | 485 | 486 | void s2p__parse_ellipse(FILE* fd, s2p_attr_t* attrs, int n_attr){ 487 | float cx=0,cy=0,rx=0,ry=0; 488 | for (int i = 0; i < n_attr; i++){ 489 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 490 | fseek(fd, attrs[i].k, SEEK_SET); 491 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 492 | if (!strcmp(keybuf,"cx")){ 493 | fseek(fd, attrs[i].v, SEEK_SET); 494 | fscanf(fd, "%f", &cx); 495 | }else if (!strcmp(keybuf,"cy")){ 496 | fseek(fd, attrs[i].v, SEEK_SET); 497 | fscanf(fd, "%f", &cy); 498 | }else if (!strcmp(keybuf,"r")){ 499 | fseek(fd, attrs[i].v, SEEK_SET); 500 | fscanf(fd, "%f", &rx); 501 | }else if (!strcmp(keybuf,"rx")){ 502 | fseek(fd, attrs[i].v, SEEK_SET); 503 | fscanf(fd, "%f", &rx); 504 | }else if (!strcmp(keybuf,"ry")){ 505 | fseek(fd, attrs[i].v, SEEK_SET); 506 | fscanf(fd, "%f", &ry); 507 | } 508 | } 509 | if (rx && !ry) ry = rx; 510 | if (ry && !rx) rx = ry; 511 | rx = fabs(rx); 512 | ry = fabs(ry); 513 | for (int i = 0; i < s2p_reso_circ; i++){ 514 | float t = (float)i/(float)(s2p_reso_circ-1); 515 | float a = t * M_PI * 2; 516 | float x = cx+cos(a)*rx; 517 | float y = cy+sin(a)*ry; 518 | if (i){ 519 | s2p__m_lineto(x,y); 520 | }else{ 521 | s2p__m_moveto(x,y); 522 | } 523 | } 524 | } 525 | 526 | void s2p__parse_poly(FILE* fd, s2p_attr_t* attrs, int n_attr, int closed){ 527 | for (int i = 0; i < n_attr; i++){ 528 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 529 | fseek(fd, attrs[i].k, SEEK_SET); 530 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 531 | if (!strcmp(keybuf,"points")){ 532 | fseek(fd, attrs[i].v, SEEK_SET); 533 | float x,y,x0,y0; 534 | int j=0; 535 | while (ftell(fd) < attrs[i].v + attrs[i].v_len){ 536 | fscanf(fd, "%f", &x); 537 | fgetc(fd); 538 | fscanf(fd, "%f", &y); 539 | fgetc(fd); 540 | if (j){ 541 | s2p__m_lineto(x,y); 542 | }else{ 543 | s2p__m_moveto(x,y); 544 | x0 = x; 545 | y0 = y; 546 | } 547 | j++; 548 | } 549 | if (closed){ 550 | s2p__m_lineto(x0,y0); 551 | } 552 | } 553 | } 554 | } 555 | 556 | 557 | 558 | 559 | void s2p__parse_d(FILE* fd, long v_pos, int v_len){ 560 | fseek(fd, v_pos, SEEK_SET); 561 | char c; 562 | char lc; 563 | float lx=0, ly=0; 564 | float ox=0, oy=0; 565 | float cx=0, cy=0; 566 | float qx=0, qy=0; 567 | float x0,y0; 568 | float x1,y1; 569 | float x2,y2; 570 | int f0,f1; 571 | while (ftell(fd) < v_pos + v_len){ 572 | s2p__d_next(fd); 573 | c = fgetc(fd); 574 | if (c < 'A'){ 575 | ungetc(c,fd); 576 | c = lc; 577 | } 578 | if (c == 'M'){ 579 | fscanf(fd, "%f", &x0); 580 | s2p__d_next(fd); 581 | fscanf(fd, "%f", &y0); 582 | s2p__m_moveto(ox=lx=x0,oy=ly=y0); 583 | while (s2p__d_next(fd)){ 584 | fscanf(fd, "%f", &x0); 585 | s2p__d_next(fd); 586 | fscanf(fd, "%f", &y0); 587 | s2p__m_lineto(lx=x0,ly=y0); 588 | } 589 | }else if (c == 'm'){ 590 | fscanf(fd, "%f", &x0); 591 | s2p__d_next(fd); 592 | fscanf(fd, "%f", &y0); 593 | s2p__m_moveto(ox=(lx+=x0),oy=(ly+=y0)); 594 | while (s2p__d_next(fd)){ 595 | fscanf(fd, "%f", &x0); 596 | s2p__d_next(fd); 597 | fscanf(fd, "%f", &y0); 598 | s2p__m_lineto(lx+=x0,ly+=y0); 599 | } 600 | }else if (c == 'L'){ 601 | fscanf(fd, "%f", &x0); 602 | s2p__d_next(fd); 603 | fscanf(fd, "%f", &y0); 604 | s2p__m_lineto(lx=x0,ly=y0); 605 | 606 | }else if (c == 'l'){ 607 | fscanf(fd, "%f", &x0); 608 | s2p__d_next(fd); 609 | fscanf(fd, "%f", &y0); 610 | s2p__m_lineto(lx+=x0,ly+=y0); 611 | 612 | }else if (c == 'H'){ 613 | fscanf(fd, "%f", &x0); 614 | s2p__m_lineto(lx=x0,ly); 615 | 616 | }else if (c == 'h'){ 617 | fscanf(fd, "%f", &x0); 618 | s2p__m_lineto(lx+=x0,ly); 619 | 620 | }else if (c == 'V'){ 621 | fscanf(fd, "%f", &y0); 622 | s2p__m_lineto(lx,ly=y0); 623 | 624 | }else if (c == 'v'){ 625 | fscanf(fd, "%f", &y0); 626 | s2p__m_lineto(lx,ly+=y0); 627 | 628 | }else if (c == 'Z' || c == 'z'){ 629 | s2p__m_lineto(lx=ox,ly=oy); 630 | }else if (c == 'C' || c == 'c'){ 631 | float _x = 0; 632 | float _y = 0; 633 | if (c == 'c'){ 634 | _x = lx; 635 | _y = ly; 636 | } 637 | fscanf(fd, "%f", &x0); 638 | s2p__d_next(fd); 639 | fscanf(fd, "%f", &y0); 640 | s2p__d_next(fd); 641 | fscanf(fd, "%f", &x1); 642 | s2p__d_next(fd); 643 | fscanf(fd, "%f", &y1); 644 | s2p__d_next(fd); 645 | fscanf(fd, "%f", &x2); 646 | s2p__d_next(fd); 647 | fscanf(fd, "%f", &y2); 648 | for (int i = 0; i < s2p_reso_curv; i++){ 649 | float t = (float)(i+1)/(float)(s2p_reso_curv); 650 | float xt,yt; 651 | s2p_cubic_bezier(lx,ly,_x+x0,_y+y0,_x+x1,_y+y1,_x+x2,_y+y2,t,&xt,&yt); 652 | s2p__m_lineto(xt,yt); 653 | } 654 | lx = _x+x2; 655 | ly = _y+y2; 656 | cx = _x+x1; 657 | cy = _y+y1; 658 | }else if (c == 'Q' || c == 'q'){ 659 | float _x = 0; 660 | float _y = 0; 661 | if (c == 'q'){ 662 | _x = lx; 663 | _y = ly; 664 | } 665 | fscanf(fd, "%f", &x0); 666 | s2p__d_next(fd); 667 | fscanf(fd, "%f", &y0); 668 | s2p__d_next(fd); 669 | fscanf(fd, "%f", &x1); 670 | s2p__d_next(fd); 671 | fscanf(fd, "%f", &y1); 672 | for (int i = 0; i < s2p_reso_curv; i++){ 673 | float t = (float)(i+1)/(float)(s2p_reso_curv); 674 | float xt,yt; 675 | s2p_quadratic_bezier(lx,ly,_x+x0,_y+y0,_x+x1,_y+y1,t,&xt,&yt); 676 | s2p__m_lineto(xt,yt); 677 | } 678 | lx = _x+x1; 679 | ly = _y+y1; 680 | qx = _x+x0; 681 | qy = _y+y0; 682 | }else if (c == 'S' || c == 's'){ 683 | float _x = 0, _y = 0; 684 | if (c == 's'){ 685 | _x = lx; 686 | _y = ly; 687 | } 688 | if (!(lc == 'C' || lc == 'c' || lc == 'S' || lc == 's')){ 689 | cx = lx; 690 | cy = ly; 691 | } 692 | x0 = (lx-cx)+lx; 693 | y0 = (ly-cy)+ly; 694 | fscanf(fd, "%f", &x1); 695 | s2p__d_next(fd); 696 | fscanf(fd, "%f", &y1); 697 | s2p__d_next(fd); 698 | fscanf(fd, "%f", &x2); 699 | s2p__d_next(fd); 700 | fscanf(fd, "%f", &y2); 701 | for (int i = 0; i < s2p_reso_curv; i++){ 702 | float t = (float)(i+1)/(float)(s2p_reso_curv); 703 | float xt,yt; 704 | s2p_cubic_bezier(lx,ly,x0,y0,_x+x1,_y+y1,_x+x2,_y+y2,t,&xt,&yt); 705 | s2p__m_lineto(xt,yt); 706 | } 707 | lx = _x+x2; 708 | ly = _y+y2; 709 | cx = _x+x1; 710 | cy = _y+y1; 711 | }else if (c == 'T' || c == 't'){ 712 | float _x = 0, _y = 0; 713 | if (c == 't'){ 714 | _x = lx; 715 | _y = ly; 716 | } 717 | if (!(lc == 'Q' || lc == 'q' || lc == 'T' || lc == 't')){ 718 | qx = lx; 719 | qy = ly; 720 | } 721 | x0 = (lx-qx)+lx; 722 | y0 = (ly-qy)+ly; 723 | fscanf(fd, "%f", &x1); 724 | s2p__d_next(fd); 725 | fscanf(fd, "%f", &y1); 726 | for (int i = 0; i < s2p_reso_curv; i++){ 727 | float t = (float)(i+1)/(float)(s2p_reso_curv); 728 | float xt,yt; 729 | s2p_quadratic_bezier(lx,ly,x0,y0,_x+x1,_y+y1,t,&xt,&yt); 730 | s2p__m_lineto(xt,yt); 731 | } 732 | lx = _x+x1; 733 | ly = _y+y1; 734 | qx = x0; 735 | qy = y0; 736 | }else if (c == 'A' || c == 'a'){ 737 | float _x = 0, _y = 0; 738 | if (c == 'a'){ 739 | _x = lx; 740 | _y = ly; 741 | } 742 | fscanf(fd, "%f", &x0);//rx 743 | s2p__d_next(fd); 744 | fscanf(fd, "%f", &y0);//ry 745 | s2p__d_next(fd); 746 | fscanf(fd, "%f", &x1);//rot 747 | s2p__d_next(fd); 748 | fscanf(fd, "%d", &f0);//fA 749 | s2p__d_next(fd); 750 | fscanf(fd, "%d", &f1);//fS 751 | s2p__d_next(fd); 752 | fscanf(fd, "%f", &x2);//nx 753 | s2p__d_next(fd); 754 | fscanf(fd, "%f", &y2);//ny 755 | 756 | s2p_arc(lx,ly,_x+x2,_y+y2,f0,f1,x0,y0,x1*M_PI/180.0); 757 | lx = _x+x2; 758 | ly = _y+y2; 759 | } 760 | lc = c; 761 | } 762 | } 763 | 764 | void s2p__parse_path(FILE* fd, s2p_attr_t* attrs, int n_attr){ 765 | for (int i = 0; i < n_attr; i++){ 766 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 767 | fseek(fd, attrs[i].k, SEEK_SET); 768 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 769 | if (!strcmp(keybuf,"d")){ 770 | 771 | s2p__parse_d(fd,attrs[i].v,attrs[i].v_len); 772 | } 773 | } 774 | } 775 | 776 | 777 | void s2p_def_tag(char* name, char tag_type, s2p_tagdef_funptr_t fun){ 778 | strncpy(s2p__tagdefs[s2p__ntd].name, name, S2P_MAX_TAG_LEN); 779 | s2p__tagdefs[s2p__ntd].type = tag_type; 780 | s2p__tagdefs[s2p__ntd].func = fun; 781 | s2p__ntd++; 782 | } 783 | 784 | void s2p_parse(FILE* fd){ 785 | int c; 786 | int state = S2P__ST_OUT; 787 | long tag; 788 | char tag_len = 0; 789 | char closing = 0; 790 | s2p_attr_t attrs[S2P_MAX_ATTR] = {0}; 791 | int n_attr = 0; 792 | char quote = 0; 793 | char cmmttyp = 0; 794 | int endcmmt = 0; 795 | s2p__mati = 0; 796 | S2P__MATSET(s2p__mats[s2p__mati], 1,0,0, 0,1,0); 797 | 798 | long stroke_stack = 0; 799 | 800 | while ((c = fgetc(fd)) != EOF){ 801 | // printf("%c %d\n",c,state); 802 | if (state == S2P__ST_OUT){ 803 | if (c == '<'){ 804 | state = S2P__ST_OPEN; 805 | } 806 | }else if (state == S2P__ST_OPEN){ 807 | if (c == '>') goto lbl_close_tag; 808 | if (c == '/') {closing = S2P_TAG_CLOSE; continue;} 809 | if (c == '!'){ state = S2P__ST_EXCL;continue;} 810 | if (c > ' '){ 811 | state = S2P__ST_TAG; 812 | tag = ftell(fd)-1; 813 | tag_len++; 814 | } 815 | }else if (state == S2P__ST_TAG){ 816 | if (c == '>') goto lbl_close_tag; 817 | if (c == '/') goto lbl_slash; 818 | if (c > ' '){ 819 | tag_len++; 820 | }else{ 821 | state = S2P__ST_IN; 822 | } 823 | }else if (state == S2P__ST_IN){ 824 | if (c == '>'){ 825 | goto lbl_close_tag; 826 | } 827 | if (c == '/') goto lbl_slash; 828 | if (c > ' '){ 829 | state = S2P__ST_AK; 830 | attrs[n_attr].k = ftell(fd)-1; 831 | attrs[n_attr].k_len++; 832 | } 833 | }else if (state == S2P__ST_AK){ 834 | if (c == '>') goto lbl_close_tag; 835 | if (c == '/') goto lbl_slash; 836 | if (c == '='){ 837 | state = S2P__ST_AVQ; 838 | }else if (c > ' '){ 839 | attrs[n_attr].k_len++; 840 | }else{ 841 | state = S2P__ST_AKE; 842 | } 843 | }else if (state == S2P__ST_AKE){ 844 | if (c == '>') goto lbl_close_tag; 845 | if (c == '/') goto lbl_slash; 846 | if (c == '='){ 847 | state = S2P__ST_AVQ; 848 | }else if (c > ' '){ 849 | n_attr ++; 850 | state = S2P__ST_AK; 851 | attrs[n_attr].k = ftell(fd)-1; 852 | attrs[n_attr].k_len++; 853 | } 854 | }else if (state == S2P__ST_AVQ){ 855 | if (c == '>') goto lbl_close_tag; 856 | if (c == '/') goto lbl_slash; 857 | if (c == '"' || c == '\''){ 858 | quote = c; 859 | state = S2P__ST_AV; 860 | attrs[n_attr].v = ftell(fd); 861 | } 862 | }else if (state == S2P__ST_AV){ 863 | if (c == quote){ 864 | n_attr ++; 865 | state = S2P__ST_IN; 866 | }else{ 867 | attrs[n_attr].v_len++; 868 | } 869 | }else if (state == S2P__ST_EXCL){ 870 | cmmttyp = c; 871 | if (c == '[') cmmttyp += 2; 872 | state = S2P__ST_CMMT; 873 | endcmmt = -1; 874 | }else if (state == S2P__ST_CMMT){ 875 | if (c == '>' && (endcmmt >= 2 || (cmmttyp != '-' && cmmttyp != ']'))) goto lbl_close_tag; 876 | if (c == cmmttyp) endcmmt ++; else endcmmt = 0; 877 | } 878 | continue; 879 | lbl_slash:; 880 | closing ++; 881 | continue; 882 | lbl_close_tag:; 883 | 884 | if (!tag_len){ 885 | goto lbl_reset; 886 | } 887 | 888 | int pos = ftell(fd); 889 | 890 | char tagbuf[S2P_MAX_TAG_LEN+1] = {0}; 891 | 892 | fseek(fd, tag, SEEK_SET); 893 | fread(tagbuf,1,S2P__MIN(tag_len,7),fd); 894 | 895 | // fprintf(stderr,"%s %d\n",tagbuf,pos); 896 | 897 | for (int i = 0; i < s2p__ntd; i++){ 898 | if (closing != s2p__tagdefs[i].type){ 899 | continue; 900 | } 901 | if (!strncmp(s2p__tagdefs[i].name, tagbuf, S2P_MAX_TAG_LEN)){ 902 | fseek(fd, pos, SEEK_SET); 903 | s2p__tagdefs[i].func(fd,attrs,n_attr); 904 | goto lbl_done_tag; 905 | } 906 | } 907 | 908 | if (!strcmp(tagbuf,"svg")){ 909 | if (closing == 0){ 910 | float x=0,y=0,w=300,h=150,vx,vy,vw,vh,par=1; 911 | char set_whv = 0; 912 | for (int i = 0; i < n_attr; i++){ 913 | char keybuf[S2P_MAX_AK_LEN+1] = {0}; 914 | fseek(fd, attrs[i].k, SEEK_SET); 915 | fread(keybuf,1,S2P__MIN(attrs[i].k_len,S2P_MAX_AK_LEN),fd); 916 | if (!strcmp(keybuf,"x")){ 917 | fseek(fd, attrs[i].v, SEEK_SET); 918 | fscanf(fd, "%f", &x); 919 | }else if (!strcmp(keybuf,"y")){ 920 | fseek(fd, attrs[i].v, SEEK_SET); 921 | fscanf(fd, "%f", &y); 922 | }else if (!strcmp(keybuf,"width")){ 923 | set_whv |= 4; 924 | fseek(fd, attrs[i].v, SEEK_SET); 925 | fscanf(fd, "%f", &w); 926 | }else if (!strcmp(keybuf,"height")){ 927 | set_whv |= 2; 928 | fseek(fd, attrs[i].v, SEEK_SET); 929 | fscanf(fd, "%f", &h); 930 | 931 | }else if (!strcmp(keybuf,"viewBox")){ 932 | set_whv |= 1; 933 | fseek(fd, attrs[i].v, SEEK_SET); 934 | fscanf(fd, "%f", &vx); 935 | s2p__d_next(fd); 936 | fscanf(fd, "%f", &vy); 937 | s2p__d_next(fd); 938 | fscanf(fd, "%f", &vw); 939 | s2p__d_next(fd); 940 | fscanf(fd, "%f", &vh); 941 | }else if (!strncmp(keybuf,"prese",5)){ 942 | fseek(fd, attrs[i].v, SEEK_SET); 943 | s2p__d_next(fd); 944 | if (fgetc(fd) == 'n'){ 945 | par = 0; 946 | } 947 | } 948 | } 949 | 950 | 951 | if (set_whv == 6 || set_whv == 0){ 952 | vx = 0; vy = 0; vw = w; vh = h; 953 | }else if (set_whv == 1){ 954 | w = vw; h = vh; 955 | }else if (set_whv == 5){ 956 | h = w * vh / vw; 957 | }else if (set_whv == 3){ 958 | w = h * vw / vh; 959 | }else if (set_whv == 2){ 960 | w = h; 961 | vx = 0; vy = 0; vw = w; vh = h; 962 | }else if (set_whv == 4){ 963 | h = w; 964 | vx = 0; vy = 0; vw = w; vh = h; 965 | } 966 | 967 | if (!s2p__mati){ 968 | S2P_SETDIM(w,h); 969 | } 970 | 971 | s2p__mati ++; 972 | memcpy(s2p__mats+s2p__mati,s2p__mats+(s2p__mati-1),9*sizeof(float)); 973 | 974 | float sx = w/vw; 975 | float sy = h/vh; 976 | float m[9] = {sx,0,-vx*sx+x, 0,sy,-vy*sy+y, 0,0,1}; 977 | if (par){ 978 | float s = fmin(sx,sy); 979 | float px = (w-vw*s)/2.0; 980 | float py = (h-vh*s)/2.0; 981 | m[0] = s; m[2] = -vx*s+x+px; 982 | m[4] = s; m[5] = -vy*s+y+py; 983 | } 984 | 985 | s2p__matmul(s2p__mats[s2p__mati],m,s2p__mats[s2p__mati]); 986 | s2p__get_transf(fd,attrs,n_attr,s2p__mats[s2p__mati]); 987 | 988 | }else if (closing == S2P_TAG_CLOSE){ 989 | s2p__mati--; 990 | } 991 | 992 | }else if (!strcmp(tagbuf,"g")){ 993 | 994 | if (closing == S2P_TAG_OPEN){ 995 | s2p__mati ++; 996 | memcpy(s2p__mats+s2p__mati,s2p__mats+(s2p__mati-1),9*sizeof(float)); 997 | s2p__get_transf(fd,attrs,n_attr,s2p__mats[s2p__mati]); 998 | 999 | if (s2p_skip_nostroke){ 1000 | stroke_stack <<= 1; 1001 | stroke_stack |= s2p__get_stroke(fd,attrs,n_attr); 1002 | } 1003 | 1004 | }else if (closing == S2P_TAG_CLOSE){ 1005 | s2p__mati--; 1006 | stroke_stack >>= 1; 1007 | } 1008 | }else if (closing != S2P_TAG_CLOSE){ 1009 | 1010 | if (s2p_skip_nostroke){ 1011 | if (!stroke_stack && !s2p__get_stroke(fd,attrs,n_attr)){ 1012 | goto lbl_done_tag; 1013 | } 1014 | } 1015 | 1016 | s2p__mati ++; 1017 | memcpy(s2p__mats+s2p__mati,s2p__mats+(s2p__mati-1),9*sizeof(float)); 1018 | s2p__get_transf(fd,attrs,n_attr,s2p__mats[s2p__mati]); 1019 | 1020 | if (!strcmp(tagbuf,"line")){ 1021 | 1022 | s2p__parse_line(fd,attrs,n_attr); 1023 | 1024 | }else if (!strncmp(tagbuf,"poly",4)){ 1025 | 1026 | s2p__parse_poly(fd,attrs,n_attr,tagbuf[4]=='g'); 1027 | 1028 | }else if (!strcmp(tagbuf,"path")){ 1029 | 1030 | s2p__parse_path(fd,attrs,n_attr); 1031 | 1032 | }else if (!strcmp(tagbuf,"rect")){ 1033 | 1034 | s2p__parse_rect(fd,attrs,n_attr); 1035 | 1036 | }else if (!strcmp(tagbuf,"ellipse") || !strcmp(tagbuf,"circle")){ 1037 | 1038 | s2p__parse_ellipse(fd,attrs,n_attr); 1039 | 1040 | } 1041 | s2p__mati --; 1042 | 1043 | } 1044 | lbl_done_tag:; 1045 | 1046 | fseek(fd,pos,SEEK_SET); 1047 | 1048 | lbl_reset:; 1049 | tag_len = 0; 1050 | tag = 0; 1051 | n_attr = 0; 1052 | memset(attrs,0,sizeof(attrs)); 1053 | state = S2P__ST_OUT; 1054 | closing = 0; 1055 | } 1056 | } 1057 | 1058 | void s2p_parse_from_file(char* path){ 1059 | FILE* fd = fopen(path,"r"); 1060 | s2p_parse(fd); 1061 | fclose(fd); 1062 | } 1063 | 1064 | void s2p_parse_from_str(char* s, int n){ 1065 | if (n == -1) n = strlen(s); 1066 | FILE* fd = fmemopen(s,n,"r"); 1067 | s2p_parse(fd); 1068 | fclose(fd); 1069 | } 1070 | 1071 | #endif 1072 | --------------------------------------------------------------------------------