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
14 #pragma implementation
17 #include "xformsImage.h"
18 #include "graphics/GraphicsParams.h"
20 #include "converter.h" // formats
22 #include "support/LAssert.h"
23 #include "support/lyxfunctional.h" // compare_memfun
25 #include FORMS_H_LOCATION
30 # ifdef HAVE_X11_FLIMAGE_H
31 # include <X11/flimage.h>
35 #include <boost/tuple/tuple.hpp>
43 unsigned int packedcolor(LColor::color c);
50 /// Access to this class is through this static method.
51 Image::ImagePtr xformsImage::newImage()
56 ptr.reset(new xformsImage);
61 /// Return the list of loadable formats.
62 Image::FormatList xformsImage::loadableFormats()
64 static FormatList fmts;
70 // The formats recognised by LyX
71 Formats::const_iterator begin = formats.begin();
72 Formats::const_iterator end = formats.end();
74 lyxerr[Debug::GRAPHICS]
75 << "\nThe image loader can load the following directly:\n";
77 // Don't forget the Fortran numbering used by xforms!
78 int const nformats = flimage_get_number_of_formats();
79 for (int i = 1; i <= nformats; ++i) {
81 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
82 string const formal_name =
83 info->formal_name ? info->formal_name : string();
85 info->extension ? info->extension : string();
87 if (ext.empty() || ext == "gz")
90 if (ext == "rgb") ext = "sgi";
92 lyxerr[Debug::GRAPHICS]
93 << formal_name << ", extension \"" << ext << "\"\n";
95 Formats::const_iterator it =
97 lyx::compare_memfun(&Format::extension, ext));
99 fmts.push_back(it->name());
102 lyxerr[Debug::GRAPHICS]
103 << "\nOf these, LyX recognises the following formats:\n";
105 FormatList::const_iterator fbegin = fmts.begin();
106 FormatList::const_iterator fend = fmts.end();
107 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
109 lyxerr[Debug::GRAPHICS] << ", ";
110 lyxerr[Debug::GRAPHICS] << *fit;
112 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
118 xformsImage::xformsImage()
121 pixmap_status_(PIXMAP_UNINITIALISED)
125 xformsImage::xformsImage(xformsImage const & other)
129 pixmap_status_(PIXMAP_UNINITIALISED)
132 image_ = flimage_dup(other.image_);
133 image_->u_vdata = this;
138 xformsImage::~xformsImage()
141 flimage_free(image_);
143 XFreePixmap(fl_get_display(), pixmap_);
147 Image * xformsImage::clone() const
149 return new xformsImage(*this);
153 unsigned int xformsImage::getWidth() const
162 unsigned int xformsImage::getHeight() const
170 bool xformsImage::isDrawable() const
176 Pixmap xformsImage::getPixmap() const
178 if (!pixmap_status_ == PIXMAP_SUCCESS)
184 void xformsImage::load(string const & filename)
187 lyxerr[Debug::GRAPHICS]
188 << "Image is loaded already!" << std::endl;
189 finishedLoading(false);
193 image_ = flimage_open(filename.c_str());
195 lyxerr[Debug::GRAPHICS]
196 << "Unable to open image" << std::endl;
197 finishedLoading(false);
201 // Set this now and we won't need to bother again.
202 image_->fill_color = packedcolor(LColor::graphicsbg);
204 // Used by the callback routines to return to this
205 image_->u_vdata = this;
207 // Begin the reading process.
208 flimage_read(image_);
212 bool xformsImage::setPixmap(Params const & params)
214 if (!image_ || params.display == NoDisplay)
217 Display * display = fl_get_display();
219 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
220 XFreePixmap(display, pixmap_);
223 switch (params.display) {
224 case MonochromeDisplay:
225 color_key = FL_IMAGE_MONO;
227 case GrayscaleDisplay:
228 color_key = FL_IMAGE_GRAY;
231 default: // NoDisplay cannot happen!
232 color_key = FL_IMAGE_RGB;
236 if (color_key != FL_IMAGE_RGB) {
237 flimage_convert(image_, color_key, 0);
240 unsigned int fill = packedcolor(LColor::graphicsbg);
241 if (fill != image_->fill_color) {
242 // the background color has changed.
243 // Note that in grayscale/monochrome images the background is
244 // grayed also, so this call will have no visible effect. Sorry!
245 flimage_replace_pixel(image_, image_->fill_color, fill);
246 image_->fill_color = fill;
249 image_->xdisplay = display;
250 Screen * screen = ScreenOfDisplay(display, fl_screen);
252 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
253 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
255 return pixmap_status_ == PIXMAP_SUCCESS;
259 void xformsImage::clip(Params const & params)
264 if (params.bb.empty())
265 // No clipping is necessary.
268 int const new_width = params.bb.xr - params.bb.xl;
269 int const new_height = params.bb.yt - params.bb.yb;
271 // No need to check if the width, height are > 0 because the
272 // Bounding Box would be empty() in this case.
273 if (new_width > image_->w || new_height > image_->h)
274 // Bounds are invalid.
277 if (new_width == image_->w && new_height == image_->h)
278 // Bounds are unchanged.
281 // flimage.h: image_ members w and h are of type int
282 // (though always >= 0)
283 // GraphicsParams.h: params.bb members xl, xr, yt and yb are of
284 // type unsigned int.
285 // We must, therefore, be careful...
286 int const xoffset_l = params.bb.xl;
287 int const yoffset_b = params.bb.yb;
288 int const xoffset_r = image_->w > params.bb.xr ?
289 image_->w - params.bb.xr : 0;
290 int const yoffset_t = image_->h > params.bb.yt ?
291 image_->h - params.bb.yt : 0;
293 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
297 void xformsImage::rotate(Params const & params)
303 // No rotation is necessary.
306 // The angle passed to flimage_rotate is the angle in one-tenth of a
309 // Work around xforms bug when params.angle == 270
310 // the 'InternalError: bad special angle' error.
311 // This bug fix is not needed in xforms 1.0 and greater.
312 if (params.angle == 270) {
313 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
314 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
316 flimage_rotate(image_,
317 int(params.angle * 10),
323 void xformsImage::scale(Params const & params)
330 boost::tie(width, height) = getScaledDimensions(params);
332 if (width == getWidth() && height == getHeight())
336 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
340 void xformsImage::statusCB(string const & status_message)
342 if (status_message.empty())
345 if (prefixIs(status_message, "Done Reading")) {
347 flimage_close(image_);
350 finishedLoading(true);
355 void xformsImage::errorCB(string const & error_message)
357 if (error_message.empty())
361 flimage_close(image_);
364 finishedLoading(false);
374 int status_report(FL_IMAGE * ob, const char *s)
376 lyx::Assert(ob && ob->u_vdata);
378 string const str = s ? rtrim(s) : string();
382 lyxerr[Debug::GRAPHICS]
383 << "xforms image loader. Status: " << str << std::endl;
385 grfx::xformsImage * ptr =
386 static_cast<grfx::xformsImage *>(ob->u_vdata);
393 static void error_report(FL_IMAGE * ob, const char *s)
395 lyx::Assert(ob && ob->u_vdata);
397 string const str = s ? rtrim(s) : string();
401 lyxerr[Debug::GRAPHICS]
402 << "xforms image loader. Error: " << str << std::endl;
404 grfx::xformsImage * ptr =
405 static_cast<grfx::xformsImage *>(ob->u_vdata);
415 static bool initialised = false;
420 flimage_enable_bmp();
421 flimage_enable_fits();
422 flimage_enable_gif();
423 #ifdef USE_JPEG_IMAGE_LOADER
424 flimage_enable_jpeg();
427 // xforms itself uses pngtopnm to convert to a loadable format.
428 // We prefer to use our own conversion mechanism, therefore.
429 // flimage_enable_png();
431 flimage_enable_pnm();
433 // xforms recognises PS but not EPS
434 // It dies horribly with lots of older PostScript files.
435 // Easiest, therefore, to disable PS support and insist that a PS-type
436 // file is converted to a bitmap format.
437 // flimage_enable_ps();
439 flimage_enable_sgi();
440 flimage_enable_tiff();
441 flimage_enable_xbm();
442 flimage_enable_xwd();
443 // xforms can load most XPM files, but will occasionally crash
444 // with some files created by ImakeMagick's convert program.
445 // Turn off xpm support for the time being.
446 // flimage_enable_xpm();
448 // xforms stores this permanently (does not make a copy) so
449 // this should never be destroyed.
450 static FLIMAGE_SETUP setup;
451 setup.visual_cue = status_report;
452 setup.error_message = error_report;
453 flimage_setup(&setup);
457 unsigned int packedcolor(LColor::color c)
459 string const x11color = lcolor.getX11Name(c);
461 Display * display = fl_get_display();
462 Colormap cmap = fl_state[fl_get_vclass()].colormap;
465 if (XLookupColor(display, cmap, x11color.c_str(), &xcol, &ccol) == 0)
466 // Unable to parse x11color.
467 return FL_PACK(255,255,255);
469 // Note that X stores the RGB values in the range 0 - 65535
470 // whilst we require them in the range 0 - 255.
471 unsigned int const r = xcol.red / 256;
472 unsigned int const g = xcol.green / 256;
473 unsigned int const b = xcol.blue / 256;
475 return FL_PACK(r, g, b);