#include #include #include "common.h" #include "modgmt_gsfuncs.h" struct gs_abilities_struct gs_abilities; static int gs_callback_out(void *caller_handle, const char *buf, int len) { struct gs_runtime* r=static_cast(caller_handle); if(0!=r->out) r->out->append(buf,len); return len; } static int gs_callback_err(void *caller_handle, const char *buf, int len) { struct gs_runtime* r=static_cast(caller_handle); if(0!=r->err) r->err->append(buf,len); return len; } static int gs_callback_in(void *caller_handle, char *buf, int len) { struct gs_runtime* r=static_cast(caller_handle); if(r->pos>=r->in->length()) return 0; size_t rem=r->in->length()-r->pos; if(rem>static_cast(len)) rem=len; memcpy(buf,r->in->c_str()+r->pos,rem); r->pos+=rem; return rem; } struct gsworkthreadpars { struct gs_runtime* r; gs_callback input_callback; int fd; const std::string* opts; int ret; }; // This function call gs_* in separate thread, because ghostscript write to stdout static void* gsworkthread(void* x) { struct gsworkthreadpars* p=reinterpret_cast(x); WordList wl; if(-1==p->fd) wl=Split("-dSAFER -q -o/dev/null "+*(p->opts)+" -"); else wl=Split("-dSAFER -dDOINTERPOLATE -q -o/dev/fd/"+ToString(p->fd)+" "+*(p->opts)+" -"); int argc=wl.size()+1; char** argv; int i; void* gs; argv=new char*[argc]; argv[0]=new char[2]; argv[0][0]='G'; argv[0][1]=0; i=1; for(auto& opt: wl) { argv[i]=new char[opt.length()+1]; memcpy(argv[i],opt.c_str(),opt.length()+1); i++; } p->ret=gsapi_new_instance(&gs,p->r); if(p->ret<0) goto end; gsapi_set_stdio(gs,p->input_callback?p->input_callback:gs_callback_in,gs_callback_out,gs_callback_err); p->ret=gsapi_init_with_args(gs,argc,argv); if(0==p->ret || e_Quit==p->ret) p->ret=gsapi_exit(gs); else gsapi_exit(gs); if(e_Quit==p->ret) p->ret=0; gsapi_delete_instance(gs); end: close(p->fd); for(i=0;iret; } // Main function for prepare and run ghostscript static int GhostRun(const std::string& opts, struct gs_runtime* r, std::string* out, gs_callback input=0) { struct gsworkthreadpars wp; int* pret; wp.r=r; wp.input_callback=input; wp.opts=&opts; wp.ret=0; wp.fd=-1; if(0!=out) { int pipefd[2]; pthread_t wthr; ssize_t br; char buffer[4096]; pipe(pipefd); wp.fd=pipefd[1]; out->erase(); pthread_create(&wthr,0,&gsworkthread,&wp); do { br=read(pipefd[0],buffer,4096); out->append(buffer,br); } while(0!=br); close(pipefd[0]); out->shrink_to_fit(); pthread_join(wthr,reinterpret_cast(&pret)); } else pret=reinterpret_cast(gsworkthread(&wp)); return *pret; } // This function run ghostscript with input data in string int GhostRun(const std::string& opts, const std::string& input, std::string* sout, std::string* serr, std::string* out) { struct gs_runtime r; r.in=&input; r.pos=0; r.out=sout; r.err=serr; return GhostRun(opts,&r,out); } // This function run ghostscript with input data provided by callback function int GhostRun(const std::string& opts, gs_callback input, void* inputdata, std::string* sout, std::string* serr, std::string* out) { struct gs_runtime r; r.indata=inputdata; r.out=sout; r.err=serr; return GhostRun(opts,&r,out,input); } void CheckGhostscriptAbilities() { std::string out; gs_abilities.havepdf=gs_abilities.havebbox=gs_abilities.havepngmono=gs_abilities.havepngmonod=gs_abilities.havepng16=gs_abilities.havepng256=gs_abilities.havepnggray=gs_abilities.havepng16m=gs_abilities.havejpeg=gs_abilities.havejpeggray=false; if(0!=GhostRun("-sDEVICE=nullpage","devicenames ==",&out,0,0)) return; WordList wl=Split(out,"[]/ \t"); for(auto& i:wl) { if("pdfwrite"==i) gs_abilities.havepdf=true; if("bbox"==i) gs_abilities.havebbox=true; if("pngmono"==i) gs_abilities.havepngmono=true; if("pngmonod"==i) gs_abilities.havepngmonod=true; if("png16"==i) gs_abilities.havepng16=true; if("png256"==i) gs_abilities.havepng256=true; if("pnggray"==i) gs_abilities.havepnggray=true; if("png16m"==i) gs_abilities.havepng16m=true; if("jpeg"==i) gs_abilities.havejpeg=true; if("jpeggray"==i) gs_abilities.havejpeggray=true; } // gs_abilities.havepdf=(0==GhostRun("-sDEVICE=pdfwrite -dCompatibilityLevel=1.4","gsave 1 0 0 setrgbcolor 5 setlinewidth 100 100 moveto 200 200 lineto stroke grestore showpage",0,0,0)); }