libcm is a C development framework with an emphasis on audio signal processing applications.
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.

cmSvgWriter.c 5.9KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254
  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. _cmSvgSize(p, &svgWidth, &svgHeight );
  160. _cmSvgWriterFlipY( p, svgHeight );
  161. if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
  162. return cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn));
  163. if( cmFilePrintf(fH,"<!DOCTYPE html>\n<html>\n<head><link rel=\"stylesheet\" type=\"text/css\" href=\"%s\"></head><body>\n<svg width=\"%f\" height=\"%f\">\n",svgWidth,svgHeight,cssFn) != kOkFileRC )
  164. {
  165. rc = cmErrMsg(&p->err,kFileFailSvgRC,"File prefix write failed.");
  166. goto errLabel;
  167. }
  168. for(; e!=NULL; e=e->link)
  169. {
  170. switch( e->id )
  171. {
  172. case kRectSvgId:
  173. if( cmFilePrintf(fH,"<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) != kOkFileRC )
  174. rc = kFileFailSvgRC;
  175. break;
  176. case kLineSvgId:
  177. if( cmFilePrintf(fH,"<line x1=\"%f\" y1=\"%f\" x2=\"%f\" y2=\"%f\" class=\"%s\"/>\n",e->x0,e->y0,e->x1,e->y1,e->cssClass) != kOkFileRC )
  178. rc = kFileFailSvgRC;
  179. break;
  180. case kTextSvgId:
  181. if( cmFilePrintf(fH,"<text x=\"%f\" y=\"%f\" class=\"%s\">%s</text>\n",e->x0,e->y0,e->cssClass,e->text) != kOkFileRC )
  182. rc = kFileFailSvgRC;
  183. break;
  184. default:
  185. { assert(0); }
  186. }
  187. if( rc != kOkSvgRC )
  188. {
  189. rc = cmErrMsg(&p->err,kFileFailSvgRC,"Element write failed.");
  190. break;
  191. }
  192. }
  193. if( cmFilePrint(fH,"</svg>\n</body>\n</html>\n") != kOkFileRC )
  194. {
  195. rc = cmErrMsg(&p->err,kFileFailSvgRC,"File suffix write failed.");
  196. goto errLabel;
  197. }
  198. errLabel:
  199. cmFileClose(&fH);
  200. return rc;
  201. }