Merge lp:~jamesh/thumbnailer/dbus-service into lp:thumbnailer

Proposed by James Henstridge
Status: Merged
Approved by: Jussi Pakkanen
Approved revision: 107
Merged at revision: 79
Proposed branch: lp:~jamesh/thumbnailer/dbus-service
Merge into: lp:thumbnailer
Prerequisite: lp:~jpakkane/thumbnailer/lastfmtest
Diff against target: 992 lines (+772/-31)
22 files modified
CMakeLists.txt (+3/-1)
debian/changelog (+6/-9)
debian/control (+31/-4)
debian/qtdeclarative5-ubuntu-thumbnailer0.1.install (+1/-0)
debian/thumbnailer-service.install (+2/-0)
plugins/Ubuntu/Thumbnailer/CMakeLists.txt (+22/-0)
plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp (+90/-0)
plugins/Ubuntu/Thumbnailer/albumartgenerator.h (+36/-0)
plugins/Ubuntu/Thumbnailer/plugin.cpp (+47/-0)
plugins/Ubuntu/Thumbnailer/plugin.h (+34/-0)
plugins/Ubuntu/Thumbnailer/qmldir (+2/-0)
plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp (+87/-0)
plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h (+36/-0)
src/CMakeLists.txt (+2/-0)
src/service/CMakeLists.txt (+34/-0)
src/service/com.canonical.Thumbnailer.service.in (+4/-0)
src/service/dbus-interface.xml (+17/-0)
src/service/dbusinterface.cpp (+168/-0)
src/service/dbusinterface.h (+40/-0)
src/service/main.cpp (+44/-0)
src/thumbnailer.cpp (+4/-17)
tests/qml/tst_image_provider.qml (+62/-0)
To merge this branch: bzr merge lp:~jamesh/thumbnailer/dbus-service
Reviewer Review Type Date Requested Status
Jussi Pakkanen (community) Approve
PS Jenkins bot (community) continuous-integration Approve
Review via email: mp+212347@code.launchpad.net

Commit message

Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.

Description of the change

Add a D-Bus service that uses libthumbnailer to download cover art and then provides that art to the client via a read only file descriptor. This allows confined applications to safely access a shared media art cache.

I've put the service in its own binary package marked "Multi-Arch: foreign", since we only need one copy installed on multi-arch systems, and the D-Bus interface should be usable by all architectures on the system.

To post a comment you must log in.
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~jamesh/thumbnailer/dbus-service updated
98. By James Henstridge

Fix up installation of service file.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

> catch (std::exception &e)

The recommended practice is to catch exceptions by const ref rather than plain ref.

> std::thread t(&getCoverArt,

This may throw, please wrap in try/catch.

> // This should be replaced with actual lookup code.

I think it has been. :)

> /**
> + * A class that sends a broadcast signal that the state of media
> + * files has changed.
> + */

This is still from InvalidationSender and thus not accurate.

review: Needs Fixing
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

The code talks about album art but the method is called GetCoverArt. We should use one term consistently here, I vote for AlbumArt.

Revision history for this message
James Henstridge (jamesh) wrote :

Good catch. It looks like I introduced that discrepancy when cleaning up the ubuntu-ui-toolkit branch (looking at the strings in the .so I was testing shows GetCoverArt). I've updated this branch in favour of GetAlbumArt, to match the C++ API name.

lp:~jamesh/thumbnailer/dbus-service updated
99. By James Henstridge

Update per Jussi's review comments.

Revision history for this message
James Henstridge (jamesh) wrote :

I've done fresh builds of thumbnailer and ubuntu-ui-toolkit packages, and verified that they talk to each other correctly with these changes.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Here's something that bothers me:

