fltk/src/Fl_Shared_Image.cxx
Matthias Melcher 5251b64d57 Changed Copyright in 'src' directory
git-svn-id: file:///fltk/svn/fltk/branches/branch-1.3@6616 ea41ed52-d2ee-0310-a9c1-e6b18d33e121
2009-01-01 21:28:26 +00:00

464 lines
11 KiB
C++

//
// "$Id$"
//
// Shared image code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2009 by Bill Spitzak and others.
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Library General Public License for more details.
//
// You should have received a copy of the GNU Library General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
// USA.
//
// Please report all bugs and problems on the following page:
//
// http://www.fltk.org/str.php
//
#include <stdio.h>
#include <stdlib.h>
#include <FL/fl_utf8.h>
#include "flstring.h"
#include <FL/Fl.H>
#include <FL/Fl_Shared_Image.H>
#include <FL/Fl_XBM_Image.H>
#include <FL/Fl_XPM_Image.H>
//
// Global class vars...
//
Fl_Shared_Image **Fl_Shared_Image::images_ = 0; // Shared images
int Fl_Shared_Image::num_images_ = 0; // Number of shared images
int Fl_Shared_Image::alloc_images_ = 0; // Allocated shared images
Fl_Shared_Handler *Fl_Shared_Image::handlers_ = 0;// Additional format handlers
int Fl_Shared_Image::num_handlers_ = 0; // Number of format handlers
int Fl_Shared_Image::alloc_handlers_ = 0; // Allocated format handlers
//
// Typedef the C API sort function type the only way I know how...
//
extern "C" {
typedef int (*compare_func_t)(const void *, const void *);
}
/** Returns the Fl_Shared_Image* array */
Fl_Shared_Image **Fl_Shared_Image::images() {
return images_;
}
/** Returns the total number of shared images in the array. */
int Fl_Shared_Image::num_images() {
return num_images_;
}
//
// 'Fl_Shared_Image::compare()' - Compare two shared images...
//
int
Fl_Shared_Image::compare(Fl_Shared_Image **i0, // I - First image
Fl_Shared_Image **i1) { // I - Second image
int i = strcmp((*i0)->name(), (*i1)->name());
if (i) return i;
else if (((*i0)->w() == 0 && (*i1)->original_) ||
((*i1)->w() == 0 && (*i0)->original_)) return 0;
else if ((*i0)->w() != (*i1)->w()) return (*i0)->w() - (*i1)->w();
else return (*i0)->h() - (*i1)->h();
}
/**
Creates an empty shared image.
The constructors create a new shared image record in the image cache.
<P>The constructors are protected and cannot be used directly
from a program. Use the get() method instead.
*/
Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) {
name_ = 0;
refcount_ = 1;
original_ = 0;
image_ = 0;
alloc_image_ = 0;
}
/**
Creates a shared image from its filename and its corresponding Fl_Image* img.
The constructors create a new shared image record in the image cache.
<P>The constructors are protected and cannot be used directly
from a program. Use the get() method instead.
*/
Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename
Fl_Image *img) // I - Image
: Fl_Image(0,0,0) {
name_ = new char[strlen(n) + 1];
strcpy((char *)name_, n);
refcount_ = 1;
image_ = img;
alloc_image_ = !img;
original_ = 1;
if (!img) reload();
else update();
}
//
// 'Fl_Shared_Image::add()' - Add a shared image to the array.
//
void
Fl_Shared_Image::add() {
Fl_Shared_Image **temp; // New image pointer array...
if (num_images_ >= alloc_images_) {
// Allocate more memory...
temp = new Fl_Shared_Image *[alloc_images_ + 32];
if (alloc_images_) {
memcpy(temp, images_, alloc_images_ * sizeof(Fl_Shared_Image *));
delete[] images_;
}
images_ = temp;
alloc_images_ += 32;
}
images_[num_images_] = this;
num_images_ ++;
if (num_images_ > 1) {
qsort(images_, num_images_, sizeof(Fl_Shared_Image *),
(compare_func_t)compare);
}
}
//
// 'Fl_Shared_Image::update()' - Update the dimensions of the shared images.
//
void
Fl_Shared_Image::update() {
if (image_) {
w(image_->w());
h(image_->h());
d(image_->d());
data(image_->data(), image_->count());
}
}
/**
The destructor free all memory and server resources that are
used by the image. The destructor is protected and cannot be
used directly from a program. Use the Fl_Shared_Image::release() method
instead.
*/
Fl_Shared_Image::~Fl_Shared_Image() {
if (name_) delete[] (char *)name_;
if (alloc_image_) delete image_;
}
//
/**
Releases and possibly destroys (if refcount <=0) a shared image.
In the latter case, it will reorganize the shared image array so that no hole will occur.
*/
void Fl_Shared_Image::release() {
int i; // Looping var...
refcount_ --;
if (refcount_ > 0) return;
for (i = 0; i < num_images_; i ++)
if (images_[i] == this) {
num_images_ --;
if (i < num_images_) {
memmove(images_ + i, images_ + i + 1,
(num_images_ - i) * sizeof(Fl_Shared_Image *));
}
break;
}
delete this;
if (num_images_ == 0 && images_) {
delete[] images_;
images_ = 0;
alloc_images_ = 0;
}
}
//
/** Reloads the shared image from disk */
void Fl_Shared_Image::reload() {
// Load image from disk...
int i; // Looping var
FILE *fp; // File pointer
uchar header[64]; // Buffer for auto-detecting files
Fl_Image *img; // New image
if (!name_) return;
if ((fp = fl_fopen(name_, "rb")) != NULL) {
fread(header, 1, sizeof(header), fp);
fclose(fp);
} else {
return;
}
// Load the image as appropriate...
if (memcmp(header, "#define", 7) == 0) // XBM file
img = new Fl_XBM_Image(name_);
else if (memcmp(header, "/* XPM */", 9) == 0) // XPM file
img = new Fl_XPM_Image(name_);
else {
// Not a standard format; try an image handler...
for (i = 0, img = 0; i < num_handlers_; i ++) {
img = (handlers_[i])(name_, header, sizeof(header));
if (img) break;
}
}
if (img) {
if (alloc_image_) delete image_;
alloc_image_ = 1;
if ((img->w() != w() && w()) || (img->h() != h() && h())) {
// Make sure the reloaded image is the same size as the existing one.
Fl_Image *temp = img->copy(w(), h());
delete img;
image_ = temp;
} else {
image_ = img;
}
update();
}
}
//
// 'Fl_Shared_Image::copy()' - Copy and resize a shared image...
//
Fl_Image *
Fl_Shared_Image::copy(int W, int H) {
Fl_Image *temp_image; // New image file
Fl_Shared_Image *temp_shared; // New shared image
// Make a copy of the image we're sharing...
if (!image_) temp_image = 0;
else temp_image = image_->copy(W, H);
// Then make a new shared image...
temp_shared = new Fl_Shared_Image();
temp_shared->name_ = new char[strlen(name_) + 1];
strcpy((char *)temp_shared->name_, name_);
temp_shared->refcount_ = 1;
temp_shared->image_ = temp_image;
temp_shared->alloc_image_ = 1;
temp_shared->update();
return temp_shared;
}
//
// 'Fl_Shared_Image::color_average()' - Blend colors...
//
void
Fl_Shared_Image::color_average(Fl_Color c, // I - Color to blend with
float i) { // I - Blend fraction
if (!image_) return;
image_->color_average(c, i);
update();
}
//
// 'Fl_Shared_Image::desaturate()' - Convert the image to grayscale...
//
void
Fl_Shared_Image::desaturate() {
if (!image_) return;
image_->desaturate();
update();
}
//
// 'Fl_Shared_Image::draw()' - Draw a shared image...
//
void
Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) {
if (image_) image_->draw(X, Y, W, H, cx, cy);
else Fl_Image::draw(X, Y, W, H, cx, cy);
}
//
// 'Fl_Shared_Image::uncache()' - Uncache the shared image...
//
void Fl_Shared_Image::uncache()
{
if (image_) image_->uncache();
}
/** Finds a shared image from its named and size specifications */
Fl_Shared_Image* Fl_Shared_Image::find(const char *n, int W, int H) {
Fl_Shared_Image *key, // Image key
**match; // Matching image
if (num_images_) {
key = new Fl_Shared_Image();
key->name_ = new char[strlen(n) + 1];
strcpy((char *)key->name_, n);
key->w(W);
key->h(H);
match = (Fl_Shared_Image **)bsearch(&key, images_, num_images_,
sizeof(Fl_Shared_Image *),
(compare_func_t)compare);
delete key;
if (match) {
(*match)->refcount_ ++;
return *match;
}
}
return 0;
}
/**
Gets a shared image, if it exists already ; it will return it.
If it does not exist or if it exist but with other size,
then the existing image is deleted and replaced
by a new image from the n filename of the proper dimension.
If n is not a valid image filename, then get() will return NULL.
*/
Fl_Shared_Image* Fl_Shared_Image::get(const char *n, int W, int H) {
Fl_Shared_Image *temp; // Image
if ((temp = find(n, W, H)) != NULL) return temp;
if ((temp = find(n)) == NULL) {
temp = new Fl_Shared_Image(n);
if (!temp->image_) {
delete temp;
return NULL;
}
temp->add();
}
if ((temp->w() != W || temp->h() != H) && W && H) {
temp = (Fl_Shared_Image *)temp->copy(W, H);
temp->add();
}
return temp;
}
/** Adds a shared image handler, which is basically a test function for adding new formats */
void Fl_Shared_Image::add_handler(Fl_Shared_Handler f) {
int i; // Looping var...
Fl_Shared_Handler *temp; // New image handler array...
// First see if we have already added the handler...
for (i = 0; i < num_handlers_; i ++) {
if (handlers_[i] == f) return;
}
if (num_handlers_ >= alloc_handlers_) {
// Allocate more memory...
temp = new Fl_Shared_Handler [alloc_handlers_ + 32];
if (alloc_handlers_) {
memcpy(temp, handlers_, alloc_handlers_ * sizeof(Fl_Shared_Handler));
delete[] handlers_;
}
handlers_ = temp;
alloc_handlers_ += 32;
}
handlers_[num_handlers_] = f;
num_handlers_ ++;
}
/** Removes a shared image handler */
void Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) {
int i; // Looping var...
// First see if the handler has been added...
for (i = 0; i < num_handlers_; i ++) {
if (handlers_[i] == f) break;
}
if (i >= num_handlers_) return;
// OK, remove the handler from the array...
num_handlers_ --;
if (i < num_handlers_) {
// Shift later handlers down 1...
memmove(handlers_ + i, handlers_ + i + 1,
(num_handlers_ - i) * sizeof(Fl_Shared_Handler ));
}
}
//
// End of "$Id$".
//