235 lines
5.6 KiB
C
235 lines
5.6 KiB
C
#include "cmPrefix.h"
|
|
#include "cmGlobal.h"
|
|
#include "cmFloatTypes.h"
|
|
#include "cmRpt.h"
|
|
#include "cmErr.h"
|
|
#include "cmCtx.h"
|
|
#include "cmMem.h"
|
|
#include "cmMallocDebug.h"
|
|
#include "cmLinkedHeap.h"
|
|
#include "cmTime.h"
|
|
#include "cmText.h"
|
|
#include "cmFile.h"
|
|
#include "cmSvgWriter.h"
|
|
|
|
enum
|
|
{
|
|
kRectSvgId,
|
|
kLineSvgId,
|
|
kTextSvgId
|
|
};
|
|
|
|
typedef struct cmSvgEle_str
|
|
{
|
|
unsigned id;
|
|
double x0;
|
|
double y0;
|
|
double x1;
|
|
double y1;
|
|
cmChar_t* text;
|
|
cmChar_t* cssClass;
|
|
struct cmSvgEle_str* link;
|
|
} cmSvgEle_t;
|
|
|
|
typedef struct cmSvg_str
|
|
{
|
|
cmErr_t err;
|
|
cmLHeapH_t lhH;
|
|
cmSvgEle_t* elist;
|
|
cmSvgEle_t* eol;
|
|
} cmSvg_t;
|
|
|
|
cmSvgH_t cmSvgNullHandle = cmSTATIC_NULL_HANDLE;
|
|
|
|
cmSvg_t* _cmSvgHandleToPtr( cmSvgH_t h )
|
|
{
|
|
cmSvg_t* p = (cmSvg_t*)h.h;
|
|
assert(p != NULL );
|
|
return p;
|
|
}
|
|
|
|
cmSvgRC_t _cmSvgInsertEle( cmSvg_t* p, unsigned id, double x0, double y0, double x1, double y1, const cmChar_t* text, const cmChar_t* class )
|
|
{
|
|
cmSvgEle_t* e = cmLhAllocZ(p->lhH,cmSvgEle_t,1);
|
|
|
|
e->id = id;
|
|
e->x0 = x0;
|
|
e->y0 = y0;
|
|
e->x1 = x1;
|
|
e->y1 = y1;
|
|
e->text = text==NULL ? "" : cmLhAllocStr(p->lhH,text);
|
|
e->cssClass = cmLhAllocStr(p->lhH,class);
|
|
|
|
if( p->eol == NULL )
|
|
p->elist = p->eol = e;
|
|
else
|
|
p->eol->link = e;
|
|
|
|
p->eol = e;
|
|
|
|
return kOkSvgRC;
|
|
}
|
|
|
|
cmSvgRC_t _cmSvgWriterFree( cmSvg_t* p )
|
|
{
|
|
cmLHeapDestroy(&p->lhH);
|
|
cmMemFree(p);
|
|
return kOkSvgRC;
|
|
}
|
|
|
|
cmSvgRC_t cmSvgWriterAlloc( cmCtx_t* ctx, cmSvgH_t* hp )
|
|
{
|
|
cmSvgRC_t rc;
|
|
if((rc = cmSvgWriterFree(hp)) != kOkSvgRC )
|
|
return rc;
|
|
|
|
cmSvg_t* p = cmMemAllocZ(cmSvg_t,1);
|
|
|
|
cmErrSetup(&p->err,&ctx->rpt,"SVG Writer");
|
|
|
|
// create a local linked heap
|
|
if( cmLHeapIsValid( p->lhH = cmLHeapCreate(8196,ctx)) == false )
|
|
{
|
|
rc = cmErrMsg(&p->err,kLHeapFailSvgRC,"Lheap create failed.");
|
|
goto errLabel;
|
|
}
|
|
|
|
hp->h = p;
|
|
|
|
errLabel:
|
|
if( rc != kOkSvgRC )
|
|
_cmSvgWriterFree(p);
|
|
|
|
return rc;
|
|
}
|
|
|
|
cmSvgRC_t cmSvgWriterFree( cmSvgH_t* hp )
|
|
{
|
|
cmSvgRC_t rc = kOkSvgRC;
|
|
|
|
if( hp==NULL || cmSvgWriterIsValid(*hp)==false )
|
|
return kOkSvgRC;
|
|
|
|
cmSvg_t* p = _cmSvgHandleToPtr(*hp);
|
|
|
|
if((rc = _cmSvgWriterFree(p)) != kOkSvgRC )
|
|
return rc;
|
|
|
|
hp->h = NULL;
|
|
|
|
return rc;
|
|
}
|
|
|
|
bool cmSvgWriterIsValid( cmSvgH_t h )
|
|
{ return h.h != NULL; }
|
|
|
|
cmSvgRC_t cmSvgWriterRect( cmSvgH_t h, double x, double y, double ww, double hh, const cmChar_t* cssClassLabel )
|
|
{
|
|
cmSvg_t* p = _cmSvgHandleToPtr(h);
|
|
return _cmSvgInsertEle( p, kRectSvgId, x, y, x+ww, y+hh, NULL, cssClassLabel==NULL?"rectclass":cssClassLabel );
|
|
}
|
|
|
|
cmSvgRC_t cmSvgWriterLine( cmSvgH_t h, double x0, double y0, double x1, double y1, const cmChar_t* cssClassLabel )
|
|
{
|
|
cmSvg_t* p = _cmSvgHandleToPtr(h);
|
|
return _cmSvgInsertEle( p, kLineSvgId, x0, y0, x1, y1, NULL, cssClassLabel==NULL?"lineclass":cssClassLabel );
|
|
}
|
|
|
|
cmSvgRC_t cmSvgWriterText( cmSvgH_t h, double x, double y, const cmChar_t* text, const cmChar_t* cssClassLabel )
|
|
{
|
|
cmSvg_t* p = _cmSvgHandleToPtr(h);
|
|
return _cmSvgInsertEle( p, kTextSvgId, x, y, 0, 0, text==NULL?"":text, cssClassLabel==NULL?"textclass":cssClassLabel );
|
|
}
|
|
|
|
void _cmSvgSize( cmSvg_t* p, double* widthRef, double* heightRef )
|
|
{
|
|
*widthRef = 0;
|
|
*heightRef = 0;
|
|
|
|
if( p->elist == NULL )
|
|
return;
|
|
|
|
cmSvgEle_t* e = p->elist;
|
|
double min_x = cmMin(e->x0,e->x1);
|
|
double max_x = cmMax(e->x0,e->x1);
|
|
double min_y = cmMin(e->y0,e->y1);
|
|
double max_y = cmMax(e->y0,e->y1);
|
|
|
|
for(e=e->link; e!=NULL; e=e->link)
|
|
{
|
|
min_x = cmMin(cmMin(min_x,e->x0),e->x1);
|
|
max_x = cmMax(cmMax(max_x,e->x0),e->x1);
|
|
min_y = cmMin(cmMin(min_y,e->y0),e->y1);
|
|
max_y = cmMax(cmMax(max_y,e->y0),e->y1);
|
|
}
|
|
|
|
*widthRef = max_x - min_x;
|
|
*heightRef = max_y - min_y;
|
|
}
|
|
|
|
|
|
cmSvgRC_t cmSvgWriterWrite( cmSvgH_t h, const cmChar_t* cssFn, const cmChar_t* outFn )
|
|
{
|
|
cmSvgRC_t rc = kOkSvgRC;
|
|
cmSvg_t* p = _cmSvgHandleToPtr(h);
|
|
double svgWidth = 0;
|
|
double svgHeight = 0;
|
|
cmSvgEle_t* e = p->elist;
|
|
cmFileH_t fH = cmFileNullHandle;
|
|
|
|
_cmSvgSize(p, &svgWidth, &svgHeight );
|
|
|
|
if( cmFileOpen(&fH,outFn,kWriteFileFl,p->err.rpt) != kOkFileRC )
|
|
return cmErrMsg(&p->err,kFileFailSvgRC,"SVG file create failed for '%s'.",cmStringNullGuard(outFn));
|
|
|
|
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 )
|
|
{
|
|
rc = cmErrMsg(&p->err,kFileFailSvgRC,"File prefix write failed.");
|
|
goto errLabel;
|
|
}
|
|
|
|
for(; e!=NULL; e=e->link)
|
|
{
|
|
switch( e->id )
|
|
{
|
|
case kRectSvgId:
|
|
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 )
|
|
rc = kFileFailSvgRC;
|
|
break;
|
|
|
|
case kLineSvgId:
|
|
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 )
|
|
rc = kFileFailSvgRC;
|
|
break;
|
|
|
|
case kTextSvgId:
|
|
if( cmFilePrintf(fH,"<text x=\"%f\" y=\"%f\" class=\"%s\">%s</text>\n",e->x0,e->y0,e->cssClass,e->text) != kOkFileRC )
|
|
rc = kFileFailSvgRC;
|
|
break;
|
|
|
|
default:
|
|
{ assert(0); }
|
|
|
|
}
|
|
|
|
if( rc != kOkSvgRC )
|
|
{
|
|
rc = cmErrMsg(&p->err,kFileFailSvgRC,"Element write failed.");
|
|
break;
|
|
}
|
|
}
|
|
|
|
if( cmFilePrint(fH,"</svg>\n</body>\n</html>\n") != kOkFileRC )
|
|
{
|
|
rc = cmErrMsg(&p->err,kFileFailSvgRC,"File suffix write failed.");
|
|
goto errLabel;
|
|
}
|
|
|
|
|
|
errLabel:
|
|
cmFileClose(&fH);
|
|
|
|
return rc;
|
|
}
|
|
|