/* This file is part of the KDE project Copyright (c) 2001 Simon Hausmann Copyright (C) 2002, 2003, 2004 Nicolas GOUTTE This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; see the file COPYING.LIB. If not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, * Boston, MA 02110-1301, USA. */ #include #include #include #include #include #include #include "KoPictureKey.h" #include "KoPictureBase.h" #include "KoPictureImage.h" #include "KoPictureEps.h" #include "KoPictureClipart.h" #include "KoPictureWmf.h" #include "KoPictureShared.h" #include KoPictureShared::KoPictureShared(void) : m_base(NULL) { } void KoPictureShared::assignPictureId( uint _id) { m_pictureId = _id; } TQString KoPictureShared::uniquePictureId() const { return "Pictures"+ TQString::number(m_pictureId); } KoPictureShared::~KoPictureShared(void) { delete m_base; } KoPictureShared::KoPictureShared(const KoPictureShared &other) : TQShared() // Some compilers want it explicitly! { // We need to use newCopy, because we want a real copy, not just a copy of the part of KoPictureBase if (other.m_base) m_base=other.m_base->newCopy(); else m_base=NULL; } KoPictureShared& KoPictureShared::operator=( const KoPictureShared &other ) { clear(); kdDebug(30003) << "KoPictureShared::= before" << endl; if (other.m_base) m_base=other.m_base->newCopy(); kdDebug(30003) << "KoPictureShared::= after" << endl; return *this; } KoPictureType::Type KoPictureShared::getType(void) const { if (m_base) return m_base->getType(); return KoPictureType::TypeUnknown; } bool KoPictureShared::isNull(void) const { if (m_base) return m_base->isNull(); return true; } void KoPictureShared::draw(TQPainter& painter, int x, int y, int width, int height, int sx, int sy, int sw, int sh, bool fastMode) { if (m_base) m_base->draw(painter, x, y, width, height, sx, sy, sw, sh, fastMode); else { // Draw a red box (easier DEBUG) kdWarning(30003) << "Drawing red rectangle! (KoPictureShared::draw)" << endl; painter.save(); painter.setBrush(TQColor(255,0,0)); painter.drawRect(x,y,width,height); painter.restore(); } } bool KoPictureShared::loadWmf(TQIODevice* io) { kdDebug(30003) << "KoPictureShared::loadWmf" << endl; if (!io) { kdError(30003) << "No TQIODevice!" << endl; return false; } clear(); // The extension .wmf was used (KOffice 1.1.x) for TQPicture files // For an extern file or in the storage, .wmf can mean a real Windows Meta File. TQByteArray array ( io->readAll() ); if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C')) { m_base=new KoPictureClipart(); setExtension("qpic"); } else { m_base=new KoPictureWmf(); setExtension("wmf"); } return m_base->loadData(array, m_extension); } bool KoPictureShared::loadTmp(TQIODevice* io) // We have a temp file, probably from a downloaded file // We must check the file type { kdDebug(30003) << "KoPictureShared::loadTmp" << endl; if (!io) { kdError(30003) << "No TQIODevice!" << endl; return false; } // The extension .wmf was used (KOffice 1.1.x) for TQPicture files // For an extern file or in the storage, .wmf can mean a real Windows Meta File. TQByteArray array ( io->readAll() ); return identifyAndLoad( array ); } bool KoPictureShared::identifyAndLoad( TQByteArray array ) { if ( array.size() < 5 ) { kdError(30003) << "Picture is less than 5 bytes long!" << endl; return false; } TQString strExtension; bool flag=false; // Try to find the file type by comparing magic on the first few bytes! // ### TODO: could not TQImageIO::imageFormat do it too? (At least most of them?) if ((array[0]==char(0x89)) && (array[1]=='P') &&(array[2]=='N') && (array[3]=='G')) { strExtension="png"; } else if ((array[0]==char(0xff)) && (array[1]==char(0xd8)) &&(array[2]==char(0xff)) && (array[3]==char(0xe0))) { strExtension="jpeg"; } else if ((array[0]=='B') && (array[1]=='M')) { strExtension="bmp"; } else if ((array[0]==char(0xd7)) && (array[1]==char(0xcd)) &&(array[2]==char(0xc6)) && (array[3]==char(0x9a))) { strExtension="wmf"; } else if ((array[0]=='<') && (array[1]=='?') && ( array[2]=='x' ) && (array[3]=='m') && ( array[4]=='l' ) ) { strExtension="svg"; } else if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C')) { strExtension="qpic"; } else if ((array[0]=='%') && (array[1]=='!') &&(array[2]=='P') && (array[3]=='S')) { strExtension="eps"; } else if ((array[0]==char(0xc5)) && (array[1]==char(0xd0)) && (array[2]==char(0xd3)) && (array[3]==char(0xc6))) { // So called "MS-DOS EPS file" strExtension="eps"; } else if ((array[0]=='G') && (array[1]=='I') && (array[2]=='F') && (array[3]=='8')) { // GIF (87a or 89a) strExtension="gif"; } else if ( ( array[0] == char( 0037 ) ) && ( array[1] == char( 0213 ) ) ) { // Gzip TQBuffer buffer(array); buffer.open(IO_ReadOnly); const bool flag = loadCompressed( &buffer, "application/x-gzip", "tmp" ); buffer.close(); return flag; } else if ( ( array[0] == 'B' ) && ( array[1] == 'Z' ) && ( array[2] == 'h') ) { // BZip2 TQBuffer buffer(array); buffer.open(IO_ReadOnly); const bool flag = loadCompressed( &buffer, "application/x-bzip2", "tmp" ); buffer.close(); return flag; } else { kdDebug(30003) << "Cannot identify the type of temp file!" << " Trying to convert to PNG! (in KoPictureShared::loadTmp" << endl; // Do not trust TQBuffer and do not work directly on the TQByteArray array // DF: It would be faster to work on array here, and to create a completely // different TQBuffer for the writing code! TQBuffer buf( array.copy() ); if (!buf.open(IO_ReadOnly)) { kdError(30003) << "Could not open read buffer!" << endl; return false; } TQImageIO imageIO(&buf,NULL); if (!imageIO.read()) { kdError(30003) << "Could not read image!" << endl; return false; } buf.close(); if ( !buf.open( IO_WriteOnly | IO_Truncate ) ) { kdError(30003) << "Could not open write buffer!" << endl; return false; } imageIO.setIODevice(&buf); imageIO.setFormat("PNG"); if (!imageIO.write()) { kdError(30003) << "Could not write converted image!" << endl; return false; } buf.close(); array = buf.buffer(); strExtension="png"; } kdDebug(30003) << "Temp file considered to be " << strExtension << endl; clearAndSetMode(strExtension); if (m_base) flag = m_base->loadData(array,strExtension); setExtension(strExtension); return flag; } bool KoPictureShared::loadXpm(TQIODevice* io) { kdDebug(30003) << "KoPictureShared::loadXpm" << endl; if (!io) { kdError(30003) << "No TQIODevice!" << endl; return false; } clear(); // Old KPresenter XPM files have char(1) instead of some " // Therefore we need to treat XPM separately TQByteArray array=io->readAll(); // As XPM files are normally only ASCII files, we can replace it without problems int pos=0; while ((pos=array.find(char(1),pos))!=-1) { array[pos]='"'; } // Now that the XPM file is corrected, we need to load it. m_base=new KoPictureImage(); TQBuffer buffer(array); bool check = m_base->load(&buffer,"xpm"); setExtension("xpm"); return check; } bool KoPictureShared::save(TQIODevice* io) const { if (!io) return false; if (m_base) return m_base->save(io); return false; } bool KoPictureShared::saveAsBase64( KoXmlWriter& writer ) const { if ( m_base ) m_base->saveAsBase64( writer ); return false; } void KoPictureShared::clear(void) { // Clear does not reset the key m_key! delete m_base; m_base=NULL; } void KoPictureShared::clearAndSetMode(const TQString& newMode) { delete m_base; m_base=NULL; const TQString mode=newMode.lower(); if ((mode=="svg") || (mode=="qpic")) { m_base=new KoPictureClipart(); } else if (mode=="wmf") { m_base=new KoPictureWmf(); } else if ( (mode=="eps") || (mode=="epsi") || (mode=="epsf") ) { m_base=new KoPictureEps(); } else { // TODO: test if TQImageIO really knows the file format m_base=new KoPictureImage(); } } TQString KoPictureShared::getExtension(void) const { return m_extension; } void KoPictureShared::setExtension(const TQString& extension) { m_extension = extension; } TQString KoPictureShared::getMimeType(void) const { if (m_base) return m_base->getMimeType(m_extension); return TQString(NULL_MIME_TYPE); } bool KoPictureShared::loadFromBase64( const TQCString& str ) { clear(); TQByteArray data; KCodecs::base64Decode( str, data ); return identifyAndLoad( data ); } bool KoPictureShared::load(TQIODevice* io, const TQString& extension) { kdDebug(30003) << "KoPictureShared::load(TQIODevice*, const TQString&) " << extension << endl; bool flag=false; TQString ext(extension.lower()); if (ext=="wmf") flag=loadWmf(io); else if (ext=="tmp") // ### TODO: also remote scripts need this, don't they? flag=loadTmp(io); else if ( ext == "bz2" ) { flag = loadCompressed( io, "application/x-bzip2", "tmp" ); } else if ( ext == "gz" ) { flag = loadCompressed( io, "application/x-gzip", "tmp" ); } else if ( ext == "svgz" ) { flag = loadCompressed( io, "application/x-gzip", "svg" ); } else { clearAndSetMode(ext); if (m_base) flag = m_base->load(io, ext); setExtension(ext); } if (!flag) { kdError(30003) << "File was not loaded! (KoPictureShared::load)" << endl; } return flag; } bool KoPictureShared::loadFromFile(const TQString& fileName) { kdDebug(30003) << "KoPictureShared::loadFromFile " << fileName << endl; if ( fileName.isEmpty() ) { kdError(30003) << "Cannot load file with empty name!" << endl; return false; } TQFile file(fileName); if (!file.open(IO_ReadOnly)) return false; bool flag = false; const int pos=fileName.findRev('.'); if (pos==-1) { kdDebug(30003) << "File with no extension!" << endl; // As we have no extension, consider it like a temporary file flag = loadTmp( &file ); } else { const TQString extension( fileName.mid( pos+1 ) ); // ### TODO: check if the extension if gz or bz2 and find the previous extension flag = load( &file, extension ); } file.close(); return flag; } TQSize KoPictureShared::getOriginalSize(void) const { if (m_base) return m_base->getOriginalSize(); return TQSize(0,0); } TQPixmap KoPictureShared::generatePixmap(const TQSize& size, bool smoothScale) { if (m_base) return m_base->generatePixmap(size, smoothScale); return TQPixmap(); } TQDragObject* KoPictureShared::dragObject( TQWidget *dragSource, const char *name ) { if (m_base) return m_base->dragObject( dragSource, name ); return 0L; } TQImage KoPictureShared::generateImage(const TQSize& size) { if (m_base) return m_base->generateImage( size ); return TQImage(); } bool KoPictureShared::hasAlphaBuffer() const { if (m_base) return m_base->hasAlphaBuffer(); return false; } void KoPictureShared::setAlphaBuffer(bool enable) { if (m_base) m_base->setAlphaBuffer(enable); } TQImage KoPictureShared::createAlphaMask(int conversion_flags) const { if (m_base) return m_base->createAlphaMask(conversion_flags); return TQImage(); } void KoPictureShared::clearCache(void) { if (m_base) m_base->clearCache(); } bool KoPictureShared::loadCompressed( TQIODevice* io, const TQString& mimeType, const TQString& extension ) { // ### TODO: check that we do not have an endless recursion TQIODevice* in = KFilterDev::device( io, mimeType, false); if ( !in ) { kdError(30003) << "Cannot create device for uncompressing! Aborting!" << endl; return false; } if ( !in->open( IO_ReadOnly ) ) { kdError(30003) << "Cannot open file for uncompressing! Aborting!" << endl; delete in; return false; } const bool flag = load( in, extension ); in->close(); delete in; return flag; }