libcm is a C development framework with an emphasis on audio signal processing applications.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

cmSvgWriter.c 7.0KB

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