static void getAlbumArt(unique_gobj<TNThumbnailer> iface,
  unique_gobj<GDBusMethodInvocation> invocation,

This function takes a unique_gobj by value but unique_gobj does not have a copy constructor or operator=. Maybe it invokes the move constructor because it is called with a temporary object?

Anyhow, it works so if no-one can give a feasible case why this would break I'm fine with merging this.

review: Approve
Revision history for this message
James Henstridge (jamesh) wrote :

The move constructor is the only way this could work, yes.

That said, there isn't much reason the type couldn't have a copy constructor: it's holding a reference counted object after all.

lp:~jamesh/thumbnailer/dbus-service updated
100. By James Henstridge

Copy over the libthumbnailer QML image providers over from
ubuntu-ui-toolkit.

101. By James Henstridge

Add packaging for thumbnailer QML plugin.

102. By James Henstridge

Register a bogus type so the QML module can be imported.

Revision history for this message
James Henstridge (jamesh) wrote :

MP updated with QML plugin code. Note that the bogus qmlRegisterType call is necessary for the plugin to be recognised: plugins that don't register any types are considered broken.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Needs Fixing (continuous-integration)
lp:~jamesh/thumbnailer/dbus-service updated
103. By James Henstridge

Merge from trunk, fixing conflicts.

104. By James Henstridge

Merge lp:~jpakkane/thumbnailer/lastfmtest

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

The main issue seems to be that the service is called thumbnailer-service. It implies that it would provide thumbnailing services for all files. However it must not do that because that would open a way for confined applications to access files outside its sandbox. For album art this is not an issue because album art images are fully public data. Maybe we should call this albumart-service or alternatively develop a confinement security policy (which is a lot of work).

That being said, here are a few minor things:

"__ThumbnailerIngoreMe" has a typo.

#ifndef PLUGIN_H is a bit too generic and may clash, should be THUMBNAILERPLUGIN_H or somesuch.

review: Needs Information
lp:~jamesh/thumbnailer/dbus-service updated
105. By James Henstridge

Add a test for the image provider. Not currently hooked up as an
automated test, since it can't run headless.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~jamesh/thumbnailer/dbus-service updated
106. By James Henstridge

Add a note to the D-Bus interface definition file warning about security
considerations when adding new methods to the service.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
lp:~jamesh/thumbnailer/dbus-service updated
107. By James Henstridge

Other fixes from Jussi's review comments.

Revision history for this message
PS Jenkins bot (ps-jenkins) wrote :
review: Approve (continuous-integration)
Revision history for this message
Jussi Pakkanen (jpakkane) wrote :

Looks good.

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
=== modified file 'CMakeLists.txt'
--- CMakeLists.txt 2014-03-28 10:11:10 +0000
+++ CMakeLists.txt 2014-03-28 10:11:10 +0000
@@ -29,9 +29,10 @@
29set(SHARE_PRIV_ABS ${CMAKE_INSTALL_PREFIX}/${SHARE_PRIV_DIR})29set(SHARE_PRIV_ABS ${CMAKE_INSTALL_PREFIX}/${SHARE_PRIV_DIR})
3030
31find_package(Threads REQUIRED)31find_package(Threads REQUIRED)
32find_package(Qt5Core REQUIRED)
32include(FindPkgConfig)33include(FindPkgConfig)
33pkg_check_modules(GST_DEPS REQUIRED gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0 gstreamer-app-1.0)34pkg_check_modules(GST_DEPS REQUIRED gstreamer-1.0 gstreamer-plugins-base-1.0 gstreamer-pbutils-1.0 gstreamer-app-1.0)
34pkg_check_modules(GIO_DEPS REQUIRED gio-2.0)35pkg_check_modules(GIO_DEPS REQUIRED gio-2.0 gio-unix-2.0)
35pkg_check_modules(IMG_DEPS REQUIRED gdk-pixbuf-2.0 libexif)36pkg_check_modules(IMG_DEPS REQUIRED gdk-pixbuf-2.0 libexif)
36pkg_check_modules(SOUP_DEPS REQUIRED libsoup-2.4)37pkg_check_modules(SOUP_DEPS REQUIRED libsoup-2.4)
37pkg_check_modules(XML_DEPS REQUIRED libxml-2.0)38pkg_check_modules(XML_DEPS REQUIRED libxml-2.0)
@@ -46,6 +47,7 @@
4647
47enable_testing()48enable_testing()
48add_subdirectory(src)49add_subdirectory(src)
50add_subdirectory(plugins/Ubuntu/Thumbnailer)
49add_subdirectory(tests)51add_subdirectory(tests)
50add_subdirectory(tools)52add_subdirectory(tools)
51add_subdirectory(include)53add_subdirectory(include)
5254
=== modified file 'debian/changelog'
--- debian/changelog 2014-03-28 10:11:10 +0000
+++ debian/changelog 2014-03-28 10:11:10 +0000
@@ -1,4 +1,9 @@
1<<<<<<< TREE1thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium
2
3 * New minor release.
4
5 -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200
6
2thumbnailer (1.0+14.04.20140327-0ubuntu1) trusty; urgency=low7thumbnailer (1.0+14.04.20140327-0ubuntu1) trusty; urgency=low
38
4 [ Jussi Pakkanen ]9 [ Jussi Pakkanen ]
@@ -13,14 +18,6 @@
1318
14 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 20:16:40 +000019 -- Ubuntu daily release <ps-jenkins@lists.canonical.com> Wed, 19 Mar 2014 20:16:40 +0000
1520
16=======
17thumbnailer (1.1-0ubuntu1) UNRELEASED; urgency=medium
18
19 * New minor release.
20
21 -- Jussi Pakkanen <jussi.pakkanen@ubuntu.com> Mon, 10 Mar 2014 15:15:28 +0200
22
23>>>>>>> MERGE-SOURCE
24thumbnailer (1.0+14.04.20140307-0ubuntu1) trusty; urgency=low21thumbnailer (1.0+14.04.20140307-0ubuntu1) trusty; urgency=low
2522
26 [ Jussi Pakkanen ]23 [ Jussi Pakkanen ]
2724
=== modified file 'debian/control'
--- debian/control 2014-03-28 10:11:10 +0000
+++ debian/control 2014-03-28 10:11:10 +0000
@@ -6,14 +6,18 @@
6Build-Depends: cmake,6Build-Depends: cmake,
7 debhelper (>= 9),7 debhelper (>= 9),
8 gstreamer1.0-plugins-good,8 gstreamer1.0-plugins-good,
9 libexif-dev,
9 libgdk-pixbuf2.0-dev,10 libgdk-pixbuf2.0-dev,
11 libgstreamer1.0-dev,
10 libgstreamer-plugins-base1.0-dev,12 libgstreamer-plugins-base1.0-dev,
11 libgstreamer1.0-dev,
12 shared-mime-info,
13 libgtest-dev,13 libgtest-dev,
14 libsoup2.4-dev,
14 libxml2-dev,15 libxml2-dev,
15 libsoup2.4-dev,16 qt5-default,
16 libexif-dev,17 qtbase5-dev,
18 qtbase5-dev-tools,
19 qtdeclarative5-dev,
20 shared-mime-info,
17Homepage: https://launchpad.net/thumbnailer21Homepage: https://launchpad.net/thumbnailer
18# if you don't have have commit access to this branch but would like to upload22# if you don't have have commit access to this branch but would like to upload
19# directly to Ubuntu, don't worry: your changes will be merged back into the23# directly to Ubuntu, don't worry: your changes will be merged back into the
@@ -43,3 +47,26 @@
43Description: development files for thumbnailer47Description: development files for thumbnailer
44 This package contains development files48 This package contains development files
45 for the thumbnailer package.49 for the thumbnailer package.
50
51Package: thumbnailer-service
52Architecture: any
53Multi-Arch: foreign
54Pre-Depends: ${misc:Pre-Depends},
55Depends: ${misc:Depends},
56 ${shlibs:Depends},
57 libthumbnailer0 (= ${binary:Version}),
58Description: D-Bus service for out of process thumbnailing
59 This package provides a D-Bus service that can provide thumbnails on
60 behalf of another process.
61
62Package: qtdeclarative5-ubuntu-thumbnailer0.1
63Architecture: any
64Multi-Arch: same
65Pre-Depends: ${misc:Pre-Depends},
66Depends: ${misc:Depends},
67 ${shlibs:Depends},
68 libthumbnailer0 (= ${binary:Version}),
69Recommends: thumbnailer-service (= ${binary:Version}),
70Description: QML interface for the thumbnailer.
71 This package provides image providers that allow access to the
72 thumbnailer from Qt Quick 2 / QML applications.
4673
=== added file 'debian/qtdeclarative5-ubuntu-thumbnailer0.1.install'
--- debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 1970-01-01 00:00:00 +0000
+++ debian/qtdeclarative5-ubuntu-thumbnailer0.1.install 2014-03-28 10:11:10 +0000
@@ -0,0 +1,1 @@
1usr/lib/*/qt5/qml/Ubuntu/Thumbnailer.0.1/*
02
=== added file 'debian/thumbnailer-service.install'
--- debian/thumbnailer-service.install 1970-01-01 00:00:00 +0000
+++ debian/thumbnailer-service.install 2014-03-28 10:11:10 +0000
@@ -0,0 +1,2 @@
1usr/lib/*/thumbnailer/thumbnailer-service
2usr/share/dbus-1/services/com.canonical.Thumbnailer.service
03
=== added directory 'plugins'
=== added directory 'plugins/Ubuntu'
=== added directory 'plugins/Ubuntu/Thumbnailer'
=== added file 'plugins/Ubuntu/Thumbnailer/CMakeLists.txt'
--- plugins/Ubuntu/Thumbnailer/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/CMakeLists.txt 2014-03-28 10:11:10 +0000
@@ -0,0 +1,22 @@
1
2set(QML_PLUGIN_DIR "${CMAKE_INSTALL_LIBDIR}/qt5/qml/Ubuntu/Thumbnailer.0.1")
3
4add_library(thumbnailer-qml MODULE
5 plugin.cpp
6 albumartgenerator.cpp
7 thumbnailgenerator.cpp
8)
9
10set_target_properties(thumbnailer-qml PROPERTIES AUTOMOC TRUE)
11qt5_use_modules(thumbnailer-qml Qml Quick DBus)
12target_link_libraries(thumbnailer-qml thumbnailer)
13
14install(
15 TARGETS thumbnailer-qml
16 LIBRARY DESTINATION ${QML_PLUGIN_DIR}
17)
18
19install(
20 FILES qmldir
21 DESTINATION ${QML_PLUGIN_DIR}
22)
023
=== added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp'
--- plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/albumartgenerator.cpp 2014-03-28 10:11:10 +0000
@@ -0,0 +1,90 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17 * James Henstridge <james.henstridge@canonical.com>
18*/
19
20#include "albumartgenerator.h"
21#include <stdexcept>
22#include <QDebug>
23#include <QFile>
24#include <QUrlQuery>
25#include <QDBusUnixFileDescriptor>
26#include <QDBusReply>
27
28static const char DEFAULT_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png";
29
30static const char BUS_NAME[] = "com.canonical.Thumbnailer";
31static const char BUS_PATH[] = "/com/canonical/Thumbnailer";
32static const char THUMBNAILER_IFACE[] = "com.canonical.Thumbnailer";
33static const char GET_ALBUM_ART[] = "GetAlbumArt";
34
35AlbumArtGenerator::AlbumArtGenerator()
36 : QQuickImageProvider(QQuickImageProvider::Image, QQmlImageProviderBase::ForceAsynchronousImageLoading),
37 iface(BUS_NAME, BUS_PATH, THUMBNAILER_IFACE) {
38}
39
40static QImage fallbackImage(QSize *realSize) {
41 QImage fallback;
42 fallback.load(DEFAULT_ALBUM_ART);
43 *realSize = fallback.size();
44 return fallback;
45}
46
47QImage AlbumArtGenerator::requestImage(const QString &id, QSize *realSize,
48 const QSize &requestedSize) {
49 QUrlQuery query(id);
50 if (!query.hasQueryItem("artist") || !query.hasQueryItem("album")) {
51 qWarning() << "Invalid albumart uri:" << id;
52 return fallbackImage(realSize);
53 }
54
55 const QString artist = query.queryItemValue("artist", QUrl::FullyDecoded);
56 const QString album = query.queryItemValue("album", QUrl::FullyDecoded);
57
58 QString desiredSize = "original";
59 int size = requestedSize.width() > requestedSize.height() ? requestedSize.width() : requestedSize.height();
60 if (size < 128) {
61 desiredSize = "small";
62 } else if (size < 256) {
63 desiredSize = "large";
64 } else if (size < 512) {
65 desiredSize = "xlarge";
66 }
67
68 // perform dbus call
69 QDBusReply<QDBusUnixFileDescriptor> reply = iface.call(
70 GET_ALBUM_ART, artist, album, desiredSize);
71 if (!reply.isValid()) {
72 qWarning() << "D-Bus error: " << reply.error().message();
73 return fallbackImage(realSize);
74 }
75
76 try {
77 QFile file;
78 file.open(reply.value().fileDescriptor(), QIODevice::ReadOnly);
79 QImage image;
80 image.load(&file, NULL);
81 *realSize = image.size();
82 return image;
83 } catch (const std::exception &e) {
84 qDebug() << "Album art loader failed: " << e.what();
85 } catch (...) {
86 qDebug() << "Unknown error when generating image.";
87 }
88
89 return fallbackImage(realSize);
90}
091
=== added file 'plugins/Ubuntu/Thumbnailer/albumartgenerator.h'
--- plugins/Ubuntu/Thumbnailer/albumartgenerator.h 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/albumartgenerator.h 2014-03-28 10:11:10 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17 * James Henstridge <james.henstridge@canonical.com>
18*/
19
20#ifndef ALBUMART_GENERATOR_H
21#define ALBUMART_GENERATOR_H
22
23#include <QDBusInterface>
24#include <QQuickImageProvider>
25
26class AlbumArtGenerator: public QQuickImageProvider
27{
28private:
29 QDBusInterface iface;
30
31public:
32 AlbumArtGenerator();
33 QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
34};
35
36#endif
037
=== added file 'plugins/Ubuntu/Thumbnailer/plugin.cpp'
--- plugins/Ubuntu/Thumbnailer/plugin.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/plugin.cpp 2014-03-28 10:11:10 +0000
@@ -0,0 +1,47 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: James Henstridge <james.henstridge@canonical.com>
17*/
18
19#include "plugin.h"
20#include "albumartgenerator.h"
21#include "thumbnailgenerator.h"
22
23void ThumbnailerPlugin::registerTypes(const char *uri) {
24 qmlRegisterTypeNotAvailable(
25 uri, 0, 1, "__ThumbnailerIgnoreMe",
26 "Ignore this: QML plugins must contain at least one type");
27}
28
29void ThumbnailerPlugin::initializeEngine(QQmlEngine *engine, const char *uri) {
30 QQmlExtensionPlugin::initializeEngine(engine, uri);
31
32 try {
33 engine->addImageProvider("albumart", new AlbumArtGenerator());
34 } catch (const std::exception &e) {
35 qWarning() << "Failed to register albumart image provider:" << e.what();
36 } catch (...) {
37 qWarning() << "Failed to register albumart image provider.";
38 }
39
40 try {
41 engine->addImageProvider("thumbnailer", new ThumbnailGenerator());
42 } catch (const std::exception &e) {
43 qWarning() << "Failed to register thumbnailer image provider:" << e.what();
44 } catch (...) {
45 qWarning() << "Failed to register thumbnailer image provider.";
46 }
47}
048
=== added file 'plugins/Ubuntu/Thumbnailer/plugin.h'
--- plugins/Ubuntu/Thumbnailer/plugin.h 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/plugin.h 2014-03-28 10:11:10 +0000
@@ -0,0 +1,34 @@
1/*
2 * Copyright 2014 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: James Henstridge <james.henstridge@canonical.com>
17*/
18
19#ifndef THUMBNAILER_PLUGIN_H
20#define THUMBNAILER_PLUGIN_H
21
22#include <QtQml>
23
24class ThumbnailerPlugin : public QQmlExtensionPlugin
25{
26 Q_OBJECT
27 Q_PLUGIN_METADATA(IID "org.qt-project.Qt.QQmlExtensionInterface")
28
29public:
30 virtual void registerTypes(const char *uri) override;
31 virtual void initializeEngine(QQmlEngine *engine, const char *uri) override;
32};
33
34#endif
035
=== added file 'plugins/Ubuntu/Thumbnailer/qmldir'
--- plugins/Ubuntu/Thumbnailer/qmldir 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/qmldir 2014-03-28 10:11:10 +0000
@@ -0,0 +1,2 @@
1module Ubuntu.Thumbnailer
2plugin thumbnailer-qml
03
=== added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp'
--- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.cpp 2014-03-28 10:11:10 +0000
@@ -0,0 +1,87 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17*/
18
19#include "thumbnailgenerator.h"
20#include <stdexcept>
21#include <QDebug>
22#include <QMimeDatabase>
23#include <QUrl>
24
25static const char *DEFAULT_VIDEO_ART = "/usr/share/unity/icons/video_missing.png";
26static const char *DEFAULT_ALBUM_ART = "/usr/share/unity/icons/album_missing.png";
27
28ThumbnailGenerator::ThumbnailGenerator() : QQuickImageProvider(QQuickImageProvider::Image,
29 QQmlImageProviderBase::ForceAsynchronousImageLoading) {
30
31}
32
33QImage ThumbnailGenerator::requestImage(const QString &id, QSize *realSize,
34 const QSize &requestedSize) {
35 /* Allow appending a query string (e.g. ?something=timestamp)
36 * to the id and then ignore it.
37 * This is workaround to force reloading a thumbnail when it has
38 * the same file name on disk but we know the content has changed.
39 * It is necessary because in such a situation the QML image cache
40 * will kick in and this ImageProvider will never get called.
41 * The only "solution" is setting Image.cache = false, but in some
42 * cases we don't want to do that for performance reasons, so this
43 * is the only way around the issue for now. */
44 std::string src_path(QUrl(id).path().toUtf8().data());
45 std::string tgt_path;
46 try {
47 ThumbnailSize desiredSize;
48 const int xlarge_cutoff = 512;
49 const int large_cutoff = 256;
50 const int small_cutoff = 128;
51 if(requestedSize.width() > xlarge_cutoff || requestedSize.height() > xlarge_cutoff) {
52 desiredSize = TN_SIZE_ORIGINAL;
53 } if(requestedSize.width() > large_cutoff || requestedSize.height() > large_cutoff) {
54 desiredSize = TN_SIZE_XLARGE;
55 } else if(requestedSize.width() > small_cutoff || requestedSize.height() > small_cutoff) {
56 desiredSize = TN_SIZE_LARGE;
57 } else {
58 desiredSize = TN_SIZE_SMALL;
59 }
60 tgt_path = tn.get_thumbnail(src_path, desiredSize);
61 if(!tgt_path.empty()) {
62 QString tgt(tgt_path.c_str());
63 QImage image;
64 image.load(tgt);
65 *realSize = image.size();
66 return image;
67 }
68 } catch(std::runtime_error &e) {
69 qDebug() << "Thumbnail generator failed: " << e.what();
70 }
71 return getFallbackImage(id, realSize, requestedSize);
72}
73
74QImage ThumbnailGenerator::getFallbackImage(const QString &id, QSize *size,
75 const QSize &requestedSize) {
76 Q_UNUSED(requestedSize);
77 QMimeDatabase db;
78 QMimeType mime = db.mimeTypeForFile(id);
79 QImage result;
80 if(mime.name().contains("audio")) {
81 result.load(DEFAULT_ALBUM_ART);
82 } else if(mime.name().contains("video")) {
83 result.load(DEFAULT_VIDEO_ART);
84 }
85 *size = result.size();
86 return result;
87}
088
=== added file 'plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h'
--- plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 1970-01-01 00:00:00 +0000
+++ plugins/Ubuntu/Thumbnailer/thumbnailgenerator.h 2014-03-28 10:11:10 +0000
@@ -0,0 +1,36 @@
1/*
2 * Copyright 2013 Canonical Ltd.
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published by
6 * the Free Software Foundation; version 3.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
15 *
16 * Authors: Jussi Pakkanen <jussi.pakkanen@canonical.com>
17*/
18
19#ifndef THUMBNAIL_GENERATOR_H
20#define THUMBNAIL_GENERATOR_H
21
22#include <QQuickImageProvider>
23#include <thumbnailer.h>
24
25class ThumbnailGenerator: public QQuickImageProvider
26{
27private:
28 Thumbnailer tn;
29
30public:
31 ThumbnailGenerator();
32 QImage requestImage(const QString &id, QSize *size, const QSize &requestedSize);
33 QImage getFallbackImage(const QString &id, QSize *size, const QSize &requestedSize);
34};
35
36#endif
037
=== modified file 'src/CMakeLists.txt'
--- src/CMakeLists.txt 2014-03-28 10:11:10 +0000
+++ src/CMakeLists.txt 2014-03-28 10:11:10 +0000
@@ -37,3 +37,5 @@
37 RUNTIME DESTINATION ${SHARE_PRIV_DIR}37 RUNTIME DESTINATION ${SHARE_PRIV_DIR}
38 LIBRARY DESTINATION ${SHARE_PRIV_DIR}38 LIBRARY DESTINATION ${SHARE_PRIV_DIR}
39)39)
40
41add_subdirectory(service)
4042
=== added directory 'src/service'
=== added file 'src/service/CMakeLists.txt'
--- src/service/CMakeLists.txt 1970-01-01 00:00:00 +0000
+++ src/service/CMakeLists.txt 2014-03-28 10:11:10 +0000
@@ -0,0 +1,34 @@
1add_definitions(${THUMBNAILER_CFLAGS})
2include_directories(${CMAKE_CURRENT_BINARY_DIR})
3
4add_executable(thumbnailer-service
5 main.cpp
6 dbusinterface.cpp
7 dbus-generated.c
8)
9
10target_link_libraries(thumbnailer-service thumbnailer)
11
12install(
13 TARGETS thumbnailer-service
14 RUNTIME DESTINATION ${SHARE_PRIV_DIR}
15)
16
17find_program(gdbus_codegen gdbus-codegen)
18if(NOT gdbus_codegen)
19 msg(FATAL_ERROR "Could not locate gdbus-codegen")
20endif()
21
22add_custom_command(
23 OUTPUT dbus-generated.c dbus-generated.h
24 COMMAND ${gdbus_codegen} --interface-prefix=com.canonical. --generate-c-code dbus-generated --c-namespace TN ${CMAKE_CURRENT_SOURCE_DIR}/dbus-interface.xml
25 MAIN_DEPENDENCY dbus-interface.xml
26)
27
28# Install the service file.
29configure_file(com.canonical.Thumbnailer.service.in com.canonical.Thumbnailer.service)
30
31install(
32 FILES ${CMAKE_CURRENT_BINARY_DIR}/com.canonical.Thumbnailer.service
33 DESTINATION ${CMAKE_INSTALL_DATADIR}/dbus-1/services
34)
035
=== added file 'src/service/com.canonical.Thumbnailer.service.in'
--- src/service/com.canonical.Thumbnailer.service.in 1970-01-01 00:00:00 +0000
+++ src/service/com.canonical.Thumbnailer.service.in 2014-03-28 10:11:10 +0000
@@ -0,0 +1,4 @@
1[D-BUS Service]
2Name=com.canonical.Thumbnailer
3Exec=@SHARE_PRIV_ABS@/thumbnailer-service
4
05
=== added file 'src/service/dbus-interface.xml'
--- src/service/dbus-interface.xml 1970-01-01 00:00:00 +0000
+++ src/service/dbus-interface.xml 2014-03-28 10:11:10 +0000
@@ -0,0 +1,17 @@
1<node>
2 <interface name="com.canonical.Thumbnailer">
3 <method name="GetAlbumArt">
4 <arg direction="in" type="s" name="artist" />
5 <arg direction="in" type="s" name="album" />
6 <!-- possible values are "small", "large", "xlarge" and "original" -->
7 <arg direction="in" type="s" name="desiredSize" />
8 <arg direction="out" type="h" name="fd" />
9 <annotation name="org.gtk.GDBus.C.UnixFD" value="true" />
10 </method>
11
12 <!-- Note: if adding additional thumbnailing methods that take a
13 file name as input, ensure that the calling process has
14 permission to read said file. Otherwise we will leak
15 information to confined applications. -->
16 </interface>
17</node>
018
=== added file 'src/service/dbusinterface.cpp'
--- src/service/dbusinterface.cpp 1970-01-01 00:00:00 +0000
+++ src/service/dbusinterface.cpp 2014-03-28 10:11:10 +0000
@@ -0,0 +1,168 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This library is free software; you can redistribute it and/or modify it under
8 * the terms of version 3 of the GNU General Public License as published
9 * by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include "dbusinterface.h"
21
22#include <cstdio>
23#include <cstring>
24#include <memory>
25#include <stdexcept>
26#include <string>
27#include <thread>
28#include <fcntl.h>
29#include <unistd.h>
30
31#include <glib.h>
32#include <glib-object.h>
33#include <gio/gio.h>
34#include <gio/gunixfdlist.h>
35#include <thumbnailer.h>
36
37#include <internal/gobj_memory.h>
38#include "dbus-generated.h"
39
40using namespace std;
41
42static const char BUS_NAME[] = "com.canonical.MediaScanner2";
43static const char ART_ERROR[] = "com.canonical.MediaScanner2.Error.Failed";
44
45static const char MISSING_ALBUM_ART[] = "/usr/share/unity/icons/album_missing.png";
46
47struct DBusInterfacePrivate {
48 const std::string bus_path;
49 unique_gobj<GDBusConnection> bus;
50 unique_gobj<TNThumbnailer> iface;
51 unsigned int handler_id;
52 std::shared_ptr<Thumbnailer> thumbnailer;
53
54 DBusInterfacePrivate(GDBusConnection *g_bus, const std::string& bus_path)
55 : bus_path(bus_path),
56 bus(static_cast<GDBusConnection*>(g_object_ref(g_bus))),
57 iface(tn_thumbnailer_skeleton_new()),
58 handler_id(0),
59 thumbnailer(std::make_shared<Thumbnailer>()) {
60 handler_id = g_signal_connect(
61 iface.get(), "handle-get-album-art",
62 G_CALLBACK(&DBusInterfacePrivate::handleGetAlbumArt), this);
63
64 GError *error = nullptr;
65 if (!g_dbus_interface_skeleton_export(
66 G_DBUS_INTERFACE_SKELETON(iface.get()), bus.get(),
67 bus_path.c_str(), &error)) {
68 string errortxt(error->message);
69 g_error_free(error);
70
71 string msg = "Failed to export interface: ";
72 msg += errortxt;
73 throw runtime_error(msg);
74 }
75 }
76
77 ~DBusInterfacePrivate() {
78 g_dbus_interface_skeleton_unexport(
79 G_DBUS_INTERFACE_SKELETON(iface.get()));
80 g_signal_handler_disconnect(iface.get(), handler_id);
81 }
82
83 static gboolean handleGetAlbumArt(TNThumbnailer *iface, GDBusMethodInvocation *invocation, GUnixFDList *, const char *artist, const char *album, const char *size, void *user_data) {
84 auto p = static_cast<DBusInterfacePrivate*>(user_data);
85 fprintf(stderr, "Look up cover art for %s/%s at size %s\n", artist, album, size);
86
87 ThumbnailSize desiredSize;
88 if (!strcmp(size, "small")) {
89 desiredSize = TN_SIZE_SMALL;
90 } else if (!strcmp(size, "large")) {
91 desiredSize = TN_SIZE_LARGE;
92 } else if (!strcmp(size, "xlarge")) {
93 desiredSize = TN_SIZE_XLARGE;
94 } else if (!strcmp(size, "original")) {
95 desiredSize = TN_SIZE_ORIGINAL;
96 } else {
97 std::string error("Unknown size: ");
98 error += size;
99 g_dbus_method_invocation_return_dbus_error(
100 invocation, ART_ERROR, error.c_str());
101 return TRUE;
102 }
103
104 try {
105 std::thread t(&getAlbumArt,
106 unique_gobj<TNThumbnailer>(static_cast<TNThumbnailer*>(g_object_ref(iface))),
107 unique_gobj<GDBusMethodInvocation>(static_cast<GDBusMethodInvocation*>(g_object_ref(invocation))),
108 p->thumbnailer,
109 std::string(artist), std::string(album), desiredSize);
110 t.detach();
111 } catch (const std::exception &e) {
112 g_dbus_method_invocation_return_dbus_error(
113 invocation, ART_ERROR, e.what());
114 }
115 return TRUE;
116 }
117
118 static void getAlbumArt(unique_gobj<TNThumbnailer> iface,
119 unique_gobj<GDBusMethodInvocation> invocation,
120 std::shared_ptr<Thumbnailer> thumbnailer,
121 const std::string artist, const std::string album,
122 ThumbnailSize desiredSize) {
123 std::string art;
124 try {
125 art = thumbnailer->get_album_art(
126 artist, album, desiredSize, TN_REMOTE);
127 } catch (const std::exception &e) {
128 g_dbus_method_invocation_return_dbus_error(
129 invocation.get(), ART_ERROR, e.what());
130 return;
131 }
132
133 if (art.empty()) {
134 g_dbus_method_invocation_return_dbus_error(
135 invocation.get(), ART_ERROR, "Could not get thumbnail");
136 return;
137 }
138 int fd = open(art.c_str(), O_RDONLY);
139 if (fd < 0) {
140 g_dbus_method_invocation_return_dbus_error(
141 invocation.get(), ART_ERROR, strerror(errno));
142 return;
143 }
144
145 unique_gobj<GUnixFDList> fd_list(g_unix_fd_list_new());
146 GError *error = nullptr;
147 g_unix_fd_list_append(fd_list.get(), fd, &error);
148 close(fd);
149 if (error != nullptr) {
150 g_dbus_method_invocation_return_dbus_error(
151 invocation.get(), ART_ERROR, error->message);
152 g_error_free(error);
153 return;
154 }
155
156 tn_thumbnailer_complete_get_album_art(
157 iface.get(), invocation.get(), fd_list.get(), g_variant_new_handle(0));
158 }
159
160};
161
162DBusInterface::DBusInterface(GDBusConnection *bus, const std::string& bus_path)
163 : p(new DBusInterfacePrivate(bus, bus_path)) {
164}
165
166DBusInterface::~DBusInterface() {
167 delete p;
168}
0169
=== added file 'src/service/dbusinterface.h'
--- src/service/dbusinterface.h 1970-01-01 00:00:00 +0000
+++ src/service/dbusinterface.h 2014-03-28 10:11:10 +0000
@@ -0,0 +1,40 @@
1/*
2 * Copyright (C) 2014 Canonical, Ltd.
3 *
4 * Authors:
5 * James Henstridge <james.henstridge@canonical.com>
6 *
7 * This library is free software; you can redistribute it and/or modify it under
8 * the terms of version 3 of the GNU General Public License as published
9 * by the Free Software Foundation.
10 *
11 * This library is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
14 * details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#ifndef DBUSINTERFACE_H
21#define DBUSINTERFACE_H
22
23#include <string>
24
25struct DBusInterfacePrivate;
26typedef struct _GDBusConnection GDBusConnection;
27
28class DBusInterface final {
29public:
30 DBusInterface(GDBusConnection *bus, const std::string& bus_path);
31 ~DBusInterface();
32
33 DBusInterface(const DBusInterface&) = delete;
34 DBusInterface& operator=(DBusInterface&) = delete;
35
36private:
37 DBusInterfacePrivate *p;
38};
39
40#endif
041
=== added file 'src/service/main.cpp'
--- src/service/main.cpp 1970-01-01 00:00:00 +0000
+++ src/service/main.cpp 2014-03-28 10:11:10 +0000
@@ -0,0 +1,44 @@
1#include <cstdio>
2#include <memory>
3#include <stdexcept>
4#include <glib.h>
5#include <gio/gio.h>
6
7#include "dbusinterface.h"
8
9static const char BUS_NAME[] = "com.canonical.Thumbnailer";
10static const char BUS_PATH[] = "/com/canonical/Thumbnailer";
11
12static std::unique_ptr<GMainLoop,void(*)(GMainLoop*)> main_loop(
13 g_main_loop_new(nullptr, FALSE), g_main_loop_unref);
14
15static void nameLost(GDBusConnection *, const char *, void *) {
16 fprintf(stderr, "Could no acquire D-Bus name %s. Quitting.\n", BUS_NAME);
17 g_main_loop_quit(main_loop.get());
18}
19
20int main(int argc, char **argv) {
21 GError *error = nullptr;
22 std::unique_ptr<GDBusConnection, void(*)(void*)> bus(
23 g_bus_get_sync(G_BUS_TYPE_SESSION, nullptr, &error),
24 g_object_unref);
25 if (error != nullptr) {
26 fprintf(stderr, "Failed to connect to session bus: %s\n", error->message);
27 g_error_free(error);
28 return 1;
29 }
30
31 DBusInterface dbus(bus.get(), BUS_PATH);
32
33 unsigned int name_id = g_bus_own_name_on_connection(
34 bus.get(), BUS_NAME, G_BUS_NAME_OWNER_FLAGS_NONE,
35 nullptr, &nameLost, nullptr, nullptr);
36
37 g_main_loop_run(main_loop.get());
38
39 if (name_id != 0) {
40 g_bus_unown_name(name_id);
41 }
42
43 return 0;
44}
045
=== modified file 'src/thumbnailer.cpp'
--- src/thumbnailer.cpp 2014-03-28 10:11:10 +0000
+++ src/thumbnailer.cpp 2014-03-28 10:11:10 +0000
@@ -53,16 +53,12 @@
5353
54 ThumbnailerPrivate() {};54 ThumbnailerPrivate() {};
5555
56<<<<<<< TREE56 string create_thumbnail(const string &abspath, ThumbnailSize desired_size,
57 string create_thumbnail(const string &abspath, ThumbnailSize desired_size);57 ThumbnailPolicy policy);
58 string create_random_filename();58 string create_random_filename();
59=======
60 string create_thumbnail(const string &abspath, ThumbnailSize desired_size,
61 ThumbnailPolicy policy);
62>>>>>>> MERGE-SOURCE
63};59};
6460
65<<<<<<< TREE61
66string ThumbnailerPrivate::create_random_filename() {62string ThumbnailerPrivate::create_random_filename() {
67 string fname;63 string fname;
68 char *dirbase = getenv("TMPDIR"); // Set when in a confined application.64 char *dirbase = getenv("TMPDIR"); // Set when in a confined application.
@@ -77,8 +73,6 @@
77 return fname;73 return fname;
78}74}
7975
80string ThumbnailerPrivate::create_thumbnail(const string &abspath, ThumbnailSize desired_size) {
81=======
82string ThumbnailerPrivate::create_audio_thumbnail(const string &/*abspath*/,76string ThumbnailerPrivate::create_audio_thumbnail(const string &/*abspath*/,
83 ThumbnailSize /*desired_size*/, ThumbnailPolicy /*policy*/) {77 ThumbnailSize /*desired_size*/, ThumbnailPolicy /*policy*/) {
84 // There was a symbol clash between 1.0 and 0.10 versions of78 // There was a symbol clash between 1.0 and 0.10 versions of
@@ -101,14 +95,8 @@
101 return "";95 return "";
102}96}
103string ThumbnailerPrivate::create_generic_thumbnail(const string &abspath, ThumbnailSize desired_size) {97string ThumbnailerPrivate::create_generic_thumbnail(const string &abspath, ThumbnailSize desired_size) {
104>>>>>>> MERGE-SOURCE
105 int tmpw, tmph;98 int tmpw, tmph;
106 string tnfile = cache.get_cache_file_name(abspath, desired_size);99 string tnfile = cache.get_cache_file_name(abspath, desired_size);
107<<<<<<< TREE
108 string tmpname = create_random_filename();
109
110=======
111>>>>>>> MERGE-SOURCE
112 // Special case: full size image files are their own preview.100 // Special case: full size image files are their own preview.
113 if(desired_size == TN_SIZE_ORIGINAL &&101 if(desired_size == TN_SIZE_ORIGINAL &&
114 gdk_pixbuf_get_file_info(abspath.c_str(), &tmpw, &tmph)) {102 gdk_pixbuf_get_file_info(abspath.c_str(), &tmpw, &tmph)) {
@@ -123,9 +111,8 @@
123}111}
124112
125string ThumbnailerPrivate::create_video_thumbnail(const string &abspath, ThumbnailSize desired_size) {113string ThumbnailerPrivate::create_video_thumbnail(const string &abspath, ThumbnailSize desired_size) {
126 char filebuf[] = "/tmp/some/long/text/here/so/path/will/fit";
127 string tnfile = cache.get_cache_file_name(abspath, desired_size);114 string tnfile = cache.get_cache_file_name(abspath, desired_size);
128 string tmpname = tmpnam(filebuf);115 string tmpname = create_random_filename();
129 if(video.extract(abspath, tmpname)) {116 if(video.extract(abspath, tmpname)) {
130 scaler.scale(tmpname, tnfile, desired_size, abspath);117 scaler.scale(tmpname, tnfile, desired_size, abspath);
131 unlink(tmpname.c_str());118 unlink(tmpname.c_str());
132119
=== added directory 'tests/qml'
=== added file 'tests/qml/tst_image_provider.qml'
--- tests/qml/tst_image_provider.qml 1970-01-01 00:00:00 +0000
+++ tests/qml/tst_image_provider.qml 2014-03-28 10:11:10 +0000
@@ -0,0 +1,62 @@
1import QtQuick 2.0
2import QtTest 1.0
3import Ubuntu.Thumbnailer 0.1
4
5Item {
6 Image {
7 id: image
8 width: 200
9 height: 200
10
11 SignalSpy {
12 id: spy
13 target: image
14 signalName: "statusChanged"
15 }
16 }
17
18 Canvas {
19 id: canvas
20 width: 200
21 height: 200
22 renderStrategy: Canvas.Immediate
23 renderTarget: Canvas.Image
24 }
25
26 TestCase {
27 name: "ThumbnailerProviderTests"
28 when: windowShown
29
30 function test_albumart() {
31 var ctx = loadImage(
32 "image://albumart/artist=Gotye&album=Making%20Mirrors");
33 comparePixel(ctx, 0, 0, 242, 228, 209, 255);
34 }
35
36 function loadImage(uri) {
37 image.source = uri
38 while (image.status == Image.Loading) {
39 spy.wait();
40 }
41 compare(image.status, Image.Ready);
42
43 var ctx = canvas.getContext("2d");
44 ctx.drawImage(image, 0, 0);
45 return ctx;
46 }
47
48 function comparePixel(ctx,x,y,r,g,b,a, d) {
49 var c = ctx.getImageData(x,y,1,1).data;
50 if (d === undefined)
51 d = 0;
52 r = Math.round(r);
53 g = Math.round(g);
54 b = Math.round(b);
55 a = Math.round(a);
56 var notSame = Math.abs(c[0]-r)>d || Math.abs(c[1]-g)>d || Math.abs(c[2]-b)>d || Math.abs(c[3]-a)>d;
57 if (notSame)
58 qtest_fail('Pixel compare fail:\nactual :[' + c[0]+','+c[1]+','+c[2]+','+c[3] + ']\nexpected:['+r+','+g+','+b+','+a+'] +/- '+d, 1);
59
60 }
61 }
62}

Subscribers

People subscribed via source and target branches

to all changes: