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.
479 lines
13 KiB
479 lines
13 KiB
/*************************************************************************** |
|
* Copyright (C) 1997-2005 the KGhostView authors. See file GV_AUTHORS. * |
|
* Copyright (C) 2005 by Piotr Szymanski <niedakh@gmail.com> * |
|
* * |
|
* Many portions of this file are based on kghostview's kpswidget code * |
|
* * |
|
* This program is free software; you can redistribute it and/or modify * |
|
* it under the terms of the GNU General Public License as published by * |
|
* the Free Software Foundation; either version 2 of the License, or * |
|
* (at your option) any later version. * |
|
***************************************************************************/ |
|
|
|
#include <math.h> |
|
#include <iapi.h> |
|
#include <ierrors.h> |
|
#include <gdevdsp.h> |
|
|
|
#include <qpixmap.h> |
|
#include <qpainter.h> |
|
#include <qstring.h> |
|
|
|
#include <kdebug.h> |
|
|
|
#include "interpreter_lib.h" |
|
#include "conf/gssettings.h" |
|
|
|
// C API wrappers |
|
int handleStdin(void *caller_handle, char *buf, int len) |
|
{ |
|
return static_cast <GSInterpreterLib*>(caller_handle) -> gs_input(buf,len); |
|
} |
|
|
|
int handleStdout(void *caller_handle, const char *str, int len) |
|
{ |
|
return static_cast <GSInterpreterLib*>(caller_handle) -> gs_output(str,len); |
|
} |
|
|
|
int handleStderr(void *caller_handle, const char *str, int len) |
|
{ |
|
return static_cast <GSInterpreterLib*>(caller_handle) -> gs_error(str,len); |
|
} |
|
|
|
int open(void */*handle */, void */*device */ ) |
|
{ |
|
kdDebug(4655) << "open called" << endl; |
|
return 0; |
|
} |
|
|
|
int preclose(void * /* handle */, void * /* device */ ) |
|
{ |
|
kdDebug(4655) << "preclose called" << endl; |
|
return 0; |
|
} |
|
|
|
int dclose(void * /* handle */, void * /* device */ ) |
|
{ |
|
kdDebug(4655) << "close called" << endl; |
|
return 0; |
|
} |
|
|
|
|
|
int presize(void * /* handle*/, void * /* device*/, int /* width*/, int /* height*/, |
|
int /* raster*/, unsigned int /* format */) |
|
{ |
|
kdDebug(4655) << "presize called" << endl; |
|
return 0; |
|
} |
|
|
|
|
|
int size(void *handle, void * /* device*/, int width, int height, |
|
int raster, unsigned int format, unsigned char *pimage) |
|
{ |
|
return static_cast <GSInterpreterLib*>(handle) -> size (width, height, |
|
raster, format, pimage); |
|
} |
|
|
|
int sync(void * /* handle */, void * /* device */ ) |
|
{ |
|
kdDebug(4655) << "sync called" << endl; |
|
return 0; |
|
} |
|
|
|
|
|
int page(void *handle, void * /* device*/, int /* copies*/, int /* flush*/) |
|
{ |
|
return static_cast <GSInterpreterLib*>(handle) -> page (); |
|
} |
|
|
|
int update(void * /* handle*/, void * /* device*/, |
|
int /* x*/, int /* y*/, int /* w*/, int /* h*/) |
|
{ |
|
// kdDebug(4655) << "update called" << endl; |
|
return 0; |
|
} |
|
|
|
int separation(void * /* handle*/, void * /* device*/, |
|
int /* comp_num*/, const char * /* name*/, |
|
unsigned short /* c*/, unsigned short /* m*/, |
|
unsigned short /* y*/, unsigned short /* k*/) |
|
{ |
|
kdDebug(4655) << "separation called" << endl; |
|
return 0; |
|
} |
|
|
|
/* |
|
device.size = sizeof ( display_callback ); |
|
device.version_major = DISPLAY_VERSION_MAJOR; |
|
device.version_minor = DISPLAY_VERSION_MINOR; |
|
device.display_open = NULL; |
|
device.display_preclose = NULL; |
|
device.display_close = NULL; |
|
device.display_presize = NULL; |
|
device.display_size = & size; |
|
device.display_sync = NULL; |
|
device.display_page = NULL; |
|
device.display_update = NULL; |
|
device.display_memalloc = NULL; |
|
device.display_memfree = NULL; */ |
|
|
|
display_callback device = |
|
{ |
|
sizeof ( display_callback ), |
|
DISPLAY_VERSION_MAJOR, |
|
DISPLAY_VERSION_MINOR, |
|
&open, |
|
&preclose, |
|
&dclose, |
|
&presize, |
|
&size, |
|
&sync, |
|
&page, |
|
&update, |
|
NULL, /* memalloc */ |
|
NULL |
|
#if DISPLAY_VERSION_MAJOR >= 2 |
|
,&separation |
|
#endif |
|
}; |
|
|
|
GSInterpreterLib::GSInterpreterLib() : m_running(false), m_argsCCount(0), m_argsChar(0) |
|
{ |
|
int exit = gsapi_new_instance(&ghostScriptInstance,this); |
|
kdDebug(4655) << "Setting image" << endl; |
|
m_ready=true; |
|
m_pix=0; |
|
Q_ASSERT (exit == 0); |
|
} |
|
|
|
|
|
// interpreter state functions |
|
|
|
bool GSInterpreterLib::startInterpreter(bool setStdio) |
|
{ |
|
m_sync=false; |
|
kdDebug(4655) << "setting m_sync to " << m_sync << " in startInterpreter " <<endl; |
|
if ( setStdio ) |
|
gsapi_set_stdio (ghostScriptInstance,&handleStdin,&handleStdout,&handleStderr); |
|
kdDebug(4655) << "setting display " << endl; |
|
int call = gsapi_set_display_callback(ghostScriptInstance, &device); |
|
argsToChar (); |
|
kdDebug(4655) << "setting args " << endl; |
|
int exit_i=gsapi_init_with_args (ghostScriptInstance,m_argsCCount,m_argsChar); |
|
|
|
|
|
m_running = handleExit ( exit_i ) ; |
|
/* if ( m_running && setMore ) |
|
{ |
|
QString set; |
|
// is this needed?? |
|
set.sprintf("<< /Orientation %d /ImagingBBox [ %d %d %d %d ] >> setpagedevice .locksafe", |
|
m_orientation,m_boundingBox.llx(), |
|
m_boundingBox.lly(),m_boundingBox.urx(),m_boundingBox.ury()); |
|
kdDebug(4655) << set << endl; |
|
gsapi_run_string_with_length (ghostScriptInstance,set.latin1(),set.length(),0,&exit_i); |
|
set="currentpagedevice {exch ==only ( ) print ==} forall"; |
|
gsapi_run_string_with_length (ghostScriptInstance,set.latin1(),set.length(),0,&exit_i); |
|
m_running = handleExit ( exit_i ); |
|
kdDebug(4655) << "After setting : " << m_running << endl; |
|
}*/ |
|
return m_running; |
|
} |
|
|
|
bool GSInterpreterLib::stopInterpreter() |
|
{ |
|
if (m_running) |
|
{ |
|
gsapi_exit(ghostScriptInstance); |
|
m_running=false; |
|
m_sync=false; |
|
kdDebug(4655) << "setting m_sync to " << m_sync << " in stopInterpreter " <<endl; |
|
} |
|
return m_running; |
|
} |
|
|
|
|
|
// set options |
|
void GSInterpreterLib::setGhostscriptArguments( const QStringList &list ) |
|
{ |
|
interpreterLock.lock(); |
|
if ( m_args != list ) |
|
{ |
|
m_args=list; |
|
stopInterpreter(); |
|
} |
|
interpreterLock.unlock(); |
|
} |
|
|
|
void GSInterpreterLib::setOrientation( int orientation ) |
|
{ |
|
interpreterLock.lock(); |
|
if( m_orientation != orientation ) |
|
{ |
|
m_orientation = orientation; |
|
stopInterpreter(); |
|
} |
|
interpreterLock.unlock(); |
|
} |
|
|
|
void GSInterpreterLib::setMagnify( double magnify ) |
|
{ |
|
interpreterLock.lock(); |
|
if( m_magnify != magnify ) |
|
{ |
|
m_magnify = magnify; |
|
stopInterpreter(); |
|
} |
|
interpreterLock.unlock(); |
|
} |
|
|
|
void GSInterpreterLib::setMedia( QString media ) |
|
{ |
|
interpreterLock.lock(); |
|
if( m_media != media ) |
|
{ |
|
m_media = media; |
|
stopInterpreter(); |
|
} |
|
interpreterLock.unlock(); |
|
} |
|
|
|
void GSInterpreterLib::setSize( int w, int h ) |
|
{ |
|
|
|
if ( m_width != w ) |
|
{ |
|
m_width=w; |
|
stopInterpreter(); |
|
|
|
} |
|
if ( m_height != h ) |
|
{ |
|
m_height=h; |
|
stopInterpreter(); |
|
} |
|
|
|
} |
|
|
|
/*void GSInterpreterLib::setBoundingBox( const KDSCBBOX& boundingBox ) |
|
{ |
|
interpreterLock.lock(); |
|
if( m_boundingBox != boundingBox ) |
|
{ |
|
m_boundingBox = boundingBox; |
|
stopInterpreter(); |
|
} |
|
interpreterLock.unlock(); |
|
}*/ |
|
|
|
|
|
bool GSInterpreterLib::run(FILE * tmp, PagePosition *pos, PixmapRequest *req, bool sync) |
|
{ |
|
if (fseek(tmp,pos->first, SEEK_SET)) |
|
return false; |
|
|
|
m_syncDone=false; |
|
m_sync=sync; |
|
kdDebug(4655) << "setting m_sync to " << m_sync << " in run" <<endl; |
|
m_req=req; |
|
char buf [4096]; |
|
int read, code, exit_code, wrote=0, left=pos->second - pos->first; |
|
bool errorExit=false; |
|
|
|
interpreterLock.lock(); |
|
code=gsapi_run_string_begin (ghostScriptInstance, 0, &exit_code); |
|
|
|
if (exit_code) |
|
errorExit=handleExit(exit_code); |
|
|
|
if (errorExit) |
|
return false; |
|
// kdDebug(4655) << "Left " << left <<endl; |
|
while (left > 0) |
|
{ |
|
read=fread (buf,sizeof(char),QMIN(sizeof(buf),left),tmp); |
|
wrote=gsapi_run_string_continue (ghostScriptInstance, buf, read, 0, &exit_code); |
|
if (exit_code) |
|
{ |
|
errorExit=handleExit(exit_code); |
|
|
|
if (errorExit) |
|
return false; |
|
} |
|
left-=read; |
|
// kdDebug(4655) << "Left " << left << " read " << read << " wrote " << wrote <<endl; |
|
} |
|
// kdDebug(4655) << "Left " << left << " wrote " << wrote <<endl; |
|
//wrote=gsapi_run_string_continue (ghostScriptInstance, "showpage", 8, 0, &exit_code); |
|
//kdDebug(4655) << "Left " << left << " wrote " << wrote <<endl; |
|
|
|
gsapi_run_string_end (ghostScriptInstance, 0, &exit_code); |
|
// kdDebug(4655) << "Ending string " << endl; |
|
|
|
if (exit_code) |
|
{ |
|
errorExit=handleExit(exit_code); |
|
|
|
if (errorExit) |
|
return false; |
|
} |
|
|
|
kdDebug(4655) << "unlocking interpreter " << left <<endl; |
|
interpreterLock.unlock(); |
|
if (m_sync && m_syncDone) |
|
emit newPageImage (m_req); |
|
m_syncDone=false; |
|
return true; |
|
} |
|
|
|
QPixmap* GSInterpreterLib::takePixmap() |
|
{ |
|
QPixmap* x=m_pix; |
|
m_pix = 0; |
|
m_req = 0; |
|
m_ready=true; |
|
return x; |
|
} |
|
|
|
GSInterpreterLib::~GSInterpreterLib() |
|
{ |
|
gsapi_exit(ghostScriptInstance); |
|
gsapi_delete_instance(ghostScriptInstance); |
|
} |
|
|
|
// gs api wrapping |
|
int GSInterpreterLib::gs_input ( char* buffer, int len ) |
|
{ |
|
emit io (Input,buffer,len); |
|
return len; |
|
} |
|
int GSInterpreterLib::gs_output ( const char* buffer, int len ) |
|
{ |
|
emit io (Output,buffer,len); |
|
return len; |
|
} |
|
|
|
int GSInterpreterLib::gs_error ( const char* buffer, int len ) |
|
{ |
|
emit io (Error,buffer,len); |
|
return len; |
|
} |
|
|
|
int GSInterpreterLib::size(int width, int height, |
|
int raster, unsigned int format, unsigned char *pimage) |
|
{ |
|
kdDebug(4655) << "size called, width/height/raster: "<< width << " " << height << " " << raster << " sizeof pimage " << sizeof(pimage) << endl; |
|
m_raster=raster; |
|
m_format=format; |
|
m_imageChar=pimage; |
|
m_Gwidth=width; |
|
m_Gheight=height; |
|
return 0; |
|
} |
|
|
|
#include <qdialog.h> |
|
#include <qlabel.h> |
|
#include <qpixmap.h> |
|
|
|
int GSInterpreterLib::page() |
|
{ |
|
kdDebug(4655) << "page called with m_sync == " << m_sync << endl; |
|
if (m_sync && !m_syncDone) |
|
{ |
|
m_ready=false; |
|
// assume the image given by the gs is of the requested widthxheight |
|
kdDebug(4655) << "Size of raster" << m_Gwidth << " " << m_Gheight << endl; |
|
kdDebug(4655) << "Needed size " << m_width << " " << m_height << endl; |
|
QImage img(m_imageChar, m_Gwidth, m_Gheight, |
|
32, (QRgb*) 0, 0, QImage::BigEndian ); |
|
//img.setAlphaBuffer(true); |
|
m_pix = new QPixmap (m_width, m_height); |
|
m_pix -> fill(); |
|
|
|
QPainter* p=new QPainter(m_pix); |
|
|
|
if (m_width != m_Gwidth || m_height != m_Gheight ) |
|
p->drawImage(0,0,img,0,0,m_Gwidth,m_Gheight); |
|
|
|
delete p; |
|
kdDebug(4655) << "Final size " << m_pix->width() << " " << m_pix->height() << endl; |
|
#ifdef SHOWMEHOWKPDFWASTESRESOURCES |
|
QDialog t(0); |
|
QLabel u(&t); |
|
u.setAutoResize(true); |
|
u.setPixmap(*m_pix); |
|
u.show(); |
|
t.exec(); |
|
#endif |
|
|
|
m_syncDone=true; |
|
} |
|
return 0; |
|
} |
|
|
|
bool GSInterpreterLib::handleExit(int code) |
|
{ |
|
switch (code) |
|
{ |
|
// quit was issued |
|
case e_Quit: |
|
// gs -h was run |
|
case e_Info: |
|
//gsapi_exit |
|
return false; |
|
|
|
// no error or we need further input |
|
case 0: |
|
case e_NeedInput: |
|
return true; |
|
|
|
// <0 - error |
|
default: |
|
return false; |
|
} |
|
} |
|
|
|
void GSInterpreterLib::argsToChar() |
|
{ |
|
if (m_argsChar) |
|
{ |
|
for (int i=0;i<m_argsCCount;i++) |
|
delete [] *(m_argsChar+i); |
|
delete [] m_argsChar; |
|
} |
|
m_args.clear(); |
|
m_args << " " |
|
<< "-q" |
|
<<"-dMaxBitmap=10000000 " |
|
<< "-dDELAYSAFER" |
|
<< "-dNOPAUSE" |
|
<< "-dNOPAGEPROMPT"; |
|
if ( GSSettings::antialiasing() ) |
|
m_args << "-dTextAlphaBits=4" |
|
<<"-dGraphicsAlphaBits=2"; |
|
if ( !GSSettings::platformFonts() ) |
|
m_args << "-dNOPLATFONTS"; |
|
m_args //<< GSSettings::arguments() |
|
<< QString("-sPAPERSIZE=%1").arg(m_media.lower()) |
|
<< QString().sprintf("-r%dx%d",(int)floor(m_magnify*QPaintDevice:: x11AppDpiX()),(int)floor(m_magnify*QPaintDevice:: x11AppDpiY())) |
|
<< QString().sprintf("-dDisplayFormat=%d", DISPLAY_COLORS_RGB | DISPLAY_UNUSED_LAST | DISPLAY_DEPTH_8 | |
|
DISPLAY_BIGENDIAN | DISPLAY_TOPFIRST) |
|
<< QString().sprintf("-dDisplayHandle=16#%llx", (unsigned long long int) this ) |
|
// FIXME orientation |
|
/*<< QString("-sOrientation=%1").arg(m_orientation)*/; |
|
|
|
|
|
int t=m_args.count(); |
|
char ** args=static_cast <char**> (new char* [t]); |
|
for (int i=0;i<t;i++) |
|
{ |
|
kdDebug(4655) << "Arg nr " << i << " : " << m_args[i].local8Bit() << endl ; |
|
*(args+i)=new char [m_args[i].length()+1]; |
|
qstrcpy (*(args+i),m_args[i].local8Bit()); |
|
} |
|
|
|
m_argsChar=args; |
|
m_argsCCount=t; |
|
} |
|
|
|
#include "interpreter_lib.moc"
|
|
|