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 "xformsGImage.h"
16 #include "graphics/GraphicsParams.h"
18 #include "converter.h" // formats
20 #include "support/LAssert.h"
21 #include "support/lyxfunctional.h" // compare_memfun
29 unsigned int packedcolor(LColor::color c);
36 /// Access to this class is through this static method.
37 ImagePtr xformsGImage::newImage()
42 ptr.reset(new xformsGImage);
47 /// Return the list of loadable formats.
48 GImage::FormatList xformsGImage::loadableFormats()
50 static FormatList fmts;
56 // The formats recognised by LyX
57 Formats::const_iterator begin = formats.begin();
58 Formats::const_iterator end = formats.end();
60 lyxerr[Debug::GRAPHICS]
61 << "\nThe image loader can load the following directly:\n";
63 // Don't forget the Fortran numbering used by xforms!
64 int const nformats = flimage_get_number_of_formats();
65 for (int i = 1; i <= nformats; ++i) {
67 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
68 string const formal_name =
69 info->formal_name ? info->formal_name : string();
71 info->extension ? info->extension : string();
73 if (ext.empty() || ext == "gz")
76 if (ext == "rgb") ext = "sgi";
78 lyxerr[Debug::GRAPHICS]
79 << formal_name << ", extension \"" << ext << "\"\n";
81 Formats::const_iterator it =
83 lyx::compare_memfun(&Format::extension, ext));
85 fmts.push_back(it->name());
88 lyxerr[Debug::GRAPHICS]
89 << "\nOf these, LyX recognises the following formats:\n";
91 FormatList::const_iterator fbegin = fmts.begin();
92 FormatList::const_iterator fend = fmts.end();
93 for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
95 lyxerr[Debug::GRAPHICS] << ", ";
96 lyxerr[Debug::GRAPHICS] << *fit;
98 lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
104 xformsGImage::xformsGImage()
107 pixmap_status_(PIXMAP_UNINITIALISED)
111 xformsGImage::xformsGImage(xformsGImage const & other)
115 pixmap_status_(PIXMAP_UNINITIALISED)
118 image_ = flimage_dup(other.image_);
119 image_->u_vdata = this;
124 xformsGImage::~xformsGImage()
127 flimage_free(image_);
129 XFreePixmap(fl_get_display(), pixmap_);
133 GImage * xformsGImage::clone() const
135 return new xformsGImage(*this);
139 unsigned int xformsGImage::getWidth() const
147 unsigned int xformsGImage::getHeight() const
155 Pixmap xformsGImage::getPixmap() const
157 if (!pixmap_status_ == PIXMAP_SUCCESS)
163 void xformsGImage::load(string const & filename, SignalTypePtr on_finish)
166 lyxerr[Debug::GRAPHICS]
167 << "Image is loaded already!" << std::endl;
168 on_finish->operator()(false);
172 image_ = flimage_open(filename.c_str());
174 lyxerr[Debug::GRAPHICS]
175 << "Unable to open image" << std::endl;
176 on_finish->operator()(false);
180 // Store the Signal that will be emitted once the image is loaded.
181 on_finish_ = on_finish;
183 // Set this now and we won't need to bother again.
184 image_->fill_color = packedcolor(LColor::graphicsbg);
186 // Used by the callback routines to return to this
187 image_->u_vdata = this;
189 // Begin the reading process.
190 flimage_read(image_);
194 bool xformsGImage::setPixmap(GParams const & params)
196 if (!image_ || params.display == GParams::NONE)
199 Display * display = fl_get_display();
201 if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
202 XFreePixmap(display, pixmap_);
205 switch (params.display) {
206 case GParams::MONOCHROME:
207 color_key = FL_IMAGE_MONO;
209 case GParams::GRAYSCALE:
210 color_key = FL_IMAGE_GRAY;
213 default: // NONE cannot happen!
214 color_key = FL_IMAGE_RGB;
218 if (color_key != FL_IMAGE_RGB) {
219 flimage_convert(image_, color_key, 0);
222 unsigned int fill = packedcolor(LColor::graphicsbg);
223 if (fill != image_->fill_color) {
224 // the background color has changed.
225 // Note that in grayscale/monochrome images the background is
226 // grayed also, so this call will have no visible effect. Sorry!
227 flimage_replace_pixel(image_, image_->fill_color, fill);
228 image_->fill_color = fill;
231 image_->xdisplay = display;
232 Screen * screen = ScreenOfDisplay(display, fl_screen);
234 pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
235 pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
237 return pixmap_status_ == PIXMAP_SUCCESS;
241 void xformsGImage::clip(GParams const & params)
246 if (params.bb.empty())
247 // No clipping is necessary.
250 int const new_width = params.bb.xr - params.bb.xl;
251 int const new_height = params.bb.yt - params.bb.yb;
253 // No need to check if the width, height are > 0 because the
254 // Bounding Box would be empty() in this case.
255 if (new_width > image_->w || new_height > image_->h)
256 // Bounds are invalid.
259 if (new_width == image_->w && new_height == image_->h)
260 // Bounds are unchanged.
263 int const xoffset_l = std::max(0, params.bb.xl);
264 int const xoffset_r = std::max(0, image_->w - params.bb.xr);
265 int const yoffset_t = std::max(0, image_->h - params.bb.yt);
266 int const yoffset_b = std::max(0, params.bb.yb);
268 flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
272 void xformsGImage::rotate(GParams const & params)
278 // No rotation is necessary.
281 // The angle passed to flimage_rotate is the angle in one-tenth of a
284 // Work around xforms bug when params.angle == 270
285 // the 'InternalError: bad special angle' error.
286 // This bug fix is not needed in xforms 1.0 and greater.
287 if (params.angle == 270) {
288 flimage_rotate(image_, 900, FLIMAGE_SUBPIXEL);
289 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
291 flimage_rotate(image_, params.angle * 10, FLIMAGE_SUBPIXEL);
296 void xformsGImage::scale(GParams const & params)
301 // boost::tie produces horrible compilation errors on my machine
303 std::pair<unsigned int, unsigned int> d = getScaledDimensions(params);
304 unsigned int const width = d.first;
305 unsigned int const height = d.second;
307 if (width == getWidth() && height == getHeight())
311 flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
315 void xformsGImage::statusCB(string const & status_message)
317 if (status_message.empty() || !on_finish_.get())
320 if (prefixIs(status_message, "Done Reading")) {
322 flimage_close(image_);
325 if (on_finish_.get()) {
326 on_finish_->operator()(true);
333 void xformsGImage::errorCB(string const & error_message)
335 if (error_message.empty() || !on_finish_.get())
339 flimage_close(image_);
342 if (on_finish_.get()) {
343 on_finish_->operator()(false);
355 int status_report(FL_IMAGE * ob, const char *s)
357 lyx::Assert(ob && ob->u_vdata);
359 string const str = s ? strip(s) : string();
363 lyxerr[Debug::GRAPHICS]
364 << "xforms image loader. Status : " << str << std::endl;
366 grfx::xformsGImage * ptr =
367 static_cast<grfx::xformsGImage *>(ob->u_vdata);
374 static void error_report(FL_IMAGE * ob, const char *s)
376 lyx::Assert(ob && ob->u_vdata);
378 string const str = s ? strip(s) : string();
382 lyxerr[Debug::GRAPHICS]
383 << "xforms image loader. Error : " << str << std::endl;
385 grfx::xformsGImage * ptr =
386 static_cast<grfx::xformsGImage *>(ob->u_vdata);
396 static bool initialised = false;
401 flimage_enable_bmp();
402 flimage_enable_fits();
403 flimage_enable_gif();
404 #ifdef HAVE_FLIMAGE_ENABLE_JPEG
405 flimage_enable_jpeg();
408 // xforms itself uses pngtopnm to convert to a loadable format.
409 // We prefer to use our own conversion mechanism, therefore.
410 // flimage_enable_png();
412 flimage_enable_pnm();
414 #ifdef HAVE_FLIMAGE_ENABLE_PS
415 // xforms recognises PS but not EPS
419 flimage_enable_sgi();
420 flimage_enable_tiff();
421 flimage_enable_xbm();
422 flimage_enable_xwd();
423 flimage_enable_xpm();
425 // xforms stores this permanently (does not make a copy) so
426 // this should never be destroyed.
427 static FLIMAGE_SETUP setup;
428 setup.visual_cue = status_report;
429 setup.error_message = error_report;
430 flimage_setup(&setup);
434 unsigned int packedcolor(LColor::color c)
436 string const x11color = lcolor.getX11Name(c);
438 Display * display = fl_get_display();
439 Colormap cmap = fl_state[fl_get_vclass()].colormap;
442 if (XLookupColor(display, cmap, x11color.c_str(), &xcol, &ccol) == 0)
443 // Unable to parse x11color.
444 return FL_PACK(255,255,255);
446 // Note that X stores the RGB values in the range 0 - 65535
447 // whilst we require them in the range 0 - 255.
448 unsigned int const r = xcol.red / 256;
449 unsigned int const g = xcol.green / 256;
450 unsigned int const b = xcol.blue / 256;
452 return FL_PACK(r, g, b);