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