lib

KoPictureShared.cpp

00001 /* This file is part of the KDE project
00002    Copyright (c) 2001 Simon Hausmann <hausmann@kde.org>
00003    Copyright (C) 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
00004 
00005    This library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Library General Public
00007    License as published by the Free Software Foundation; either
00008    version 2 of the License, or (at your option) any later version.
00009 
00010    This library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Library General Public License for more details.
00014 
00015    You should have received a copy of the GNU Library General Public License
00016    along with this library; see the file COPYING.LIB.  If not, write to
00017    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018  * Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include <qpainter.h>
00022 #include <qfile.h>
00023 
00024 #include <kdebug.h>
00025 #include <kurl.h>
00026 #include <kfilterdev.h>
00027 #include <kio/netaccess.h>
00028 
00029 #include "KoPictureKey.h"
00030 #include "KoPictureBase.h"
00031 #include "KoPictureImage.h"
00032 #include "KoPictureEps.h"
00033 #include "KoPictureClipart.h"
00034 #include "KoPictureWmf.h"
00035 #include "KoPictureShared.h"
00036 #include <kmdcodec.h>
00037 
00038 
00039 KoPictureShared::KoPictureShared(void) : m_base(NULL)
00040 {
00041 }
00042 
00043 void KoPictureShared::assignPictureId( uint _id)
00044 {
00045     m_pictureId = _id;
00046 }
00047 
00048 QString KoPictureShared::uniquePictureId() const
00049 {
00050     return "Pictures"+ QString::number(m_pictureId);
00051 }
00052 
00053 KoPictureShared::~KoPictureShared(void)
00054 {
00055     delete m_base;
00056 }
00057 
00058 KoPictureShared::KoPictureShared(const KoPictureShared &other)
00059     : QShared() // Some compilers want it explicitly!
00060 {
00061     // We need to use newCopy, because we want a real copy, not just a copy of the part of KoPictureBase
00062     if (other.m_base)
00063         m_base=other.m_base->newCopy();
00064     else
00065         m_base=NULL;
00066 }
00067 
00068 KoPictureShared& KoPictureShared::operator=( const KoPictureShared &other )
00069 {
00070     clear();
00071     kdDebug(30003) << "KoPictureShared::= before" << endl;
00072     if (other.m_base)
00073         m_base=other.m_base->newCopy();
00074     kdDebug(30003) << "KoPictureShared::= after" << endl;
00075     return *this;
00076 }
00077 
00078 KoPictureType::Type KoPictureShared::getType(void) const
00079 {
00080     if (m_base)
00081         return m_base->getType();
00082     return KoPictureType::TypeUnknown;
00083 }
00084 
00085 bool KoPictureShared::isNull(void) const
00086 {
00087     if (m_base)
00088         return m_base->isNull();
00089     return true;
00090 }
00091 
00092 void KoPictureShared::draw(QPainter& painter, int x, int y, int width, int height, int sx, int sy, int sw, int sh, bool fastMode)
00093 {
00094     if (m_base)
00095         m_base->draw(painter, x, y, width, height, sx, sy, sw, sh, fastMode);
00096     else
00097     {
00098         // Draw a red box (easier DEBUG)
00099         kdWarning(30003) << "Drawing red rectangle! (KoPictureShared::draw)" << endl;
00100         painter.save();
00101         painter.setBrush(QColor(255,0,0));
00102         painter.drawRect(x,y,width,height);
00103         painter.restore();
00104     }
00105 }
00106 
00107 bool KoPictureShared::loadWmf(QIODevice* io)
00108 {
00109     kdDebug(30003) << "KoPictureShared::loadWmf" << endl;
00110     if (!io)
00111     {
00112         kdError(30003) << "No QIODevice!" << endl;
00113         return false;
00114     }
00115 
00116     clear();
00117 
00118     // The extension .wmf was used (KOffice 1.1.x) for QPicture files
00119     // For an extern file or in the storage, .wmf can mean a real Windows Meta File.
00120 
00121     QByteArray array ( io->readAll() );
00122 
00123     if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C'))
00124     {
00125         m_base=new KoPictureClipart();
00126         setExtension("qpic");
00127     }
00128     else
00129     {
00130         m_base=new KoPictureWmf();
00131         setExtension("wmf");
00132     }
00133     return m_base->loadData(array, m_extension);
00134 }
00135 
00136 bool KoPictureShared::loadTmp(QIODevice* io)
00137 // We have a temp file, probably from a downloaded file
00138 //   We must check the file type
00139 {
00140     kdDebug(30003) << "KoPictureShared::loadTmp" << endl;
00141     if (!io)
00142     {
00143         kdError(30003) << "No QIODevice!" << endl;
00144         return false;
00145     }
00146 
00147     // The extension .wmf was used (KOffice 1.1.x) for QPicture files
00148     // For an extern file or in the storage, .wmf can mean a real Windows Meta File.
00149 
00150     QByteArray array ( io->readAll() );
00151     return identifyAndLoad( array );
00152 }
00153 
00154 bool KoPictureShared::identifyAndLoad( QByteArray array )
00155 {
00156     if ( array.size() < 5 )
00157     {
00158         kdError(30003) << "Picture is less than 5 bytes long!" << endl;
00159         return false;
00160     }
00161 
00162     QString strExtension;
00163     bool flag=false;
00164 
00165     // Try to find the file type by comparing magic on the first few bytes!
00166     // ### TODO: could not QImageIO::imageFormat do it too? (At least most of them?)
00167     if ((array[0]==char(0x89)) && (array[1]=='P') &&(array[2]=='N') && (array[3]=='G'))
00168     {
00169         strExtension="png";
00170     }
00171     else if ((array[0]==char(0xff)) && (array[1]==char(0xd8)) &&(array[2]==char(0xff)) && (array[3]==char(0xe0)))
00172     {
00173         strExtension="jpeg";
00174     }
00175     else if ((array[0]=='B') && (array[1]=='M'))
00176     {
00177         strExtension="bmp";
00178     }
00179     else if ((array[0]==char(0xd7)) && (array[1]==char(0xcd)) &&(array[2]==char(0xc6)) && (array[3]==char(0x9a)))
00180     {
00181         strExtension="wmf";
00182     }
00183     else if ((array[0]=='<') && (array[1]=='?') && ( array[2]=='x' ) && (array[3]=='m') && ( array[4]=='l' ) )
00184     {
00185         strExtension="svg";
00186     }
00187     else if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C'))
00188     {
00189         strExtension="qpic";
00190     }
00191     else if ((array[0]=='%') && (array[1]=='!') &&(array[2]=='P') && (array[3]=='S'))
00192     {
00193         strExtension="eps";
00194     }
00195     else if ((array[0]==char(0xc5)) && (array[1]==char(0xd0)) && (array[2]==char(0xd3)) && (array[3]==char(0xc6)))
00196     {
00197         // So called "MS-DOS EPS file"
00198         strExtension="eps";
00199     }
00200     else if ((array[0]=='G') && (array[1]=='I') && (array[2]=='F') && (array[3]=='8'))
00201     {
00202         // GIF (87a or 89a)
00203         strExtension="gif";
00204     }
00205     else if ( ( array[0] == char( 0037 ) ) && ( array[1] == char( 0213 ) ) )
00206     {
00207         // Gzip
00208         QBuffer buffer(array);
00209         buffer.open(IO_ReadOnly);
00210 
00211         const bool flag = loadCompressed( &buffer, "application/x-gzip", "tmp" );
00212         buffer.close();
00213         return flag;
00214     }
00215     else if ( ( array[0] == 'B' ) && ( array[1] == 'Z' ) && ( array[2] == 'h') )
00216     {
00217         // BZip2
00218         QBuffer buffer(array);
00219         buffer.open(IO_ReadOnly);
00220         const bool flag = loadCompressed( &buffer, "application/x-bzip2", "tmp" );
00221         buffer.close();
00222         return flag;
00223     }
00224     else
00225     {
00226         kdDebug(30003) << "Cannot identify the type of temp file!"
00227             << " Trying to convert to PNG! (in KoPictureShared::loadTmp" << endl;
00228 
00229         // Do not trust QBuffer and do not work directly on the QByteArray array
00230         // DF: It would be faster to work on array here, and to create a completely
00231         // different QBuffer for the writing code!
00232         QBuffer buf( array.copy() );
00233         if (!buf.open(IO_ReadOnly))
00234         {
00235             kdError(30003) << "Could not open read buffer!" << endl;
00236             return false;
00237         }
00238 
00239         QImageIO imageIO(&buf,NULL);
00240 
00241         if (!imageIO.read())
00242         {
00243             kdError(30003) << "Could not read image!" << endl;
00244             return false;
00245         }
00246 
00247         buf.close();
00248 
00249         if ( !buf.open( IO_WriteOnly | IO_Truncate ) )
00250         {
00251             kdError(30003) << "Could not open write buffer!" << endl;
00252             return false;
00253         }
00254 
00255         imageIO.setIODevice(&buf);
00256         imageIO.setFormat("PNG");
00257 
00258         if (!imageIO.write())
00259         {
00260             kdError(30003) << "Could not write converted image!" << endl;
00261             return false;
00262         }
00263         buf.close();
00264 
00265         array = buf.buffer();
00266 
00267         strExtension="png";
00268     }
00269 
00270     kdDebug(30003) << "Temp file considered to be " << strExtension << endl;
00271 
00272     clearAndSetMode(strExtension);
00273     if (m_base)
00274         flag = m_base->loadData(array,strExtension);
00275     setExtension(strExtension);
00276 
00277     return flag;
00278 }
00279 
00280 
00281 
00282 bool KoPictureShared::loadXpm(QIODevice* io)
00283 {
00284     kdDebug(30003) << "KoPictureShared::loadXpm" << endl;
00285     if (!io)
00286     {
00287         kdError(30003) << "No QIODevice!" << endl;
00288         return false;
00289     }
00290 
00291     clear();
00292 
00293     // Old KPresenter XPM files have char(1) instead of some "
00294     // Therefore we need to treat XPM separately
00295 
00296     QByteArray array=io->readAll();
00297 
00298     // As XPM files are normally only ASCII files, we can replace it without problems
00299 
00300     int pos=0;
00301 
00302     while ((pos=array.find(char(1),pos))!=-1)
00303     {
00304         array[pos]='"';
00305     }
00306 
00307     // Now that the XPM file is corrected, we need to load it.
00308 
00309     m_base=new KoPictureImage();
00310 
00311     QBuffer buffer(array);
00312     bool check = m_base->load(&buffer,"xpm");
00313     setExtension("xpm");
00314     return check;
00315 }
00316 
00317 bool KoPictureShared::save(QIODevice* io) const
00318 {
00319     if (!io)
00320         return false;
00321     if (m_base)
00322         return m_base->save(io);
00323     return false;
00324 }
00325 
00326 bool KoPictureShared::saveAsBase64( KoXmlWriter& writer ) const
00327 {
00328     if ( m_base )
00329         m_base->saveAsBase64( writer );
00330     return false;
00331 }
00332 
00333 void KoPictureShared::clear(void)
00334 {
00335     // Clear does not reset the key m_key!
00336     delete m_base;
00337     m_base=NULL;
00338 }
00339 
00340 void KoPictureShared::clearAndSetMode(const QString& newMode)
00341 {
00342     delete m_base;
00343     m_base=NULL;
00344 
00345     const QString mode=newMode.lower();
00346 
00347     if ((mode=="svg") || (mode=="qpic"))
00348     {
00349         m_base=new KoPictureClipart();
00350     }
00351     else if (mode=="wmf")
00352     {
00353         m_base=new KoPictureWmf();
00354     }
00355     else if ( (mode=="eps") || (mode=="epsi") || (mode=="epsf") )
00356     {
00357         m_base=new KoPictureEps();
00358     }
00359     else
00360     {   // TODO: test if QImageIO really knows the file format
00361         m_base=new KoPictureImage();
00362     }
00363 }
00364 
00365 QString KoPictureShared::getExtension(void) const
00366 {
00367     return m_extension;
00368 }
00369 
00370 void KoPictureShared::setExtension(const QString& extension)
00371 {
00372     m_extension = extension;
00373 }
00374 
00375 QString KoPictureShared::getMimeType(void) const
00376 {
00377    if (m_base)
00378         return m_base->getMimeType(m_extension);
00379     return QString(NULL_MIME_TYPE);
00380 }
00381 
00382 
00383 bool KoPictureShared::loadFromBase64( const QCString& str )
00384 {
00385     clear();
00386     QByteArray data;
00387     KCodecs::base64Decode( str, data );
00388     return identifyAndLoad( data );
00389 }
00390 
00391 bool KoPictureShared::load(QIODevice* io, const QString& extension)
00392 {
00393     kdDebug(30003) << "KoPictureShared::load(QIODevice*, const QString&) " << extension << endl;
00394     bool flag=false;
00395     QString ext(extension.lower());
00396     if (ext=="wmf")
00397         flag=loadWmf(io);
00398     else if (ext=="tmp") // ### TODO: also remote scripts need this, don't they?
00399         flag=loadTmp(io);
00400     else if ( ext == "bz2" )
00401     {
00402         flag = loadCompressed( io, "application/x-bzip2", "tmp" );
00403     }
00404     else if ( ext == "gz" )
00405     {
00406         flag = loadCompressed( io, "application/x-gzip", "tmp" );
00407     }
00408     else if ( ext == "svgz" )
00409     {
00410         flag = loadCompressed( io, "application/x-gzip", "svg" );
00411     }
00412     else
00413     {
00414         clearAndSetMode(ext);
00415         if (m_base)
00416             flag = m_base->load(io, ext);
00417         setExtension(ext);
00418     }
00419     if (!flag)
00420     {
00421         kdError(30003) << "File was not loaded! (KoPictureShared::load)" << endl;
00422     }
00423     return flag;
00424 }
00425 
00426 bool KoPictureShared::loadFromFile(const QString& fileName)
00427 {
00428     kdDebug(30003) << "KoPictureShared::loadFromFile " << fileName << endl;
00429     if ( fileName.isEmpty() )
00430     {
00431         kdError(30003) << "Cannot load file with empty name!" << endl;
00432         return false;
00433     }
00434     QFile file(fileName);
00435     if (!file.open(IO_ReadOnly))
00436         return false;
00437 
00438     bool flag = false;
00439     const int pos=fileName.findRev('.');
00440     if (pos==-1)
00441     {
00442         kdDebug(30003) << "File with no extension!" << endl;
00443         // As we have no extension, consider it like a temporary file
00444         flag = loadTmp( &file );
00445     }
00446     else
00447     {
00448         const QString extension( fileName.mid( pos+1 ) );
00449         // ### TODO: check if the extension if gz or bz2 and find the previous extension
00450         flag = load( &file, extension );
00451     }
00452     file.close();
00453     return flag;
00454 }
00455 
00456 QSize KoPictureShared::getOriginalSize(void) const
00457 {
00458     if (m_base)
00459         return m_base->getOriginalSize();
00460     return QSize(0,0);
00461 }
00462 
00463 QPixmap KoPictureShared::generatePixmap(const QSize& size, bool smoothScale)
00464 {
00465     if (m_base)
00466         return m_base->generatePixmap(size, smoothScale);
00467     return QPixmap();
00468 }
00469 
00470 QDragObject* KoPictureShared::dragObject( QWidget *dragSource, const char *name )
00471 {
00472     if (m_base)
00473         return m_base->dragObject( dragSource, name );
00474     return 0L;
00475 }
00476 
00477 QImage KoPictureShared::generateImage(const QSize& size)
00478 {
00479     if (m_base)
00480         return m_base->generateImage( size );
00481     return QImage();
00482 }
00483 
00484 bool KoPictureShared::hasAlphaBuffer() const
00485 {
00486    if (m_base)
00487        return m_base->hasAlphaBuffer();
00488    return false;
00489 }
00490 
00491 void KoPictureShared::setAlphaBuffer(bool enable)
00492 {
00493     if (m_base)
00494         m_base->setAlphaBuffer(enable);
00495 }
00496 
00497 QImage KoPictureShared::createAlphaMask(int conversion_flags) const
00498 {
00499     if (m_base)
00500         return m_base->createAlphaMask(conversion_flags);
00501     return QImage();
00502 }
00503 
00504 void KoPictureShared::clearCache(void)
00505 {
00506     if (m_base)
00507         m_base->clearCache();
00508 }
00509 
00510 bool KoPictureShared::loadCompressed( QIODevice* io, const QString& mimeType, const QString& extension )
00511 {
00512     // ### TODO: check that we do not have an endless recursion
00513     QIODevice* in = KFilterDev::device( io, mimeType, false);
00514 
00515     if ( !in )
00516     {
00517         kdError(30003) << "Cannot create device for uncompressing! Aborting!" << endl;
00518         return false;
00519     }
00520 
00521 
00522     if ( !in->open( IO_ReadOnly ) )
00523     {
00524         kdError(30003) << "Cannot open file for uncompressing! Aborting!" << endl;
00525         delete in;
00526         return false;
00527     }
00528 
00529     const bool flag = load( in, extension );
00530 
00531     in->close();
00532     delete in;
00533 
00534     return flag;
00535 }
KDE Home | KDE Accessibility Home | Description of Access Keys