KoPictureShared.cpp
1/* This file is part of the KDE project
2 Copyright (c) 2001 Simon Hausmann <hausmann@kde.org>
3 Copyright (C) 2002, 2003, 2004 Nicolas GOUTTE <goutte@kde.org>
4
5 This library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Library General Public
7 License as published by the Free Software Foundation; either
8 version 2 of the License, or (at your option) any later version.
9
10 This library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Library General Public License for more details.
14
15 You should have received a copy of the GNU Library General Public License
16 along with this library; see the file COPYING.LIB. If not, write to
17 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02110-1301, USA.
19*/
20
21#include <tqpainter.h>
22#include <tqfile.h>
23
24#include <kdebug.h>
25#include <kurl.h>
26#include <kfilterdev.h>
27#include <tdeio/netaccess.h>
28
29#include "KoPictureKey.h"
30#include "KoPictureBase.h"
31#include "KoPictureImage.h"
32#include "KoPictureEps.h"
33#include "KoPictureClipart.h"
34#include "KoPictureWmf.h"
35#include "KoPictureShared.h"
36#include <kmdcodec.h>
37
38
39KoPictureShared::KoPictureShared(void) : m_base(NULL)
40{
41}
42
43void KoPictureShared::assignPictureId( uint _id)
44{
45 m_pictureId = _id;
46}
47
48TQString KoPictureShared::uniquePictureId() const
49{
50 return "Pictures"+ TQString::number(m_pictureId);
51}
52
53KoPictureShared::~KoPictureShared(void)
54{
55 delete m_base;
56}
57
58KoPictureShared::KoPictureShared(const KoPictureShared &other)
59 : TQShared() // Some compilers want it explicitly!
60{
61 // We need to use newCopy, because we want a real copy, not just a copy of the part of KoPictureBase
62 if (other.m_base)
63 m_base=other.m_base->newCopy();
64 else
65 m_base=NULL;
66}
67
68KoPictureShared& KoPictureShared::operator=( const KoPictureShared &other )
69{
70 clear();
71 kdDebug(30003) << "KoPictureShared::= before" << endl;
72 if (other.m_base)
73 m_base=other.m_base->newCopy();
74 kdDebug(30003) << "KoPictureShared::= after" << endl;
75 return *this;
76}
77
78KoPictureType::Type KoPictureShared::getType(void) const
79{
80 if (m_base)
81 return m_base->getType();
82 return KoPictureType::TypeUnknown;
83}
84
85bool KoPictureShared::isNull(void) const
86{
87 if (m_base)
88 return m_base->isNull();
89 return true;
90}
91
92void KoPictureShared::draw(TQPainter& painter, int x, int y, int width, int height, int sx, int sy, int sw, int sh, bool fastMode)
93{
94 if (m_base)
95 m_base->draw(painter, x, y, width, height, sx, sy, sw, sh, fastMode);
96 else
97 {
98 // Draw a red box (easier DEBUG)
99 kdWarning(30003) << "Drawing red rectangle! (KoPictureShared::draw)" << endl;
100 painter.save();
101 painter.setBrush(TQColor(255,0,0));
102 painter.drawRect(x,y,width,height);
103 painter.restore();
104 }
105}
106
107bool KoPictureShared::loadWmf(TQIODevice* io)
108{
109 kdDebug(30003) << "KoPictureShared::loadWmf" << endl;
110 if (!io)
111 {
112 kdError(30003) << "No TQIODevice!" << endl;
113 return false;
114 }
115
116 clear();
117
118 // The extension .wmf was used (KOffice 1.1.x) for TQPicture files
119 // For an extern file or in the storage, .wmf can mean a real Windows Meta File.
120
121 TQByteArray array ( io->readAll() );
122
123 if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C'))
124 {
125 m_base=new KoPictureClipart();
126 setExtension("qpic");
127 }
128 else
129 {
130 m_base=new KoPictureWmf();
131 setExtension("wmf");
132 }
133 return m_base->loadData(array, m_extension);
134}
135
136bool KoPictureShared::loadTmp(TQIODevice* io)
137// We have a temp file, probably from a downloaded file
138// We must check the file type
139{
140 kdDebug(30003) << "KoPictureShared::loadTmp" << endl;
141 if (!io)
142 {
143 kdError(30003) << "No TQIODevice!" << endl;
144 return false;
145 }
146
147 // The extension .wmf was used (KOffice 1.1.x) for TQPicture files
148 // For an extern file or in the storage, .wmf can mean a real Windows Meta File.
149
150 TQByteArray array ( io->readAll() );
151 return identifyAndLoad( array );
152}
153
154bool KoPictureShared::identifyAndLoad( TQByteArray array )
155{
156 if ( array.size() < 5 )
157 {
158 kdError(30003) << "Picture is less than 5 bytes long!" << endl;
159 return false;
160 }
161
162 TQString strExtension;
163 bool flag=false;
164
165 // Try to find the file type by comparing magic on the first few bytes!
166 // ### TODO: could not TQImageIO::imageFormat do it too? (At least most of them?)
167 if ((array[0]==char(0x89)) && (array[1]=='P') &&(array[2]=='N') && (array[3]=='G'))
168 {
169 strExtension="png";
170 }
171 else if ((array[0]==char(0xff)) && (array[1]==char(0xd8)) &&(array[2]==char(0xff)) && (array[3]==char(0xe0)))
172 {
173 strExtension="jpeg";
174 }
175 else if ((array[0]=='B') && (array[1]=='M'))
176 {
177 strExtension="bmp";
178 }
179 else if ((array[0]==char(0xd7)) && (array[1]==char(0xcd)) &&(array[2]==char(0xc6)) && (array[3]==char(0x9a)))
180 {
181 strExtension="wmf";
182 }
183 else if ((array[0]=='<') && (array[1]=='?') && ( array[2]=='x' ) && (array[3]=='m') && ( array[4]=='l' ) )
184 {
185 strExtension="svg";
186 }
187 else if ((array[0]=='Q') && (array[1]=='P') &&(array[2]=='I') && (array[3]=='C'))
188 {
189 strExtension="qpic";
190 }
191 else if ((array[0]=='%') && (array[1]=='!') &&(array[2]=='P') && (array[3]=='S'))
192 {
193 strExtension="eps";
194 }
195 else if ((array[0]==char(0xc5)) && (array[1]==char(0xd0)) && (array[2]==char(0xd3)) && (array[3]==char(0xc6)))
196 {
197 // So called "MS-DOS EPS file"
198 strExtension="eps";
199 }
200 else if ((array[0]=='G') && (array[1]=='I') && (array[2]=='F') && (array[3]=='8'))
201 {
202 // GIF (87a or 89a)
203 strExtension="gif";
204 }
205 else if ( ( array[0] == char( 0037 ) ) && ( array[1] == char( 0213 ) ) )
206 {
207 // Gzip
208 TQBuffer buffer(array);
209 buffer.open(IO_ReadOnly);
210
211 const bool flag = loadCompressed( &buffer, "application/x-gzip", "tmp" );
212 buffer.close();
213 return flag;
214 }
215 else if ( ( array[0] == 'B' ) && ( array[1] == 'Z' ) && ( array[2] == 'h') )
216 {
217 // BZip2
218 TQBuffer buffer(array);
219 buffer.open(IO_ReadOnly);
220 const bool flag = loadCompressed( &buffer, "application/x-bzip2", "tmp" );
221 buffer.close();
222 return flag;
223 }
224 else
225 {
226 kdDebug(30003) << "Cannot identify the type of temp file!"
227 << " Trying to convert to PNG! (in KoPictureShared::loadTmp" << endl;
228
229 // Do not trust TQBuffer and do not work directly on the TQByteArray array
230 // DF: It would be faster to work on array here, and to create a completely
231 // different TQBuffer for the writing code!
232 TQBuffer buf( array.copy() );
233 if (!buf.open(IO_ReadOnly))
234 {
235 kdError(30003) << "Could not open read buffer!" << endl;
236 return false;
237 }
238
239 TQImageIO imageIO(&buf,NULL);
240
241 if (!imageIO.read())
242 {
243 kdError(30003) << "Could not read image!" << endl;
244 return false;
245 }
246
247 buf.close();
248
249 if ( !buf.open( IO_WriteOnly | IO_Truncate ) )
250 {
251 kdError(30003) << "Could not open write buffer!" << endl;
252 return false;
253 }
254
255 imageIO.setIODevice(&buf);
256 imageIO.setFormat("PNG");
257
258 if (!imageIO.write())
259 {
260 kdError(30003) << "Could not write converted image!" << endl;
261 return false;
262 }
263 buf.close();
264
265 array = buf.buffer();
266
267 strExtension="png";
268 }
269
270 kdDebug(30003) << "Temp file considered to be " << strExtension << endl;
271
272 clearAndSetMode(strExtension);
273 if (m_base)
274 flag = m_base->loadData(array,strExtension);
275 setExtension(strExtension);
276
277 return flag;
278}
279
280
281
282bool KoPictureShared::loadXpm(TQIODevice* io)
283{
284 kdDebug(30003) << "KoPictureShared::loadXpm" << endl;
285 if (!io)
286 {
287 kdError(30003) << "No TQIODevice!" << endl;
288 return false;
289 }
290
291 clear();
292
293 // Old KPresenter XPM files have char(1) instead of some "
294 // Therefore we need to treat XPM separately
295
296 TQByteArray array=io->readAll();
297
298 // As XPM files are normally only ASCII files, we can replace it without problems
299
300 int pos=0;
301
302 while ((pos=array.find(char(1),pos))!=-1)
303 {
304 array[pos]='"';
305 }
306
307 // Now that the XPM file is corrected, we need to load it.
308
309 m_base=new KoPictureImage();
310
311 TQBuffer buffer(array);
312 bool check = m_base->load(&buffer,"xpm");
313 setExtension("xpm");
314 return check;
315}
316
317bool KoPictureShared::save(TQIODevice* io) const
318{
319 if (!io)
320 return false;
321 if (m_base)
322 return m_base->save(io);
323 return false;
324}
325
326bool KoPictureShared::saveAsBase64( KoXmlWriter& writer ) const
327{
328 if ( m_base )
329 m_base->saveAsBase64( writer );
330 return false;
331}
332
333void KoPictureShared::clear(void)
334{
335 // Clear does not reset the key m_key!
336 delete m_base;
337 m_base=NULL;
338}
339
340void KoPictureShared::clearAndSetMode(const TQString& newMode)
341{
342 delete m_base;
343 m_base=NULL;
344
345 const TQString mode=newMode.lower();
346
347 if ((mode=="svg") || (mode=="qpic"))
348 {
349 m_base=new KoPictureClipart();
350 }
351 else if (mode=="wmf")
352 {
353 m_base=new KoPictureWmf();
354 }
355 else if ( (mode=="eps") || (mode=="epsi") || (mode=="epsf") )
356 {
357 m_base=new KoPictureEps();
358 }
359 else
360 { // TODO: test if TQImageIO really knows the file format
361 m_base=new KoPictureImage();
362 }
363}
364
365TQString KoPictureShared::getExtension(void) const
366{
367 return m_extension;
368}
369
370void KoPictureShared::setExtension(const TQString& extension)
371{
372 m_extension = extension;
373}
374
375TQString KoPictureShared::getMimeType(void) const
376{
377 if (m_base)
378 return m_base->getMimeType(m_extension);
379 return TQString(NULL_MIME_TYPE);
380}
381
382
383bool KoPictureShared::loadFromBase64( const TQCString& str )
384{
385 clear();
386 TQByteArray data;
387 KCodecs::base64Decode( str, data );
388 return identifyAndLoad( data );
389}
390
391bool KoPictureShared::load(TQIODevice* io, const TQString& extension)
392{
393 kdDebug(30003) << "KoPictureShared::load(TQIODevice*, const TQString&) " << extension << endl;
394 bool flag=false;
395 TQString ext(extension.lower());
396 if (ext=="wmf")
397 flag=loadWmf(io);
398 else if (ext=="tmp") // ### TODO: also remote scripts need this, don't they?
399 flag=loadTmp(io);
400 else if ( ext == "bz2" )
401 {
402 flag = loadCompressed( io, "application/x-bzip2", "tmp" );
403 }
404 else if ( ext == "gz" )
405 {
406 flag = loadCompressed( io, "application/x-gzip", "tmp" );
407 }
408 else if ( ext == "svgz" )
409 {
410 flag = loadCompressed( io, "application/x-gzip", "svg" );
411 }
412 else
413 {
414 clearAndSetMode(ext);
415 if (m_base)
416 flag = m_base->load(io, ext);
417 setExtension(ext);
418 }
419 if (!flag)
420 {
421 kdError(30003) << "File was not loaded! (KoPictureShared::load)" << endl;
422 }
423 return flag;
424}
425
426bool KoPictureShared::loadFromFile(const TQString& fileName)
427{
428 kdDebug(30003) << "KoPictureShared::loadFromFile " << fileName << endl;
429 if ( fileName.isEmpty() )
430 {
431 kdError(30003) << "Cannot load file with empty name!" << endl;
432 return false;
433 }
434 TQFile file(fileName);
435 if (!file.open(IO_ReadOnly))
436 return false;
437
438 bool flag = false;
439 const int pos=fileName.findRev('.');
440 if (pos==-1)
441 {
442 kdDebug(30003) << "File with no extension!" << endl;
443 // As we have no extension, consider it like a temporary file
444 flag = loadTmp( &file );
445 }
446 else
447 {
448 const TQString extension( fileName.mid( pos+1 ) );
449 // ### TODO: check if the extension if gz or bz2 and find the previous extension
450 flag = load( &file, extension );
451 }
452 file.close();
453 return flag;
454}
455
456TQSize KoPictureShared::getOriginalSize(void) const
457{
458 if (m_base)
459 return m_base->getOriginalSize();
460 return TQSize(0,0);
461}
462
463TQPixmap KoPictureShared::generatePixmap(const TQSize& size, bool smoothScale)
464{
465 if (m_base)
466 return m_base->generatePixmap(size, smoothScale);
467 return TQPixmap();
468}
469
470TQDragObject* KoPictureShared::dragObject( TQWidget *dragSource, const char *name )
471{
472 if (m_base)
473 return m_base->dragObject( dragSource, name );
474 return 0L;
475}
476
477TQImage KoPictureShared::generateImage(const TQSize& size)
478{
479 if (m_base)
480 return m_base->generateImage( size );
481 return TQImage();
482}
483
484bool KoPictureShared::hasAlphaBuffer() const
485{
486 if (m_base)
487 return m_base->hasAlphaBuffer();
488 return false;
489}
490
491void KoPictureShared::setAlphaBuffer(bool enable)
492{
493 if (m_base)
494 m_base->setAlphaBuffer(enable);
495}
496
497TQImage KoPictureShared::createAlphaMask(int conversion_flags) const
498{
499 if (m_base)
500 return m_base->createAlphaMask(conversion_flags);
501 return TQImage();
502}
503
504void KoPictureShared::clearCache(void)
505{
506 if (m_base)
507 m_base->clearCache();
508}
509
510bool KoPictureShared::loadCompressed( TQIODevice* io, const TQString& mimeType, const TQString& extension )
511{
512 // ### TODO: check that we do not have an endless recursion
513 TQIODevice* in = KFilterDev::device( io, mimeType, false);
514
515 if ( !in )
516 {
517 kdError(30003) << "Cannot create device for uncompressing! Aborting!" << endl;
518 return false;
519 }
520
521
522 if ( !in->open( IO_ReadOnly ) )
523 {
524 kdError(30003) << "Cannot open file for uncompressing! Aborting!" << endl;
525 delete in;
526 return false;
527 }
528
529 const bool flag = load( in, extension );
530
531 in->close();
532 delete in;
533
534 return flag;
535}
A class for writing out XML (to any TQIODevice), with a special attention on performance.
Definition KoXmlWriter.h:37
TDEAction * clear(const TQObject *recvr, const char *slot, TDEActionCollection *parent, const char *name=0)