3 * Copyright 2002 the LyX Team
4 * Read the file COPYING
6 * \author Angus Leeming, a.leeming@ic.ac.uk
12 #pragma implementation
15 #include "xformsImage.h"
16 #include "graphics/GraphicsParams.h"
18 #include "converter.h" // formats
20 #include "support/LAssert.h"
21 #include "support/lyxfunctional.h" // compare_memfun
23 #include FORMS_H_LOCATION
28 # ifdef HAVE_X11_FLIMAGE_H
29 # include <X11/flimage.h>
33 #include <boost/tuple/tuple.hpp>
41 unsigned int packedcolor(LColor::color c);
48 /// Access to this class is through this static method.
49 Image::ImagePtr xformsImage::newImage()
54 ptr.reset(new xformsImage);
59 /// Return the list of loadable formats.
60 Image::FormatList xformsImage::loadableFormats()
62 static FormatList fmts;
68 // The formats recognised by LyX
69 Formats::const_iterator begin = formats.begin();
70 Formats::const_iterator end = formats.end();
72 lyxerr[Debug::GRAPHICS]
73 << "\nThe image loader can load the following directly:\n";
75 // Don't forget the Fortran numbering used by xforms!
76 int const nformats = flimage_get_number_of_formats();
77 for (int i = 1; i <= nformats; ++i) {
79 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
80 string const formal_name =
81 info->formal_name ? info->formal_name : string();
83 info->extension ? info->extension : string();
85 if (ext.empty() || ext == "gz")
88 if (ext == "rgb") ext = "sgi";
90 lyxerr[Debug::GRAPHICS]
91 << formal_name << ", extension \"" << ext << "\"\n";
93 Formats::const_iterator it =
95 lyx::compare_memfun(&Format::extension, ext));
97 fmts.push_back(it->name());
100 lyxerr[Debug::GRAPHICS]
101 << "\nOf these, LyX recognises the following formats:\n";
103 FormatList::const_iterator fbegin = fmts.begin();
104 FormatList::const_iterator fend = fmts.end();
105 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
107 lyxerr[Debug::GRAPHICS] << ", ";
108 lyxerr[Debug::GRAPHICS] << *fit;
110 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
116 xformsImage::xformsImage()
119 pixmap_status_(PIXMAP_UNINITIALISED)
123 xformsImage::xformsImage(xformsImage const & other)
127 pixmap_status_(PIXMAP_UNINITIALISED)
130 image_ = flimage_dup(other.image_);
131 image_->u_vdata = this;
136 xformsImage::~xformsImage()
139 flimage_free(image_);
141 XFreePixmap(fl_get_display(), pixmap_);
145 Image * xformsImage::clone() const
147 return new xformsImage(*this);
151 unsigned int xformsImage::getWidth() const
156 #if FL_VERSION == 0 && FL_REVISION == 89 && FL_FIXLEVEL <= 6
157 // Used to fix a bug in xforms <= 0.89.6 which
158 // crops the image unnecessarily.
159 return image_->w + 5;
166 unsigned int xformsImage::getHeight() const
174 Pixmap xformsImage::getPixmap() const
176 if (!pixmap_status_ == PIXMAP_SUCCESS)
182 void xformsImage::load(string const & filename)
185 lyxerr[Debug::GRAPHICS]
186 << "Image is loaded already!" << std::endl;
187 finishedLoading(false);
191 image_ = flimage_open(filename.c_str());
193 lyxerr[Debug::GRAPHICS]
194 << "Unable to open image" << std::endl;
195 finishedLoading(false);
199 // Set this now and we won't need to bother again.
200 image_->fill_color = packedcolor(LColor::graphicsbg);
202 // Used by the callback routines to return to this
203 image_->u_vdata = this;
205 // Begin the reading process.
206 flimage_read(image_);
210 bool xformsImage::setPixmap(Params const & params)
212 if (!image_ || params.display == NoDisplay)
215 Display * display = fl_get_display();
217 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
218 XFreePixmap(display, pixmap_);
221 switch (params.display) {
222 case MonochromeDisplay:
223 color_key = FL_IMAGE_MONO;
225 case GrayscaleDisplay:
226 color_key = FL_IMAGE_GRAY;
229 default: // NoDisplay cannot happen!
230 color_key = FL_IMAGE_RGB;
234 if (color_key != FL_IMAGE_RGB) {
235 flimage_convert(image_, color_key, 0);
238 unsigned int fill = packedcolor(LColor::graphicsbg);
239 if (fill != image_->fill_color) {
240 // the background color has changed.
241 // Note that in grayscale/monochrome images the background is
242 // grayed also, so this call will have no visible effect. Sorry!
243 flimage_replace_pixel(image_, image_->fill_color, fill);
244 image_->fill_color = fill;
247 image_->xdisplay = display;
248 Screen * screen = ScreenOfDisplay(display, fl_screen);
250 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
251 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
253 return pixmap_status_ == PIXMAP_SUCCESS;
257 void xformsImage::clip(Params const & params)
262 if (params.bb.empty())
263 // No clipping is necessary.
266 int const new_width = params.bb.xr - params.bb.xl;
267 int const new_height = params.bb.yt - params.bb.yb;
269 // No need to check if the width, height are > 0 because the
270 // Bounding Box would be empty() in this case.
271 if (new_width > image_->w || new_height > image_->h)
272 // Bounds are invalid.
275 if (new_width == image_->w && new_height == image_->h)
276 // Bounds are unchanged.
279 int const xoffset_l = std::max(0, params.bb.xl);
280 int const xoffset_r = std::max(0, image_->w - params.bb.xr);
281 int const yoffset_t = std::max(0, image_->h - params.bb.yt);
282 int const yoffset_b = std::max(0, params.bb.yb);
284 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
288 void xformsImage::rotate(Params const & params)
294 // No rotation is necessary.
297 // The angle passed to flimage_rotate is the angle in one-tenth of a
300 // Work around xforms bug when params.angle == 270
301 // the 'InternalError: bad special angle' error.
302 // This bug fix is not needed in xforms 1.0 and greater.
303 if (params.angle == 270) {
304 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
305 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
307 flimage_rotate(image_, params.angle * 10, FLIMAGE_SUBPIXEL);
312 void xformsImage::scale(Params const & params)
319 boost::tie(width, height) = getScaledDimensions(params);
321 if (width == getWidth() && height == getHeight())
325 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
329 void xformsImage::statusCB(string const & status_message)
331 if (status_message.empty())
334 if (prefixIs(status_message, "Done Reading")) {
336 flimage_close(image_);
339 finishedLoading(true);
344 void xformsImage::errorCB(string const & error_message)
346 if (error_message.empty())
350 flimage_close(image_);
353 finishedLoading(false);
363 int status_report(FL_IMAGE * ob, const char *s)
365 lyx::Assert(ob && ob->u_vdata);
367 string const str = s ? strip(s) : string();
371 lyxerr[Debug::GRAPHICS]
372 << "xforms image loader. Status : " << str << std::endl;
374 grfx::xformsImage * ptr =
375 static_cast<grfx::xformsImage *>(ob->u_vdata);
382 static void error_report(FL_IMAGE * ob, const char *s)
384 lyx::Assert(ob && ob->u_vdata);
386 string const str = s ? strip(s) : string();
390 lyxerr[Debug::GRAPHICS]
391 << "xforms image loader. Error : " << str << std::endl;
393 grfx::xformsImage * ptr =
394 static_cast<grfx::xformsImage *>(ob->u_vdata);
404 static bool initialised = false;
409 flimage_enable_bmp();
410 flimage_enable_fits();
411 flimage_enable_gif();
412 #ifdef HAVE_FLIMAGE_ENABLE_JPEG
413 flimage_enable_jpeg();
416 // xforms itself uses pngtopnm to convert to a loadable format.
417 // We prefer to use our own conversion mechanism, therefore.
418 // flimage_enable_png();
420 flimage_enable_pnm();
422 #ifdef HAVE_FLIMAGE_ENABLE_PS
423 // xforms recognises PS but not EPS
427 flimage_enable_sgi();
428 flimage_enable_tiff();
429 flimage_enable_xbm();
430 flimage_enable_xwd();
431 flimage_enable_xpm();
433 // xforms stores this permanently (does not make a copy) so
434 // this should never be destroyed.
435 static FLIMAGE_SETUP setup;
436 setup.visual_cue = status_report;
437 setup.error_message = error_report;
438 flimage_setup(&setup);
442 unsigned int packedcolor(LColor::color c)
444 string const x11color = lcolor.getX11Name(c);
446 Display * display = fl_get_display();
447 Colormap cmap = fl_state[fl_get_vclass()].colormap;
450 if (XLookupColor(display, cmap, x11color.c_str(), &xcol, &ccol) == 0)
451 // Unable to parse x11color.
452 return FL_PACK(255,255,255);
454 // Note that X stores the RGB values in the range 0 - 65535
455 // whilst we require them in the range 0 - 255.
456 unsigned int const r = xcol.red / 256;
457 unsigned int const g = xcol.green / 256;
458 unsigned int const b = xcol.blue / 256;
460 return FL_PACK(r, g, b);