]> git.lyx.org Git - lyx.git/blob - src/frontends/qt4/QLImage.cpp
* src/frontends/qt4/ui/TextLayoutUi.ui:
[lyx.git] / src / frontends / qt4 / QLImage.cpp
1 /**
2  * \file QLImage.cpp
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  * \author John Levon
8  *
9  * Full author contact details are available in file CREDITS.
10  */
11
12 #include <config.h>
13
14 #include "QLImage.h"
15 #include "qt_helpers.h"
16
17 #include "debug.h"
18 #include "Format.h"
19
20 #include "graphics/GraphicsParams.h"
21
22 #include "support/FileName.h"
23 #include "support/lstrings.h"       // ascii_lowercase
24
25 #include <QPainter>
26 #include <QPictureIO>
27 #include <QPicture>
28 #include <QImage>
29 #include <QImageReader>
30
31 #include <boost/bind.hpp>
32 #include <boost/tuple/tuple.hpp>
33
34 using lyx::support::ascii_lowercase;
35
36 using boost::bind;
37
38 using std::endl;
39 using std::equal_to;
40 using std::find_if;
41 using std::string;
42
43 QPictureIO StaticPicture;
44
45 namespace lyx {
46 namespace graphics {
47
48 /// Access to this class is through this static method.
49 Image::ImagePtr QLImage::newImage()
50 {
51         ImagePtr ptr;
52         ptr.reset(new QLImage);
53         return ptr;
54 }
55
56
57 /// Return the list of loadable formats.
58 Image::FormatList QLImage::loadableFormats()
59 {
60         static FormatList fmts;
61
62         if (!fmts.empty())
63                 return fmts;
64
65         // The formats recognised by LyX
66         Formats::const_iterator begin = formats.begin();
67         Formats::const_iterator end   = formats.end();
68
69
70 //      LYXERR(Debug::GRAPHICS)
71 //              << "D:/msys/home/yns/src/lyx-devel/lib/images/banner.png mis of format: "
72 //              << fromqstr(Pic.pictureFormat("D:/msys/home/yns/src/lyx-devel/lib/images/banner.png"))
73 //              << endl;
74 //      if (Pic.pictureFormat("D:/msys/home/yns/src/lyx-devel/lib/images/banner.png"))
75 //              LYXERR(Debug::GRAPHICS)
76 //                      << "pictureFormat not returned NULL\n" << endl;
77 //                      << "Supported formats are: " << Pic.inputFormats() << endl;
78
79         QList<QByteArray> qt_formats = QImageReader::supportedImageFormats ();
80
81         LYXERR(Debug::GRAPHICS)
82                 << "\nThe image loader can load the following directly:\n";
83
84         if (qt_formats.empty())
85                 LYXERR(Debug::GRAPHICS)
86                         << "\nQt4 Problem: No Format available!" << endl;
87
88         for (QList<QByteArray>::const_iterator it =qt_formats.begin(); it != qt_formats.end(); ++it) {
89
90                 LYXERR(Debug::GRAPHICS) << (const char *) *it << ", ";
91
92                 string ext = ascii_lowercase((const char *) *it);
93
94                 // special case
95                 if (ext == "jpeg")
96                         ext = "jpg";
97
98                 Formats::const_iterator fit =
99                         find_if(begin, end,
100                                 bind(equal_to<string>(),
101                                      bind(&Format::extension, _1),
102                                      ext));
103                 if (fit != end)
104                         fmts.push_back(fit->name());
105         }
106
107         if (lyxerr.debugging()) {
108                 LYXERR(Debug::GRAPHICS)
109                         << "\nOf these, LyX recognises the following formats:\n";
110
111                 FormatList::const_iterator fbegin = fmts.begin();
112                 FormatList::const_iterator fend   = fmts.end();
113                 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
114                         if (fit != fbegin)
115                                 LYXERR(Debug::GRAPHICS) << ", ";
116                         LYXERR(Debug::GRAPHICS) << *fit;
117                 }
118                 LYXERR(Debug::GRAPHICS) << '\n' << endl;
119         }
120
121         return fmts;
122 }
123
124
125 QLImage::QLImage()
126         : Image()
127 {
128 }
129
130
131 QLImage::QLImage(QLImage const & other)
132         : Image(other), original_(other.original_),
133           transformed_(other.transformed_),
134           transformed_pixmap_(other.transformed_pixmap_)
135 {}
136
137
138 Image * QLImage::clone_impl() const
139 {
140         return new QLImage(*this);
141 }
142
143
144 unsigned int QLImage::getWidth_impl() const
145 {
146         return transformed_.width();
147 }
148
149
150 unsigned int QLImage::getHeight_impl() const
151 {
152         return transformed_.height();
153 }
154
155
156 void QLImage::load_impl(support::FileName const & filename)
157 {
158         if (!original_.isNull()) {
159                 LYXERR(Debug::GRAPHICS)
160                         << "Image is loaded already!" << endl;
161                 finishedLoading(false);
162                 return;
163         }
164
165         if (!original_.load(toqstr(filename.absFilename()))) {
166                 LYXERR(Debug::GRAPHICS)
167                         << "Unable to open image" << endl;
168                 finishedLoading(false);
169                 return;
170         }
171         transformed_ = original_;
172         finishedLoading(true);
173 }
174
175
176 namespace {
177
178 // This code is taken from KImageEffect::toGray
179 QImage & toGray(QImage & img)
180 {
181         if (img.width() == 0 || img.height() == 0)
182                 return img;
183
184         int const pixels = img.depth() > 8 ?
185                 img.width() * img.height() : img.numColors();
186
187         unsigned int *data = img.depth() > 8 ?
188                 reinterpret_cast<unsigned int *>(img.bits()) :
189                 reinterpret_cast<unsigned int *>(&img.colorTable()[0]);
190
191         for(int i = 0; i < pixels; ++i){
192                 int const val = qGray(data[i]);
193                 data[i] = qRgba(val, val, val, qAlpha(data[i]));
194         }
195         return img;
196 }
197
198 } // namespace anon
199
200
201 bool QLImage::setPixmap_impl(Params const & params)
202 {
203         if (original_.isNull() || params.display == NoDisplay)
204                 return false;
205
206         switch (params.display) {
207         case GrayscaleDisplay: {
208                 toGray(transformed_);
209                 break;
210         }
211
212         case MonochromeDisplay: {
213                 transformed_.convertToFormat(transformed_.format(), Qt::MonoOnly);
214                 break;
215         }
216
217         default:
218                 break;
219         }
220
221         transformed_pixmap_ = QPixmap::fromImage(transformed_);
222         return true;
223 }
224
225
226 void QLImage::clip_impl(Params const & params)
227 {
228         if (transformed_.isNull())
229                 return;
230
231         if (params.bb.empty())
232                 // No clipping is necessary.
233                 return;
234
235         int const new_width  = params.bb.xr - params.bb.xl;
236         int const new_height = params.bb.yt - params.bb.yb;
237
238         // No need to check if the width, height are > 0 because the
239         // Bounding Box would be empty() in this case.
240         if (new_width > original_.width() || new_height > original_.height()) {
241                 // Bounds are invalid.
242                 return;
243         }
244
245         if (new_width == original_.width() && new_height == original_.height())
246                 return;
247
248         int const xoffset_l = params.bb.xl;
249         int const yoffset_t = (original_.height() > int(params.bb.yt) ?
250                                original_.height() - params.bb.yt : 0);
251
252         transformed_ = original_.copy(xoffset_l, yoffset_t,
253                                       new_width, new_height);
254 }
255
256
257 void QLImage::rotate_impl(Params const & params)
258 {
259         if (transformed_.isNull())
260                 return;
261
262         if (!params.angle)
263                 return;
264
265         QMatrix m;
266         m.rotate(-params.angle);
267
268         transformed_ = transformed_.transformed(m);
269 }
270
271
272 void QLImage::scale_impl(Params const & params)
273 {
274         if (transformed_.isNull())
275                 return;
276
277         unsigned int width;
278         unsigned int height;
279         boost::tie(width, height) = getScaledDimensions(params);
280
281         if (width == getWidth() && height == getHeight())
282                 return;
283
284         QMatrix m;
285         m.scale(double(width) / getWidth(), double(height) / getHeight());
286         transformed_ = transformed_.transformed(m);
287 }
288
289 } // namespace graphics
290 } // lyx