]> git.lyx.org Git - lyx.git/blobdiff - src/graphics/GraphicsImageXPM.C
fix typo that put too many include paths for most people
[lyx.git] / src / graphics / GraphicsImageXPM.C
index 06edf6241aa274229bcac0b7096fd135b5381148..37aaec0741b9120825a6cb097e6d016cda204ed3 100644 (file)
@@ -17,7 +17,7 @@
 #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"
@@ -34,7 +34,7 @@ ImagePtr GImageXPM::newImage()
        ptr.reset(new GImageXPM());
        return ptr;
 }
-       
+
 
 /// Return the list of loadable formats.
 GImage::FormatList GImageXPM::loadableFormats()
@@ -43,28 +43,28 @@ 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
 {
@@ -124,7 +124,7 @@ void GImageXPM::load(string const & filename, GImage::SignalTypePtr on_finish)
                break;
 
        case XpmNoMemory:
-               lyxerr[Debug::GRAPHICS] 
+               lyxerr[Debug::GRAPHICS]
                        << "Insufficient memory to read in XPM file"
                        << std::endl;
                break;
@@ -135,7 +135,7 @@ void GImageXPM::load(string const & filename, GImage::SignalTypePtr on_finish)
                delete xpm_image;
 
                lyxerr[Debug::GRAPHICS]
-                       << "Error reading XPM file '" 
+                       << "Error reading XPM file '"
                        << XpmGetErrorString(success) << "'"
                        << std::endl;
        } else {
@@ -152,17 +152,11 @@ bool GImageXPM::setPixmap(GParams const & params)
                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());
@@ -206,15 +200,15 @@ bool GImageXPM::setPixmap(GParams const & params)
        // Load up the pixmap
        XpmImage xpm_image = image_.get();
        int const status =
-               XpmCreatePixmapFromXpmImage(display, 
-                                           XRootWindowOfScreen(screen), 
-                                           &xpm_image, 
+               XpmCreatePixmapFromXpmImage(display,
+                                           XRootWindowOfScreen(screen),
+                                           &xpm_image,
                                            &pixmap, &mask, &attrib);
 
        XpmFreeAttributes(&attrib);
 
        if (status != XpmSuccess) {
-               lyxerr << "Error creating pixmap from xpm_image '" 
+               lyxerr << "Error creating pixmap from xpm_image '"
                       << XpmGetErrorString(status) << "'"
                       << std::endl;
                pixmap_status_ = PIXMAP_FAILED;
@@ -236,25 +230,27 @@ void GImageXPM::clip(GParams const & params)
                // No clipping is necessary.
                return;
 
-       unsigned int const new_width  = params.bb.xr - params.bb.xl;
-       unsigned 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();
        }
@@ -301,28 +297,30 @@ void GImageXPM::rotate(GParams const & params)
        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);
 
-       unsigned int const new_width  = 1 + int(max_x - min_x); // round up!
-       unsigned int const new_height = 1 + int(max_y - min_y);
+       typedef unsigned int dimension;
 
-       unsigned int * new_data = image_.initialisedData(new_width, new_height);
-       unsigned int const * old_data = image_.data();
+       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];
                }
        }
 
@@ -335,36 +333,39 @@ void GImageXPM::scale(GParams const & params)
        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);
-       unsigned int const new_width  = d.first;
-       unsigned 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);
 }
 
@@ -376,24 +377,23 @@ namespace {
 void free_color_table(XpmColor * colorTable, size_t size);
 
 void copy_color_table(XpmColor const * in, size_t 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; 
+
+// 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)
 {}
@@ -401,9 +401,8 @@ GImageXPM::Data::Data()
 
 GImageXPM::Data::~Data()
 {
-       // Introduce temporary memory leak to fix crash.
-//     if (colorTable_.unique())
-//             free_color_table(colorTable_.get(), ncolors_);
+       if (colorTable_.unique())
+               free_color_table(colorTable_.get(), ncolors_);
 }
 
 
@@ -428,7 +427,7 @@ void GImageXPM::Data::reset(XpmImage & image)
        // 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;
@@ -465,17 +464,40 @@ void GImageXPM::Data::reset(XpmImage & image)
 
        // 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) {
-               // 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);
+               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());
+               }
 
                // 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);
+               // grayscale or monochrome ones are not, then define them.
+               mapcolor(entry.c_color, &entry.g_color, &entry.m_color);
+       }
+
+       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;
        }
 }
 
@@ -529,19 +551,27 @@ unsigned int GImageXPM::Data::color_none_id() const
 
 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.
@@ -551,20 +581,27 @@ char * mapcolor(char * color, bool toGray)
 
        // 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());
 }
 
 
@@ -591,7 +628,8 @@ void free_color_table(XpmColor * table, size_t size)
                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);
 }
 
 
@@ -600,7 +638,7 @@ char * clone_c_string(char const * in)
        if (!in)
                return 0;
 
-        // Don't forget the '\0'
+       // Don't forget the '\0'
        char * out = static_cast<char *>(malloc(strlen(in) + 1));
        return strcpy(out, in);
 }
@@ -619,7 +657,7 @@ bool contains_color_none(XpmImage const & image)
 
 string const unique_color_string(XpmImage const & image)
 {
-       string id(image.cpp, 'A');
+       string id(image.cpp, ' ');
 
        for(;;) {
                bool found_it = false;
@@ -634,22 +672,28 @@ string const unique_color_string(XpmImage const & image)
                if (!found_it)
                        return id;
 
-               // A base 57 counter!
-               // eg AAAz+1 = AABA, AABz+1 = AACA, AAzz+1 = ABAA
+               // 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) {
                        continue_loop = false;
-                       
-                       if (id[current_index] == 'z') {
+
+                       if (id[current_index] == 126) {
                                continue_loop = true;
-                               if (current_index == 0) // failed!
-                                       break;
+                               if (current_index == 0)
+                                       // Unable to find a unique string
+                                       return image.colorTable[0].string;
 
-                               id[current_index] = 'A';
+                               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 (continue_loop)