3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
9 * Full author contact details are available in file CREDITS.
13 // #define QT3_SUPPORT
19 #include "qt_helpers.h"
24 #include "graphics/GraphicsParams.h"
26 #include "support/lstrings.h" // lowercase
32 #include <QImageReader>
34 #include <boost/bind.hpp>
35 #include <boost/tuple/tuple.hpp>
37 using lyx::support::lowercase;
46 QPictureIO StaticPicture;
51 /// Access to this class is through this static method.
52 Image::ImagePtr QLImage::newImage()
55 ptr.reset(new QLImage);
60 /// Return the list of loadable formats.
61 Image::FormatList QLImage::loadableFormats()
63 static FormatList fmts;
68 // The formats recognised by LyX
69 Formats::const_iterator begin = formats.begin();
70 Formats::const_iterator end = formats.end();
73 // lyxerr[Debug::GRAPHICS]
74 // << "D:/msys/home/yns/src/lyx-devel/lib/images/banner.ppm is of format: "
75 // << fromqstr(Pic.pictureFormat("D:/msys/home/yns/src/lyx-devel/lib/images/banner.ppm"))
77 // if (Pic.pictureFormat("D:/msys/home/yns/src/lyx-devel/lib/images/banner.ppm"))
78 // lyxerr[Debug::GRAPHICS]
79 // << "pictureFormat not returned NULL\n" << endl;
80 // << "Supported formats are: " << Pic.inputFormats() << endl;
82 QList<QByteArray> qt_formats = QImageReader::supportedImageFormats ();
84 lyxerr[Debug::GRAPHICS]
85 << "\nThe image loader can load the following directly:\n";
87 if (qt_formats.empty())
88 lyxerr[Debug::GRAPHICS]
89 << "\nQt4 Problem: No Format available!" << endl;
91 for (QList<QByteArray>::const_iterator it =qt_formats.begin(); it != qt_formats.end(); ++it) {
93 lyxerr[Debug::GRAPHICS] << (const char *) *it << ", ";
95 string ext = lowercase((const char *) *it);
101 Formats::const_iterator fit =
103 bind(equal_to<string>(),
104 bind(&Format::extension, _1),
107 fmts.push_back(fit->name());
110 if (lyxerr.debugging()) {
111 lyxerr[Debug::GRAPHICS]
112 << "\nOf these, LyX recognises the following formats:\n";
114 FormatList::const_iterator fbegin = fmts.begin();
115 FormatList::const_iterator fend = fmts.end();
116 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
118 lyxerr[Debug::GRAPHICS] << ", ";
119 lyxerr[Debug::GRAPHICS] << *fit;
121 lyxerr[Debug::GRAPHICS] << '\n' << endl;
134 QLImage::QLImage(QLImage const & other)
135 : Image(other), original_(other.original_),
136 transformed_(other.transformed_),
137 transformed_pixmap_(other.transformed_pixmap_)
141 Image * QLImage::clone_impl() const
143 return new QLImage(*this);
147 unsigned int QLImage::getWidth_impl() const
149 return transformed_.width();
153 unsigned int QLImage::getHeight_impl() const
155 return transformed_.height();
159 void QLImage::load_impl(string const & filename)
161 if (!original_.isNull()) {
162 lyxerr[Debug::GRAPHICS]
163 << "Image is loaded already!" << endl;
164 finishedLoading(false);
168 if (!original_.load(toqstr(filename))) {
169 lyxerr[Debug::GRAPHICS]
170 << "Unable to open image" << endl;
171 finishedLoading(false);
174 transformed_ = original_;
175 finishedLoading(true);
181 // This code is taken from KImageEffect::toGray
182 QImage & toGray(QImage & img)
184 if (img.width() == 0 || img.height() == 0)
187 int const pixels = img.depth() > 8 ?
188 img.width() * img.height() : img.numColors();
190 // FIXME this code used to be like this:
192 //unsigned int * const data = img.depth() > 8 ?
193 // (unsigned int *)img.bits() :
194 // (unsigned int *)img.jumpTable();
196 // But Qt doc just say use bits...
197 unsigned int * const data = (unsigned int *)img.bits();
199 for(int i = 0; i < pixels; ++i){
200 int const val = qGray(data[i]);
201 data[i] = qRgba(val, val, val, qAlpha(data[i]));
209 bool QLImage::setPixmap_impl(Params const & params)
211 if (original_.isNull() || params.display == NoDisplay)
214 switch (params.display) {
215 case GrayscaleDisplay: {
216 toGray(transformed_);
220 case MonochromeDisplay: {
221 transformed_.convertToFormat(transformed_.format(), Qt::MonoOnly);
229 transformed_pixmap_ = QPixmap::fromImage(transformed_);
234 void QLImage::clip_impl(Params const & params)
236 if (transformed_.isNull())
239 if (params.bb.empty())
240 // No clipping is necessary.
243 int const new_width = params.bb.xr - params.bb.xl;
244 int const new_height = params.bb.yt - params.bb.yb;
246 // No need to check if the width, height are > 0 because the
247 // Bounding Box would be empty() in this case.
248 if (new_width > original_.width() || new_height > original_.height()) {
249 // Bounds are invalid.
253 if (new_width == original_.width() && new_height == original_.height())
256 int const xoffset_l = params.bb.xl;
257 int const yoffset_t = (original_.height() > int(params.bb.yt) ?
258 original_.height() - params.bb.yt : 0);
260 transformed_ = original_.copy(xoffset_l, yoffset_t,
261 new_width, new_height);
265 void QLImage::rotate_impl(Params const & params)
267 if (transformed_.isNull())
274 m.rotate(-params.angle);
276 // FIXME: alpha chanel detection is automautic for monochrome
277 // and 8-bit images. For 32 bit, is something like still necessary?
278 //transformed_.setAlphaBuffer(true);
279 transformed_ = transformed_.transformed(m);
283 void QLImage::scale_impl(Params const & params)
285 if (transformed_.isNull())
290 boost::tie(width, height) = getScaledDimensions(params);
292 if (width == getWidth() && height == getHeight())
296 m.scale(double(width) / getWidth(), double(height) / getHeight());
297 transformed_ = transformed_.transformed(m);
300 } // namespace graphics