// -*- c++ -*-
/* $Id: pixbuf.ccg,v 1.8 2006/05/11 11:40:23 murrayc Exp $ */

/* Copyright 1998-2002 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free
 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#include <gdk/gdk.h>
#include <gdk-pixbuf/gdk-pixbuf.h>


namespace
{

static void pixbuf_destroy_data_callback(guint8* pixels, void* user_data)
{
  Gdk::Pixbuf::SlotDestroyData *const slot = static_cast<Gdk::Pixbuf::SlotDestroyData*>(user_data);
  g_return_if_fail(slot != 0);

  #ifdef GLIBMM_EXCEPTIONS_ENABLED
  try
  {
  #endif //GLIBMM_EXCEPTIONS_ENABLED
    (*slot)(pixels); // invoke callback
  #ifdef GLIBMM_EXCEPTIONS_ENABLED
  }
  catch(...)
  {
    Glib::exception_handlers_invoke();
  }
  #endif //GLIBMM_EXCEPTIONS_ENABLED

  delete slot;
}

} // anonymous namespace


namespace Gdk
{

_DEPRECATE_IFDEF_START
Pixbuf::Pixbuf(const Glib::RefPtr<Image>& src,
               const Glib::RefPtr<Colormap>& cmap,
               int src_x, int src_y,
               int dest_x, int dest_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_image(
      0, src->gobj(), cmap->gobj(), src_x, src_y, dest_x, dest_y, width, height))
{}
_DEPRECATE_IFDEF_END

Pixbuf::Pixbuf(const Glib::RefPtr<Image>& src,
               const Glib::RefPtr<Colormap>& cmap,
               int src_x, int src_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_image(
      0, src->gobj(), cmap->gobj(), src_x, src_y, 0, 0, width, height))
{}

Pixbuf::Pixbuf(const Glib::RefPtr<Image>& src,
               int src_x, int src_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_image(
      0, src->gobj(), 0, src_x, src_y, 0, 0, width, height))
{}

_DEPRECATE_IFDEF_START
Pixbuf::Pixbuf(const Glib::RefPtr<Drawable>& src,
               const Glib::RefPtr<Colormap>& cmap,
               int src_x, int src_y,
               int dest_x, int dest_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_drawable(
      0, src->gobj(), cmap->gobj(), src_x, src_y, dest_x, dest_y, width, height))
{}
_DEPRECATE_IFDEF_END

Pixbuf::Pixbuf(const Glib::RefPtr<Drawable>& src,
               const Glib::RefPtr<Colormap>& cmap,
               int src_x, int src_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_drawable(
      0, src->gobj(), cmap->gobj(), src_x, src_y, 0, 0, width, height))
{}

Pixbuf::Pixbuf(const Glib::RefPtr<Drawable>& src,
               int src_x, int src_y,
               int width, int height)
:
  Object((GObject*) gdk_pixbuf_get_from_drawable(
      0, src->gobj(), 0, src_x, src_y, 0, 0, width, height))
{}

_DEPRECATE_IFDEF_START
Glib::RefPtr<Pixbuf> Pixbuf::create(const Glib::RefPtr<Drawable>& src,
                                    const Glib::RefPtr<Colormap>& cmap,
                                    int src_x, int src_y,
                                    int dest_x, int dest_y,
                                    int width, int height)
{
  return Glib::RefPtr<Pixbuf>( new Pixbuf(src, cmap, src_x, src_y, dest_x, dest_y, width, height) );
}

Glib::RefPtr<Pixbuf> Pixbuf::create(const Glib::RefPtr<Image>& src,
                                    const Glib::RefPtr<Colormap>& cmap,
                                    int src_x, int src_y,
                                    int dest_x, int dest_y,
                                    int width, int height)
{
  return Glib::RefPtr<Pixbuf>( new Pixbuf(src, cmap, src_x, src_y, dest_x, dest_y, width, height) );
}
_DEPRECATE_IFDEF_END

Glib::RefPtr<Pixbuf> Pixbuf::create_from_data(const guint8* data, Colorspace colorspace,
                                              bool has_alpha, int bits_per_sample,
                                              int width, int height, int rowstride)
{
  GdkPixbuf *const pixbuf = gdk_pixbuf_new_from_data(
      data, (GdkColorspace) colorspace, has_alpha, bits_per_sample, width, height, rowstride,
      0, 0);

  return Glib::wrap(pixbuf);
}

Glib::RefPtr<Pixbuf> Pixbuf::create_from_data(const guint8* data, Colorspace colorspace,
                                              bool has_alpha, int bits_per_sample,
                                              int width, int height, int rowstride,
                                              const Pixbuf::SlotDestroyData& destroy_slot)
{
  GdkPixbuf *const pixbuf = gdk_pixbuf_new_from_data(
      data, (GdkColorspace) colorspace, has_alpha, bits_per_sample, width, height, rowstride,
      &pixbuf_destroy_data_callback, new SlotDestroyData(destroy_slot));

  return Glib::wrap(pixbuf);
}

#ifdef GLIBMM_EXCEPTIONS_ENABLED
Glib::RefPtr<Pixbuf> Pixbuf::create_from_stream(const Glib::RefPtr<Gio::InputStream>& stream)
#else
Glib::RefPtr<Pixbuf> Pixbuf::create_from_stream(const Glib::RefPtr<Gio::InputStream>& stream, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;
  Glib::RefPtr<Pixbuf> retvalue = Glib::wrap(gdk_pixbuf_new_from_stream(const_cast<GInputStream*>(Glib::unwrap(stream)), 0, &(gerror)));

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED

  return retvalue;
}

#ifdef GLIBMM_EXCEPTIONS_ENABLED
Glib::RefPtr<Pixbuf> Pixbuf::create_from_stream_at_scale(const Glib::RefPtr<Gio::InputStream>& stream, int width, int height, bool preserve_aspect_ratio)
#else
Glib::RefPtr<Pixbuf> Pixbuf::create_from_stream_at_scale(const Glib::RefPtr<Gio::InputStream>& stream, int width, int height, bool preserve_aspect_ratio, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;
  Glib::RefPtr<Pixbuf> retvalue = Glib::wrap(gdk_pixbuf_new_from_stream_at_scale(const_cast<GInputStream*>(Glib::unwrap(stream)), width, height, static_cast<int>(preserve_aspect_ratio), 0, &(gerror)));

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED

  return retvalue;
}

void Pixbuf::render_pixmap_and_mask_for_colormap(const Glib::RefPtr<Colormap>& colormap,
                                                 Glib::RefPtr<Pixmap>& pixmap_return,
                                                 Glib::RefPtr<Bitmap>& mask_return,
                                                 int alpha_threshold)
{
  GdkPixmap* pPixmap = 0;
  GdkBitmap* pBitmap = 0;

  gdk_pixbuf_render_pixmap_and_mask_for_colormap(
      gobj(), colormap->gobj(), &pPixmap, &pBitmap, alpha_threshold);

  pixmap_return = Glib::wrap((GdkPixmapObject*) pPixmap);
  mask_return   = Glib::RefPtr<Gdk::Bitmap>::cast_dynamic(Glib::wrap((GdkPixmapObject*) pBitmap));
}

void Pixbuf::render_pixmap_and_mask(Glib::RefPtr<Pixmap>& pixmap_return,
                                    Glib::RefPtr<Bitmap>& mask_return,
                                    int alpha_threshold)
{
  GdkPixmap* pPixmap = 0;
  GdkBitmap* pBitmap = 0;

  gdk_pixbuf_render_pixmap_and_mask(gobj(), &pPixmap, &pBitmap, alpha_threshold);

  pixmap_return = Glib::wrap((GdkPixmapObject*) pPixmap);
  mask_return   = Glib::RefPtr<Gdk::Bitmap>::cast_dynamic(Glib::wrap((GdkPixmapObject*) pBitmap));
}


#ifdef GLIBMM_EXCEPTIONS_ENABLED
void Pixbuf::save(const std::string& filename, const Glib::ustring& type)
#else
void Pixbuf::save(const std::string& filename, const Glib::ustring& type, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;
  gdk_pixbuf_savev(gobj(), filename.c_str(), type.c_str(), 0, 0, &gerror);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED
}


#ifdef GLIBMM_EXCEPTIONS_ENABLED
void Pixbuf::save(const std::string& filename, const Glib::ustring& type,
                  const Glib::StringArrayHandle& option_keys,
                  const Glib::StringArrayHandle& option_values)
#else
void Pixbuf::save(const std::string& filename, const Glib::ustring& type,
                  const Glib::StringArrayHandle& option_keys,
                  const Glib::StringArrayHandle& option_values, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;

  gdk_pixbuf_savev(
      gobj(), filename.c_str(), type.c_str(),
      const_cast<char**>(option_keys.data()), const_cast<char**>(option_values.data()),
      &gerror);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED
}


#ifdef GLIBMM_EXCEPTIONS_ENABLED
void Pixbuf::save_to_buffer(gchar*& buffer, gsize& buffer_size,
                            const Glib::ustring& type)
#else
void Pixbuf::save_to_buffer(gchar*& buffer, gsize& buffer_size,
                            const Glib::ustring& type, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;

  gdk_pixbuf_save_to_buffer(
      gobj(), &buffer, &buffer_size,
      type.c_str(),
      &gerror, NULL);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED
}

#ifdef GLIBMM_EXCEPTIONS_ENABLED
void Pixbuf::save_to_buffer(gchar*& buffer, gsize& buffer_size,
                            const Glib::ustring& type,
                            const Glib::StringArrayHandle& option_keys,
                            const Glib::StringArrayHandle& option_values)
#else
void Pixbuf::save_to_buffer(gchar*& buffer, gsize& buffer_size,
                            const Glib::ustring& type,
                            const Glib::StringArrayHandle& option_keys,
                            const Glib::StringArrayHandle& option_values, std::auto_ptr<Glib::Error>& error)
#endif //GLIBMM_EXCEPTIONS_ENABLED
{
  GError* gerror = 0;

  gdk_pixbuf_save_to_bufferv(
      gobj(), &buffer, &buffer_size,
      type.c_str(),
      const_cast<char**>(option_keys.data()), const_cast<char**>(option_values.data()),
      &gerror);

#ifdef GLIBMM_EXCEPTIONS_ENABLED
  if(gerror)
    ::Glib::Error::throw_exception(gerror);
#else
  if(gerror)
    error = ::Glib::Error::throw_exception(gerror);
#endif //GLIBMM_EXCEPTIONS_ENABLED
}

Pixbuf::SListHandle_PixbufFormat Pixbuf::get_formats()
{
  return SListHandle_PixbufFormat(gdk_pixbuf_get_formats(), Glib::OWNERSHIP_SHALLOW);
}

} // namespace Gdk

