Browse Source

Gmt module: Add interface to ghostscript.

ObjPtr
Michael Uleysky 8 years ago
parent
commit
8802277bdb
  1. 6
      modules/gmt/modgmt.cpp
  2. 165
      modules/gmt/modgmt_gsfuncs.cpp
  3. 38
      modules/gmt/modgmt_gsfuncs.h

6
modules/gmt/modgmt.cpp

@ -1,6 +1,7 @@
#include "modgmt.h"
#include "modgmt_func.h"
#include "modgmt_internals.h"
#include "modgmt_gsfuncs.h"
// Initialisation function
int gmt_module_init(void* p)
@ -42,5 +43,10 @@ int gmt_module_init(void* p)
RegisterFunction("Font",GMT_Type<struct gmt_font>);
RegisterFunction("Shift",GMT_LayerShift);
RegisterFunction("DrawFrame",GMT_DrawFrame);
CheckGhostscriptAbilities();
// Calculating bounding box is critical
if(!gs_abilities.havebbox) return 1;
return 0;
}

165
modules/gmt/modgmt_gsfuncs.cpp

@ -0,0 +1,165 @@
#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));
}

38
modules/gmt/modgmt_gsfuncs.h

@ -0,0 +1,38 @@
#ifndef MODGMT_GSFUNCS_H
#define MODGMT_GSFUNCS_H
#include <string>
#include <ghostscript/iapi.h>
#include <ghostscript/ierrors.h>
struct gs_abilities_struct
{
bool havepngmono,havepngmonod,havepng16,havepng256,havepnggray,havepng16m;
bool havejpeg,havejpeggray;
bool havepdf,havebbox;
};
extern struct gs_abilities_struct gs_abilities;
struct gs_runtime
{
union
{
struct
{
const std::string* in;
uint pos;
};
void* indata;
};
std::string* out;
std::string* err;
};
typedef int (*gs_callback)(void *caller_handle, char *buf, int len);
int GhostRun(const std::string& opts, const std::string& input, std::string* sout, std::string* serr, std::string* out);
int GhostRun(const std::string& opts, gs_callback input, void* inputdata, std::string* sout, std::string* serr, std::string* out);
void CheckGhostscriptAbilities();
#endif
Loading…
Cancel
Save