Browse Source

Gmt module: Functions Map, Convert2PNG and Convert2JPEG now using new parameter reading scheme and error reporting.

gmtdatadir
Michael Uleysky 8 years ago
parent
commit
4709ebe1fb
  1. 319
      modules/gmt/modgmt_map.cpp
  2. 23
      modules/gmt/modgmt_map.h

319
modules/gmt/modgmt_map.cpp

@ -61,13 +61,9 @@ Resulted shift is added to own shift of layer (setted by function LayerShift).
*/
const ObjectBase* GMT_Map(const ObjectList* input)
{
const ObjectList* list=input;
auto size=list->Size();
if(0==size) return 0;
decltype(size) pos=0;
std::string err;
std::string title;
std::stack<std::pair<const ObjectList*,decltype(pos)> > lstack;
bool first=true;
double xg,yg,x,y;
bool xislocal=false, yislocal=false;
std::list<std::shared_ptr<std::string> > data;
@ -78,45 +74,29 @@ const ObjectBase* GMT_Map(const ObjectList* input)
// See http://bugs.ghostscript.com/show_bug.cgi?id=202735
data.emplace_back(new std::string("4000 4000 translate"));
data.emplace_back(new std::string(header));
while(pos<size)
{
// Check if next argument is list
for(auto i=input->begin(); i!=input->end(); ++i)
{
OBType<ObjectList> l(list->At(pos));
// Descending
if(l)
{
if(0==l->Size()) goto next;
lstack.push(std::make_pair(list,pos));
list=l;
pos=0;
size=l->Size();
continue;
}
}
// Check if first argument is string
if(first)
if(input->begin()==i)
{
first=false;
OBType<ObjectString> s(list->At(pos));
OBType<ObjectString> s(*i);
if(s)
{
title=s->Value();
goto next;
continue;
}
}
// Check if argument is pair
{
OBType<ObjectPair> p(list->At(pos));
OBType<ObjectPair> p(*i);
if(p)
{
std::string name=p->Name();
tolower(name);
Base2Double d(p->Value());
Base2Double d;
bool suc=true;
double val=d(&suc);
double val=d.Convert(p->Value(),&suc,err);
if(!suc) goto fail; // Conversion failed
suc=false;
if("x"==name) {suc=true; xislocal=true; x=val;}
@ -127,14 +107,14 @@ const ObjectBase* GMT_Map(const ObjectList* input)
if("yg"==name) {suc=true; yg=val;}
if("xgr"==name) {suc=true; xg+=val;}
if("ygr"==name) {suc=true; yg+=val;}
if(!suc) goto fail; // Unknown name
goto next;
if(!suc) {err="Unknown parameter name: "+p->Name(); goto fail;} // Unknown name
continue;
}
}
// Check if argument is layer
{
OBType<ObjectGMTLayer> l(list->At(pos));
OBType<ObjectGMTLayer> l(*i);
if(l)
{
struct gmt_layer layer=l->Data();
@ -148,22 +128,11 @@ const ObjectBase* GMT_Map(const ObjectList* input)
data.emplace_back(new std::string(layer.EndShift()));
}
else data.emplace_back(layer.data);
goto next;
continue;
}
}
err="Unknown argument type: "+i->Type();
goto fail; // Unknown type of argument
next:
pos++;
// Ascending
if(pos==size && !lstack.empty())
{
list=lstack.top().first;
pos=lstack.top().second;
lstack.pop();
size=list->Size();
goto next;
}
}
data.emplace_back(new std::string(footer));
@ -175,7 +144,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
int ret;
ret=GhostRun("-sDEVICE=bbox",gs_bbox_callback,&in,0,&bboxes,0); // Bounding box is writed on stderr
if(0!=ret) goto fail; // Something wrong
if(0!=ret) {err="Can't determine BoundingBox"; goto fail;} // Something wrong
std::smatch m;
std::smatch::const_iterator ci;
@ -183,7 +152,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
bool ok=true;
std::regex_search(bboxes,m,r);
if(5!=m.size()) goto fail; // This is strange and scary
if(5!=m.size()) {err="Something go wrong, this is strange and scary"; goto fail; }// This is strange and scary
ci=m.cbegin();
ci++; // Skip full match
@ -191,7 +160,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
ok=ok && str2int(*ci++,&bbly);
ok=ok && str2int(*ci++,&bbrx);
ok=ok && str2int(*ci++,&bbry);
if(!ok) goto fail; // Unexpected!
if(!ok) {err="Unexpected error!"; goto fail;} // Unexpected!
// FIXME: Workaround ghostscript bug 202735
// We add 5 points to each margin because ghostscript does'nt count linewidths when calculate bounding box
bblx-=4005;
@ -224,7 +193,7 @@ const ObjectBase* GMT_Map(const ObjectList* input)
}
fail:
return 0;
return new ObjectError("Map",err);
}
// Creating pdf from eps
@ -235,39 +204,24 @@ Optionally, resolution can be specified by pair with name resolution, res or r a
*/
const ObjectBase* GMT_Convert2PDF(const ObjectList* input)
{
if(!gs_abilities.havepdf) return 0; // No pdf support
double r;
bool suc=true;
const ObjectGMTMap* map=0;
std::string err;
RNFPar<SearchGMTMap,ObjectGMTMap> map("map");
ONPar<Base2PosD> r("resolution",720);
ParseNamedParameters params(input,map,r);
const ObjectGMTMap* m=map;
{
SearchParameterWDefO<double,DoubleDefaultVal<720>,false,PMin<1> > res(input,"r","res","resolution");
r=res(&suc);
if(!suc) goto fail; // Error
}
{
for(ObjectList::IndexType i=0;i<input->Size();i++)
{
OBType<ObjectGMTMap> m(input->At(i));
if(m)
{
if(0!=map) goto fail; // Duplicate
map=m;
}
}
if(0==map) goto fail; // Map not found
}
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support
if(!params) {err=params.Error(); goto fail;} // Parsing error
{
std::string* out=new std::string;
int ret=eps2pdf(*(map->pValue()),out,r);
if(0!=ret) { delete out; goto fail; } // Something wrong
return new ObjectGMTMapPDF(out,map->Bblx(),map->Bbly(),map->Bbrx(),map->Bbry());
int ret=eps2pdf(*(m->pValue()),out,r);
if(0!=ret) {err="Conversion of EPS to PDF failed"; delete out; goto fail; } // Something wrong
return new ObjectGMTMapPDF(out,m->Bblx(),m->Bbly(),m->Bbrx(),m->Bbry());
}
fail:
return 0;
return new ObjectError("EPS2PDF",err);
}
@ -286,112 +240,101 @@ antialiasing or aa - can be used to set graphics and text antialiasing simultane
*/
const ObjectBase* GMT_Convert2PNG(const ObjectList* input)
{
if(!gs_abilities.havepdf) return 0; // No pdf support, so, no png
double r;
bool suc=true;
const GMTMap* map=0;
std::string gsdev("");
bool ispdf;
uint aat=0,aag=0;
std::string aats("full"),aags("full");
uint dscale=0;
std::string gsdev,err;
double res;
// Map to convert
{
for(ObjectList::IndexType i=0;i<input->Size();i++)
{
OBType<ObjectGMTMap> m(input->At(i));
OBType<ObjectGMTMapPDF> p(input->At(i));
if(m)
ONPar<Base2PosD> r("resolution",300),ds("d[own]scale",1.0);
ONPar<Base2Pos> w("width"),h("height");
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full");
const ObjectGMTMap* me;
const ObjectGMTMapPDF* mp;
const GMTMap* m;
uint aat,aag;
uint dscale;
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no png
// Search map
{
if(0!=map) goto fail; // Duplicate
map=m;
ispdf=false;
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map");
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map");
ParseNamedParameters peps(input,mapeps);
ParseNamedParameters ppdf(input,mappdf);
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;}
me=mapeps; mp=mappdf;
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened
if(nullptr!=me) m=me; else m=mp;
}
if(p)
// Parse other parameters
{
if(0!=map) goto fail; // Duplicate
map=p;
ispdf=true;
}
}
if(0==map) goto fail; // Map not found
ParseNamedParameters params(input,r,ds,w,h,cs,taa,gaa,aa);
if(!params) {err=params.Error(); goto fail;}
}
// Determine resolution
{
SearchParameter<double,false,PMin<1> > res(input,"r","res","resolution");
BaseM2Double w(input,"width","w"), h(input,"height","h");
// Check existence
if( ( res.Exist() && w.Exist() ) || ( res.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) goto fail; // Only one parameter allowed
r=300; // Default value
if(res.Exist()) r=res(&suc);
if(w.Exist()) r=w(&suc)*72.0/(map->Bbrx()-map->Bblx());
if(h.Exist()) r=h(&suc)*72.0/(map->Bbry()-map->Bbly());
if(!suc) goto fail; // Error
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed
if(r.Exist()) res=r;
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx());
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly());
}
// Color model
{
std::string cs;
BaseMD2String cspace(input,"8bit","colorspace","cspace","cs");
cs=cspace(&suc);
if(!suc) goto fail; // Error
tolower(cs);
if(("mono"==cs || "monochrome"==cs) && gs_abilities.havepngmono) gsdev="pngmono";
if(("monod"==cs || "monodiffused"==cs) && gs_abilities.havepngmonod) gsdev="pngmonod";
if(("16c"==cs || "16"==cs) && gs_abilities.havepng16) gsdev="png16";
if(("256c"==cs || "256"==cs) && gs_abilities.havepng256) gsdev="png256";
if(("gray"==cs || "grey"==cs || "g"==cs) && gs_abilities.havepnggray) gsdev="pnggray";
if(("full"==cs || "8bit"==cs || "color"==cs) && gs_abilities.havepng16m) gsdev="png16m";
if(""==gsdev) goto fail; // Incorrect value
std::string cspace=cs;
tolower(cspace);
if(("mono" ==cspace || "monochrome" ==cspace ) && gs_abilities.havepngmono) gsdev="pngmono";
if(("monod"==cspace || "monodiffused"==cspace ) && gs_abilities.havepngmonod) gsdev="pngmonod";
if(("16c" ==cspace || "16" ==cspace ) && gs_abilities.havepng16) gsdev="png16";
if(("256c" ==cspace || "256" ==cspace ) && gs_abilities.havepng256) gsdev="png256";
if(("gray" ==cspace || "grey" ==cspace || "g" ==cspace) && gs_abilities.havepnggray) gsdev="pnggray";
if(("full" ==cspace || "8bit" ==cspace || "color"==cspace) && gs_abilities.havepng16m) gsdev="png16m";
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value
}
// Antialiasing
{
BaseM2String aa(input,"antialiasing","aa"),taa(input,"textantialiasing","taa"),gaa(input,"graphicsantialiasing","gaa");
if(aa.Exist()) aags=aats=aa(&suc);
if(taa.Exist()) aats=taa(&suc);
if(gaa.Exist()) aags=gaa(&suc);
if(!suc) goto fail; // Error
std::string aags=aa,aats=aa;
if(taa.Exist()) aats=taa;
if(gaa.Exist()) aags=gaa;
tolower(aags); tolower(aats);
if("none" ==aags || "no"==aags || "n"==aags) aag=1; if("none" ==aats || "no"==aats || "n"==aats) aat=1;
if("small"==aags || "s" ==aags ) aag=2; if("small"==aats || "s" ==aats ) aat=2;
if("full" ==aags || "f" ==aags ) aag=4; if("full" ==aats || "f" ==aats ) aat=4;
if(0==aat || 0==aag) goto fail; // Incorrect value
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;}
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;}
}
// Downscale
if("pngmonod"==gsdev || "pnggray"==gsdev || "png16m"==gsdev)
{
SearchParameterWDefO<double,DoubleDefaultVal<1>,false,PMin<1>,PMax<10>,PInt > ds(input,"downscale","dscale","ds");
dscale=static_cast<uint>(ds(&suc));
if(!suc) goto fail; // Error
r*=dscale;
dscale=static_cast<uint>(ds);
if(dscale<1 || dscale>10) {err="Downscale must be in interval from 1 to 10"; goto fail;}
res*=dscale;
}
// Go!
{
std::string* pdf=0;
int ret;
if(!ispdf)
if(nullptr!=me)
{
pdf=new std::string;
ret=eps2pdf(*(map->pValue()),pdf,r,aat,aag);
if(0!=ret) { delete pdf; goto fail; } // Something wrong
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag);
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong
}
{
std::string* out=new std::string;
ret=GhostRun("-r"+ToString(r)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+((dscale>1)?(" -dDownScaleFactor="+ToString(dscale)):""),((0!=pdf)?*pdf:*(map->pValue())),0,0,out);
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+((dscale>1)?(" -dDownScaleFactor="+ToString(dscale)):""),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out);
if(0!=pdf) delete pdf;
if(0!=ret) { delete out; goto fail; } // Something wrong
if(0!=ret) {err="Can't convert PDF to PNG"; delete out; goto fail; } // Something wrong
return new ObjectGMTImage(out);
}
}
fail:
return 0;
return new ObjectError("EPS2PNG",err);
}
@ -410,104 +353,94 @@ antialiasing or aa - can be used to set graphics and text antialiasing simultane
*/
const ObjectBase* GMT_Convert2JPG(const ObjectList* input)
{
if(!gs_abilities.havepdf) return 0; // No pdf support, so, no jpeg
double r;
bool suc=true;
const GMTMap* map=0;
std::string gsdev("");
bool ispdf;
uint aat=0,aag=0;
std::string aats("full"),aags("full");
std::string gsdev,err;
ONPar<Base2PosD> r("resolution",300);
ONPar<Base2Pos> w("width"),h("height");
ONPar<Base2StringD> cs("c[olor][ ]space","color"),taa("t[ext]a[nti]aliasing","full"),gaa("g[raphics]a[nti]aliasing","full"),aa("a[nti]aliasing","full");
ONPar<Base2NonNegD> q("quality",75);
const ObjectGMTMap* me;
const ObjectGMTMapPDF* mp;
const GMTMap* m;
double res;
uint aat,aag;
uint qual;
// Map to convert
{
for(ObjectList::IndexType i=0;i<input->Size();i++)
if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no jpeg
// Search map
{
OBType<ObjectGMTMap> m(input->At(i));
OBType<ObjectGMTMapPDF> p(input->At(i));
if(m)
{
if(0!=map) goto fail; // Duplicate
map=m;
ispdf=false;
RNFPar<SearchGMTMap,ObjectGMTMap> mapeps("map");
RNFPar<SearchGMTMapPDF,ObjectGMTMap> mappdf("map");
ParseNamedParameters peps(input,mapeps);
ParseNamedParameters ppdf(input,mappdf);
if(!(peps || ppdf)) {err="Error parsing map parameter"; goto fail;}
me=mapeps; mp=mappdf;
if(nullptr==me && nullptr==mp) {err="Map parameter not specified"; goto fail;} // This must never happened
if(nullptr!=me) m=me; else m=mp;
}
if(p)
// Parse other parameters
{
if(0!=map) goto fail; // Duplicate
map=p;
ispdf=true;
}
}
if(0==map) goto fail; // Map not found
ParseNamedParameters params(input,r,q,w,h,cs,taa,gaa,aa);
if(!params) {err=params.Error(); goto fail;}
}
// Determine resolution
{
SearchParameter<double,false,PMin<1> > res(input,"r","res","resolution");
BaseM2Double w(input,"width","w"), h(input,"height","h");
// Check existence
if( ( res.Exist() && w.Exist() ) || ( res.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) goto fail; // Only one parameter allowed
r=300; // Default value
if(res.Exist()) r=res(&suc);
if(w.Exist()) r=w(&suc)*72.0/(map->Bbrx()-map->Bblx());
if(h.Exist()) r=h(&suc)*72.0/(map->Bbry()-map->Bbly());
if(!suc) goto fail; // Error
if( ( r.Exist() && w.Exist() ) || ( r.Exist() && h.Exist() ) || ( w.Exist() && h.Exist() )) {err="Only one of resolution, width or height may be specified"; goto fail;} // Only one parameter allowed
if(r.Exist()) res=r;
if(w.Exist()) res=w*72.0/(m->Bbrx()-m->Bblx());
if(h.Exist()) res=h*72.0/(m->Bbry()-m->Bbly());
}
// Color model
{
std::string cs;
BaseMD2String cspace(input,"8bit","colorspace","cspace","cs");
cs=cspace(&suc);
if(!suc) goto fail; // Error
tolower(cs);
if(("gray"==cs || "grey"==cs || "g"==cs) && gs_abilities.havejpeggray) gsdev="jpeggray";
if(("full"==cs || "8bit"==cs || "color"==cs) && gs_abilities.havejpeg) gsdev="jpeg";
if(""==gsdev) goto fail; // Incorrect value
std::string cspace=cs;
tolower(cspace);
if(("gray"==cspace || "grey"==cspace || "g" ==cspace) && gs_abilities.havejpeggray) gsdev="jpeggray";
if(("full"==cspace || "8bit"==cspace || "color"==cspace) && gs_abilities.havejpeg) gsdev="jpeg";
if(gsdev.empty()) {err="Colorspace "+cs.Value()+" is bad or unsupported"; goto fail;} // Incorrect value
}
// Antialiasing
{
BaseM2String aa(input,"antialiasing","aa"),taa(input,"textantialiasing","taa"),gaa(input,"graphicsantialiasing","gaa");
if(aa.Exist()) aags=aats=aa(&suc);
if(taa.Exist()) aats=taa(&suc);
if(gaa.Exist()) aags=gaa(&suc);
if(!suc) goto fail; // Error
std::string aags=aa,aats=aa;
if(taa.Exist()) aats=taa;
if(gaa.Exist()) aags=gaa;
tolower(aags); tolower(aats);
if("none" ==aags || "no"==aags || "n"==aags) aag=1; if("none" ==aats || "no"==aats || "n"==aats) aat=1;
if("small"==aags || "s" ==aags ) aag=2; if("small"==aats || "s" ==aats ) aat=2;
if("full" ==aags || "f" ==aags ) aag=4; if("full" ==aats || "f" ==aats ) aat=4;
if(0==aat || 0==aag) goto fail; // Incorrect value
if(0==aat) {err="Incorrect value for text antialiasing: "+aats; goto fail;}
if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;}
}
// Quality
{
SearchParameterWDefO<double,DoubleDefaultVal<75>,false,PMin<0>,PMax<100>,PInt > q(input,"quality","qual","q");
qual=static_cast<uint>(q(&suc));
if(!suc) goto fail; // Error
qual=static_cast<uint>(q);
if(q>100) {err="JPEG quality must not exceed 100"; goto fail;} // Error
}
// Go!
{
std::string* pdf=0;
int ret;
if(!ispdf)
if(nullptr!=me)
{
pdf=new std::string;
ret=eps2pdf(*(map->pValue()),pdf,r,aat,aag);
if(0!=ret) { delete pdf; goto fail; } // Something wrong
ret=eps2pdf(*(me->pValue()),pdf,r,aat,aag);
if(0!=ret) {err="Can't convert EPS to PDF"; delete pdf; goto fail; } // Something wrong
}
{
std::string* out=new std::string;
ret=GhostRun("-r"+ToString(r)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+" -dJPEGQ="+ToString(qual),((0!=pdf)?*pdf:*(map->pValue())),0,0,out);
ret=GhostRun("-r"+ToString(res)+" -dTextAlphaBits="+ToString(aat)+" -dGraphicAlphaBits="+ToString(aag)+" -sDEVICE="+gsdev+" -dJPEGQ="+ToString(qual),((0!=pdf)?*pdf:*(mp->pValue())),0,0,out);
if(0!=pdf) delete pdf;
if(0!=ret) { delete out; goto fail; } // Something wrong
if(0!=ret) {err="Can't convert PDF to JPEG"; delete out; goto fail; } // Something wrong
return new ObjectGMTImage(out);
}
}
fail:
return 0;
return new ObjectError("EPS2JPEG",err);
}

23
modules/gmt/modgmt_map.h

@ -72,12 +72,29 @@ class ObjectGMTImage: public GMTBlob
std::string Type() const override {return "GMTImage";}
};
// Policy for get integer value
class PInt
// Convertor to search object
template<class Object>
class SearchObject
{
public:
double operator()(double v, bool* suc) const {if(v!=floor(v)) *suc=false; return v;}
using ValueType=const Object*;
template<class... Args>
ValueType Convert(const ObjectBase* ob, bool* res, std::string& err, Args... args)
{
OBType<Object> gp(ob);
switch(gp.Error())
{
case(OBTypeErr::OK): return gp;
case(OBTypeErr::NULLPTR): {err="Can't convert zero ObjectBase pointer to something meaningfull"; break;}
case(OBTypeErr::TYPEMISMATCH): {err=ob->Type()+" is not correct: type mismatch"; break;}
}
*res=false;
return nullptr;
}
};
// Convertor to search GMTMap objects
using SearchGMTMap=SearchObject<ObjectGMTMap>;
using SearchGMTMapPDF=SearchObject<ObjectGMTMapPDF>;
// Creating eps map from set of layers
const ObjectBase* GMT_Map(const ObjectList* input);

Loading…
Cancel
Save