1 | /* |
2 | Copyright (C) 2009 Canonical |
3 | Author: Aurélien Gâteau <aurelien.gateau@canonical.com> |
4 | |
5 | This program is free software: you can redistribute it and/or modify it |
6 | under the terms of the GNU Lesser General Public License as published by |
7 | the Free Software Foundation, either version 2 or 3 of the License. |
8 | |
9 | This program is distributed in the hope that it will be useful, but |
10 | WITHOUT ANY WARRANTY; without even the implied warranty of |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser |
12 | General Public License for more details. |
13 | |
14 | You should have received a copy of the GNU Lesser General Public License |
15 | along with this program. If not, see <http://www.gnu.org/licenses/>. |
16 | */ |
17 | #include "imageconverter.h" |
18 | |
19 | #include <QDBusArgument> |
20 | #include <QDBusMetaType> |
21 | #include <QImage> |
22 | |
23 | namespace ImageConverter |
24 | { |
25 | |
26 | /** |
27 | * A structure representing an image which can be marshalled to fit the |
28 | * notification spec. |
29 | */ |
30 | struct SpecImage |
31 | { |
32 | int width, height, rowStride; |
33 | bool hasAlpha; |
34 | int bitsPerSample, channels; |
35 | QByteArray data; |
36 | }; |
37 | |
38 | QDBusArgument &operator<<(QDBusArgument &argument, const SpecImage &image) |
39 | { |
40 | argument.beginStructure(); |
41 | argument << image.width << image.height << image.rowStride << image.hasAlpha; |
42 | argument << image.bitsPerSample << image.channels << image.data; |
43 | argument.endStructure(); |
44 | return argument; |
45 | } |
46 | |
47 | const QDBusArgument &operator>>(const QDBusArgument &argument, SpecImage &image) |
48 | { |
49 | argument.beginStructure(); |
50 | argument >> image.width >> image.height >> image.rowStride >> image.hasAlpha; |
51 | argument >> image.bitsPerSample >> image.channels >> image.data; |
52 | argument.endStructure(); |
53 | return argument; |
54 | } |
55 | |
56 | } // namespace |
57 | |
58 | // This must be before the QVariant::fromValue below (#211726) |
59 | Q_DECLARE_METATYPE(ImageConverter::SpecImage) |
60 | |
61 | namespace ImageConverter |
62 | { |
63 | QVariant variantForImage(const QImage &_image) |
64 | { |
65 | qDBusRegisterMetaType<SpecImage>(); |
66 | |
67 | QImage image = _image.convertToFormat(QImage::Format_ARGB32); |
68 | |
69 | int rowStride = image.width() * 4; |
70 | |
71 | // Notification spec stores pixels in R,G,B,A order, regardless of |
72 | // endianess |
73 | // Qt represents pixels as 32 bit unsigned int. So the order depend on |
74 | // endianess: |
75 | // - In big endian the order is A,R,G,B |
76 | // - In little endian the order is B,G,R,A |
77 | QByteArray data; |
78 | data.resize(rowStride * image.height()); |
79 | char* dst = data.data(); |
80 | for (int y=0; y<image.height(); ++y) { |
81 | QRgb* src = (QRgb*)image.scanLine(y); |
82 | QRgb* end = src + image.width(); |
83 | for (;src != end; ++src) { |
84 | // Probably slow, but free of endianess issues |
85 | *dst++ = qRed(*src); |
86 | *dst++ = qGreen(*src); |
87 | *dst++ = qBlue(*src); |
88 | *dst++ = qAlpha(*src); |
89 | } |
90 | } |
91 | |
92 | SpecImage specImage; |
93 | specImage.width = image.width(); |
94 | specImage.height = image.height(); |
95 | specImage.rowStride = rowStride; |
96 | specImage.hasAlpha = true; |
97 | specImage.bitsPerSample = 8; |
98 | specImage.channels = 4; |
99 | specImage.data = data; |
100 | |
101 | return QVariant::fromValue(specImage); |
102 | } |
103 | |
104 | } // namespace |
105 | |
106 | |