@@ -939,79 +939,166 @@ void cleanup_path(PathIterator &path,
939
939
}
940
940
}
941
941
942
+ void quad2cubic (double x0, double y0,
943
+ double x1, double y1,
944
+ double x2, double y2,
945
+ double *outx, double *outy)
946
+ {
947
+
948
+ outx[0 ] = x0 + 2 ./3 . * (x1 - x0);
949
+ outy[0 ] = y0 + 2 ./3 . * (y1 - y0 );
950
+ outx[1 ] = outx[0 ] + 1 ./3 . * (x2 - x0);
951
+ outy[1 ] = outy[0 ] + 1 ./3 . * (y2 - y0 );
952
+ outx[2 ] = x2;
953
+ outy[2 ] = y2;
954
+ }
955
+
956
+ char *__append_to_string (char *p, char *buffer, size_t buffersize,
957
+ const char *content)
958
+ {
959
+ int buffersize_int = (int )buffersize;
960
+
961
+ for (const char *i = content; *i; ++i) {
962
+ if (p < buffer || p - buffer >= buffersize_int) {
963
+ return NULL ;
964
+ }
965
+
966
+ *p++ = *i;
967
+ }
968
+
969
+ return p;
970
+ }
971
+
942
972
template <class PathIterator >
943
- void convert_to_svg (PathIterator &path,
944
- agg::trans_affine &trans,
945
- agg::rect_d &clip_rect,
946
- bool simplify,
947
- int precision,
948
- char *buffer,
949
- size_t *buffersize)
973
+ int __convert_to_string (PathIterator &path,
974
+ int precision,
975
+ char **codes,
976
+ bool postfix,
977
+ char *buffer,
978
+ size_t *buffersize)
950
979
{
951
980
#if PY_VERSION_HEX < 0x02070000
952
981
char format[64 ];
953
982
snprintf (format, 64 , " %s.%dg" , " %" , precision);
954
983
#endif
955
984
956
- typedef agg::conv_transform<py::PathIterator> transformed_path_t ;
957
- typedef PathNanRemover<transformed_path_t > nan_removal_t ;
958
- typedef PathClipper<nan_removal_t > clipped_t ;
959
- typedef PathSimplifier<clipped_t > simplify_t ;
960
-
961
- bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2 );
962
-
963
- transformed_path_t tpath (path, trans);
964
- nan_removal_t nan_removed (tpath, true , path.has_curves ());
965
- clipped_t clipped (nan_removed, do_clip, clip_rect);
966
- simplify_t simplified (clipped, simplify, path.simplify_threshold ());
967
-
968
985
char *p = buffer;
986
+ double x[3 ];
987
+ double y[3 ];
988
+ double last_x = 0.0 ;
989
+ double last_y = 0.0 ;
969
990
970
- const char codes[] = { ' M' , ' L' , ' Q' , ' C' };
971
- const int waits[] = { 1 , 1 , 2 , 3 };
972
-
973
- int wait = 0 ;
991
+ const int sizes[] = { 1 , 1 , 2 , 3 };
992
+ int size = 0 ;
974
993
unsigned code;
975
- double x = 0 , y = 0 ;
976
- while ((code = simplified.vertex (&x, &y)) != agg::path_cmd_stop) {
977
- if (wait == 0 ) {
978
- *p++ = ' \n ' ;
979
994
980
- if (code == 0x4f ) {
981
- *p++ = ' z' ;
982
- *p++ = ' \n ' ;
983
- continue ;
995
+ while ((code = path.vertex (&x[0 ], &y[0 ])) != agg::path_cmd_stop) {
996
+ if (code == 0x4f ) {
997
+ if ((p = __append_to_string (p, buffer, *buffersize, codes[4 ])) == NULL ) return 1 ;
998
+ } else if (code < 5 ) {
999
+ size = sizes[code - 1 ];
1000
+
1001
+ for (int i = 1 ; i < size; ++i) {
1002
+ unsigned subcode = path.vertex (&x[i], &y[i]);
1003
+ if (subcode != code) {
1004
+ return 2 ;
1005
+ }
984
1006
}
985
1007
986
- *p++ = codes[code - 1 ];
987
- wait = waits[code - 1 ];
988
- } else {
989
- *p++ = ' ' ;
990
- }
1008
+ /* For formats that don't support quad curves, convert to
1009
+ cubic curves */
1010
+ if (code == CURVE3 && codes[code - 1 ][0 ] == ' \0 ' ) {
1011
+ quad2cubic (last_x, last_y, x[0 ], y[0 ], x[1 ], y[1 ], x, y);
1012
+ code++;
1013
+ size = 3 ;
1014
+ }
991
1015
1016
+ if (!postfix) {
1017
+ if ((p = __append_to_string (p, buffer, *buffersize, codes[code - 1 ])) == NULL ) return 1 ;
1018
+ if ((p = __append_to_string (p, buffer, *buffersize, " " )) == NULL ) return 1 ;
1019
+ }
1020
+
1021
+ for (int i = 0 ; i < size; ++i) {
992
1022
#if PY_VERSION_HEX >= 0x02070000
993
- char *str;
994
- str = PyOS_double_to_string (x, ' g' , precision, 0 , NULL );
995
- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
996
- PyMem_Free (str);
997
- *p++ = ' ' ;
998
- str = PyOS_double_to_string (y, ' g' , precision, 0 , NULL );
999
- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1000
- PyMem_Free (str);
1023
+ char *str;
1024
+ str = PyOS_double_to_string (x[i], ' g' , precision, 0 , NULL );
1025
+ if ((p = __append_to_string (p, buffer, *buffersize, str)) == NULL ) {
1026
+ PyMem_Free (str);
1027
+ return 1 ;
1028
+ }
1029
+ PyMem_Free (str);
1030
+ if ((p = __append_to_string (p, buffer, *buffersize, " " )) == NULL ) return 1 ;
1031
+ str = PyOS_double_to_string (y[i], ' g' , precision, 0 , NULL );
1032
+ if ((p = __append_to_string (p, buffer, *buffersize, str)) == NULL ) {
1033
+ PyMem_Free (str);
1034
+ return 1 ;
1035
+ }
1036
+ PyMem_Free (str);
1037
+ if ((p = __append_to_string (p, buffer, *buffersize, " " )) == NULL ) return 1 ;
1001
1038
#else
1002
- char str[64 ];
1003
- PyOS_ascii_formatd (str, 64 , format, x);
1004
- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1005
- *p++ = ' ' ;
1006
- PyOS_ascii_formatd (str, 64 , format, y);
1007
- p += snprintf (p, *buffersize - (p - buffer), " %s" , str);
1039
+ char str[64 ];
1040
+ PyOS_ascii_formatd (str, 64 , format, x[i]);
1041
+ if ((p = __append_to_string (p, buffer, *buffersize, str)) == NULL ) return 1 ;
1042
+ p = __append_to_string (p, buffer, *buffersize, " " );
1043
+ PyOS_ascii_formatd (str, 64 , format, y[i]);
1044
+ if ((p = __append_to_string (p, buffer, *buffersize, str)) == NULL ) return 1 ;
1045
+ if ((p = __append_to_string (p, buffer, *buffersize, " " )) == NULL ) return 1 ;
1008
1046
#endif
1047
+ }
1048
+
1049
+ if (postfix) {
1050
+ if ((p = __append_to_string (p, buffer, *buffersize, codes[code - 1 ])) == NULL ) return 1 ;
1051
+ }
1052
+
1053
+ last_x = x[size - 1 ];
1054
+ last_y = y[size - 1 ];
1055
+ } else {
1056
+ // Unknown code value
1057
+ return 2 ;
1058
+ }
1009
1059
1010
- -- wait ;
1060
+ if ((p = __append_to_string (p, buffer, *buffersize, " \n " )) == NULL ) return 1 ;
1011
1061
}
1012
1062
1013
- *p = ' \0 ' ;
1014
1063
*buffersize = p - buffer;
1064
+
1065
+ return 0 ;
1066
+ }
1067
+
1068
+ template <class PathIterator >
1069
+ int convert_to_string (PathIterator &path,
1070
+ agg::trans_affine &trans,
1071
+ agg::rect_d &clip_rect,
1072
+ bool simplify,
1073
+ SketchParams sketch_params,
1074
+ int precision,
1075
+ char **codes,
1076
+ bool postfix,
1077
+ char *buffer,
1078
+ size_t *buffersize)
1079
+ {
1080
+ typedef agg::conv_transform<py::PathIterator> transformed_path_t ;
1081
+ typedef PathNanRemover<transformed_path_t > nan_removal_t ;
1082
+ typedef PathClipper<nan_removal_t > clipped_t ;
1083
+ typedef PathSimplifier<clipped_t > simplify_t ;
1084
+ typedef agg::conv_curve<simplify_t > curve_t ;
1085
+ typedef Sketch<curve_t > sketch_t ;
1086
+
1087
+ bool do_clip = (clip_rect.x1 < clip_rect.x2 && clip_rect.y1 < clip_rect.y2 );
1088
+
1089
+ transformed_path_t tpath (path, trans);
1090
+ nan_removal_t nan_removed (tpath, true , path.has_curves ());
1091
+ clipped_t clipped (nan_removed, do_clip, clip_rect);
1092
+ simplify_t simplified (clipped, simplify, path.simplify_threshold ());
1093
+
1094
+ if (sketch_params.scale == 0.0 ) {
1095
+ return __convert_to_string (simplified, precision, codes, postfix, buffer, buffersize);
1096
+ } else {
1097
+ curve_t curve (simplified);
1098
+ sketch_t sketch (curve, sketch_params.scale , sketch_params.length , sketch_params.randomness );
1099
+ return __convert_to_string (sketch, precision, codes, postfix, buffer, buffersize);
1100
+ }
1101
+
1015
1102
}
1016
1103
1017
1104
#endif
0 commit comments