00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
#include <unistd.h>
00022
#include <stdio.h>
00023
00024
#include <qbuffer.h>
00025
#include <qpainter.h>
00026
#include <qpaintdevicemetrics.h>
00027
#include <qfile.h>
00028
#include <qtextstream.h>
00029
#include <qregexp.h>
00030
#include <qimage.h>
00031
#include <qpixmap.h>
00032
#include <qapplication.h>
00033
#include <qdragobject.h>
00034
00035
#include <kglobal.h>
00036
#include <kdebug.h>
00037
#include <kdeversion.h>
00038
#if ! KDE_IS_VERSION( 3,1,90 )
00039
#include <kdebugclasses.h>
00040
#endif
00041
#include <ktempfile.h>
00042
#include <kprocess.h>
00043
00044
#include "koPictureKey.h"
00045
#include "koPictureBase.h"
00046
#include "koPictureEps.h"
00047
00048
00049 KoPictureEps::KoPictureEps(
void) : m_psStreamStart(0), m_psStreamLength(0), m_cacheIsInFastMode(true)
00050 {
00051
00052 m_cachedPixmap.setOptimization(QPixmap::MemoryOptim);
00053 }
00054
00055 KoPictureEps::~KoPictureEps(
void)
00056 {
00057 }
00058
00059 KoPictureBase* KoPictureEps::newCopy(
void)
const
00060
{
00061
return new KoPictureEps(*
this);
00062 }
00063
00064 KoPictureType::Type KoPictureEps::getType(
void)
const
00065
{
00066
return KoPictureType::TypeEps;
00067 }
00068
00069
bool KoPictureEps::isNull(
void)
const
00070
{
00071
return m_rawData.isNull();
00072 }
00073
00074
QImage KoPictureEps::scaleWithGhostScript(
const QSize& size,
const int resolutionx,
const int resolutiony )
00075 {
00076
if (!m_boundingBox.width() || !m_boundingBox.height())
00077 {
00078 kdDebug(30003) <<
"EPS image has a null size! (in KoPictureEps::scaleWithGhostScript)" << endl;
00079
return QImage();
00080 }
00081
00082
00083
00084
QImage img;
00085
int ret = tryScaleWithGhostScript(img, size, resolutionx, resolutiony,
"png16m");
00086
if ( ret == -1 )
00087 {
00088 ret = tryScaleWithGhostScript(img, size, resolutionx, resolutiony,
"bmp16m");
00089
if ( ret == -1 )
00090 {
00091 ret = tryScaleWithGhostScript(img, size, resolutionx, resolutiony,
"ppm");
00092
if ( ret == -1 )
00093 kdError(30003) <<
"Image from GhostScript cannot be loaded (in KoPictureEps::scaleWithGhostScript)" << endl;
00094 }
00095 }
00096
return img;
00097 }
00098
00099
00100
00101
int KoPictureEps::tryScaleWithGhostScript(
QImage &image,
const QSize& size,
const int resolutionx,
const int resolutiony,
const char* device )
00102
00103 {
00104 kdDebug(30003) <<
"Sampling with GhostScript, using device " << device <<
" (in KoPictureEps::tryScaleWithGhostScript)" << endl;
00105
00106 KTempFile tmpFile;
00107 tmpFile.setAutoDelete(
true);
00108
00109
if ( tmpFile.status() )
00110 {
00111 kdError(30003) <<
"No KTempFile! (in KoPictureEps::tryScaleWithGhostScript)" << endl;
00112
return 0;
00113 }
00114
00115
const int wantedWidth = size.width();
00116
const int wantedHeight = size.height();
00117
const double xScale = double(size.width()) / double(m_boundingBox.width());
00118
const double yScale = double(size.height()) / double(m_boundingBox.height());
00119
00120
00121
00122
QString cmdBuf (
"gs -sOutputFile=" );
00123 cmdBuf += KProcess::quote(tmpFile.name());
00124 cmdBuf +=
" -q -g";
00125 cmdBuf += QString::number( wantedWidth );
00126 cmdBuf +=
"x";
00127 cmdBuf += QString::number( wantedHeight );
00128
00129
if ( ( resolutionx > 0) && ( resolutiony > 0) )
00130 {
00131
#if 0
00132
00133
00134 cmdBuf +=
" -r";
00135 cmdBuf += QString::number( resolutionx );
00136 cmdBuf +=
"x";
00137 cmdBuf += QString::number( resolutiony );
00138
#endif
00139
}
00140
00141 cmdBuf +=
" -dSAFER -dPARANOIDSAFER -dNOPAUSE -sDEVICE=";
00142 cmdBuf += device;
00143
00144 cmdBuf +=
" -";
00145 cmdBuf +=
" -c showpage quit";
00146
00147
00148
00149 FILE* ghostfd = popen (QFile::encodeName(cmdBuf),
"w");
00150
00151
if ( ghostfd == 0 )
00152 {
00153 kdError(30003) <<
"No connection to GhostScript (in KoPictureEps::tryScaleWithGhostScript)" << endl;
00154
return 0;
00155 }
00156
00157
00158 fprintf (ghostfd,
"\n%d %d translate\n", -qRound(m_boundingBox.left()*xScale), -qRound(m_boundingBox.top()*yScale));
00159 fprintf (ghostfd,
"%g %g scale\n", xScale, yScale);
00160
00161
00162
00163 fwrite( m_rawData.data() + m_psStreamStart,
sizeof(
char), m_psStreamLength, ghostfd);
00164
00165 pclose ( ghostfd );
00166
00167
00168
if( !image.load (tmpFile.name()) )
00169 {
00170
00171
return -1;
00172 }
00173
if ( image.size() != size )
00174 {
00175
00176
00177 image = image.scale( size );
00178 }
00179 kdDebug(30003) <<
"Image parameters: " << image.width() <<
"x" << image.height() <<
"x" << image.depth() << endl;
00180
return 1;
00181 }
00182
00183
void KoPictureEps::scaleAndCreatePixmap(
const QSize& size,
bool fastMode,
const int resolutionx,
const int resolutiony )
00184 {
00185 kdDebug(30003) <<
"KoPictureEps::scaleAndCreatePixmap " << size <<
" " << (fastMode?
QString(
"fast"):QString("slow"))
00186 << " resolutionx: " << resolutionx << " resolutiony: " << resolutiony << endl;
00187
if ((size==m_cachedSize)
00188 && ((fastMode) || (!m_cacheIsInFastMode)))
00189 {
00190
00191
00192
00193
00194 kdDebug(30003) <<
"Already cached!" << endl;
00195
return;
00196 }
00197
00198
00199
if ( !isSlowResizeModeAllowed() )
00200 {
00201 kdDebug(30003) <<
"User has disallowed slow mode!" << endl;
00202 fastMode =
true;
00203 }
00204
00205
00206
if ( fastMode && !m_cachedSize.isEmpty())
00207 {
00208 kdDebug(30003) <<
"Fast scaling!" << endl;
00209
00210
QImage image( m_cachedPixmap.convertToImage() );
00211 m_cachedPixmap=image.scale( size );
00212 m_cacheIsInFastMode=
true;
00213 m_cachedSize=size;
00214 }
00215
else
00216 {
00217
QTime time;
00218 time.start();
00219
00220 QApplication::setOverrideCursor( Qt::waitCursor );
00221 m_cachedPixmap = scaleWithGhostScript( size, resolutionx, resolutiony );
00222 QApplication::restoreOverrideCursor();
00223 m_cacheIsInFastMode=
false;
00224 m_cachedSize=size;
00225
00226 kdDebug(30003) <<
"Time: " << (time.elapsed()/1000.0) <<
" s" << endl;
00227 }
00228 kdDebug(30003) <<
"New size: " << size << endl;
00229 }
00230
00231
void KoPictureEps::draw(
QPainter& painter,
int x,
int y,
int width,
int height,
int sx,
int sy,
int sw,
int sh,
bool fastMode)
00232 {
00233
if ( !width || !height )
00234
return;
00235
00236
QSize screenSize( width, height );
00237
00238
00239
QPaintDeviceMetrics metrics (painter.device());
00240 kdDebug(30003) <<
"Metrics: X: " << metrics.logicalDpiX() <<
" x Y: " << metrics.logicalDpiX() <<
" (in KoPictureEps::draw)" << endl;
00241
00242
if ( painter.device()->isExtDev() )
00243 {
00244 kdDebug(30003) <<
"Drawing for a printer (in KoPictureEps::draw)" << endl;
00245
00246
QImage image( scaleWithGhostScript( screenSize, metrics.logicalDpiX(), metrics.logicalDpiY() ) );
00247
00248
00249 painter.drawImage( x + sx, y + sy, image, sx, sy, sw, sh );
00250 }
00251
else
00252 {
00253 scaleAndCreatePixmap(screenSize, fastMode, metrics.logicalDpiX(), metrics.logicalDpiY() );
00254
00255
00256
00257 painter.drawPixmap( x + sx, y + sy, m_cachedPixmap, sx, sy, sw, sh );
00258 }
00259 }
00260
00261
bool KoPictureEps::extractPostScriptStream(
void )
00262 {
00263 kdDebug(30003) <<
"KoPictureEps::extractPostScriptStream" << endl;
00264
QDataStream data( m_rawData, IO_ReadOnly );
00265 data.setByteOrder( QDataStream::LittleEndian );
00266 Q_UINT32 magic, offset, length;
00267 data >> magic;
00268 data >> offset;
00269 data >> length;
00270
if ( !length )
00271 {
00272 kdError(30003) <<
"Length of PS stream is zero!" << endl;
00273
return false;
00274 }
00275
if ( offset+length>m_rawData.size() )
00276 {
00277 kdError(30003) <<
"Data stream of the EPSF file is longer than file: " << offset <<
"+" << length <<
">" << m_rawData.size() << endl;
00278
return false;
00279 }
00280 m_psStreamStart = offset;
00281 m_psStreamLength = length;
00282
return true;
00283 }
00284
00285 QString KoPictureEps::readLine(
const QByteArray& array,
const uint start,
const uint length, uint& pos,
bool& lastCharWasCr )
00286 {
00287 QString strLine;
00288
const uint finish = kMin( start + length, array.size() );
00289
for ( ; pos < finish; ++pos )
00290 {
00291
const char ch = array[ pos ];
00292
if ( ch ==
'\n' )
00293 {
00294
if ( lastCharWasCr )
00295 {
00296
00297
00298
00299 lastCharWasCr =
false;
00300 }
00301
else
00302 {
00303
00304
break;
00305 }
00306 }
00307
else if ( ch ==
'\r' )
00308 {
00309
00310 lastCharWasCr =
true;
00311
break;
00312 }
00313
else if ( ch == char(12) )
00314 {
00315
00316
continue;
00317 }
00318
else
00319 {
00320 strLine += ch;
00321 lastCharWasCr =
false;
00322 }
00323 }
00324
return strLine;
00325 }
00326
00327
00328
bool KoPictureEps::load(
const QByteArray& array,
const QString& )
00329 {
00330
00331 kdDebug(30003) <<
"KoPictureEps::load" << endl;
00332
00333 m_rawData=array;
00334
00335
if (m_rawData.isNull())
00336 {
00337 kdError(30003) <<
"No data was loaded!" << endl;
00338
return false;
00339 }
00340
00341
if ( ( m_rawData[0]==char(0xc5) ) && ( m_rawData[1]==char(0xd0) )
00342 && ( m_rawData[2]==char(0xd3) ) && ( m_rawData[3]==char(0xc6) ) )
00343 {
00344
00345
if (!extractPostScriptStream())
00346
return false;
00347 }
00348
else
00349 {
00350 m_psStreamStart = 0;
00351 m_psStreamLength = m_rawData.size();
00352 }
00353
00354 QString lineBox;
00355
bool lastWasCr =
false;
00356 uint pos = m_psStreamStart;
00357 QString line( readLine( m_rawData, m_psStreamStart, m_psStreamLength, pos, lastWasCr ) );
00358 kdDebug(30003) <<
"Header: " << line << endl;
00359
if (!line.startsWith(
"%!"))
00360 {
00361 kdError(30003) <<
"Not a PostScript file!" << endl;
00362
return false;
00363 }
00364
QRect rect;
00365
for(;;)
00366 {
00367 ++pos;
00368 line = readLine( m_rawData, m_psStreamStart, m_psStreamLength, pos, lastWasCr );
00369 kdDebug(30003) <<
"Checking line: " << line << endl;
00370
00371
if (line.startsWith(
"%%BoundingBox:"))
00372 {
00373 lineBox=line;
00374
break;
00375 }
00376
else if (!line.startsWith(
"%%"))
00377
break;
00378 }
00379
if (lineBox.isEmpty())
00380 {
00381 kdError(30003) <<
"KoPictureEps::load: could not find bounding box!" << endl;
00382
return false;
00383 }
00384
QRegExp exp(
"(\\-?[0-9]+\\.?[0-9]*)\\s(\\-?[0-9]+\\.?[0-9]*)\\s(\\-?[0-9]+\\.?[0-9]*)\\s(\\-?[0-9]+\\.?[0-9]*)");
00385
00386 exp.search(lineBox);
00387 kdDebug(30003) <<
"Reg. Exp. Found: " << exp.capturedTexts() << endl;
00388 rect.setLeft((
int)exp.cap(1).toDouble());
00389 rect.setTop((
int)exp.cap(2).toDouble());
00390 rect.setRight((
int)exp.cap(3).toDouble());
00391 rect.setBottom((
int)exp.cap(4).toDouble());
00392 m_boundingBox=rect;
00393 m_originalSize=rect.size();
00394 kdDebug(30003) <<
"Rect: " << rect <<
" Size: " << m_originalSize << endl;
00395
return true;
00396 }
00397
00398
bool KoPictureEps::save(
QIODevice* io)
00399 {
00400
00401 Q_ULONG size=io->writeBlock(m_rawData);
00402
return (size==m_rawData.size());
00403 }
00404
00405
QSize KoPictureEps::getOriginalSize(
void)
const
00406
{
00407
return m_originalSize;
00408 }
00409
00410
QPixmap KoPictureEps::generatePixmap(
const QSize& size,
bool smoothScale)
00411 {
00412 scaleAndCreatePixmap(size,!smoothScale, 0, 0);
00413
return m_cachedPixmap;
00414 }
00415
00416 QString KoPictureEps::getMimeType(
const QString&)
const
00417
{
00418
return "image/x-eps";
00419 }
00420
00421
QImage KoPictureEps::generateImage(
const QSize& size)
00422 {
00423
00424
return scaleWithGhostScript(size, 0, 0);
00425 }
00426
00427
void KoPictureEps::clearCache(
void)
00428 {
00429 m_cachedPixmap.resize(0, 0);
00430 m_cacheIsInFastMode=
true;
00431 m_cachedSize=
QSize();
00432 }