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