You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
165 lines
4.4 KiB
165 lines
4.4 KiB
#include <string.h> |
|
#include <unistd.h> |
|
#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<struct gs_runtime*>(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<struct gs_runtime*>(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<struct gs_runtime*>(caller_handle); |
|
if(r->pos>=r->in->length()) return 0; |
|
size_t rem=r->in->length()-r->pos; |
|
if(rem>static_cast<size_t>(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<struct gsworkthreadpars*>(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;i<argc;i++) delete[] argv[i]; |
|
delete[] argv; |
|
return &p->ret; |
|
} |
|
|
|
// 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<void**>(&pret)); |
|
} |
|
else pret=reinterpret_cast<int*>(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)); |
|
}
|
|
|