3 * This file is part of LyX, the document processor.
4 * Licence details can be found in the file COPYING.
6 * \author Angus Leeming
8 * Full author contact details are available in file CREDITS
13 #include "xformsImage.h"
14 #include "graphics/GraphicsParams.h"
18 #include "support/LAssert.h"
19 #include "support/lyxfunctional.h" // compare_memfun
21 #include "lyx_forms.h"
26 # ifdef HAVE_X11_FLIMAGE_H
27 # include <X11/flimage.h>
31 #include <boost/tuple/tuple.hpp>
39 unsigned int packedcolor(LColor::color c);
46 /// Access to this class is through this static method.
47 Image::ImagePtr xformsImage::newImage()
52 ptr.reset(new xformsImage);
57 /// Return the list of loadable formats.
58 Image::FormatList xformsImage::loadableFormats()
60 static FormatList fmts;
66 // The formats recognised by LyX
67 Formats::const_iterator begin = formats.begin();
68 Formats::const_iterator end = formats.end();
70 lyxerr[Debug::GRAPHICS]
71 << "\nThe image loader can load the following directly:\n";
73 // Don't forget the Fortran numbering used by xforms!
74 int const nformats = flimage_get_number_of_formats();
75 for (int i = 1; i <= nformats; ++i) {
77 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
78 string const formal_name =
79 info->formal_name ? info->formal_name : string();
81 info->extension ? info->extension : string();
83 if (ext.empty() || ext == "gz")
86 if (ext == "rgb") ext = "sgi";
88 lyxerr[Debug::GRAPHICS]
89 << formal_name << ", extension \"" << ext << "\"\n";
91 Formats::const_iterator it =
93 lyx::compare_memfun(&Format::extension, ext));
95 fmts.push_back(it->name());
98 lyxerr[Debug::GRAPHICS]
99 << "\nOf these, LyX recognises the following formats:\n";
101 FormatList::const_iterator fbegin = fmts.begin();
102 FormatList::const_iterator fend = fmts.end();
103 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
105 lyxerr[Debug::GRAPHICS] << ", ";
106 lyxerr[Debug::GRAPHICS] << *fit;
108 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
114 xformsImage::xformsImage()
117 pixmap_status_(PIXMAP_UNINITIALISED)
121 xformsImage::xformsImage(xformsImage const & other)
125 pixmap_status_(PIXMAP_UNINITIALISED)
128 image_ = flimage_dup(other.image_);
129 image_->u_vdata = this;
134 xformsImage::~xformsImage()
137 flimage_free(image_);
139 XFreePixmap(fl_get_display(), pixmap_);
143 Image * xformsImage::clone() const
145 return new xformsImage(*this);
149 unsigned int xformsImage::getWidth() const
158 unsigned int xformsImage::getHeight() const
166 bool xformsImage::isDrawable() const
172 Pixmap xformsImage::getPixmap() const
174 if (!pixmap_status_ == PIXMAP_SUCCESS)
180 void xformsImage::load(string const & filename)
183 lyxerr[Debug::GRAPHICS]
184 << "Image is loaded already!" << std::endl;
185 finishedLoading(false);
189 image_ = flimage_open(filename.c_str());
191 lyxerr[Debug::GRAPHICS]
192 << "Unable to open image" << std::endl;
193 finishedLoading(false);
197 // Set this now and we won't need to bother again.
198 image_->fill_color = packedcolor(LColor::graphicsbg);
200 // Used by the callback routines to return to this
201 image_->u_vdata = this;
203 // Begin the reading process.
204 flimage_read(image_);
208 bool xformsImage::setPixmap(Params const & params)
210 if (!image_ || params.display == NoDisplay)
213 Display * display = fl_get_display();
215 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
216 XFreePixmap(display, pixmap_);
219 switch (params.display) {
220 case MonochromeDisplay:
221 color_key = FL_IMAGE_MONO;
223 case GrayscaleDisplay:
224 color_key = FL_IMAGE_GRAY;
227 default: // NoDisplay cannot happen!
228 color_key = FL_IMAGE_RGB;
232 if (color_key != FL_IMAGE_RGB) {
233 flimage_convert(image_, color_key, 0);
236 unsigned int fill = packedcolor(LColor::graphicsbg);
237 if (fill != image_->fill_color) {
238 // the background color has changed.
239 // Note that in grayscale/monochrome images the background is
240 // grayed also, so this call will have no visible effect. Sorry!
241 flimage_replace_pixel(image_, image_->fill_color, fill);
242 image_->fill_color = fill;
245 image_->xdisplay = display;
246 Screen * screen = ScreenOfDisplay(display, fl_screen);
248 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
249 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
251 return pixmap_status_ == PIXMAP_SUCCESS;
255 void xformsImage::clip(Params const & params)
260 if (params.bb.empty())
261 // No clipping is necessary.
264 int const new_width = params.bb.xr - params.bb.xl;
265 int const new_height = params.bb.yt - params.bb.yb;
267 // No need to check if the width, height are > 0 because the
268 // Bounding Box would be empty() in this case.
269 if (new_width > image_->w || new_height > image_->h)
270 // Bounds are invalid.
273 if (new_width == image_->w && new_height == image_->h)
274 // Bounds are unchanged.
277 // flimage.h: image_ members w and h are of type int
278 // (though always >= 0)
279 // GraphicsParams.h: params.bb members xl, xr, yt and yb are of
280 // type unsigned int.
281 // We must, therefore, be careful...
282 int const xoffset_l = params.bb.xl;
283 int const yoffset_b = params.bb.yb;
284 int const xoffset_r = image_->w > int(params.bb.xr) ?
285 image_->w - params.bb.xr : 0;
286 int const yoffset_t = image_->h > int(params.bb.yt) ?
287 image_->h - params.bb.yt : 0;
289 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
293 void xformsImage::rotate(Params const & params)
298 if (lyx::float_equal(params.angle, 0.0, 0.1))
299 // No rotation is necessary.
302 // The angle passed to flimage_rotate is the angle in one-tenth of a
305 // Work around xforms bug when params.angle == 270
306 // the 'InternalError: bad special angle' error.
307 // This bug fix is not needed in xforms 1.0 and greater.
308 if (lyx::float_equal(params.angle, 270.0, 0.1)) {
309 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
310 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
312 flimage_rotate(image_,
313 int(params.angle * 10),
319 void xformsImage::scale(Params const & params)
326 boost::tie(width, height) = getScaledDimensions(params);
328 if (width == getWidth() && height == getHeight())
332 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
336 void xformsImage::statusCB(string const & status_message)
338 if (status_message.empty())
341 if (prefixIs(status_message, "Done Reading")) {
343 flimage_close(image_);
346 finishedLoading(true);
351 void xformsImage::errorCB(string const & error_message)
353 if (error_message.empty())
357 flimage_close(image_);
360 finishedLoading(false);
370 int status_report(FL_IMAGE * ob, const char *s)
372 lyx::Assert(ob && ob->u_vdata);
374 string const str = s ? rtrim(s) : string();
378 lyxerr[Debug::GRAPHICS]
379 << "xforms image loader. Status: " << str << std::endl;
381 grfx::xformsImage * ptr =
382 static_cast<grfx::xformsImage *>(ob->u_vdata);
389 static void error_report(FL_IMAGE * ob, const char *s)
391 lyx::Assert(ob && ob->u_vdata);
393 string const str = s ? rtrim(s) : string();
397 lyxerr[Debug::GRAPHICS]
398 << "xforms image loader. Error: " << str << std::endl;
400 grfx::xformsImage * ptr =
401 static_cast<grfx::xformsImage *>(ob->u_vdata);
411 static bool initialised = false;
416 flimage_enable_bmp();
417 flimage_enable_fits();
418 flimage_enable_gif();
419 #ifdef USE_JPEG_IMAGE_LOADER
420 flimage_enable_jpeg();
423 // xforms itself uses pngtopnm to convert to a loadable format.
424 // We prefer to use our own conversion mechanism, therefore.
425 // flimage_enable_png();
427 flimage_enable_pnm();
429 // xforms recognises PS but not EPS
430 // It dies horribly with lots of older PostScript files.
431 // Easiest, therefore, to disable PS support and insist that a PS-type
432 // file is converted to a bitmap format.
433 // flimage_enable_ps();
435 flimage_enable_sgi();
436 flimage_enable_tiff();
437 flimage_enable_xbm();
438 flimage_enable_xwd();
439 // xforms can load most XPM files, but will occasionally crash
440 // with some files created by ImakeMagick's convert program.
441 // Turn off xpm support for the time being.
442 // flimage_enable_xpm();
444 // xforms stores this permanently (does not make a copy) so
445 // this should never be destroyed.
446 static FLIMAGE_SETUP setup;
447 setup.visual_cue = status_report;
448 setup.error_message = error_report;
449 flimage_setup(&setup);
453 unsigned int packedcolor(LColor::color col)
455 unsigned int r, g, b;
456 bool const success = getRGBColor(col, r, g, b);
458 // Set to black on failure
459 return FL_PACK(255,255,255);
461 return FL_PACK(r, g, b);