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.
 
 
 
 
 

542 lines
15 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 <kdebug.h>
#include <kglobal.h>
#include <klocale.h>
#include <qfile.h>
#include <qstring.h>
#include <qstringlist.h>
extern "C" {
#include "ps.h"
}
#include <errno.h>
#include <okular/core/document.h>
#include "internaldocument.h"
QStringList GSInternalDocument::paperSizes()
{
QStringList list;
int i=0;
for (;i<CDSC_KNOWN_MEDIA;i++)
{
if ( ! dsc_known_media[i].name )
break;
list << QString ( dsc_known_media[i].name );
}
return list;
}
void GSInternalDocument::scanDSC()
{
m_dsc = new KDSC();
char buf[4096];
int count=1;
while( count != 0 )
{
count = fread( buf, sizeof(char), sizeof( buf ), m_internalFile );
m_dsc->scanData( buf, count );
}
m_dsc->fixup();
}
GSInternalDocument::GSInternalDocument(const QString &fname, Format form) : m_error(false), m_fileName(fname), docInfo(0), m_format(form)
{
m_internalFile = fopen(QFile::encodeName(fname),"r");
if( m_internalFile == 0 )
{
m_error=true;
m_errorString=strerror(errno);
}
if (!m_error)
{
m_fallbackMedia = pageSizeToString( static_cast< QPrinter::PageSize >( KGlobal::locale()->pageSize() ) );
m_overrideOrientation = CDSC_ORIENT_UNKNOWN;
m_overrideMedia = QString();
scanDSC();
if (!m_dsc)
{
m_error=true;
m_errorString="Failed to construct KDSC";
}
if ( !m_error && ! m_dsc->dsc() )
{
m_error=true;
// note this is not a fatal error, just a notice, we support docs without dsc
m_errorString="Document has no DSC.";
}
}
if (!m_error)
{
// available media information
// 1. known predefined media
const CDSCMEDIA* m = dsc_known_media;
while( m->name )
{
m_mediaNames << m->name;
m++;
}
// 2. media defined in the document
if( m_dsc->media() )
{
unsigned int end=m_dsc->media_count();
for( unsigned int i = 0; i < end ; i++ )
{
if( m_dsc->media()[i] && m_dsc->media()[i]->name )
m_mediaNames << m_dsc->media()[i]->name;
}
}
}
if (m_error)
kDebug(4656) << m_errorString << endl;
}
GSInternalDocument::~GSInternalDocument()
{
delete docInfo;
}
const Okular::DocumentInfo * GSInternalDocument::generateDocumentInfo()
{
if (! m_dsc->dsc() )
return 0L;
if (!docInfo)
{
docInfo = new Okular::DocumentInfo();
docInfo->set( Okular::DocumentInfo::Title, m_dsc->dsc_title() );
docInfo->set( Okular::DocumentInfo::Author, m_dsc->dsc_for() );
docInfo->set( Okular::DocumentInfo::Creator, m_dsc->dsc_creator() );
docInfo->set( Okular::DocumentInfo::CreationDate, m_dsc->dsc_date() );
docInfo->set( Okular::DocumentInfo::Copyright, m_dsc->dsc_copyright() );
QString dscVer=m_dsc->dsc_version();
docInfo->set( "dscversion", dscVer, i18n("DSC version") );
switch (m_format)
{
case PDF:
docInfo->set( Okular::DocumentInfo::MimeType, "application/pdf" );
break;
case PS:
docInfo->set( "langlevel", QString::number(m_dsc->language_level()), i18n("Language Level") );
if (dscVer.contains ("EPS"))
docInfo->set( Okular::DocumentInfo::MimeType, "image/x-eps" );
else
docInfo->set( Okular::DocumentInfo::MimeType, "application/postscript" );
break;
}
int pages=m_dsc->page_pages();
if (!pages)
pages = m_dsc->page_count();
docInfo->set( Okular::DocumentInfo::Pages, QString::number(pages) );
}
return docInfo;
}
QString GSInternalDocument::pageSizeToString( QPrinter::PageSize pSize )
{
switch( pSize )
{
case QPrinter::A3:
return "A3";
case QPrinter::A4:
return "A4";
case QPrinter::A5:
return "A5";
case QPrinter::B4:
return "B4";
case QPrinter::Ledger:
return "Ledger";
case QPrinter::Legal:
return "Legal";
case QPrinter::Letter:
return "Letter";
default:
return "Unknown";
}
}
QString GSInternalDocument::pageMedia() const
{
if( !m_overrideMedia.isNull() )
return m_overrideMedia;
else if( m_dsc->page_media() != 0 )
return QString( m_dsc->page_media()->name );
else if( m_dsc->bbox().get() != 0 )
return QString( "BoundingBox" );
else
return m_fallbackMedia;
}
QString GSInternalDocument::pageMedia( int pagenumber ) const
{
if ( !m_dsc )
return pageMedia();
if ( unsigned( pagenumber ) >= m_dsc->page_count() )
return pageMedia();
if( !m_overrideMedia.isNull() )
return m_overrideMedia;
else if( m_dsc->page()[ pagenumber ].media != 0 )
return QString( m_dsc->page()[ pagenumber ].media->name );
else if( m_dsc->page_media() != 0 )
return QString( m_dsc->page_media()->name );
else if( m_dsc->bbox().get() != 0 )
return QString( "BoundingBox" );
else
return m_fallbackMedia;
}
const CDSCMEDIA* GSInternalDocument::findMediaByName( const QString& mediaName ) const
{
if( m_dsc->media() )
{
for( unsigned int i = 0; i < m_dsc->media_count(); i++ )
{
if( m_dsc->media()[i] && m_dsc->media()[i]->name
&& qstricmp( mediaName.toLocal8Bit(), m_dsc->media()[i]->name ) == 0 )
{
return m_dsc->media()[i];
}
}
}
/* It didn't match %%DocumentPaperSizes: */
/* Try our known media */
const CDSCMEDIA *m = dsc_known_media;
while( m->name )
{
if( qstricmp( mediaName.toLocal8Bit(), m->name ) == 0 )
return m;
m++;
}
return 0;
}
QString GSInternalDocument::getPaperSize( const QString& mediaName ) const
{
const CDSCMEDIA * r = 0;
r=findMediaByName( mediaName );
if (!r)
{
const CDSCMEDIA *m = dsc_known_media;
while( m->name )
{
if( qstricmp( m_fallbackMedia.toLocal8Bit(), m->name ) == 0 )
return QString(m->name);
m++;
}
// should never happen as we have fallback
kDebug(4656) << "UNABLE TO FIND PAPER SIZE FOR MEDIA NAME: " << mediaName << endl;
return QString("a4");
}
return QString(r->name);
}
QSize GSInternalDocument::computePageSize( const QString& mediaName ) const
{
if( mediaName == "BoundingBox" )
{
if( m_dsc->bbox().get() != 0 )
return m_dsc->bbox()->size();
else
return QSize( 0, 0 );
}
const CDSCMEDIA* m = findMediaByName( mediaName );
Q_ASSERT( m );
return QSize( static_cast<int>( m->width ), static_cast<int>( m->height ) );
}
CDSC_ORIENTATION_ENUM GSInternalDocument::orientation() const
{
if( m_overrideOrientation != CDSC_ORIENT_UNKNOWN )
return m_overrideOrientation;
else if( m_dsc->page_orientation() != CDSC_ORIENT_UNKNOWN )
return static_cast< CDSC_ORIENTATION_ENUM >( m_dsc->page_orientation());
else if( m_dsc->bbox().get() != 0
&& m_dsc->bbox()->width() > m_dsc->bbox()->height() )
return CDSC_LANDSCAPE;
else
return CDSC_PORTRAIT;
}
CDSC_ORIENTATION_ENUM GSInternalDocument::orientation( int pagenumber ) const
{
if ( !m_dsc || unsigned( pagenumber ) >= m_dsc->page_count() )
{
return orientation();
}
if( m_overrideOrientation != CDSC_ORIENT_UNKNOWN )
{
return m_overrideOrientation;
}
if( m_dsc->page()[ pagenumber ].orientation != CDSC_ORIENT_UNKNOWN )
{
return static_cast< CDSC_ORIENTATION_ENUM >( m_dsc->page()[ pagenumber ].orientation );
}
if( m_dsc->page_orientation() != CDSC_ORIENT_UNKNOWN )
{
return static_cast< CDSC_ORIENTATION_ENUM >( m_dsc->page_orientation());
}
if( !m_dsc->epsf() )
{
return CDSC_PORTRAIT;
}
if( m_dsc->bbox().get() != 0
&& m_dsc->bbox()->width() > m_dsc->bbox()->height() ) {
return CDSC_LANDSCAPE;
}
return CDSC_PORTRAIT;
}
KDSCBBOX GSInternalDocument::boundingBox() const
{
QString currentMedia = pageMedia();
if( currentMedia == "BoundingBox" )
return KDSCBBOX( * (m_dsc->bbox().get()) );
else {
QSize size = computePageSize( currentMedia );
return KDSCBBOX( 0, 0, size.width(), size.height() );
}
}
KDSCBBOX GSInternalDocument::boundingBox( int pageNo ) const
{
QString currentMedia = pageMedia( pageNo );
if( currentMedia == "BoundingBox" )
return KDSCBBOX( *(m_dsc->bbox().get()) );
else
{
QSize size = computePageSize( currentMedia );
return KDSCBBOX( 0, 0, size.width(), size.height() );
}
}
bool GSInternalDocument::savePages( const QString& saveFileName,
const PageList& pageList )
{
if( pageList.empty() )
return true;
/* if( _format == PDF )
{
KTempFile psSaveFile( QString::null, ".ps" );
psSaveFile.setAutoDelete( true );
if( psSaveFile.status() != 0 )
return false;
// Find the minimum and maximum pagenumber in pageList.
int minPage = pageList.first(), maxPage = pageList.first();
for( PageList::const_iterator ci = pageList.begin();
ci != pageList.end(); ++ci )
{
minPage = qMin( *ci, minPage );
maxPage = qMax( *ci, maxPage );
}
// TODO: Optimize "print whole document" case
//
// The convertion below from PDF to PS creates a temporary file which, in
// the case where we are printing the whole document will then be
// completelly copied to another temporary file.
//
// In very large files, the inefficiency is visible (measured in
// seconds).
//
// luis_pedro 4 Jun 2003
// Convert the pages in the range [minPage,maxPage] from PDF to
// PostScript.
if( !convertFromPDF( psSaveFile.name(),
minPage, maxPage ) )
return false;
// The page minPage in the original file becomes page 1 in the
// converted file. We still have to select the desired pages from
// this file, so we need to take into account that difference.
PageList normedPageList;
transform( pageList.begin(), pageList.end(),
back_inserter( normedPageList ),
bind2nd( minus<int>(), minPage - 1 ) );
// Finally select the desired pages from the converted file.
psCopyDoc( psSaveFile.name(), saveFileName, normedPageList );
}
else
{*/
psCopyDoc( m_fileName, saveFileName, pageList );
//}
return true;
}
// length calculates string length at compile time
// can only be used with character constants
#define length( a ) ( sizeof( a ) - 1 )
// Copy the headers, marked pages, and trailer to fp
bool GSInternalDocument::psCopyDoc( const QString& inputFile,
const QString& outputFile, const PageList& pageList )
{
FILE* from;
FILE* to;
char text[ PSLINELENGTH ];
char* comment;
bool pages_written = false;
bool pages_atend = false;
unsigned int i = 0;
unsigned int pages = 0;
long here;
kDebug(4656) << "Copying pages from " << inputFile << " to "
<< outputFile << endl;
pages = pageList.size();
if( pages == 0 )
{
// FIXME ERROR HANDLING
/* KMessageBox::sorry( document()->widget(),
i18n( "Printing failed because the list of "
"pages to be printed was empty." ),
i18n( "Error Printing" ) );*/
return false;
}
from = fopen( QFile::encodeName( inputFile ), "r" );
to = fopen( QFile::encodeName( outputFile ), "w" );
// Hack in order to make printing of PDF files work. FIXME
CDSC* dsc = NULL;
if( m_format == PS )
dsc = m_dsc->cdsc();
/* else {
FILE* fp = fopen( QFile::encodeName( inputFile ), "r");
char buf[256];
int count;
dsc = dsc_init( 0 );
while( ( count = fread( buf, 1, sizeof( buf ), fp ) ) != 0 )
dsc_scan_data( dsc, buf, count );
dsc_fixup( dsc );
fclose( fp );
}*/
if( !dsc )
return false;
here = dsc->begincomments;
while( ( comment = pscopyuntil( from, to, here,
dsc->endcomments, "%%Pages:" ) ) )
{
here = ftell( from );
if( pages_written || pages_atend )
{
free( comment );
continue;
}
sscanf( comment + length("%%Pages:" ), "%256s", text );
text[256] = 0; // Just in case of an overflow
if( strcmp( text, "(atend)" ) == 0 )
{
fputs( comment, to );
pages_atend = true;
}
else
{
switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) )
{
case 1:
fprintf( to, "%%%%Pages: %d %d\n", pages, i );
break;
default:
fprintf( to, "%%%%Pages: %d\n", pages );
break;
}
pages_written = true;
}
free(comment);
}
pscopy( from, to, dsc->beginpreview, dsc->endpreview );
pscopy( from, to, dsc->begindefaults, dsc->enddefaults );
pscopy( from, to, dsc->beginprolog, dsc->endprolog );
pscopy( from, to, dsc->beginsetup, dsc->endsetup );
//TODO -- Check that a all dsc attributes are copied
unsigned int count = 1;
PageList::const_iterator it;
for( it = pageList.begin(); it != pageList.end(); ++it )
{
i = (*it) - 1;
comment = pscopyuntil( from, to, dsc->page[i].begin,
dsc->page[i].end, "%%Page:" );
if ( comment )
free( comment );
fprintf( to, "%%%%Page: %s %d\n", dsc->page[i].label,
count++ );
pscopy( from, to, -1, dsc->page[i].end );
}
here = dsc->begintrailer;
while( ( comment = pscopyuntil( from, to, here,
dsc->endtrailer, "%%Pages:" ) ) )
{
here = ftell( from );
if ( pages_written )
{
free( comment );
continue;
}
switch ( sscanf( comment + length( "%%Pages:" ), "%*d %u", &i ) )
{
case 1:
fprintf( to, "%%%%Pages: %d %d\n", pages, i );
break;
default:
fprintf( to, "%%%%Pages: %d\n", pages );
break;
}
pages_written = true;
free( comment );
}
fclose( from );
fclose( to );
/* if( format == PDF )
dsc_free( dsc );*/
return true;
}
#undef length