]> git.lyx.org Git - features.git/blob - src/frontends/xforms/xformsGImage.C
94e95d65a84b792da80a7693d26abb4ad0bcff85
[features.git] / src / frontends / xforms / xformsGImage.C
1 /*
2  * \file xformsGImage.C
3  * Copyright 2002 the LyX Team
4  * Read the file COPYING
5  *
6  * \author Angus Leeming, a.leeming@ic.ac.uk
7  */
8
9 #include <config.h>
10
11 #ifdef __GNUG__
12 #pragma implementation
13 #endif
14
15 #include "xformsGImage.h"
16 #include "graphics/GraphicsParams.h"
17 #include "LColor.h"
18 #include "converter.h"              // formats
19 #include "debug.h"
20 #include "support/LAssert.h"
21 #include "support/lyxfunctional.h"  // compare_memfun
22
23 using std::find_if;
24
25 namespace {
26
27 void init_graphics();
28
29 unsigned int packedcolor(LColor::color c);
30
31 } // namespace anon
32
33
34 namespace grfx {
35
36 /// Access to this class is through this static method.
37 ImagePtr xformsGImage::newImage()
38 {
39         init_graphics();
40
41         ImagePtr ptr;
42         ptr.reset(new xformsGImage);
43         return ptr;
44 }
45
46
47 /// Return the list of loadable formats.
48 GImage::FormatList xformsGImage::loadableFormats()
49 {
50         static FormatList fmts;
51         if (!fmts.empty())
52                 return fmts;
53
54         init_graphics();
55
56         // The formats recognised by LyX
57         Formats::const_iterator begin = formats.begin();
58         Formats::const_iterator end   = formats.end();
59
60         lyxerr[Debug::GRAPHICS]
61                 << "\nThe image loader can load the following directly:\n";
62
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) {
66
67                 FLIMAGE_FORMAT_INFO const * info = flimage_get_format_info(i);
68                 string const formal_name =
69                         info->formal_name ? info->formal_name : string();
70                 string ext =
71                         info->extension   ? info->extension   : string();
72
73                 if (ext.empty() || ext == "gz")
74                         continue;
75
76                 if (ext == "rgb") ext = "sgi";
77
78                 lyxerr[Debug::GRAPHICS]
79                         << formal_name << ", extension \"" << ext << "\"\n";
80
81                 Formats::const_iterator it =
82                         find_if(begin, end,
83                                 lyx::compare_memfun(&Format::extension, ext));
84                 if (it != end)
85                         fmts.push_back(it->name());
86         }
87
88         lyxerr[Debug::GRAPHICS]
89                 << "\nOf these, LyX recognises the following formats:\n";
90
91         FormatList::const_iterator fbegin = fmts.begin();
92         FormatList::const_iterator fend   = fmts.end();
93         for (FormatList::const_iterator fit = fbegin; fit != fend; ++fit) {
94                 if (fit != fbegin)
95                         lyxerr[Debug::GRAPHICS] << ", ";
96                 lyxerr[Debug::GRAPHICS] << *fit;
97         }
98         lyxerr[Debug::GRAPHICS] << '\n' << std::endl;
99
100         return fmts;
101 }
102
103
104 xformsGImage::xformsGImage()
105         : image_(0),
106           pixmap_(0),
107           pixmap_status_(PIXMAP_UNINITIALISED)
108 {}
109
110
111 xformsGImage::xformsGImage(xformsGImage const & other)
112         : GImage(other),
113           image_(0),
114           pixmap_(0),
115           pixmap_status_(PIXMAP_UNINITIALISED)
116 {
117         if (other.image_) {
118                 image_ = flimage_dup(other.image_);
119                 image_->u_vdata = this;
120         }
121 }
122
123
124 xformsGImage::~xformsGImage()
125 {
126         if (image_)
127                 flimage_free(image_);
128         if (pixmap_)
129                 XFreePixmap(fl_get_display(), pixmap_);
130 }
131
132
133 GImage * xformsGImage::clone() const
134 {
135         return new xformsGImage(*this);
136 }
137
138
139 unsigned int xformsGImage::getWidth() const
140 {
141         if (!image_)
142                 return 0;
143         return image_->w;
144 }
145
146
147 unsigned int xformsGImage::getHeight() const
148 {
149         if (!image_)
150                 return 0;
151         return image_->h;
152 }
153
154
155 Pixmap xformsGImage::getPixmap() const
156 {
157         if (!pixmap_status_ == PIXMAP_SUCCESS)
158                 return 0;
159         return pixmap_;
160 }
161
162
163 void xformsGImage::load(string const & filename, SignalTypePtr on_finish)
164 {
165         if (image_) {
166                 lyxerr[Debug::GRAPHICS]
167                         << "Image is loaded already!" << std::endl;
168                 on_finish->operator()(false);
169                 return;
170         }
171
172         image_ = flimage_open(filename.c_str());
173         if (!image_) {
174                 lyxerr[Debug::GRAPHICS]
175                         << "Unable to open image" << std::endl;
176                 on_finish->operator()(false);
177                 return;
178         }
179
180         // Store the Signal that will be emitted once the image is loaded.
181         on_finish_ = on_finish;
182
183         // Set this now and we won't need to bother again.
184         image_->fill_color = packedcolor(LColor::graphicsbg);
185
186         // Used by the callback routines to return to this
187         image_->u_vdata = this;
188
189         // Begin the reading process.
190         flimage_read(image_);
191 }
192
193
194 bool xformsGImage::setPixmap(GParams const & params)
195 {
196         if (!image_ || params.display == GParams::NONE)
197                 return false;
198
199         Display * display = fl_get_display();
200
201         if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
202                 XFreePixmap(display, pixmap_);
203
204         int color_key;
205         switch (params.display) {
206         case GParams::MONOCHROME:
207                 color_key = FL_IMAGE_MONO;
208                 break;
209         case GParams::GRAYSCALE:
210                 color_key = FL_IMAGE_GRAY;
211                 break;
212         case GParams::COLOR:
213         default: // NONE cannot happen!
214                 color_key = FL_IMAGE_RGB;
215                 break;
216         }
217
218         if (color_key != FL_IMAGE_RGB) {
219                 flimage_convert(image_, color_key, 0);
220         }
221
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;
229         }
230
231         image_->xdisplay = display;
232         Screen * screen  = ScreenOfDisplay(display, fl_screen);
233
234         pixmap_ = flimage_to_pixmap(image_, XRootWindowOfScreen(screen));
235         pixmap_status_ = pixmap_ ? PIXMAP_SUCCESS : PIXMAP_FAILED;
236
237         return pixmap_status_ == PIXMAP_SUCCESS;
238 }
239
240
241 void xformsGImage::clip(GParams const & params)
242 {
243         if (!image_)
244                 return;
245
246         if (params.bb.empty())
247                 // No clipping is necessary.
248                 return;
249
250         int const new_width  = params.bb.xr - params.bb.xl;
251         int const new_height = params.bb.yt - params.bb.yb;
252
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.
257                 return;
258
259         if (new_width == image_->w && new_height == image_->h)
260                 // Bounds are unchanged.
261                 return;
262
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);
267
268         flimage_crop(image_, xoffset_l, yoffset_t, xoffset_r, yoffset_b);
269 }
270
271
272 void xformsGImage::rotate(GParams const & params)
273 {
274         if (!image_)
275                 return ;
276
277         if (!params.angle)
278                 // No rotation is necessary.
279                 return;
280
281         // The angle passed to flimage_rotate is the angle in one-tenth of a
282         // degree units.
283
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);
290         } else {
291                 flimage_rotate(image_, params.angle * 10, FLIMAGE_SUBPIXEL);
292         }
293 }
294
295
296 void xformsGImage::scale(GParams const & params)
297 {
298         if (!image_)
299                 return;
300
301         // boost::tie produces horrible compilation errors on my machine
302         // Angus 25 Feb 2002
303         std::pair<unsigned int, unsigned int> d = getScaledDimensions(params);
304         unsigned int const width  = d.first;
305         unsigned int const height = d.second;
306
307         if (width == getWidth() && height == getHeight())
308                 // No scaling needed
309                 return;
310
311         flimage_scale(image_, width, height, FLIMAGE_SUBPIXEL);
312 }
313
314
315 void xformsGImage::statusCB(string const & status_message)
316 {
317         if (status_message.empty() || !on_finish_.get())
318                 return;
319
320         if (prefixIs(status_message, "Done Reading")) {
321                 if (image_) {
322                         flimage_close(image_);
323                 }
324
325                 if (on_finish_.get()) {
326                         on_finish_->operator()(true);
327                         on_finish_.reset();
328                 }
329         }
330 }
331
332
333 void xformsGImage::errorCB(string const & error_message)
334 {
335         if (error_message.empty() || !on_finish_.get())
336                 return;
337
338         if (image_) {
339                 flimage_close(image_);
340         }
341
342         if (on_finish_.get()) {
343                 on_finish_->operator()(false);
344                 on_finish_.reset();
345         }
346 }
347
348 } // namespace grfx
349
350
351 namespace {
352
353 extern "C" {
354
355 int status_report(FL_IMAGE * ob, const char *s)
356 {
357         lyx::Assert(ob && ob->u_vdata);
358
359         string const str = s ? strip(s) : string();
360         if (str.empty())
361                 return 0;
362
363         lyxerr[Debug::GRAPHICS]
364                 << "xforms image loader. Status : " << str << std::endl;
365
366         grfx::xformsGImage * ptr =
367                 static_cast<grfx::xformsGImage *>(ob->u_vdata);
368         ptr->statusCB(str);
369
370         return 0;
371 }
372
373
374 static void error_report(FL_IMAGE * ob, const char *s)
375 {
376         lyx::Assert(ob && ob->u_vdata);
377
378         string const str = s ? strip(s) : string();
379         if (str.empty())
380                 return;
381
382         lyxerr[Debug::GRAPHICS]
383                 << "xforms image loader. Error : " << str << std::endl;
384
385         grfx::xformsGImage * ptr =
386                 static_cast<grfx::xformsGImage *>(ob->u_vdata);
387         ptr->errorCB(str);
388 }
389
390 } // extern "C"
391
392
393 void init_graphics()
394 {
395         // Paranoia check
396         static bool initialised = false;
397         if (initialised)
398                 return;
399         initialised = true;
400
401         flimage_enable_bmp();
402         flimage_enable_fits();
403         flimage_enable_gif();
404 #ifdef HAVE_FLIMAGE_ENABLE_JPEG
405         flimage_enable_jpeg();
406 #endif
407
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();
411
412         flimage_enable_pnm();
413
414 #ifdef HAVE_FLIMAGE_ENABLE_PS
415         // xforms recognises PS but not EPS
416         flimage_enable_ps();
417 #endif
418
419         flimage_enable_sgi();
420         flimage_enable_tiff();
421         flimage_enable_xbm();
422         flimage_enable_xwd();
423         flimage_enable_xpm();
424
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);
431 }
432
433
434 unsigned int packedcolor(LColor::color c)
435 {
436         string const x11color = lcolor.getX11Name(c);
437
438         Display * display = fl_get_display();
439         Colormap cmap     = fl_state[fl_get_vclass()].colormap;
440         XColor xcol;
441         XColor ccol;
442         if (XLookupColor(display, cmap, x11color.c_str(), &xcol, &ccol) == 0)
443                 // Unable to parse x11color.
444                 return FL_PACK(255,255,255);
445
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;
451
452         return FL_PACK(r, g, b);
453 }
454
455 } // namespace anon