1 /* This file is part of the KDE libraries
2 Copyright (C) 2000 Malte Starostik <malte@kde.org>
3 2000 Carsten Pfeiffer <pfeiffer@kde.org>
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.
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.
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.
21 #include "thumbnail.h"
26 #include <machine/param.h>
28 #include <sys/types.h>
34 #include <QtCore/QBuffer>
35 #include <QtCore/QFile>
36 #include <QtGui/QBitmap>
37 #include <QtGui/QImage>
38 #include <QtGui/QPainter>
39 #include <QtGui/QPixmap>
42 #include <kapplication.h>
43 #include <kcmdlineargs.h>
44 #include <kaboutdata.h>
46 #include <kiconloader.h>
47 #include <kmimetype.h>
48 #include <klibloader.h>
51 #include <kservicetype.h>
52 #include <kservicetypetrader.h>
53 #include <kmimetypetrader.h>
54 #include <kfilemetainfo.h>
57 #include <config-runtime.h> // For HAVE_NICE
58 #include <kio/thumbcreator.h>
59 #include <kconfiggroup.h>
61 // Use correctly KComponentData instead of KApplication (but then no QPixmap)
63 // Fix thumbnail: protocol
64 #define THUMBNAIL_HACK (1)
70 // Recognized metadata entries:
71 // mimeType - the mime type of the file, used for the overlay icon if any
72 // width - maximum width for the thumbnail
73 // height - maximum height for the thumbnail
74 // iconSize - the size of the overlay icon to use if any
75 // iconAlpha - the transparency value used for icon overlays
76 // plugin - the name of the plugin library to be used for thumbnail creation.
77 // Provided by the application to save an addition KTrader
79 // shmid - the shared memory segment id to write the image's data to.
80 // The segment is assumed to provide enough space for a 32-bit
81 // image sized width x height pixels.
82 // If this is given, the data returned by the slave will be:
86 // Otherwise, the data returned is the image in PNG format.
92 KDE_EXPORT
int kdemain(int argc
, char **argv
);
96 int kdemain(int argc
, char **argv
)
103 KComponentData
componentData("kio_thumbnail");
105 // creating KApplication in a slave in not a very good idea,
106 // as dispatchLoop() doesn't allow it to process its messages,
107 // so it for example wouldn't reply to ksmserver - on the other
108 // hand, this slave uses QPixmaps for some reason, and they
110 // and HTML previews need even KApplication :(
111 putenv(strdup("SESSION_MANAGER="));
112 //KApplication::disableAutoDcopRegistration();
113 KAboutData
about("kio_thumbnail", 0, ki18n("kio_thumbmail"), "KDE 4.x.x");
114 KCmdLineArgs::init(&about
);
116 KApplication
app( true);
121 kError(7115) << "Usage: kio_thumbnail protocol domain-socket1 domain-socket2" << endl
;
125 ThumbnailProtocol
slave(argv
[2], argv
[3]);
126 slave
.dispatchLoop();
131 ThumbnailProtocol::ThumbnailProtocol(const QByteArray
&pool
, const QByteArray
&app
)
132 : SlaveBase("thumbnail", pool
, app
)
137 ThumbnailProtocol::~ThumbnailProtocol()
139 qDeleteAll( m_creators
);
143 void ThumbnailProtocol::get(const KUrl
&url
)
145 m_mimeType
= metaData("mimeType");
146 kDebug(7115) << "Wanting MIME Type:" << m_mimeType
;
147 #ifdef THUMBNAIL_HACK
150 if (m_mimeType
.isEmpty())
152 kDebug(7115) << "PATH: " << url
.path();
153 QFileInfo
info(url
.path());
156 // We cannot process a directory
157 error(KIO::ERR_IS_DIRECTORY
,url
.path());
160 else if (!info
.exists())
162 // The file does not exist
163 error(KIO::ERR_DOES_NOT_EXIST
,url
.path());
166 else if (!info
.isReadable())
168 // The file is not readable!
169 error(KIO::ERR_COULD_NOT_READ
,url
.path());
172 m_mimeType
= KMimeType::findByUrl(url
)->name();
173 kDebug(7115) << "Guessing MIME Type:" << m_mimeType
;
174 direct
=true; // thumbnail: was probably called from Konqueror
178 if (m_mimeType
.isEmpty())
180 error(KIO::ERR_INTERNAL
, i18n("No MIME Type specified."));
184 m_width
= metaData("width").toInt();
185 m_height
= metaData("height").toInt();
186 int iconSize
= metaData("iconSize").toInt();
188 if (m_width
< 0 || m_height
< 0)
190 error(KIO::ERR_INTERNAL
, i18n("No or invalid size specified."));
193 #ifdef THUMBNAIL_HACK
194 else if (!m_width
|| !m_height
)
196 kDebug(7115) << "Guessing height, width, icon size!";
204 iconSize
= KIconLoader::global()->currentSize(KIconLoader::Desktop
);
205 if (iconSize
!= m_iconSize
) {
208 m_iconSize
= iconSize
;
210 m_iconAlpha
= metaData("iconAlpha").toInt();
214 KConfigGroup
group( KGlobal::config(), "PreviewSettings" );
218 bool kfmiThumb
= false;
219 if (group
.readEntry( "UseFileThumbnails", true)) {
220 KService::Ptr service
=
221 KMimeTypeTrader::self()->preferredService( m_mimeType
, "KFilePlugin");
223 if (service
&& service
->isValid() &&
224 service
->property("SupportsThumbnail").toBool())
226 // was: KFileMetaInfo info(url.path(), m_mimeType, KFileMetaInfo::Thumbnail);
227 // but m_mimeType and WhatFlags are now unused in KFileMetaInfo, and not present in the
228 // call that takes a KUrl
229 KFileMetaInfo
info(url
);
232 KFileMetaInfoItem item
= info
.item("thumbnail");
233 if (item
.isValid() && item
.value().type() == QVariant::Image
)
235 img
= item
.value().value
<QImage
>();
236 kDebug(7115) << "using KFMI for the thumbnail\n";
242 ThumbCreator::Flags flags
= ThumbCreator::None
;
246 kDebug(7115) << "using thumb creator for the thumbnail\n";
247 QString plugin
= metaData("plugin");
248 #ifdef THUMBNAIL_HACK
249 if (plugin
.isEmpty())
251 KService::List offers
= KMimeTypeTrader::self()->query( m_mimeType
, QLatin1String( "ThumbCreator" ) );
253 if(!offers
.isEmpty())
256 serv
= offers
.first();
257 plugin
= serv
->library();
260 kDebug(7115) << "Guess plugin: " << plugin
;
262 if (plugin
.isEmpty())
264 error(KIO::ERR_INTERNAL
, i18n("No plugin specified."));
268 ThumbCreator
*creator
= m_creators
[plugin
];
271 // Don't use KLibFactory here, this is not a QObject and
272 // neither is ThumbCreator
273 KLibrary
*library
= KLibLoader::self()->library(plugin
);
276 newCreator create
= (newCreator
)library
->resolveFunction("new_creator");
282 error(KIO::ERR_INTERNAL
, i18n("Cannot load ThumbCreator %1", plugin
));
285 m_creators
.insert(plugin
, creator
);
288 if (!creator
->create(url
.path(), m_width
, m_height
, img
))
290 error(KIO::ERR_INTERNAL
, i18n("Cannot create thumbnail for %1", url
.path()));
293 flags
= creator
->flags();
296 if (img
.width() > m_width
|| img
.height() > m_height
)
298 double imgRatio
= (double)img
.height() / (double)img
.width();
299 if (imgRatio
> (double)m_height
/ (double)m_width
)
300 img
= img
.scaled( int(qMax((double)m_height
/ imgRatio
, 1.0)), m_height
, Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
302 img
= img
.scaled(m_width
, int(qMax((double)m_width
* imgRatio
, 1.0)), Qt::IgnoreAspectRatio
, Qt::SmoothTransformation
);
306 #ifndef USE_KINSTANCE
307 if (flags
& ThumbCreator::DrawFrame
)
309 QPixmap pix
= QPixmap::fromImage( img
);
310 int x2
= pix
.width() - 1;
311 int y2
= pix
.height() - 1;
312 // paint a black rectangle around the "page"
315 p
.setPen( QColor( 48, 48, 48 ));
316 p
.drawLine( x2
, 0, x2
, y2
);
317 p
.drawLine( 0, y2
, x2
, y2
);
318 p
.setPen( QColor( 215, 215, 215 ));
319 p
.drawLine( 0, 0, x2
, 0 );
320 p
.drawLine( 0, 0, 0, y2
);
323 const QBitmap
& mask
= pix
.mask();
324 if ( !mask
.isNull() ) // need to update it so we can see the frame
326 QBitmap
bitmap( mask
);
328 painter
.begin( &bitmap
);
329 painter
.drawLine( x2
, 0, x2
, y2
);
330 painter
.drawLine( 0, y2
, x2
, y2
);
331 painter
.drawLine( 0, 0, x2
, 0 );
332 painter
.drawLine( 0, 0, 0, y2
);
335 pix
.setMask( bitmap
);
342 if ((flags
& ThumbCreator::BlendIcon
) && KIconLoader::global()->alphaBlending(KIconLoader::Desktop
))
344 // blending the mimetype icon in
345 QImage icon
= getIcon();
347 int x
= img
.width() - icon
.width() - 4;
349 int y
= img
.height() - icon
.height() - 6;
352 p
.setOpacity(m_iconAlpha
/255.0);
353 p
.drawImage(x
, y
, icon
);
358 error(KIO::ERR_INTERNAL
, i18n("Failed to create a thumbnail."));
362 const QString shmid
= metaData("shmid");
365 #ifdef THUMBNAIL_HACK
368 // If thumbnail was called directly from Konqueror, then the image needs to be raw
369 //kDebug(7115) << "RAW IMAGE TO STREAM";
371 if (!buf
.open(QIODevice::WriteOnly
))
373 error(KIO::ERR_INTERNAL
, i18n("Could not write image."));
376 img
.save(&buf
,"PNG");
384 QDataStream
stream( &imgData
, QIODevice::WriteOnly
);
385 //kDebug(7115) << "IMAGE TO STREAM";
394 QDataStream
stream( &imgData
, QIODevice::WriteOnly
);
395 //kDebug(7115) << "IMAGE TO SHMID";
396 void *shmaddr
= shmat(shmid
.toInt(), 0, 0);
397 if (shmaddr
== (void *)-1)
399 error(KIO::ERR_INTERNAL
, i18n("Failed to attach to shared memory segment %1", shmid
));
402 if (img
.width() * img
.height() > m_width
* m_height
)
404 error(KIO::ERR_INTERNAL
, i18n("Image is too big for the shared memory segment"));
405 shmdt((char*)shmaddr
);
408 if( img
.depth() != 32 ) // KIO::PreviewJob and this code below completely ignores colortable :-/,
409 img
= img
.convertToFormat(QImage::Format_ARGB32
); // so make sure there is none
410 // Keep in sync with kdelibs/kio/kio/previewjob.cpp
411 stream
<< img
.width() << img
.height() << quint8(img
.format());
412 memcpy(shmaddr
, img
.bits(), img
.numBytes());
413 shmdt((char*)shmaddr
);
420 const QImage
ThumbnailProtocol::getIcon()
422 if ( !m_iconDict
.contains(m_mimeType
) ) { // generate it
423 QImage
icon( KIconLoader::global()->loadMimeTypeIcon( KMimeType::mimeType(m_mimeType
)->iconName(), KIconLoader::Desktop
, m_iconSize
).toImage() );
424 icon
= icon
.convertToFormat( QImage::Format_ARGB32
);
425 m_iconDict
.insert( m_mimeType
, icon
);
430 return m_iconDict
.value( m_mimeType
);