3 * Read the file COPYING
5 * \author Angus Leeming
7 * Full author contact details are available in file CREDITS
13 #pragma implementation
16 #include "xformsImage.h"
17 #include "graphics/GraphicsParams.h"
19 #include "converter.h" // formats
21 #include "support/LAssert.h"
22 #include "support/lyxfunctional.h" // compare_memfun
24 #include FORMS_H_LOCATION
29 # ifdef HAVE_X11_FLIMAGE_H
30 # include <X11/flimage.h>
34 #include <boost/tuple/tuple.hpp>
42 unsigned int packedcolor(LColor::color c);
49 /// Access to this class is through this static method.
50 Image::ImagePtr xformsImage::newImage()
55 ptr.reset(new xformsImage);
60 /// Return the list of loadable formats.
61 Image::FormatList xformsImage::loadableFormats()
63 static FormatList fmts;
69 // The formats recognised by LyX
70 Formats::const_iterator begin = formats.begin();
71 Formats::const_iterator end = formats.end();
73 lyxerr[Debug::GRAPHICS]
74 << "\nThe image loader can load the following directly:\n";
76 // Don't forget the Fortran numbering used by xforms!
77 int const nformats = flimage_get_number_of_formats();
78 for (int i = 1; i <= nformats; ++i) {
80 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
81 string const formal_name =
82 info->formal_name ? info->formal_name : string();
84 info->extension ? info->extension : string();
86 if (ext.empty() || ext == "gz")
89 if (ext == "rgb") ext = "sgi";
91 lyxerr[Debug::GRAPHICS]
92 << formal_name << ", extension \"" << ext << "\"\n";
94 Formats::const_iterator it =
96 lyx::compare_memfun(&Format::extension, ext));
98 fmts.push_back(it->name());
101 lyxerr[Debug::GRAPHICS]
102 << "\nOf these, LyX recognises the following formats:\n";
104 FormatList::const_iterator fbegin = fmts.begin();
105 FormatList::const_iterator fend = fmts.end();
106 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
108 lyxerr[Debug::GRAPHICS] << ", ";
109 lyxerr[Debug::GRAPHICS] << *fit;
111 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
117 xformsImage::xformsImage()
120 pixmap_status_(PIXMAP_UNINITIALISED)
124 xformsImage::xformsImage(xformsImage const & other)
128 pixmap_status_(PIXMAP_UNINITIALISED)
131 image_ = flimage_dup(other.image_);
132 image_->u_vdata = this;
137 xformsImage::~xformsImage()
140 flimage_free(image_);
142 XFreePixmap(fl_get_display(), pixmap_);
146 Image * xformsImage::clone() const
148 return new xformsImage(*this);
152 unsigned int xformsImage::getWidth() const
157 // Why, oh why do we need such hacks?
158 // Angus 12 July 2002
159 return image_->w + 2;
163 unsigned int xformsImage::getHeight() const
171 bool xformsImage::isDrawable() const
177 Pixmap xformsImage::getPixmap() const
179 if (!pixmap_status_ == PIXMAP_SUCCESS)
185 void xformsImage::load(string const & filename)
188 lyxerr[Debug::GRAPHICS]
189 << "Image is loaded already!" << std::endl;
190 finishedLoading(false);
194 image_ = flimage_open(filename.c_str());
196 lyxerr[Debug::GRAPHICS]
197 << "Unable to open image" << std::endl;
198 finishedLoading(false);
202 // Set this now and we won't need to bother again.
203 image_->fill_color = packedcolor(LColor::graphicsbg);
205 // Used by the callback routines to return to this
206 image_->u_vdata = this;
208 // Begin the reading process.
209 flimage_read(image_);
213 bool xformsImage::setPixmap(Params const & params)
215 if (!image_ || params.display == NoDisplay)
218 Display * display = fl_get_display();
220 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
221 XFreePixmap(display, pixmap_);
224 switch (params.display) {
225 case MonochromeDisplay:
226 color_key = FL_IMAGE_MONO;
228 case GrayscaleDisplay:
229 color_key = FL_IMAGE_GRAY;
232 default: // NoDisplay cannot happen!
233 color_key = FL_IMAGE_RGB;
237 if (color_key != FL_IMAGE_RGB) {
238 flimage_convert(image_, color_key, 0);
241 unsigned int fill = packedcolor(LColor::graphicsbg);
242 if (fill != image_->fill_color) {
243 // the background color has changed.
244 // Note that in grayscale/monochrome images the background is
245 // grayed also, so this call will have no visible effect. Sorry!
246 flimage_replace_pixel(image_, image_->fill_color, fill);
247 image_->fill_color = fill;
250 image_->xdisplay = display;
251 Screen * screen = ScreenOfDisplay(display, fl_screen);
253 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
254 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
256 return pixmap_status_ == PIXMAP_SUCCESS;
260 void xformsImage::clip(Params const & params)
265 if (params.bb.empty())
266 // No clipping is necessary.
269 int const new_width = params.bb.xr - params.bb.xl;
270 int const new_height = params.bb.yt - params.bb.yb;
272 // No need to check if the width, height are > 0 because the
273 // Bounding Box would be empty() in this case.
274 if (new_width > image_->w || new_height > image_->h)
275 // Bounds are invalid.
278 if (new_width == image_->w && new_height == image_->h)
279 // Bounds are unchanged.
282 // FIXME: these values are unsigned so this makes NO sense
284 int const xoffset_l = std::max(0U, params.bb.xl);
285 int const xoffset_r = std::max(0U, image_->w - params.bb.xr);
286 int const yoffset_t = std::max(0U, image_->h - params.bb.yt);
287 int const yoffset_b = std::max(0U, params.bb.yb);
289 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
293 void xformsImage::rotate(Params const & params)
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 (params.angle == 270) {
309 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
310 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
312 flimage_rotate(image_, params.angle * 10, FLIMAGE_SUBPIXEL);
317 void xformsImage::scale(Params const & params)
324 boost::tie(width, height) = getScaledDimensions(params);
326 if (width == getWidth() && height == getHeight())
330 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
334 void xformsImage::statusCB(string const & status_message)
336 if (status_message.empty())
339 if (prefixIs(status_message, "Done Reading")) {
341 flimage_close(image_);
344 finishedLoading(true);
349 void xformsImage::errorCB(string const & error_message)
351 if (error_message.empty())
355 flimage_close(image_);
358 finishedLoading(false);
368 int status_report(FL_IMAGE * ob, const char *s)
370 lyx::Assert(ob && ob->u_vdata);
372 string const str = s ? rtrim(s) : string();
376 lyxerr[Debug::GRAPHICS]
377 << "xforms image loader. Status : " << str << std::endl;
379 grfx::xformsImage * ptr =
380 static_cast<grfx::xformsImage *>(ob->u_vdata);
387 static void error_report(FL_IMAGE * ob, const char *s)
389 lyx::Assert(ob && ob->u_vdata);
391 string const str = s ? rtrim(s) : string();
395 lyxerr[Debug::GRAPHICS]
396 << "xforms image loader. Error : " << str << std::endl;
398 grfx::xformsImage * ptr =
399 static_cast<grfx::xformsImage *>(ob->u_vdata);
409 static bool initialised = false;
414 flimage_enable_bmp();
415 flimage_enable_fits();
416 flimage_enable_gif();
417 #ifdef HAVE_FLIMAGE_ENABLE_JPEG
418 flimage_enable_jpeg();
421 // xforms itself uses pngtopnm to convert to a loadable format.
422 // We prefer to use our own conversion mechanism, therefore.
423 // flimage_enable_png();
425 flimage_enable_pnm();
427 #ifdef HAVE_FLIMAGE_ENABLE_PS
428 // xforms recognises PS but not EPS
429 // It dies horribly with lots of older PostScript files.
430 // Easiest, therefore, to disable PS support and insist that a PS-type
431 // file is converted to a bitmap format.
432 // flimage_enable_ps();
435 flimage_enable_sgi();
436 flimage_enable_tiff();
437 flimage_enable_xbm();
438 flimage_enable_xwd();
439 flimage_enable_xpm();
441 // xforms stores this permanently (does not make a copy) so
442 // this should never be destroyed.
443 static FLIMAGE_SETUP setup;
444 setup.visual_cue = status_report;
445 setup.error_message = error_report;
446 flimage_setup(&setup);
450 unsigned int packedcolor(LColor::color c)
452 string const x11color = lcolor.getX11Name(c);
454 Display * display = fl_get_display();
455 Colormap cmap = fl_state[fl_get_vclass()].colormap;
458 if (XLookupColor(display, cmap, x11color.c_str(), &xcol, &ccol) == 0)
459 // Unable to parse x11color.
460 return FL_PACK(255,255,255);
462 // Note that X stores the RGB values in the range 0 - 65535
463 // whilst we require them in the range 0 - 255.
464 unsigned int const r = xcol.red / 256;
465 unsigned int const g = xcol.green / 256;
466 unsigned int const b = xcol.blue / 256;
468 return FL_PACK(r, g, b);