blob: 13598a9e2a9d222632e4e3c5662d06ca6649bb83 [file] [log] [blame]
DRC2ff39b82011-07-28 08:38:59 +00001//
2// "$Id: Fl_Shared_Image.cxx 8306 2011-01-24 17:04:22Z matt $"
3//
4// Shared image code for the Fast Light Tool Kit (FLTK).
5//
6// Copyright 1998-2010 by Bill Spitzak and others.
7//
8// This library is free software; you can redistribute it and/or
9// modify it under the terms of the GNU Library General Public
10// License as published by the Free Software Foundation; either
11// version 2 of the License, or (at your option) any later version.
12//
13// This library is distributed in the hope that it will be useful,
14// but WITHOUT ANY WARRANTY; without even the implied warranty of
15// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16// Library General Public License for more details.
17//
18// You should have received a copy of the GNU Library General Public
19// License along with this library; if not, write to the Free Software
20// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21// USA.
22//
23// Please report all bugs and problems on the following page:
24//
25// http://www.fltk.org/str.php
26//
27
28#include <stdio.h>
29#include <stdlib.h>
30#include <FL/fl_utf8.h>
31#include "flstring.h"
32
33#include <FL/Fl.H>
34#include <FL/Fl_Shared_Image.H>
35#include <FL/Fl_XBM_Image.H>
36#include <FL/Fl_XPM_Image.H>
37
38
39//
40// Global class vars...
41//
42
43Fl_Shared_Image **Fl_Shared_Image::images_ = 0; // Shared images
44int Fl_Shared_Image::num_images_ = 0; // Number of shared images
45int Fl_Shared_Image::alloc_images_ = 0; // Allocated shared images
46
47Fl_Shared_Handler *Fl_Shared_Image::handlers_ = 0;// Additional format handlers
48int Fl_Shared_Image::num_handlers_ = 0; // Number of format handlers
49int Fl_Shared_Image::alloc_handlers_ = 0; // Allocated format handlers
50
51
52//
53// Typedef the C API sort function type the only way I know how...
54//
55
56extern "C" {
57 typedef int (*compare_func_t)(const void *, const void *);
58}
59
60
61/** Returns the Fl_Shared_Image* array */
62Fl_Shared_Image **Fl_Shared_Image::images() {
63 return images_;
64}
65/** Returns the total number of shared images in the array. */
66int Fl_Shared_Image::num_images() {
67 return num_images_;
68}
69
70
71//
72// 'Fl_Shared_Image::compare()' - Compare two shared images...
73//
74
75int
76Fl_Shared_Image::compare(Fl_Shared_Image **i0, // I - First image
77 Fl_Shared_Image **i1) { // I - Second image
78 int i = strcmp((*i0)->name(), (*i1)->name());
79
80 if (i) return i;
81 else if (((*i0)->w() == 0 && (*i1)->original_) ||
82 ((*i1)->w() == 0 && (*i0)->original_)) return 0;
83 else if ((*i0)->w() != (*i1)->w()) return (*i0)->w() - (*i1)->w();
84 else return (*i0)->h() - (*i1)->h();
85}
86
87
88/**
89 Creates an empty shared image.
90 The constructors create a new shared image record in the image cache.
91
92 <P>The constructors are protected and cannot be used directly
93 from a program. Use the get() method instead.
94*/
95Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) {
96 name_ = 0;
97 refcount_ = 1;
98 original_ = 0;
99 image_ = 0;
100 alloc_image_ = 0;
101}
102
103
104/**
105 Creates a shared image from its filename and its corresponding Fl_Image* img.
106 The constructors create a new shared image record in the image cache.
107
108 <P>The constructors are protected and cannot be used directly
109 from a program. Use the get() method instead.
110*/
111Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename
112 Fl_Image *img) // I - Image
113 : Fl_Image(0,0,0) {
114 name_ = new char[strlen(n) + 1];
115 strcpy((char *)name_, n);
116
117 refcount_ = 1;
118 image_ = img;
119 alloc_image_ = !img;
120 original_ = 1;
121
122 if (!img) reload();
123 else update();
124}
125
126
127//
128// 'Fl_Shared_Image::add()' - Add a shared image to the array.
129//
130
131void
132Fl_Shared_Image::add() {
133 Fl_Shared_Image **temp; // New image pointer array...
134
135 if (num_images_ >= alloc_images_) {
136 // Allocate more memory...
137 temp = new Fl_Shared_Image *[alloc_images_ + 32];
138
139 if (alloc_images_) {
140 memcpy(temp, images_, alloc_images_ * sizeof(Fl_Shared_Image *));
141
142 delete[] images_;
143 }
144
145 images_ = temp;
146 alloc_images_ += 32;
147 }
148
149 images_[num_images_] = this;
150 num_images_ ++;
151
152 if (num_images_ > 1) {
153 qsort(images_, num_images_, sizeof(Fl_Shared_Image *),
154 (compare_func_t)compare);
155 }
156}
157
158
159//
160// 'Fl_Shared_Image::update()' - Update the dimensions of the shared images.
161//
162
163void
164Fl_Shared_Image::update() {
165 if (image_) {
166 w(image_->w());
167 h(image_->h());
168 d(image_->d());
169 data(image_->data(), image_->count());
170 }
171}
172
173/**
174 The destructor free all memory and server resources that are
175 used by the image. The destructor is protected and cannot be
176 used directly from a program. Use the Fl_Shared_Image::release() method
177 instead.
178*/
179Fl_Shared_Image::~Fl_Shared_Image() {
180 if (name_) delete[] (char *)name_;
181 if (alloc_image_) delete image_;
182}
183
184
185//
186/**
187 Releases and possibly destroys (if refcount <=0) a shared image.
188 In the latter case, it will reorganize the shared image array so that no hole will occur.
189*/
190void Fl_Shared_Image::release() {
191 int i; // Looping var...
192
193 refcount_ --;
194 if (refcount_ > 0) return;
195
196 for (i = 0; i < num_images_; i ++)
197 if (images_[i] == this) {
198 num_images_ --;
199
200 if (i < num_images_) {
201 memmove(images_ + i, images_ + i + 1,
202 (num_images_ - i) * sizeof(Fl_Shared_Image *));
203 }
204
205 break;
206 }
207
208 delete this;
209
210 if (num_images_ == 0 && images_) {
211 delete[] images_;
212
213 images_ = 0;
214 alloc_images_ = 0;
215 }
216}
217
218
219//
220/** Reloads the shared image from disk */
221void Fl_Shared_Image::reload() {
222 // Load image from disk...
223 int i; // Looping var
224 FILE *fp; // File pointer
225 uchar header[64]; // Buffer for auto-detecting files
226 Fl_Image *img; // New image
227
228 if (!name_) return;
229
230 if ((fp = fl_fopen(name_, "rb")) != NULL) {
231 if (fread(header, 1, sizeof(header), fp)==0) { /* ignore */ }
232 fclose(fp);
233 } else {
234 return;
235 }
236
237 // Load the image as appropriate...
238 if (memcmp(header, "#define", 7) == 0) // XBM file
239 img = new Fl_XBM_Image(name_);
240 else if (memcmp(header, "/* XPM */", 9) == 0) // XPM file
241 img = new Fl_XPM_Image(name_);
242 else {
243 // Not a standard format; try an image handler...
244 for (i = 0, img = 0; i < num_handlers_; i ++) {
245 img = (handlers_[i])(name_, header, sizeof(header));
246
247 if (img) break;
248 }
249 }
250
251 if (img) {
252 if (alloc_image_) delete image_;
253
254 alloc_image_ = 1;
255
256 if ((img->w() != w() && w()) || (img->h() != h() && h())) {
257 // Make sure the reloaded image is the same size as the existing one.
258 Fl_Image *temp = img->copy(w(), h());
259 delete img;
260 image_ = temp;
261 } else {
262 image_ = img;
263 }
264
265 update();
266 }
267}
268
269
270//
271// 'Fl_Shared_Image::copy()' - Copy and resize a shared image...
272//
273
274Fl_Image *
275Fl_Shared_Image::copy(int W, int H) {
276 Fl_Image *temp_image; // New image file
277 Fl_Shared_Image *temp_shared; // New shared image
278
279 // Make a copy of the image we're sharing...
280 if (!image_) temp_image = 0;
281 else temp_image = image_->copy(W, H);
282
283 // Then make a new shared image...
284 temp_shared = new Fl_Shared_Image();
285
286 temp_shared->name_ = new char[strlen(name_) + 1];
287 strcpy((char *)temp_shared->name_, name_);
288
289 temp_shared->refcount_ = 1;
290 temp_shared->image_ = temp_image;
291 temp_shared->alloc_image_ = 1;
292
293 temp_shared->update();
294
295 return temp_shared;
296}
297
298
299//
300// 'Fl_Shared_Image::color_average()' - Blend colors...
301//
302
303void
304Fl_Shared_Image::color_average(Fl_Color c, // I - Color to blend with
305 float i) { // I - Blend fraction
306 if (!image_) return;
307
308 image_->color_average(c, i);
309 update();
310}
311
312
313//
314// 'Fl_Shared_Image::desaturate()' - Convert the image to grayscale...
315//
316
317void
318Fl_Shared_Image::desaturate() {
319 if (!image_) return;
320
321 image_->desaturate();
322 update();
323}
324
325
326//
327// 'Fl_Shared_Image::draw()' - Draw a shared image...
328//
329
330void
331Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
332 if (image_) image_->draw(X, Y, W, H, cx, cy);
333 else Fl_Image::draw(X, Y, W, H, cx, cy);
334}
335
336
337//
338// 'Fl_Shared_Image::uncache()' - Uncache the shared image...
339//
340
341void Fl_Shared_Image::uncache()
342{
343 if (image_) image_->uncache();
344}
345
346
347
348/** Finds a shared image from its named and size specifications */
349Fl_Shared_Image* Fl_Shared_Image::find(const char *n, int W, int H) {
350 Fl_Shared_Image *key, // Image key
351 **match; // Matching image
352
353 if (num_images_) {
354 key = new Fl_Shared_Image();
355 key->name_ = new char[strlen(n) + 1];
356 strcpy((char *)key->name_, n);
357 key->w(W);
358 key->h(H);
359
360 match = (Fl_Shared_Image **)bsearch(&key, images_, num_images_,
361 sizeof(Fl_Shared_Image *),
362 (compare_func_t)compare);
363
364 delete key;
365
366 if (match) {
367 (*match)->refcount_ ++;
368 return *match;
369 }
370 }
371
372 return 0;
373}
374
375
376/**
377 \brief Find or load an image that can be shared by multiple widgets.
378
379 Gets a shared image, if it exists already ; it will return it.
380 If it does not exist or if it exist but with other size,
381 then the existing image is deleted and replaced
382 by a new image from the n filename of the proper dimension.
383 If n is not a valid image filename, then get() will return NULL.
384
385 Shared JPEG and PNG images can also be created from memory by using their
386 named memory access constructor.
387
388 \param n name of the image
389 \param W, H desired size
390
391 \see Fl_Shared_Image::find(const char *n, int W, int H)
392 \see Fl_Shared_Image::release()
393 \see Fl_JPEG_Image::Fl_JPEG_Image(const char *name, const unsigned char *data)
394 \see Fl_PNG_Image::Fl_PNG_Image (const char *name_png, const unsigned char *buffer, int maxsize)
395*/
396Fl_Shared_Image* Fl_Shared_Image::get(const char *n, int W, int H) {
397 Fl_Shared_Image *temp; // Image
398
399 if ((temp = find(n, W, H)) != NULL) return temp;
400
401 if ((temp = find(n)) == NULL) {
402 temp = new Fl_Shared_Image(n);
403
404 if (!temp->image_) {
405 delete temp;
406 return NULL;
407 }
408
409 temp->add();
410 }
411
412 if ((temp->w() != W || temp->h() != H) && W && H) {
413 temp = (Fl_Shared_Image *)temp->copy(W, H);
414 temp->add();
415 }
416
417 return temp;
418}
419
420
421
422/** Adds a shared image handler, which is basically a test function for adding new formats */
423void Fl_Shared_Image::add_handler(Fl_Shared_Handler f) {
424 int i; // Looping var...
425 Fl_Shared_Handler *temp; // New image handler array...
426
427 // First see if we have already added the handler...
428 for (i = 0; i < num_handlers_; i ++) {
429 if (handlers_[i] == f) return;
430 }
431
432 if (num_handlers_ >= alloc_handlers_) {
433 // Allocate more memory...
434 temp = new Fl_Shared_Handler [alloc_handlers_ + 32];
435
436 if (alloc_handlers_) {
437 memcpy(temp, handlers_, alloc_handlers_ * sizeof(Fl_Shared_Handler));
438
439 delete[] handlers_;
440 }
441
442 handlers_ = temp;
443 alloc_handlers_ += 32;
444 }
445
446 handlers_[num_handlers_] = f;
447 num_handlers_ ++;
448}
449
450
451
452/** Removes a shared image handler */
453void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
454 int i; // Looping var...
455
456 // First see if the handler has been added...
457 for (i = 0; i < num_handlers_; i ++) {
458 if (handlers_[i] == f) break;
459 }
460
461 if (i >= num_handlers_) return;
462
463 // OK, remove the handler from the array...
464 num_handlers_ --;
465
466 if (i < num_handlers_) {
467 // Shift later handlers down 1...
468 memmove(handlers_ + i, handlers_ + i + 1,
469 (num_handlers_ - i) * sizeof(Fl_Shared_Handler ));
470 }
471}
472
473
474//
475// End of "$Id: Fl_Shared_Image.cxx 8306 2011-01-24 17:04:22Z matt $".
476//