#include "GraphicsParams.h"
#include "ColorHandler.h"
#include "debug.h"
-#include "frontends/GUIRunTime.h" // x11Display
+#include "frontends/GUIRunTime.h" // x11Display, x11Screen
#include "support/filetools.h" // IsFileReadable
#include "support/lstrings.h"
#include "Lsstream.h"
ptr.reset(new GImageXPM());
return ptr;
}
-
+
/// Return the list of loadable formats.
GImage::FormatList GImageXPM::loadableFormats()
formats[0] = "xpm";
return formats;
}
-
+
GImageXPM::GImageXPM()
: pixmap_(0),
pixmap_status_(PIXMAP_UNINITIALISED)
{}
-
+
GImageXPM::GImageXPM(GImageXPM const & other)
: GImage(other),
image_(other.image_),
- pixmap_(other.pixmap_),
- pixmap_status_(other.pixmap_status_)
+ pixmap_(0),
+ pixmap_status_(PIXMAP_UNINITIALISED)
{}
-
+
GImageXPM::~GImageXPM()
{
- if (pixmap_status_ == PIXMAP_SUCCESS)
+ if (pixmap_)
XFreePixmap(GUIRunTime::x11Display(), pixmap_);
}
-
+
GImage * GImageXPM::clone() const
{
return false;
}
- if (pixmap_status_ == PIXMAP_FAILED) {
- return false;
- }
-
- if (pixmap_status_ == PIXMAP_SUCCESS) {
- return true;
- }
-
- using namespace grfx;
Display * display = GUIRunTime::x11Display();
+ if (pixmap_ && pixmap_status_ == PIXMAP_SUCCESS)
+ XFreePixmap(display, pixmap_);
+
//(BE 2000-08-05)
// This might be a dirty thing, but I dont know any other solution.
Screen * screen = ScreenOfDisplay(display, GUIRunTime::x11Screen());
// No clipping is necessary.
return;
- int const new_width = params.bb.xr - params.bb.xl;
- int const new_height = params.bb.yt - params.bb.yb;
+ typedef unsigned int dimension;
+
+ dimension const new_width = params.bb.xr - params.bb.xl;
+ dimension const new_height = params.bb.yt - params.bb.yb;
if (new_width > image_.width() || new_height > image_.height())
// Bounds are invalid.
return;
- if (new_width == image_.width() && new_height == image_.height())
+ if (new_width == image_.width() && new_height == image_.height())
// Bounds are unchanged.
return;
- unsigned int * new_data = image_.initialisedData(new_width, new_height);
- unsigned int const * old_data = image_.data();
+ dimension * new_data = image_.initialisedData(new_width, new_height);
+ dimension const * old_data = image_.data();
- unsigned int * it = new_data;
- unsigned int const * start_row = old_data;
- for (int row = params.bb.yb; row < params.bb.yt; ++row) {
- unsigned int const * begin = start_row + params.bb.xl;
- unsigned int const * end = start_row + params.bb.xr;
+ dimension * it = new_data;
+ dimension const * start_row = old_data;
+ for (size_t row = params.bb.yb; row < params.bb.yt; ++row) {
+ dimension const * begin = start_row + params.bb.xl;
+ dimension const * end = start_row + params.bb.xr;
it = std::copy(begin, end, it);
start_row += image_.width();
}
max_x = std::max(max_x, x_rot); min_x = std::min(min_x, x_rot);
max_y = std::max(max_y, y_rot); min_y = std::min(min_y, y_rot);
- int const new_width = 1 + int(max_x - min_x); // round up!
- int const new_height = 1 + int(max_y - min_y);
-
- unsigned int * new_data = image_.initialisedData(new_width, new_height);
- unsigned int const * old_data = image_.data();
+ typedef unsigned int dimension;
+ dimension const new_width = 1 + int(max_x - min_x); // round up!
+ dimension const new_height = 1 + int(max_y - min_y);
+
+ dimension * new_data = image_.initialisedData(new_width, new_height);
+ dimension const * old_data = image_.data();
+
// rotate the data
- for (int y_old = 0; y_old < image_.height(); ++y_old) {
- for (int x_old = 0; x_old < image_.width(); ++x_old) {
- int x_new = int(cos_a * x_old - sin_a * y_old - min_x);
- int y_new = int(sin_a * x_old + cos_a * y_old - min_y);
+ for (dimension y_old = 0; y_old < image_.height(); ++y_old) {
+ for (dimension x_old = 0; x_old < image_.width(); ++x_old) {
+ double const x_pos = cos_a*x_old - sin_a*y_old - min_x;
+ double const y_pos = sin_a*x_old + cos_a*y_old - min_y;
// ensure that there are no rounding errors
- y_new = std::min(int(new_height - 1), y_new);
- y_new = std::max(0, y_new);
- x_new = std::min(int(new_width - 1), x_new);
- x_new = std::max(0, x_new);
+ dimension x_new = (x_pos > 0) ? dimension(x_pos) : 0;
+ dimension y_new = (y_pos > 0) ? dimension(y_pos) : 0;
+ x_new = std::min(new_width - 1, x_new);
+ y_new = std::min(new_height - 1, y_new);
- int const old_id = x_old + image_.width() * y_old;
- int const new_id = x_new + new_width * y_new;
+ size_t const id_old = x_old + image_.width() * y_old;
+ size_t const id_new = x_new + new_width * y_new;
- new_data[new_id] = old_data[old_id];
+ new_data[id_new] = old_data[id_old];
}
}
if (image_.empty())
return;
+ typedef unsigned int dimension;
+
// boost::tie produces horrible compilation errors on my machine
// Angus 25 Feb 2002
- std::pair<unsigned int, unsigned int> d = getScaledDimensions(params);
- int const new_width = d.first;
- int const new_height = d.second;
+ std::pair<dimension, dimension> d = getScaledDimensions(params);
+ dimension const new_width = d.first;
+ dimension const new_height = d.second;
if (new_width == getWidth() && new_height == getHeight())
// No scaling needed
return;
- unsigned int * new_data = image_.initialisedData(new_width, new_height);
- unsigned int const * old_data = image_.data();
-
+ dimension * new_data = image_.initialisedData(new_width, new_height);
+ dimension const * old_data = image_.data();
+
double const x_scale = double(image_.width()) / double(new_width);
double const y_scale = double(image_.height()) / double(new_height);
// A very simple scaling routine.
// Ascertain the old pixel corresponding to the new one.
// There is no dithering at all here.
- for (int x_new = 0; x_new < new_width; ++x_new) {
- int x_old = int(x_new * x_scale);
- for (int y_new = 0; y_new < new_height; ++y_new) {
- int y_old = int(y_new * y_scale);
+ for (dimension x_new = 0; x_new < new_width; ++x_new) {
+ dimension x_old = dimension(x_new * x_scale);
+
+ for (dimension y_new = 0; y_new < new_height; ++y_new) {
+ dimension y_old = dimension(y_new * y_scale);
- int const old_id = x_old + image_.width() * y_old;
- int const new_id = x_new + new_width * y_new;
+ size_t const id_old = x_old + image_.width() * y_old;
+ size_t const id_new = x_new + new_width * y_new;
- new_data[new_id] = old_data[old_id];
+ new_data[id_new] = old_data[id_old];
}
}
-
+
image_.resetData(new_width, new_height, new_data);
}
namespace {
-void free_color_table(XpmColor * colorTable, int ncolors);
+void free_color_table(XpmColor * colorTable, size_t size);
+
+void copy_color_table(XpmColor const * in, size_t size, XpmColor * out);
-void copy_color_table(XpmColor const * in, int size, XpmColor * out);
-
bool contains_color_none(XpmImage const & image);
string const unique_color_string(XpmImage const & image);
-
+
// create a copy (using malloc and strcpy). If (!in) return 0;
char * clone_c_string(char const * in);
-
-// Given a string of the form #ff0571 create a string for the appropriate
-// grayscale or monochrome color.
-char * mapcolor(char * color, bool toGray);
+
+// Given a string of the form #ff0571 create appropriate grayscale and
+// monochrome colors.
+void mapcolor(char const * c_color, char ** g_color_ptr, char ** m_color_ptr);
} // namespace anon
namespace grfx {
-
GImageXPM::Data::Data()
: width_(0), height_(0), cpp_(0), ncolors_(0)
{}
// 1. Create a copy of the color table.
// Add a c_color "none" entry to the table if it isn't already there.
bool const add_color = !contains_color_none(image);
-
+
if (add_color) {
ncolors_ = 1 + image.ncolors;
// 2. Ensure that the color table has g_color and m_color entries
XpmColor * table = colorTable_.get();
+ string buggy_color;
+
+ for (size_t i = 0; i < ncolors_; ++i) {
+ XpmColor & entry = table[i];
+ if (!entry.c_color)
+ continue;
+
+ // A work-around for buggy XPM files that may be created by
+ // ImageMagick's convert.
+ string c_color = entry.c_color;
+ if (c_color[0] == '#' && c_color.size() > 7) {
+ if (buggy_color.empty())
+ buggy_color = c_color;
+
+ c_color = c_color.substr(0, 7);
+ free(entry.c_color);
+ entry.c_color = clone_c_string(c_color.c_str());
+ }
- for (int i = 0; i < ncolors_; ++i) {
// If the c_color is defined and the equivalent
- // grayscale one is not, then define it.
- if (table[i].c_color && !table[i].g_color)
- table[i].g_color = mapcolor(table[i].c_color, true);
+ // grayscale or monochrome ones are not, then define them.
+ mapcolor(entry.c_color, &entry.g_color, &entry.m_color);
+ }
- // If the c_color is defined and the equivalent
- // monochrome one is not, then define it.
- if (table[i].c_color && !table[i].m_color)
- table[i].m_color = mapcolor(table[i].c_color, false);
+ if (!buggy_color.empty()) {
+ lyxerr << "The XPM file contains silly colors, "
+ << "an example being \""
+ << buggy_color << "\".\n"
+ << "This was cropped to \""
+ << buggy_color.substr(0, 7)
+ << "\" so you can see something!\n"
+ << "If this file was created by ImageMagick's convert,\n"
+ << "then upgrading may cure the problem."
+ << std::endl;
}
}
unsigned int GImageXPM::Data::color_none_id() const
{
XpmColor * table = colorTable_.get();
- for (int i = 0; i < ncolors_; ++i) {
+ for (size_t i = 0; i < ncolors_; ++i) {
char const * const color = table[i].c_color;
if (color && lowercase(color) == "none")
- return i;
+ return uint(i);
}
return 0;
}
namespace {
-// Given a string of the form #ff0571 create a string for the appropriate
-// grayscale or monochrome color.
-char * mapcolor(char * color, bool toGray)
+// Given a string of the form #ff0571 create appropriate grayscale and
+// monochrome colors.
+void mapcolor(char const * c_color, char ** g_color_ptr, char ** m_color_ptr)
{
- if (!color)
- return 0;
-
+ if (!c_color)
+ return;
+
+ char * g_color = *g_color_ptr;
+ char * m_color = *m_color_ptr;
+
+ if (g_color && m_color)
+ // Already filled.
+ return;
+
Display * display = GUIRunTime::x11Display();
Colormap cmap = GUIRunTime::x11Colormap();
XColor xcol;
XColor ccol;
- if (XLookupColor(display, cmap, color, &xcol, &ccol) == 0)
- return 0;
+ if (XLookupColor(display, cmap, c_color, &xcol, &ccol) == 0)
+ // Unable to parse c_color.
+ return;
// Note that X stores the RGB values in the range 0 - 65535
// whilst we require them in the range 0 - 255.
// This gives a good match to a human's RGB to luminance conversion.
// (From xv's Postscript code --- Mike Ressler.)
- int mapped_color = int((0.32 * r) + (0.5 * g) + (0.18 * b));
- if (!toGray) // monochrome
- mapped_color = (mapped_color < 128) ? 0 : 255;
-
- ostringstream ostr;
-
- ostr << "#" << std::setbase(16) << std::setfill('0')
- << std::setw(2) << mapped_color
- << std::setw(2) << mapped_color
- << std::setw(2) << mapped_color;
-
- // This string is going into an XpmImage struct, so create a copy that
+ int const gray = int((0.32 * r) + (0.5 * g) + (0.18 * b));
+
+ ostringstream gray_stream;
+ gray_stream << "#" << std::setbase(16) << std::setfill('0')
+ << std::setw(2) << gray
+ << std::setw(2) << gray
+ << std::setw(2) << gray;
+
+ int const mono = (gray < 128) ? 0 : 255;
+ ostringstream mono_stream;
+ mono_stream << "#" << std::setbase(16) << std::setfill('0')
+ << std::setw(2) << mono
+ << std::setw(2) << mono
+ << std::setw(2) << mono;
+
+ // This string is going into an XpmImage struct, so create copies that
// libXPM can free successfully.
- return clone_c_string(ostr.str().c_str());
+ if (!g_color)
+ *g_color_ptr = clone_c_string(gray_stream.str().c_str());
+ if (!m_color)
+ *m_color_ptr = clone_c_string(mono_stream.str().c_str());
}
-void copy_color_table(XpmColor const * in, int size, XpmColor * out)
+void copy_color_table(XpmColor const * in, size_t size, XpmColor * out)
{
- for (int i = 0; i < size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
out[i].string = clone_c_string(in[i].string);
out[i].symbolic = clone_c_string(in[i].symbolic);
out[i].m_color = clone_c_string(in[i].m_color);
}
-void free_color_table(XpmColor * table, int size)
+void free_color_table(XpmColor * table, size_t size)
{
- for (int i = 0; i < size; ++i) {
+ for (size_t i = 0; i < size; ++i) {
free(table[i].string);
free(table[i].symbolic);
free(table[i].m_color);
free(table[i].g4_color);
free(table[i].c_color);
}
- free(table);
+ // Don't free the table itself. Let the shared_c_ptr do that.
+ // free(table);
}
bool contains_color_none(XpmImage const & image)
{
- for (int i = 0; i < image.ncolors; ++i) {
+ for (size_t i = 0; i < image.ncolors; ++i) {
char const * const color = image.colorTable[i].c_color;
if (color && lowercase(color) == "none")
return true;
string const unique_color_string(XpmImage const & image)
{
- string id;
- for (int i = 0; i < image.cpp; ++i) {
- id.push_back('A');
- }
+ string id(image.cpp, ' ');
for(;;) {
bool found_it = false;
- for (int i = 0; i < image.ncolors; ++i) {
+ for (size_t i = 0; i < image.ncolors; ++i) {
string const c_id = image.colorTable[i].string;
if (c_id == id) {
found_it = true;
if (!found_it)
return id;
- // A base 57 counter!
- // eg AAAz+1 = AABA, AABz+1 = AACA, AAzz+1 = ABAA
- int current_index = int(id.size() - 1);
+ // Loop over the printable characters in the ASCII table.
+ // Ie, count from char 32 (' ') to char 126 ('~')
+ // A base 94 counter!
+ string::size_type current_index = id.size() - 1;
bool continue_loop = true;
- while(continue_loop && current_index >= 0) {
+ while(continue_loop) {
continue_loop = false;
-
- if (id[current_index] == 'z') {
- id[current_index] = 'A';
- current_index -= 1;
+
+ if (id[current_index] == 126) {
continue_loop = true;
+ if (current_index == 0)
+ // Unable to find a unique string
+ return image.colorTable[0].string;
+
+ id[current_index] = 32;
+ current_index -= 1;
} else {
id[current_index] += 1;
+ // Note that '"' is an illegal char in this
+ // context
+ if (id[current_index] == '"')
+ id[current_index] += 1;
}
}
- if (current_index < 0)
+ if (continue_loop)
// Unable to find a unique string
return string();
}