]> git.lyx.org Git - lyx.git/blob - src/frontends/xforms/xformsImage.C
Removed all redundant using directives from the source.
[lyx.git] / src / frontends / xforms / xformsImage.C
1 /**
2  * \file xformsImage.C
3  * This file is part of LyX, the document processor.
4  * Licence details can be found in the file COPYING.
5  *
6  * \author Angus Leeming
7  *
8  * Full author contact details are available in file CREDITS.
9  */
10
11 #include <config.h>
12
13 #include "xformsImage.h"
14 #include "graphics/GraphicsParams.h"
15 #include "Color.h"
16 #include "format.h"
17 #include "debug.h"
18 #include "support/LAssert.h"
19 #include "support/lstrings.h"
20 #include "support/lyxfunctional.h"  // compare_memfun
21 #include "support/lyxlib.h"
22
23 #include "lyx_forms.h"
24
25 #ifdef HAVE_FLIMAGE_H
26 # include <flimage.h>
27 #else
28 # ifdef HAVE_X11_FLIMAGE_H
29 # include <X11/flimage.h>
30 # endif
31 #endif
32
33 #include <boost/tuple/tuple.hpp>
34
35 using namespace lyx::support;
36
37 using std::find_if;
38
39
40 namespace {
41
42 void init_graphics();
43
44 unsigned int packedcolor(LColor::color c);
45
46 } // namespace anon
47
48
49 namespace lyx {
50 namespace graphics {
51
52 /// Access to this class is through this static method.
53 Image::ImagePtr xformsImage::newImage()
54 {
55         init_graphics();
56
57         ImagePtr ptr;
58         ptr.reset(new xformsImage);
59         return ptr;
60 }
61
62
63 /// Return the list of loadable formats.
64 Image::FormatList xformsImage::loadableFormats()
65 {
66         static FormatList fmts;
67         if (!fmts.empty())
68                 return fmts;
69
70         init_graphics();
71
72         // The formats recognised by LyX
73         Formats::const_iterator begin = formats.begin();
74         Formats::const_iterator end   = formats.end();
75
76         lyxerr[Debug::GRAPHICS]
77                 << "\nThe image loader can load the following directly:\n";
78
79         // Don't forget the Fortran numbering used by xforms!
80         int const nformats = flimage_get_number_of_formats();
81         for (int i = 1; i <= nformats; ++i) {
82
83                 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
84                 string const formal_name =
85                         info->formal_name ? info->formal_name : string();
86                 string ext =
87                         info->extension   ? info->extension   : string();
88
89                 if (ext.empty() || ext == "gz")
90                         continue;
91
92                 if (ext == "rgb") ext = "sgi";
93
94                 lyxerr[Debug::GRAPHICS]
95                         << formal_name << ", extension \"" << ext << "\"\n";
96
97                 Formats::const_iterator it =
98                         find_if(begin, end,
99                                 lyx::compare_memfun(&Format::extension, ext));
100                 if (it != end)
101                         fmts.push_back(it->name());
102         }
103
104         lyxerr[Debug::GRAPHICS]
105                 << "\nOf these, LyX recognises the following formats:\n";
106
107         FormatList::const_iterator fbegin = fmts.begin();
108         FormatList::const_iterator fend   = fmts.end();
109         for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
110                 if (fit != fbegin)
111                         lyxerr[Debug::GRAPHICS] << ", ";
112                 lyxerr[Debug::GRAPHICS] << *fit;
113         }
114         lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
115
116         return fmts;
117 }
118
119
120 xformsImage::xformsImage()
121         : image_(0),
122           pixmap_(0),
123           pixmap_status_(PIXMAP_UNINITIALISED)
124 {}
125
126
127 xformsImage::xformsImage(xformsImage const & other)
128         : Image(other),
129           image_(0),
130           pixmap_(0),
131           pixmap_status_(PIXMAP_UNINITIALISED)
132 {
133         if (other.image_) {
134                 image_ = flimage_dup(other.image_);
135                 image_->u_vdata = this;
136         }
137 }
138
139
140 xformsImage::~xformsImage()
141 {
142         if (image_)
143                 flimage_free(image_);
144         if (pixmap_)
145                 XFreePixmap(fl_get_display(), pixmap_);
146 }
147
148
149 Image * xformsImage::clone() const
150 {
151         return new xformsImage(*this);
152 }
153
154
155 unsigned int xformsImage::getWidth() const
156 {
157         if (!image_)
158                 return 0;
159
160         return image_->w;
161 }
162
163
164 unsigned int xformsImage::getHeight() const
165 {
166         if (!image_)
167                 return 0;
168         return image_->h;
169 }
170
171
172 bool xformsImage::isDrawable() const
173 {
174         return pixmap_;
175 }
176
177
178 Pixmap xformsImage::getPixmap() const
179 {
180         if (!pixmap_status_ == PIXMAP_SUCCESS)
181                 return 0;
182         return pixmap_;
183 }
184
185
186 void xformsImage::load(string const & filename)
187 {
188         if (image_) {
189                 lyxerr[Debug::GRAPHICS]
190                         << "Image is loaded already!" << std::endl;
191                 finishedLoading(false);
192                 return;
193         }
194
195         image_ = flimage_open(filename.c_str());
196         if (!image_) {
197                 lyxerr[Debug::GRAPHICS]
198                         << "Unable to open image" << std::endl;
199                 finishedLoading(false);
200                 return;
201         }
202
203         // Set this now and we won't need to bother again.
204         image_->fill_color = packedcolor(LColor::graphicsbg);
205
206         // Used by the callback routines to return to this
207         image_->u_vdata = this;
208
209         // Begin the reading process.
210         flimage_read(image_);
211 }
212
213
214 bool xformsImage::setPixmap(Params const & params)
215 {
216         if (!image_ || params.display == NoDisplay)
217                 return false;
218
219         Display * display = fl_get_display();
220
221         if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
222                 XFreePixmap(display, pixmap_);
223
224         int color_key;
225         switch (params.display) {
226         case MonochromeDisplay:
227                 color_key = FL_IMAGE_MONO;
228                 break;
229         case GrayscaleDisplay:
230                 color_key = FL_IMAGE_GRAY;
231                 break;
232         case ColorDisplay:
233         default: // NoDisplay cannot happen!
234                 color_key = FL_IMAGE_RGB;
235                 break;
236         }
237
238         if (color_key != FL_IMAGE_RGB) {
239                 flimage_convert(image_, color_key, 0);
240         }
241
242         unsigned int fill = packedcolor(LColor::graphicsbg);
243         if (fill != image_->fill_color) {
244                 // the background color has changed.
245                 // Note that in grayscale/monochrome images the background is
246                 // grayed also, so this call will have no visible effect. Sorry!
247                 flimage_replace_pixel(image_, image_->fill_color, fill);
248                 image_->fill_color = fill;
249         }
250
251         image_->xdisplay = display;
252         Screen * screen  = ScreenOfDisplay(display, fl_screen);
253
254         pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
255         pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
256
257         return pixmap_status_ == PIXMAP_SUCCESS;
258 }
259
260
261 void xformsImage::clip(Params const & params)
262 {
263         if (!image_)
264                 return;
265
266         if (params.bb.empty())
267                 // No clipping is necessary.
268                 return;
269
270         int const new_width  = params.bb.xr - params.bb.xl;
271         int const new_height = params.bb.yt - params.bb.yb;
272
273         // No need to check if the width, height are > 0 because the
274         // Bounding Box would be empty() in this case.
275         if (new_width > image_->w || new_height > image_->h)
276                 // Bounds are invalid.
277                 return;
278
279         if (new_width == image_->w && new_height == image_->h)
280                 // Bounds are unchanged.
281                 return;
282
283         // flimage.h: image_ members w and h are of type int
284         // (though always >= 0)
285         // GraphicsParams.h: params.bb members xl, xr, yt and yb are of
286         // type unsigned int.
287         // We must, therefore, be careful...
288         int const xoffset_l = params.bb.xl;
289         int const yoffset_b = params.bb.yb;
290         int const xoffset_r = image_->w > int(params.bb.xr) ?
291                 image_->w - params.bb.xr : 0;
292         int const yoffset_t = image_->h > int(params.bb.yt) ?
293                 image_->h - params.bb.yt : 0;
294
295         flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
296 }
297
298
299 void xformsImage::rotate(Params const & params)
300 {
301         if (!image_)
302                 return ;
303
304         if (float_equal(params.angle, 0.0, 0.1))
305                 // No rotation is necessary.
306                 return;
307
308         // The angle passed to flimage_rotate is the angle in one-tenth of a
309         // degree units.
310
311         // Work around xforms bug when params.angle == 270
312         // the 'InternalError: bad special angle' error.
313         // This bug fix is not needed in xforms 1.0 and greater.
314         if (float_equal(params.angle, 270.0, 0.1)) {
315                 flimage_rotate(image_,  900, FLIMAGE_SUBPIXEL);
316                 flimage_rotate(image_, 1800, FLIMAGE_SUBPIXEL);
317         } else {
318                 flimage_rotate(image_,
319                                int(params.angle * 10),
320                                FLIMAGE_SUBPIXEL);
321         }
322 }
323
324
325 void xformsImage::scale(Params const & params)
326 {
327         if (!image_)
328                 return;
329
330         unsigned int width;
331         unsigned int height;
332         boost::tie(width, height) = getScaledDimensions(params);
333
334         if (width == getWidth() && height == getHeight())
335                 // No scaling needed
336                 return;
337
338         flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
339 }
340
341
342 void xformsImage::statusCB(string const & status_message)
343 {
344         if (status_message.empty())
345                 return;
346
347         if (prefixIs(status_message, "Done Reading")) {
348                 if (image_) {
349                         flimage_close(image_);
350                 }
351
352                 finishedLoading(true);
353         }
354 }
355
356
357 void xformsImage::errorCB(string const & error_message)
358 {
359         if (error_message.empty())
360                 return;
361
362         if (image_) {
363                 flimage_close(image_);
364         }
365
366         finishedLoading(false);
367 }
368
369 } // namespace graphics
370 } // namespace lyx
371
372
373 namespace {
374
375 extern "C" {
376
377 int status_report(FL_IMAGE * ob, const char *s)
378 {
379         Assert(ob && ob->u_vdata);
380
381         string const str = s ? rtrim(s) : string();
382         if (str.empty())
383                 return 0;
384
385         lyxerr[Debug::GRAPHICS]
386                 << "xforms image loader. Status: " << str << std::endl;
387
388         lyx::graphics::xformsImage * ptr =
389                 static_cast<lyx::graphics::xformsImage *>(ob->u_vdata);
390         ptr->statusCB(str);
391
392         return 0;
393 }
394
395
396 static void error_report(FL_IMAGE * ob, const char *s)
397 {
398         Assert(ob && ob->u_vdata);
399
400         string const str = s ? rtrim(s) : string();
401         if (str.empty())
402                 return;
403
404         lyxerr[Debug::GRAPHICS]
405                 << "xforms image loader. Error: " << str << std::endl;
406
407         lyx::graphics::xformsImage * ptr =
408                 static_cast<lyx::graphics::xformsImage *>(ob->u_vdata);
409         ptr->errorCB(str);
410 }
411
412 } // extern "C"
413
414
415 void init_graphics()
416 {
417         // Paranoia check
418         static bool initialised = false;
419         if (initialised)
420                 return;
421         initialised = true;
422
423         flimage_enable_bmp();
424         flimage_enable_fits();
425         flimage_enable_gif();
426 #ifdef USE_JPEG_IMAGE_LOADER
427         flimage_enable_jpeg();
428 #endif
429
430         // xforms itself uses pngtopnm to convert to a loadable format.
431         // We prefer to use our own conversion mechanism, therefore.
432         // flimage_enable_png();
433
434         flimage_enable_pnm();
435
436         // xforms recognises PS but not EPS
437         // It dies horribly with lots of older PostScript files.
438         // Easiest, therefore, to disable PS support and insist that a PS-type
439         // file is converted to a bitmap format.
440         // flimage_enable_ps();
441
442         flimage_enable_sgi();
443         flimage_enable_tiff();
444         flimage_enable_xbm();
445         flimage_enable_xwd();
446         // xforms can load most XPM files, but will occasionally crash
447         // with some files created by ImakeMagick's convert program.
448         // Turn off xpm support for the time being.
449         // flimage_enable_xpm();
450
451         // xforms stores this permanently (does not make a copy) so
452         // this should never be destroyed.
453         static FLIMAGE_SETUP setup;
454         setup.visual_cue    = status_report;
455         setup.error_message = error_report;
456         flimage_setup(&setup);
457 }
458
459
460 unsigned int packedcolor(LColor::color col)
461 {
462         unsigned int r, g, b;
463         bool const success = getRGBColor(col, r, g, b);
464         if (!success)
465                 // Set to black on failure
466                 return FL_PACK(255,255,255);
467
468         return FL_PACK(r, g, b);
469 }
470
471 } // namespace anon