libcm is a C development framework with an emphasis on audio signal processing applications.
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

cmSvgWriter.c 6.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. #include "cmPrefix.h"
  2. #include "cmGlobal.h"
  3. #include "cmFloatTypes.h"
  4. #include "cmRpt.h"
  5. #include "cmErr.h"
  6. #include "cmCtx.h"
  7. #include "cmMem.h"
  8. #include "cmMallocDebug.h"
  9. #include "cmLinkedHeap.h"
  10. #include "cmTime.h"
  11. #include "cmText.h"
  12. #include "cmFile.h"
  13. #include "cmSvgWriter.h"
  14. enum
  15. {
  16. kRectSvgId,
  17. kLineSvgId,
  18. kTextSvgId
  19. };
  20. typedef struct cmSvgEle_str
  21. {
  22. unsigned id;
  23. double x0;
  24. double y0;
  25. double x1;
  26. double y1;
  27. cmChar_t* text;
  28. cmChar_t* cssClass;
  29. struct cmSvgEle_str* link;
  30. } cmSvgEle_t;
  31. typedef struct cmSvg_str
  32. {
  33. cmErr_t err;
  34. cmLHeapH_t lhH;
  35. cmSvgEle_t* elist;
  36. cmSvgEle_t* eol;
  37. } cmSvg_t;
  38. cmSvgH_t cmSvgNullHandle = cmSTATIC_NULL_HANDLE;
  39. cmSvg_t* _cmSvgHandleToPtr( cmSvgH_t h )
  40. {
  41. cmSvg_t* p = (cmSvg_t*)h.h;
  42. assert(p != NULL );
  43. return p;
  44. }
  45. cmSvgRC_t _cmSvgInsertEle( cmSvg_t* p, unsigned id, double x0, double y0, double x1, double y1, const cmChar_t* text, const cmChar_t* class )
  46. {
  47. cmSvgEle_t* e = cmLhAllocZ(p->lhH,cmSvgEle_t,1);
  48. e->id = id;
  49. e->x0 = x0;
  50. e->y0 = y0;
  51. e->x1 = x1;
  52. e->y1 = y1;
  53. e->text = text==NULL ? "" : cmLhAllocStr(p->lhH,text);
  54. e->cssClass = cmLhAllocStr(p->lhH,class);
  55. if( p->eol == NULL )
  56. p->elist = p->eol = e;
  57. else
  58. p->eol->link = e;
  59. p->eol = e;
  60. return kOkSvgRC;
  61. }
  62. cmSvgRC_t _cmSvgWriterFree( cmSvg_t* p )
  63. {
  64. cmLHeapDestroy(&p->lhH);
  65. cmMemFree(p);
  66. return kOkSvgRC;
  67. }
  68. cmSvgRC_t cmSvgWriterAlloc( cmCtx_t* ctx, cmSvgH_t* hp )
  69. {
  70. cmSvgRC_t rc;
  71. if((rc = cmSvgWriterFree(hp)) != kOkSvgRC )
  72. return rc;
  73. cmSvg_t* p = cmMemAllocZ(cmSvg_t,1);
  74. cmErrSetup(&p->err,&ctx->rpt,"SVG Writer");
  75. // create a local linked heap
  76. if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false )
  77. {
  78. rc = cmErrMsg(&p->err,kLHeapFailSvgRC,"Lheap create failed.");
  79. goto errLabel;
  80. }
  81. hp->h = p;
  82. errLabel:
  83. if( rc != kOkSvgRC )
  84. _cmSvgWriterFree(p);
  85. return rc;
  86. }
  87. cmSvgRC_t cmSvgWriterFree( cmSvgH_t* hp )
  88. {
  89. cmSvgRC_t rc = kOkSvgRC;
  90. if( hp==NULL || cmSvgWriterIsValid(*hp)==false )
  91. return kOkSvgRC;
  92. cmSvg_t* p = _cmSvgHandleToPtr(*hp);
  93. if((rc = _cmSvgWriterFree(p)) != kOkSvgRC )
  94. return rc;
  95. hp->h = NULL;
  96. return rc;
  97. }
  98. bool cmSvgWriterIsValid( cmSvgH_t h )
  99. { return h.h != NULL; }
  100. cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double x, double y, double ww, double hh, const cmChar_t* cssClassLabel )
  101. {
  102. cmSvg_t* p = _cmSvgHandleToPtr(h);
  103. return _cmSvgInsertEle( p, kRectSvgId, x, y, x+ww, y+hh, NULL, cssClassLabel==NULL?"rectclass":cssClassLabel );
  104. }
  105. cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel )
  106. {
  107. cmSvg_t* p = _cmSvgHandleToPtr(h);
  108. return _cmSvgInsertEle( p, kLineSvgId, x0, y0, x1, y1, NULL, cssClassLabel==NULL?"lineclass":cssClassLabel );
  109. }
  110. cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double x, double y, const cmChar_t* text, const cmChar_t* cssClassLabel )
  111. {
  112. cmSvg_t* p = _cmSvgHandleToPtr(h);
  113. return _cmSvgInsertEle( p, kTextSvgId, x, y, 0, 0, text==NULL?"":text, cssClassLabel==NULL?"textclass":cssClassLabel );
  114. }
  115. void _cmSvgSize( cmSvg_t* p, double* widthRef, double* heightRef )
  116. {
  117. *widthRef = 0;
  118. *heightRef = 0;
  119. if( p->elist == NULL )
  120. return;
  121. cmSvgEle_t* e = p->elist;
  122. double min_x = cmMin(e->x0,e->x1);
  123. double max_x = cmMax(e->x0,e->x1);
  124. double min_y = cmMin(e->y0,e->y1);
  125. double max_y = cmMax(e->y0,e->y1);
  126. for(e=e->link; e!=NULL; e=e->link)
  127. {
  128. min_x = cmMin(cmMin(min_x,e->x0),e->x1);
  129. max_x = cmMax(cmMax(max_x,e->x0),e->x1);
  130. min_y = cmMin(cmMin(min_y,e->y0),e->y1);
  131. max_y = cmMax(cmMax(max_y,e->y0),e->y1);
  132. }
  133. *widthRef = max_x - min_x;
  134. *heightRef = max_y - min_y;
  135. }
  136. void _cmSvgWriterFlipY( cmSvg_t* p, unsigned height )
  137. {
  138. cmSvgEle_t* e = p->elist;
  139. for(; e!=NULL; e=e->link)
  140. {
  141. e->y0 = (-e->y0) + height;
  142. e->y1 = (-e->y1) + height;
  143. if( e->id == kRectSvgId )
  144. {
  145. double t = e->y1;
  146. e->y1 = e->y0;
  147. e->y0 = t;
  148. }
  149. }
  150. }
  151. cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn )
  152. {
  153. cmSvgRC_t rc = kOkSvgRC;
  154. cmSvg_t* p = _cmSvgHandleToPtr(h);
  155. double svgWidth = 0;
  156. double svgHeight = 0;
  157. cmSvgEle_t* e = p->elist;
  158. cmFileH_t fH = cmFileNullHandle;
  159. cmChar_t* s0 = NULL;
  160. cmChar_t* s1 = NULL;
  161. cmChar_t hdr[] =
  162. "<!DOCTYPE html>\n"
  163. "<html>\n"
  164. "<head>\n"
  165. "<meta charset=\"utf-8\">\n"
  166. "<link rel=\"stylesheet\" type=\"text/css\" href=\"%s\">\n"
  167. "<script type=\"text/javascript\" src=\"svg-pan-zoom.min.js\"></script>\n"
  168. "<script>\n"
  169. " var panZoom = null;\n"
  170. " function doOnLoad() { panZoom = svgPanZoom(document.querySelector('#mysvg'), { controlIconsEnabled:true } ) }\n"
  171. "</script>\n"
  172. "</head>\n"
  173. "<body onload=\"doOnLoad()\">\n"
  174. "<svg id=\"mysvg\" width=\"%f\" height=\"%f\">\n";
  175. _cmSvgSize(p, &svgWidth, &svgHeight );
  176. _cmSvgWriterFlipY( p, svgHeight );
  177. // print the file header
  178. if( (s0 = cmTsPrintfP(s0,hdr,cssFn,svgWidth,svgHeight)) == NULL )
  179. {
  180. rc = cmErrMsg(&p->err,kPrintFailSvgRC,"File prefix write failed.");
  181. goto errLabel;
  182. }
  183. for(; e!=NULL; e=e->link)
  184. {
  185. switch( e->id )
  186. {
  187. case kRectSvgId:
  188. if( (s1 = cmTsPrintfP(s1,"<rect x=\"%f\" y=\"%f\" width=\"%f\" height=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1-e->x0,e->y1-e->y0,e->cssClass)) == NULL )
  189. rc = kPrintFailSvgRC;
  190. break;
  191. case kLineSvgId:
  192. if( (s1 = cmTsPrintfP(s1,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1,e->y1,e->cssClass)) == NULL )
  193. rc = kPrintFailSvgRC;
  194. break;
  195. case kTextSvgId:
  196. if( (s1 = cmTsPrintfP(s1,"<text x=\"%f\" y=\"%f\" class=\"%s\">%s</text>\n",e->x0,e->y0,e->cssClass,e->text)) == NULL )
  197. rc = kPrintFailSvgRC;
  198. break;
  199. default:
  200. { assert(0); }
  201. }
  202. if( rc != kOkSvgRC )
  203. {
  204. rc = cmErrMsg(&p->err,kPrintFailSvgRC,"Element write failed.");
  205. break;
  206. }
  207. s0 = cmTextAppendSS(s0,s1);
  208. }
  209. if( (s1 = cmTsPrintfP(s1,"</svg>\n</body>\n</html>\n")) == NULL )
  210. {
  211. rc = cmErrMsg(&p->err,kPrintFailSvgRC,"File suffix write failed.");
  212. goto errLabel;
  213. }
  214. if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
  215. {
  216. rc = cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn));
  217. goto errLabel;
  218. }
  219. if( cmFilePrint(fH,s0 = cmTextAppendSS(s0,s1)) != kOkFileRC )
  220. {
  221. rc = cmErrMsg(&p->err,kFileFailSvgRC,"File write failed.");
  222. goto errLabel;
  223. }
  224. errLabel:
  225. cmFileClose(&fH);
  226. cmMemFree(s0);
  227. cmMemFree(s1);
  228. return rc;
  229. }