diff --git a/modules/gmt/modgmt_map.cpp b/modules/gmt/modgmt_map.cpp index c0f71c4..d35f064 100644 --- a/modules/gmt/modgmt_map.cpp +++ b/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 > lstack; - bool first=true; + double xg,yg,x,y; bool xislocal=false, yislocal=false; std::list > 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(posbegin(); i!=input->end(); ++i) { - // Check if next argument is list - { - OBType 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 s(list->At(pos)); + OBType s(*i); if(s) { title=s->Value(); - goto next; + continue; } } // Check if argument is pair { - OBType p(list->At(pos)); + OBType 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 l(list->At(pos)); + OBType 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 map("map"); + ONPar r("resolution",720); + ParseNamedParameters params(input,map,r); + const ObjectGMTMap* m=map; - { - SearchParameterWDefO,false,PMin<1> > res(input,"r","res","resolution"); - r=res(&suc); - if(!suc) goto fail; // Error - } - - { - for(ObjectList::IndexType i=0;iSize();i++) - { - OBType 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; - - // Map to convert + std::string gsdev,err; + double res; + + ONPar r("resolution",300),ds("d[own]scale",1.0); + ONPar w("width"),h("height"); + ONPar 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 { - for(ObjectList::IndexType i=0;iSize();i++) - { - OBType m(input->At(i)); - OBType p(input->At(i)); - if(m) - { - if(0!=map) goto fail; // Duplicate - map=m; - ispdf=false; - } - if(p) - { - if(0!=map) goto fail; // Duplicate - map=p; - ispdf=true; - } - } - if(0==map) goto fail; // Map not found + RNFPar mapeps("map"); + RNFPar 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; + } + // Parse other parameters + { + ParseNamedParameters params(input,r,ds,w,h,cs,taa,gaa,aa); + if(!params) {err=params.Error(); goto fail;} } // Determine resolution { - SearchParameter > 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("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) {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,false,PMin<1>,PMax<10>,PInt > ds(input,"downscale","dscale","ds"); - dscale=static_cast(ds(&suc)); - if(!suc) goto fail; // Error - r*=dscale; + dscale=static_cast(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 r("resolution",300); + ONPar w("width"),h("height"); + ONPar 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 q("quality",75); + const ObjectGMTMap* me; + const ObjectGMTMapPDF* mp; + const GMTMap* m; + double res; + uint aat,aag; uint qual; - // Map to convert + if(!gs_abilities.havepdf) {err="No PDF support in Ghostscript"; goto fail;} // No pdf support, so, no jpeg + // Search map { - for(ObjectList::IndexType i=0;iSize();i++) - { - OBType m(input->At(i)); - OBType p(input->At(i)); - if(m) - { - if(0!=map) goto fail; // Duplicate - map=m; - ispdf=false; - } - if(p) - { - if(0!=map) goto fail; // Duplicate - map=p; - ispdf=true; - } - } - if(0==map) goto fail; // Map not found + RNFPar mapeps("map"); + RNFPar 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; + } + // Parse other parameters + { + ParseNamedParameters params(input,r,q,w,h,cs,taa,gaa,aa); + if(!params) {err=params.Error(); goto fail;} } // Determine resolution { - SearchParameter > 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("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) {err="Incorrect value for text antialiasing: "+aats; goto fail;} + if(0==aag) {err="Incorrect value for graphics antialiasing: "+aags; goto fail;} } // Quality { - SearchParameterWDefO,false,PMin<0>,PMax<100>,PInt > q(input,"quality","qual","q"); - qual=static_cast(q(&suc)); - if(!suc) goto fail; // Error + qual=static_cast(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); } diff --git a/modules/gmt/modgmt_map.h b/modules/gmt/modgmt_map.h index cad08c4..57e7f91 100644 --- a/modules/gmt/modgmt_map.h +++ b/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 SearchObject { public: - double operator()(double v, bool* suc) const {if(v!=floor(v)) *suc=false; return v;} + using ValueType=const Object*; + template + ValueType Convert(const ObjectBase* ob, bool* res, std::string& err, Args... args) + { + OBType 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; +using SearchGMTMapPDF=SearchObject; // Creating eps map from set of layers const ObjectBase* GMT_Map(const ObjectList* input);