Logo Search packages:      
Sourcecode: videolink version File versions  Download package

pixbufs.cpp

// Copyright 2005-6 Ben Hutchings <ben@decadent.org.uk>.
// See the file "COPYING" for licence details.

#include "pixbufs.hpp"

#include <cassert>

#include <gdkmm/pixbuf.h>

#include "auto_array.hpp"
#include "jquant2.h"

// Find pixel differences between an "old" and "new" RGB Pixbuf
// (or RGBA, but the alpha component will be ignored) and copy the
// differing pixels from the new one to a third RGBA Pixbuf at the
// specified offset with full opacity.
// The width and height of the new Pixbufs must be equal and match
// the specified dimensions.  The width and height of the old and
// third Pixbuf must be large enough to store a rectangle of
// those dimensions at the specified offset.
void diff_rgb_pixbufs(Glib::RefPtr<Gdk::Pixbuf> old_buf,
                  Glib::RefPtr<Gdk::Pixbuf> new_buf,
                  Glib::RefPtr<Gdk::Pixbuf> diff_buf,
                  int offset_x, int offset_y,
                  int width, int height)
{
    assert(old_buf->get_colorspace() == Gdk::COLORSPACE_RGB);
    assert(new_buf->get_colorspace() == Gdk::COLORSPACE_RGB);
    assert(diff_buf->get_colorspace() == Gdk::COLORSPACE_RGB
         && diff_buf->get_has_alpha());
    int old_bpr = old_buf->get_rowstride();
    int old_bpp = old_buf->get_n_channels();
    assert(old_bpp >= 3);
    assert(old_buf->get_width() >= offset_x + width);
    assert(old_buf->get_height() >= offset_y + height);
    int new_bpr = new_buf->get_rowstride();
    int new_bpp = new_buf->get_n_channels();
    assert(new_bpp >= 3);
    assert(new_buf->get_width() == width);
    assert(new_buf->get_height() == height);
    int diff_bpr = diff_buf->get_rowstride();
    int diff_bpp = diff_buf->get_n_channels();
    assert(diff_bpp == 4);
    assert(diff_buf->get_width() >= offset_x + width);
    assert(diff_buf->get_height() >= offset_y + height);

    const guint8 * old_p = (old_buf->get_pixels()
                      + old_bpr * offset_y
                      + old_bpp * offset_x);
    const guint8 * new_p = new_buf->get_pixels();
    guint8 * diff_p = (diff_buf->get_pixels()
                   + diff_bpr * offset_y
                   + diff_bpp * offset_x);

    for (int y = 0; y != height; ++y)
    {
      for (int x = 0; x != width; ++x)
      {
          if (old_p[0] != new_p[0]
            || old_p[1] != new_p[1]
            || old_p[2] != new_p[2])
          {
            diff_p[0] = new_p[0];
            diff_p[1] = new_p[1];
            diff_p[2] = new_p[2];
            diff_p[3] = 0xFF; // fully opaque
          }
          old_p += old_bpp;
          new_p += new_bpp;
          diff_p += diff_bpp;
      }
      old_p += old_bpr - old_bpp * width;
      new_p += new_bpr - new_bpp * width;
      diff_p += diff_bpr - diff_bpp * width;
    }
}

// Quantise an RGBA Pixbuf to the specified number of colours, including
// one transparent colour.  Currently uses Floyd-Steinberg dithering.
void quantise_rgba_pixbuf(Glib::RefPtr<Gdk::Pixbuf> buf, int n_colours)
{
    assert(buf->get_colorspace() == Gdk::COLORSPACE_RGB
         && buf->get_has_alpha());
    int bpr = buf->get_rowstride();
    assert(buf->get_n_channels() == 4);
    int width = buf->get_width();
    int height = buf->get_height();

    unsigned char * buf_p = buf->get_pixels();
    auto_array<unsigned char *> rows(new unsigned char *[height]);
    for (int y = 0; y != height; ++y)
      rows[y] = &buf_p[y * bpr];
    auto_array<unsigned char> quant_buf_p(
      new unsigned char[width * height]);
    auto_array<unsigned char *> quant_rows(
      new unsigned char *[height]);
    for (int y = 0; y != height; ++y)
      quant_rows[y] = &quant_buf_p[y * width];
    auto_array<unsigned int> colours(new unsigned int[n_colours]);

    quantize(rows.get(), quant_rows.get(), width, height,
           JDITHER_FS, n_colours, colours.get());

    // Pixbuf doesn't support quantised images, so convert back to RGBA.
    for (int y = 0; y != height; ++y)
      for (int x = 0; x != width; ++x)
      {
          unsigned int colour = colours[quant_rows[y][x]];
          rows[y][4*x]   = colour;
          rows[y][4*x+1] = colour >> 8;
          rows[y][4*x+2] = colour >> 16;
          rows[y][4*x+3] = colour >> 24;
      }
}

Generated by  Doxygen 1.6.0   Back to index