[gtkmm] Improved Gdk::Pixbuf pixel interface



Hi,

Currently, the interface for manipulating pixel data in a Gdk::Pixbuf
consists of:

  int get_n_channels () const
  bool get_has_alpha () const
  int get_bits_per_sample () const
  guint8* get_pixels () const
  int get_width () const
  int get_height () const
  int get_rowstride () const

This is a very inconvient interface since it requires manual
computations to actually locate a pixel. I been thinking about this,
and I think a better one would be:

  PixelIterator begin();
  PixelIterator end();

  PixelPosition get_position(int x, int y);

PixelIterator is then a bidirectional STL-like iterator which simply
iterates over the pixels (row by row), returning a Pixel if
dereferenced. The interface of PixelPosition is:

  Pixel pixel();

  // move a number of positions, returning *this
  PixelPosition &left(int n = 1);
  PixelPosition &right(int n = 1);
  PixelPosition &up(int n = 1);
  PixelPosition &down(int n = 1);

Pixel is then a simple proxy class for the pixel array index with the
interface:

  unsigned char &red();
  unsigned char &green();
  unsigned char &blue();
  unsigned char &alpha(); // undefined if pixbuf doesn't have alpha


With this, you can do stuff like this:

  void scale_alpha(const Glib::RefPtr<Gdk::Pixbuf> &pixbuf, int scale)
  {
    for (PixelIterator i = pixbuf.begin(), e = pixbuf.end(); i != e; ++i)
      i->alpha() = i->alpha() * scale / 256;
  }

Or like this (visits all even rows):

  int width = p.get_width(), height = p.get_height();

  for (int y = 0; y < height; y += 2) {
    PixelPosition ppos = p.get_position(0, y);
    for (int x = 0; x < width; ++x, ppos.right()) {
      Pixel pixel = ppos.pixel();

      pixel.red() = somevalue;
      pixel.green() = someothervalue;
      pixel.blue() = athirdvalue;
      pixel.alpha() = thealphavalue;
    }
  }

Or to simply colour a single pixel:

  Pixel pixel = p.get_position(x, y).pixel();

  pixel.red() = 74;
  pixel.green() = 174;
  pixel.blue() = 34;


The reason for having PixelPosition with its movements methods is that
the multiplication required for converting a (x, y) point to the
correct array index is expensive compared to just adding a fixed
amount to a precomputed index. On the order of 3-5 times slower it
seems.

I've already implemented the interfaces - you can have a look here:

  http://www.cs.auc.dk/~olau/misc/pixbuf-drawing.hpp   - the interfaces
  http://www.cs.auc.dk/~olau/misc/test.cpp             - timing tests

Comments?


With the iterator interface, manually setting the pixel colours:

  for (PixelIterator i = p.begin(), e = p.end(); i != e; ++i) {
    Pixel pixel = *i;
    pixel.red() = 0;
    pixel.green() = 0;
    pixel.blue() = 0;
    pixel.alpha() = 0;
  }

is just as fast as using the dedicated, wrapped C function:

  p->fill(0);

-- 
Ole Laursen
http://www.cs.auc.dk/~olau/



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]