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"
20 #include "graphics/GraphicsParams.h"
22 #include "support/lstrings.h"
23 #include "support/lyxlib.h"
25 #include "lyx_forms.h"
27 #if defined (HAVE_FLIMAGE_H)
29 #elif defined (HAVE_X11_FLIMAGE_H)
30 # include <X11/flimage.h>
33 #include <boost/bind.hpp>
34 #include <boost/tuple/tuple.hpp>
36 using lyx::frontend::getRGBColor;
38 using lyx::support::float_equal;
39 using lyx::support::prefixIs;
40 using lyx::support::rtrim;
53 unsigned int packedcolor(LColor::color c);
61 /// Access to this class is through this static method.
62 Image::ImagePtr xformsImage::newImage()
67 ptr.reset(new xformsImage);
72 /// Return the list of loadable formats.
73 Image::FormatList xformsImage::loadableFormats()
75 static FormatList fmts;
81 // The formats recognised by LyX
82 Formats::const_iterator begin = formats.begin();
83 Formats::const_iterator end = formats.end();
85 lyxerr[Debug::GRAPHICS]
86 << "\nThe image loader can load the following directly:\n";
88 // Don't forget the Fortran numbering used by xforms!
89 int const nformats = flimage_get_number_of_formats();
90 for (int i = 1; i <= nformats; ++i) {
92 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
93 string const formal_name =
94 info->formal_name ? info->formal_name : string();
96 info->extension ? info->extension : string();
98 if (ext.empty() || ext == "gz")
101 if (ext == "rgb") ext = "sgi";
103 lyxerr[Debug::GRAPHICS]
104 << formal_name << ", extension \"" << ext << "\"\n";
106 Formats::const_iterator it =
108 bind(equal_to<string>(),
109 bind(&Format::extension, _1),
112 fmts.push_back(it->name());
115 lyxerr[Debug::GRAPHICS]
116 << "\nOf these, LyX recognises the following formats:\n";
118 FormatList::const_iterator fbegin = fmts.begin();
119 FormatList::const_iterator fend = fmts.end();
120 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
122 lyxerr[Debug::GRAPHICS] << ", ";
123 lyxerr[Debug::GRAPHICS] << *fit;
125 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
131 xformsImage::xformsImage()
134 pixmap_status_(PIXMAP_UNINITIALISED)
138 xformsImage::xformsImage(xformsImage const & other)
142 pixmap_status_(PIXMAP_UNINITIALISED)
145 image_ = flimage_dup(other.image_);
146 image_->u_vdata = this;
151 xformsImage::~xformsImage()
154 flimage_free(image_);
156 XFreePixmap(fl_get_display(), pixmap_);
160 Pixmap xformsImage::getPixmap() const
162 if (!pixmap_status_ == PIXMAP_SUCCESS)
168 Image * xformsImage::clone_impl() const
170 return new xformsImage(*this);
174 unsigned int xformsImage::getWidth_impl() const
183 unsigned int xformsImage::getHeight_impl() const
191 bool xformsImage::isDrawable_impl() const
197 void xformsImage::load_impl(string const & filename)
200 lyxerr[Debug::GRAPHICS]
201 << "Image is loaded already!" << std::endl;
202 finishedLoading(false);
206 image_ = flimage_open(filename.c_str());
208 lyxerr[Debug::GRAPHICS]
209 << "Unable to open image" << std::endl;
210 finishedLoading(false);
214 // Set this now and we won't need to bother again.
215 image_->fill_color = packedcolor(LColor::graphicsbg);
217 // Used by the callback routines to return to this
218 image_->u_vdata = this;
220 // Begin the reading process.
221 flimage_read(image_);
225 bool xformsImage::setPixmap_impl(Params const & params)
227 if (!image_ || params.display == NoDisplay)
230 Display * display = fl_get_display();
232 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
233 XFreePixmap(display, pixmap_);
236 switch (params.display) {
237 case MonochromeDisplay:
238 color_key = FL_IMAGE_MONO;
240 case GrayscaleDisplay:
241 color_key = FL_IMAGE_GRAY;
244 default: // NoDisplay cannot happen!
245 color_key = FL_IMAGE_RGB;
249 if (color_key != FL_IMAGE_RGB) {
250 flimage_convert(image_, color_key, 0);
253 unsigned int fill = packedcolor(LColor::graphicsbg);
254 if (fill != image_->fill_color) {
255 // the background color has changed.
256 // Note that in grayscale/monochrome images the background is
257 // grayed also, so this call will have no visible effect. Sorry!
258 flimage_replace_pixel(image_, image_->fill_color, fill);
259 image_->fill_color = fill;
262 image_->xdisplay = display;
263 Screen * screen = ScreenOfDisplay(display, fl_screen);
265 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
266 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
268 return pixmap_status_ == PIXMAP_SUCCESS;
272 void xformsImage::clip_impl(Params const & params)
277 if (params.bb.empty())
278 // No clipping is necessary.
281 int const new_width = params.bb.xr - params.bb.xl;
282 int const new_height = params.bb.yt - params.bb.yb;
284 // No need to check if the width, height are > 0 because the
285 // Bounding Box would be empty() in this case.
286 if (new_width > image_->w || new_height > image_->h)
287 // Bounds are invalid.
290 if (new_width == image_->w && new_height == image_->h)
291 // Bounds are unchanged.
294 // flimage.h: image_ members w and h are of type int
295 // (though always >= 0)
296 // GraphicsParams.h: params.bb members xl, xr, yt and yb are of
297 // type unsigned int.
298 // We must, therefore, be careful...
299 int const xoffset_l = params.bb.xl;
300 int const yoffset_b = params.bb.yb;
301 int const xoffset_r = image_->w > int(params.bb.xr) ?
302 image_->w - params.bb.xr : 0;
303 int const yoffset_t = image_->h > int(params.bb.yt) ?
304 image_->h - params.bb.yt : 0;
306 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
310 void xformsImage::rotate_impl(Params const & params)
315 if (float_equal(params.angle, 0.0, 0.1))
316 // No rotation is necessary.
319 // The angle passed to flimage_rotate is the angle in one-tenth of a
322 // Work around xforms bug when params.angle == 270
323 // the 'InternalError: bad special angle' error.
324 // This bug fix is not needed in xforms 1.0 and greater.
325 if (float_equal(params.angle, 270.0, 0.1)) {
326 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
327 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
329 flimage_rotate(image_,
330 int(params.angle * 10),
336 void xformsImage::scale_impl(Params const & params)
343 boost::tie(width, height) = getScaledDimensions(params);
345 if (width == getWidth() && height == getHeight())
349 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
353 void xformsImage::statusCB(string const & status_message)
355 if (status_message.empty())
358 if (prefixIs(status_message, "Done Reading")) {
360 flimage_close(image_);
363 finishedLoading(true);
368 void xformsImage::errorCB(string const & error_message)
370 if (error_message.empty())
374 flimage_close(image_);
377 finishedLoading(false);
380 } // namespace graphics
388 int status_report(FL_IMAGE * ob, const char *s)
390 BOOST_ASSERT(ob && ob->u_vdata);
392 string const str = s ? rtrim(s) : string();
396 lyxerr[Debug::GRAPHICS]
397 << "xforms image loader. Status: " << str << std::endl;
399 lyx::graphics::xformsImage * ptr =
400 static_cast<lyx::graphics::xformsImage *>(ob->u_vdata);
407 static void error_report(FL_IMAGE * ob, const char *s)
409 BOOST_ASSERT(ob && ob->u_vdata);
411 string const str = s ? rtrim(s) : string();
415 lyxerr[Debug::GRAPHICS]
416 << "xforms image loader. Error: " << str << std::endl;
418 lyx::graphics::xformsImage * ptr =
419 static_cast<lyx::graphics::xformsImage *>(ob->u_vdata);
429 static bool initialised = false;
434 flimage_enable_bmp();
435 flimage_enable_fits();
436 flimage_enable_gif();
437 #ifdef USE_JPEG_IMAGE_LOADER
438 flimage_enable_jpeg();
441 // xforms itself uses pngtopnm to convert to a loadable format.
442 // We prefer to use our own conversion mechanism, therefore.
443 // flimage_enable_png();
445 flimage_enable_pnm();
447 // xforms recognises PS but not EPS
448 // It dies horribly with lots of older PostScript files.
449 // Easiest, therefore, to disable PS support and insist that a PS-type
450 // file is converted to a bitmap format.
451 // flimage_enable_ps();
453 flimage_enable_sgi();
454 flimage_enable_tiff();
455 flimage_enable_xbm();
456 flimage_enable_xwd();
457 // xforms can load most XPM files, but will occasionally crash
458 // with some files created by ImakeMagick's convert program.
459 // Turn off xpm support for the time being.
460 // flimage_enable_xpm();
462 // xforms stores this permanently (does not make a copy) so
463 // this should never be destroyed.
464 static FLIMAGE_SETUP setup;
465 setup.visual_cue = status_report;
466 setup.error_message = error_report;
467 flimage_setup(&setup);
471 unsigned int packedcolor(LColor::color col)
473 unsigned int r, g, b;
474 bool const success = getRGBColor(col, r, g, b);
476 // Set to black on failure
477 return FL_PACK(255, 255, 255);
479 return FL_PACK(r, g, b);