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

blur.cc

// timfx 
// Copyright 2002, Timothy M. Shead
//
// Contact: tshead@k-3d.com
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public
// License as published by the Free Software Foundation; either
// version 2 of the License, or (at your option) any later version.
//
// This program 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
// General Public License for more details.
//
// You should have received a copy of the GNU General Public
// License along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

#include "blur.h"
#include "kino_plugin_types.h"

#include <kino/image_filters.h>

#include <gtkmm/adjustment.h>
#include <gtkmm/box.h>
#include <gtkmm/checkbutton.h>
#include <gtkmm/label.h>
#include <gtkmm/main.h>
#include <gtkmm/spinbutton.h>
#include <gtkmm/window.h>


#include <deque>
#include <numeric>
#include <vector>

namespace
{

class blur :
      public GDKImageFilter
{
public:
      blur() :
            m_radius(5),
            m_horizontal(true),
            m_vertical(true)
      {
            Gtk::Main main(0, 0);

            m_radius_spin_button.set_adjustment(*manage(new Gtk::Adjustment(m_radius, 1, 1000, 1, 10)));
            m_radius_spin_button.set_numeric(true);
            m_radius_spin_button.set_digits(0);
            m_radius_spin_button.set_wrap(false);
            m_radius_spin_button.set_snap_to_ticks(true);
            m_radius_spin_button.set_value(m_radius);

            m_horizontal_button.add(*manage(new Gtk::Label("Blur Horizontally")));
            m_horizontal_button.set_active(m_horizontal);
            
            m_vertical_button.add(*manage(new Gtk::Label("Blur Vertically")));
            m_vertical_button.set_active(m_vertical);

            Gtk::HBox* const options_group = new Gtk::HBox(false, 0);
            options_group->pack_start(*manage(new Gtk::Label("Radius:")), false, true);
            options_group->pack_start(m_radius_spin_button, true, true);

            Gtk::VBox* const vbox = new Gtk::VBox(false, 0);
            vbox->pack_start(*manage(options_group), false, true);
            vbox->pack_start(m_horizontal_button, false, true);
            vbox->pack_start(m_vertical_button, false, true);
            vbox->show_all();

            m_window.add(*manage(vbox));
      }

      char *GetDescription( ) const
      {
            return "Blur"; 
      }

      void FilterFrame(uint8_t* pixels, int width, int height, double position, double frame_delta)
      {
            // Create an N-pixel filter kernel
            kino::convolve_filter<kino::basic_rgb<double> > filter;
            
            unsigned int n = m_radius * 2;
            
/* Gaussian distribution            
            for(unsigned int i = 0; i <= n; ++i)
                  filter.push_weight(factorial(n) / (factorial(i) * factorial(n - i)));
*/

/* Box distribution 
            for(unsigned int i = 0; i <= n; ++i)
                  filter.push_weight(1);
*/

/* Triangle distribution */
            for(int i = 0; i <= n; ++i)
                  filter.push_weight((n * 0.5) - fabs(i - (n * 0.5)));

            // Filter horizontally ...
            if(m_horizontal)
                  {
                        for(int row = 0; row < height; ++row)
                              {
                                    kino::basic_rgb<uint8_t>* const a = reinterpret_cast<kino::basic_rgb<uint8_t>*>(pixels) + (row * width);
                                    kino::basic_rgb<uint8_t>* const b = a + filter.neighbors();
                                    kino::basic_rgb<uint8_t>* const c = a + width - filter.neighbors();
                                    kino::basic_rgb<uint8_t>* const d = a + width;
                                    
                                    // Initialize the kernel ...
                                    for(const kino::basic_rgb<uint8_t>* neighbor = a; neighbor != b; ++neighbor)
                                          filter.push_value(*neighbor);
                                    
                                    // First border zone ...
                                    unsigned int start = filter.middle();
                                    for(kino::basic_rgb<uint8_t>* current = a; current != b; ++current, --start)
                                          {
                                                filter.push_value(*(current + filter.neighbors()));
                                                *current = filter.get_value(start, filter.width());
                                          }

                                    // Image body ...
                                    for(kino::basic_rgb<uint8_t>* current = b; current != c; ++current)
                                          {
                                                filter.push_value(*(current + filter.neighbors()));
                                                *current = filter.get_value();
                                          }

                                    // Second border zone ...
                                    unsigned int remaining_width = filter.width()-1;
                                    for(kino::basic_rgb<uint8_t>* current = c; current != d; ++current, --remaining_width)
                                          {
                                                filter.push_value(kino::basic_rgb<uint8_t>());
                                                *current = filter.get_value(0, remaining_width);
                                          }
                              }
                  }

            // Filter vertically ...
            if(m_vertical)
                  {
                        for(int column = 0; column < width; ++column)
                              {
                                    kino::basic_rgb<uint8_t>* const a = reinterpret_cast<kino::basic_rgb<uint8_t>*>(pixels) + column;
                                    kino::basic_rgb<uint8_t>* const b = a + filter.neighbors() * width;
                                    kino::basic_rgb<uint8_t>* const c = a + (height - filter.neighbors()) * width;
                                    kino::basic_rgb<uint8_t>* const d = a + height * width;
                                    
                                    // Initialize the kernel ...
                                    for(const kino::basic_rgb<uint8_t>* neighbor = a; neighbor != b; neighbor += width)
                                          filter.push_value(*neighbor);
                                    
                                    // First border zone ...
                                    unsigned int start = filter.middle();
                                    for(kino::basic_rgb<uint8_t>* current = a; current != b; current += width, --start)
                                          {
                                                filter.push_value(*(current + filter.neighbors() * width));
                                                *current = filter.get_value(start, filter.width());
                                          }

                                    // Image body ...
                                    for(kino::basic_rgb<uint8_t>* current = b; current != c; current += width)
                                          {
                                                filter.push_value(*(current + filter.neighbors() * width));
                                                *current = filter.get_value();
                                          }

                                    // Second border zone ...
                                    unsigned int remaining_width = filter.width() - 1;
                                    for(kino::basic_rgb<uint8_t>* current = c; current != d; current += width, --remaining_width)
                                          {
                                                filter.push_value(kino::basic_rgb<uint8_t>());
                                                *current = filter.get_value(0, remaining_width);
                                          }
                              }
                  }
      }

      void AttachWidgets(GtkBin* bin)
      {
            gtk_widget_reparent( ( GTK_BIN( m_window.gobj() ) )->child, GTK_WIDGET( bin ) );
      }

      void DetachWidgets(GtkBin* bin)
      {
            gtk_widget_reparent( ( GTK_BIN( bin ) )->child, GTK_WIDGET( m_window.gobj() ) );
      }

      void InterpretWidgets( GtkBin *bin )
      {
            m_radius = m_radius_spin_button.get_value_as_int();
            m_horizontal = m_horizontal_button.get_active();
            m_vertical = m_vertical_button.get_active();
      }

private:
      Gtk::SpinButton m_radius_spin_button;
      Gtk::CheckButton m_horizontal_button;
      Gtk::CheckButton m_vertical_button;
      
      Gtk::Window m_window;
      
      unsigned int m_radius;
      bool m_horizontal;
      bool m_vertical;
};

} // namespace

GDKImageFilter* blur_factory()
{
      return new blur();
}

Generated by  Doxygen 1.6.0   Back to index