Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Gimp/plug-ins/print/   (Gimp Bildeditor Version 3.2.0©)  Datei vom 14.2.2026 mit Größe 27 kB image not shown  

Quelle  print-preview.c   Sprache: C

 

/* GIMP - The GNU Image Manipulation Program
 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
 *
 * 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 3 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, see <https://www.gnu.org/licenses/>.
 */


#include "config.h"

#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>

#include "print-preview.h"


enum
{
  OFFSETS_CHANGED,
  LAST_SIGNAL
};


#define SIZE_REQUEST  200


struct _PrintPreview
{
  GtkEventBox      parent_instance;

  GdkCursor       *cursor;

  GtkPageSetup    *page;
  cairo_surface_t *thumbnail;
  gboolean         dragging;
  gboolean         inside;

  GimpDrawable    *drawable;

  gdouble          image_offset_x;
  gdouble          image_offset_y;
  gdouble          image_offset_x_max;
  gdouble          image_offset_y_max;
  gdouble          image_width;
  gdouble          image_height;

  gboolean         use_full_page;

  /* for mouse drags */
  gdouble          orig_offset_x;
  gdouble          orig_offset_y;
  gint             start_x;
  gint             start_y;
};

struct _PrintPreviewClass
{
  GtkEventBoxClass  parent_class;

  void (* offsets_changed)  (PrintPreview *print_preview,
                             gint          offset_x,
                             gint          offset_y);
};


static void      print_preview_finalize             (GObject          *object);

static void      print_preview_realize              (GtkWidget        *widget);
static void      print_preview_unrealize            (GtkWidget        *widget);
static void      print_preview_get_preferred_width  (GtkWidget        *widget,
                                                     gint             *minimum_width,
                                                     gint             *natural_width);
static void      print_preview_get_preferred_height (GtkWidget        *widget,
                                                     gint             *minimum_height,
                                                     gint             *natural_height);
static void      print_preview_size_allocate        (GtkWidget        *widget,
                                                     GtkAllocation    *allocation);
static gboolean  print_preview_draw                 (GtkWidget        *widget,
                                                     cairo_t          *cr);
static gboolean  print_preview_button_press_event   (GtkWidget        *widget,
                                                     GdkEventButton   *event);
static gboolean  print_preview_button_release_event (GtkWidget        *widget,
                                                     GdkEventButton   *event);
static gboolean  print_preview_motion_notify_event  (GtkWidget        *widget,
                                                     GdkEventMotion   *event);
static gboolean  print_preview_leave_notify_event   (GtkWidget        *widget,
                                                     GdkEventCrossing *event);

static gboolean  print_preview_is_inside            (PrintPreview     *preview,
                                                     gdouble           x,
                                                     gdouble           y);
static void      print_preview_set_inside           (PrintPreview     *preview,
                                                     gboolean          inside);

static gdouble   print_preview_get_scale            (PrintPreview     *preview);

static void      print_preview_get_page_size        (PrintPreview     *preview,
                                                     gdouble          *paper_width,
                                                     gdouble          *paper_height);
static void      print_preview_get_page_margins     (PrintPreview     *preview,
                                                     gdouble          *left_margin,
                                                     gdouble          *right_margin,
                                                     gdouble          *top_margin,
                                                     gdouble          *bottom_margin);
static cairo_surface_t * print_preview_get_thumbnail (GimpDrawable    *drawable,
                                                      gint             width,
                                                      gint             height);


G_DEFINE_TYPE (PrintPreview, print_preview, GTK_TYPE_EVENT_BOX)

#define parent_class print_preview_parent_class

static guint print_preview_signals[LAST_SIGNAL] = { 0 };


#define g_marshal_value_peek_double(v)   (v)->data[0].v_double

static void
marshal_VOID__DOUBLE_DOUBLE (GClosure     *closure,
                             GValue       *return_value,
                             guint         n_param_values,
                             const GValue *param_values,
                             gpointer      invocation_hint,
                             gpointer      marshal_data)
{
  typedef void (*GMarshalFunc_VOID__DOUBLE_DOUBLE) (gpointer     data1,
                                                    gdouble      arg_1,
                                                    gdouble      arg_2,
                                                    gpointer     data2);
  register GMarshalFunc_VOID__DOUBLE_DOUBLE callback;
  register GCClosure *cc = (GCClosure*) closure;
  register gpointer data1, data2;

  g_return_if_fail (n_param_values == 3);

  if (G_CCLOSURE_SWAP_DATA (closure))
    {
      data1 = closure->data;
      data2 = g_value_peek_pointer (param_values + 0);
    }
  else
    {
      data1 = g_value_peek_pointer (param_values + 0);
      data2 = closure->data;
    }

  callback = (GMarshalFunc_VOID__DOUBLE_DOUBLE) (marshal_data ?
                                                 marshal_data : cc->callback);

  callback (data1,
            g_marshal_value_peek_double (param_values + 1),
            g_marshal_value_peek_double (param_values + 2),
            data2);
}

static void
print_preview_class_init (PrintPreviewClass *klass)
{
  GObjectClass   *object_class = G_OBJECT_CLASS (klass);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);

  print_preview_signals[OFFSETS_CHANGED] =
    g_signal_new ("offsets-changed",
                  G_TYPE_FROM_CLASS (klass),
                  G_SIGNAL_RUN_FIRST,
                  G_STRUCT_OFFSET (PrintPreviewClass, offsets_changed),
                  NULL, NULL,
                  marshal_VOID__DOUBLE_DOUBLE,
                  G_TYPE_NONE, 2,
                  G_TYPE_DOUBLE,
                  G_TYPE_DOUBLE);

  object_class->finalize             = print_preview_finalize;

  widget_class->realize              = print_preview_realize;
  widget_class->unrealize            = print_preview_unrealize;
  widget_class->get_preferred_width  = print_preview_get_preferred_width;
  widget_class->get_preferred_height = print_preview_get_preferred_height;
  widget_class->size_allocate        = print_preview_size_allocate;
  widget_class->draw                 = print_preview_draw;
  widget_class->button_press_event   = print_preview_button_press_event;
  widget_class->button_release_event = print_preview_button_release_event;
  widget_class->motion_notify_event  = print_preview_motion_notify_event;
  widget_class->leave_notify_event   = print_preview_leave_notify_event;

  klass->offsets_changed = NULL;
}

static void
print_preview_init (PrintPreview *preview)
{
  gtk_event_box_set_visible_window (GTK_EVENT_BOX (preview), FALSE);

  gtk_widget_add_events (GTK_WIDGET (preview),
                         GDK_BUTTON_PRESS_MASK   |
                         GDK_BUTTON_RELEASE_MASK |
                         GDK_POINTER_MOTION_MASK);
}


static void
print_preview_finalize (GObject *object)
{
  PrintPreview *preview = PRINT_PREVIEW (object);

  if (preview->thumbnail)
    {
      cairo_surface_destroy (preview->thumbnail);
      preview->thumbnail = NULL;
    }

  if (preview->page)
    {
      g_object_unref (preview->page);
      preview->page = NULL;
    }

  G_OBJECT_CLASS (print_preview_parent_class)->finalize (object);
}

static void
print_preview_realize (GtkWidget *widget)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  GTK_WIDGET_CLASS (print_preview_parent_class)->realize (widget);

  preview->cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
                                                GDK_HAND1);
}

static void
print_preview_unrealize (GtkWidget *widget)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  if (preview->cursor)
    g_object_unref (preview->cursor);

  GTK_WIDGET_CLASS (print_preview_parent_class)->unrealize (widget);
}

static void
print_preview_size_request (GtkWidget      *widget,
                            GtkRequisition *requisition)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);
  gdouble       paper_width;
  gdouble       paper_height;
  gint          border;

  border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;

  print_preview_get_page_size (preview, &paper_width, &paper_height);

  if (paper_width > paper_height)
    {
      requisition->height = SIZE_REQUEST;
      requisition->width  = paper_width * SIZE_REQUEST / paper_height;
      requisition->width  = MIN (requisition->width, 2 * SIZE_REQUEST);
    }
  else
    {
      requisition->width  = SIZE_REQUEST;
      requisition->height = paper_height * SIZE_REQUEST / paper_width;
      requisition->height = MIN (requisition->height, 2 * SIZE_REQUEST);
    }

  requisition->width  += 2 * border;
  requisition->height += 2 * border;
}

static void
print_preview_get_preferred_width (GtkWidget *widget,
                                   gint      *minimum_width,
                                   gint      *natural_width)
{
  GtkRequisition requisition;

  print_preview_size_request (widget, &requisition);

  *minimum_width = *natural_width = requisition.width;
}

static void
print_preview_get_preferred_height (GtkWidget *widget,
                                    gint      *minimum_height,
                                    gint      *natural_height)
{
  GtkRequisition requisition;

  print_preview_size_request (widget, &requisition);

  *minimum_height = *natural_height = requisition.height;
}

static void
print_preview_size_allocate (GtkWidget     *widget,
                             GtkAllocation *allocation)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  GTK_WIDGET_CLASS (print_preview_parent_class)->size_allocate (widget,
                                                                allocation);

  if (preview->thumbnail)
    {
      cairo_surface_destroy (preview->thumbnail);
      preview->thumbnail = NULL;
    }
}

static gboolean
print_preview_button_press_event (GtkWidget      *widget,
                                  GdkEventButton *event)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  if (event->type == GDK_BUTTON_PRESS && event->button == 1 && preview->inside)
    {
      GdkDisplay *display = gtk_widget_get_display (widget);
      GdkSeat    *seat    = gdk_display_get_default_seat (display);
      GdkCursor  *cursor;

      cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
                                           GDK_FLEUR);

      if (gdk_seat_grab (seat, gdk_event_get_window ((GdkEvent *) event),
                         GDK_SEAT_CAPABILITY_ALL_POINTING, FALSE,
                         cursor,
                         (GdkEvent *) event,
                         NULL, NULL) == GDK_GRAB_SUCCESS)
        {
          preview->orig_offset_x = preview->image_offset_x;
          preview->orig_offset_y = preview->image_offset_y;

          preview->start_x = event->x;
          preview->start_y = event->y;

          preview->dragging = TRUE;
        }

      g_object_unref (cursor);
    }

  return FALSE;
}

static gboolean
print_preview_button_release_event (GtkWidget      *widget,
                                    GdkEventButton *event)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  if (preview->dragging)
    {
      GdkDisplay *display = gtk_widget_get_display (widget);
      GdkSeat    *seat    = gdk_display_get_default_seat (display);

      gdk_seat_ungrab (seat);

      preview->dragging = FALSE;

      print_preview_set_inside (preview,
                                print_preview_is_inside (preview,
                                                         event->x, event->y));
    }

  return FALSE;
}

static gboolean
print_preview_motion_notify_event (GtkWidget      *widget,
                                   GdkEventMotion *event)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  if (preview->dragging)
    {
      gdouble scale = print_preview_get_scale (preview);
      gdouble offset_x;
      gdouble offset_y;

      offset_x = (preview->orig_offset_x +
                  (event->x - preview->start_x) / scale);
      offset_y = (preview->orig_offset_y +
                  (event->y - preview->start_y) / scale);

      offset_x = CLAMP (offset_x, 0, preview->image_offset_x_max);
      offset_y = CLAMP (offset_y, 0, preview->image_offset_y_max);

      if (preview->image_offset_x != offset_x ||
          preview->image_offset_y != offset_y)
        {
          print_preview_set_image_offsets (preview, offset_x, offset_y);

          g_signal_emit (preview,
                         print_preview_signals[OFFSETS_CHANGED], 0,
                         preview->image_offset_x,
                         preview->image_offset_y);
        }
    }
  else
    {
      print_preview_set_inside (preview,
                                print_preview_is_inside (preview,
                                                         event->x, event->y));
    }

  return FALSE;
}

static gboolean
print_preview_leave_notify_event (GtkWidget        *widget,
                                  GdkEventCrossing *event)
{
  PrintPreview *preview = PRINT_PREVIEW (widget);

  if (event->mode == GDK_CROSSING_NORMAL)
    print_preview_set_inside (preview, FALSE);

  return FALSE;
}

static gboolean
print_preview_draw (GtkWidget *widget,
                    cairo_t   *cr)
{
  PrintPreview  *preview = PRINT_PREVIEW (widget);
  GtkAllocation  allocation;
  GdkRGBA        color;
  gdouble        paper_width;
  gdouble        paper_height;
  gdouble        left_margin;
  gdouble        right_margin;
  gdouble        top_margin;
  gdouble        bottom_margin;
  gdouble        scale;
  gint           border;

  gtk_widget_get_allocation (widget, &allocation);

  border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;

  print_preview_get_page_size (preview, &paper_width, &paper_height);
  print_preview_get_page_margins (preview,
                                  &left_margin, &right_margin,
                                  &top_margin,  &bottom_margin);

  scale = print_preview_get_scale (preview);

  cairo_translate (cr, border, border);

  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
    {
      gint width = allocation.width - 2 * border;

      cairo_translate (cr, width - scale * paper_width, 0);
    }

  cairo_set_line_width (cr, 1.0);

  /* draw page background */
  cairo_rectangle (cr, 0, 0, scale * paper_width, scale * paper_height);

  color = (GdkRGBA) { 0.0, 0.0, 0.0, 1.0 };
  gdk_cairo_set_source_rgba (cr, &color);
  cairo_stroke_preserve (cr);

  color = (GdkRGBA) { 1.0, 1.0, 1.0, 1.0 };
  gdk_cairo_set_source_rgba (cr, &color);
  cairo_fill (cr);

  /* draw page_margins */
  cairo_rectangle (cr,
                   scale * left_margin,
                   scale * top_margin,
                   scale * (paper_width - left_margin - right_margin),
                   scale * (paper_height - top_margin - bottom_margin));

  color = (GdkRGBA) { 0.0, 0.0, 0.0, 0.3 };
  gdk_cairo_set_source_rgba (cr, &color);
  cairo_stroke (cr);

  cairo_translate (cr,
                   scale * (left_margin + preview->image_offset_x),
                   scale * (top_margin  + preview->image_offset_y));

  if (preview->dragging || preview->inside)
    {
      cairo_rectangle (cr,
                       0, 0,
                       scale * preview->image_width,
                       scale * preview->image_height);

      color = (GdkRGBA) { 0.0, 0.0, 0.0, 1.0 };
      gdk_cairo_set_source_rgba (cr, &color);
      cairo_stroke (cr);
    }

  if (preview->thumbnail == NULL &&
      gimp_item_is_valid (GIMP_ITEM (preview->drawable)))
    {
      preview->thumbnail =
        print_preview_get_thumbnail (preview->drawable,
                                     MIN (allocation.width,  1024),
                                     MIN (allocation.height, 1024));
    }

  if (preview->thumbnail != NULL)
    {
      gdouble scale_x;
      gdouble scale_y;

      scale_x = (preview->image_width  /
                 cairo_image_surface_get_width (preview->thumbnail));
      scale_y = (preview->image_height /
                 cairo_image_surface_get_height (preview->thumbnail));

      cairo_rectangle (cr, 0, 0, preview->image_width, preview->image_height);

      cairo_scale (cr, scale_x * scale, scale_y * scale);

      cairo_set_source_surface (cr, preview->thumbnail, 0, 0);
      cairo_fill (cr);
    }

  return FALSE;
}

/**
 * print_preview_new:
 * @page: page setup
 * @drawable: the drawable to print
 *
 * Creates a new #PrintPreview widget.
 *
 * Returns: the new #PrintPreview widget.
 **/

GtkWidget *
print_preview_new (GtkPageSetup *page,
                   GimpDrawable *drawable)
{
  PrintPreview *preview;

  g_return_val_if_fail (GTK_IS_PAGE_SETUP (page), NULL);

  preview = g_object_new (PRINT_TYPE_PREVIEW, NULL);

  preview->drawable = drawable;

  print_preview_set_page_setup (preview, page);

  return GTK_WIDGET (preview);
}

/**
 * print_preview_set_image_dpi:
 * @preview: a #PrintPreview.
 * @xres: the X resolution
 * @yres: the Y resolution
 *
 * Sets the resolution of the image/drawable displayed by the
 * #PrintPreview.
 **/

void
print_preview_set_image_dpi (PrintPreview *preview,
                             gdouble       xres,
                             gdouble       yres)
{
  gdouble width;
  gdouble height;

  g_return_if_fail (PRINT_IS_PREVIEW (preview));
  g_return_if_fail (xres > 0.0 && yres > 0.0);

  width  = gimp_drawable_get_width  (preview->drawable) * 72.0 / xres;
  height = gimp_drawable_get_height (preview->drawable) * 72.0 / yres;

  if (width != preview->image_width || height != preview->image_height)
    {
      preview->image_width  = width;
      preview->image_height = height;

      gtk_widget_queue_draw (GTK_WIDGET (preview));
    }
}

/**
 * print_preview_set_page_setup:
 * @preview: a #PrintPreview.
 * @page: the page setup to use
 *
 * Sets the page setup to use by the #PrintPreview.
 **/

void
print_preview_set_page_setup (PrintPreview *preview,
                              GtkPageSetup *page)
{
  g_return_if_fail (PRINT_IS_PREVIEW (preview));
  g_return_if_fail (GTK_IS_PAGE_SETUP (page));

  if (preview->page)
    g_object_unref (preview->page);

  preview->page = gtk_page_setup_copy (page);

  gtk_widget_queue_resize (GTK_WIDGET (preview));
}

/**
 * print_preview_set_image_offsets:
 * @preview: a #PrintPreview.
 * @offset_x: the X offset
 * @offset_y: the Y offset
 *
 * Sets the offsets of the image/drawable displayed by the #PrintPreview.
 * It does not emit the "offsets-changed" signal.
 **/

void
print_preview_set_image_offsets (PrintPreview *preview,
                                 gdouble       offset_x,
                                 gdouble       offset_y)
{
  g_return_if_fail (PRINT_IS_PREVIEW (preview));

  preview->image_offset_x = offset_x;
  preview->image_offset_y = offset_y;

  gtk_widget_queue_draw (GTK_WIDGET (preview));
}

/**
 * print_preview_set_image_offsets_max:
 * @preview: a #PrintPreview.
 * @offset_x_max: the maximum X offset allowed
 * @offset_y_max: the maximum Y offset allowed
 *
 * Sets the maximum offsets of the image/drawable displayed by the
 * #PrintPreview.  It does not emit the "offsets-changed" signal.
 **/

void
print_preview_set_image_offsets_max (PrintPreview *preview,
                                     gdouble       offset_x_max,
                                     gdouble       offset_y_max)
{
  g_return_if_fail (PRINT_IS_PREVIEW (preview));

  preview->image_offset_x_max = offset_x_max;
  preview->image_offset_y_max = offset_y_max;

  gtk_widget_queue_draw (GTK_WIDGET (preview));
}

/**
 * print_preview_set_use_full_page:
 * @preview: a #PrintPreview.
 * @full_page: TRUE to ignore the page margins
 *
 * If @full_page is TRUE, the page margins are ignored and the full page
 * can be used to setup printing.
 **/

void
print_preview_set_use_full_page (PrintPreview *preview,
                                 gboolean      full_page)
{
  g_return_if_fail (PRINT_IS_PREVIEW (preview));

  preview->use_full_page = full_page;

  gtk_widget_queue_draw (GTK_WIDGET (preview));
}

static gboolean
print_preview_is_inside (PrintPreview *preview,
                         gdouble       x,
                         gdouble       y)
{
  GtkWidget     *widget = GTK_WIDGET (preview);
  GtkAllocation  allocation;
  gdouble        left_margin;
  gdouble        right_margin;
  gdouble        top_margin;
  gdouble        bottom_margin;
  gdouble        scale;
  gint           border;

  gtk_widget_get_allocation (widget, &allocation);

  border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;

  x -= border;

  scale = print_preview_get_scale (preview);

  if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
    {
      gdouble paper_width;
      gdouble paper_height;
      gint    width = allocation.width - 2 * border;

      print_preview_get_page_size (preview, &paper_width, &paper_height);

      x -= width - scale * paper_width;
    }

  print_preview_get_page_margins (preview,
                                  &left_margin, &right_margin,
                                  &top_margin,  &bottom_margin);

  x = x / scale - left_margin;
  y = y / scale - top_margin;

  return (x > preview->image_offset_x                        &&
          x < preview->image_offset_x + preview->image_width &&
          y > preview->image_offset_y                        &&
          y < preview->image_offset_y + preview->image_height);
}

static void
print_preview_set_inside (PrintPreview *preview,
                          gboolean      inside)
{
  if (inside != preview->inside)
    {
      GtkWidget *widget = GTK_WIDGET (preview);

      preview->inside = inside;

      if (gtk_widget_is_drawable (widget))
        gdk_window_set_cursor (gtk_widget_get_window (widget),
                               inside ? preview->cursor : NULL);

      gtk_widget_queue_draw (widget);
    }
}

static gdouble
print_preview_get_scale (PrintPreview *preview)
{
  GtkWidget     *widget = GTK_WIDGET (preview);
  GtkAllocation  allocation;
  gdouble        paper_width;
  gdouble        paper_height;
  gdouble        scale_x;
  gdouble        scale_y;
  gint           border;

  gtk_widget_get_allocation (widget, &allocation);

  border = gtk_container_get_border_width (GTK_CONTAINER (widget)) + 1;

  print_preview_get_page_size (preview, &paper_width, &paper_height);

  scale_x = (gdouble) (allocation.width  - 2 * border) / paper_width;
  scale_y = (gdouble) (allocation.height - 2 * border) / paper_height;

  return MIN (scale_x, scale_y);
}

static void
print_preview_get_page_size (PrintPreview *preview,
                             gdouble      *paper_width,
                             gdouble      *paper_height)
{
  *paper_width  = gtk_page_setup_get_paper_width  (preview->page,
                                                   GTK_UNIT_POINTS);
  *paper_height = gtk_page_setup_get_paper_height (preview->page,
                                                   GTK_UNIT_POINTS);
}

static void
print_preview_get_page_margins (PrintPreview *preview,
                                gdouble      *left_margin,
                                gdouble      *right_margin,
                                gdouble      *top_margin,
                                gdouble      *bottom_margin)
{
  if (preview->use_full_page)
    {
      *left_margin   = 0.0;
      *right_margin  = 0.0;
      *top_margin    = 0.0;
      *bottom_margin = 0.0;
    }
  else
    {
      *left_margin   = gtk_page_setup_get_left_margin   (preview->page,
                                                         GTK_UNIT_POINTS);
      *right_margin  = gtk_page_setup_get_right_margin  (preview->page,
                                                         GTK_UNIT_POINTS);
      *top_margin    = gtk_page_setup_get_top_margin    (preview->page,
                                                         GTK_UNIT_POINTS);
      *bottom_margin = gtk_page_setup_get_bottom_margin (preview->page,
                                                         GTK_UNIT_POINTS);
    }
}


/*  This thumbnail code should eventually end up in libgimpui.  */

static cairo_surface_t *
print_preview_get_thumbnail (GimpDrawable *drawable,
                             gint          width,
                             gint          height)
{
  cairo_surface_t *surface;
  cairo_format_t   format;
  GBytes          *data;
  guchar          *dest;
  const guchar    *src;
  gint             src_stride;
  gint             dest_stride;
  gint             y;
  gint             bpp;

  g_return_val_if_fail (width  > 0 && width  <= 1024, NULL);
  g_return_val_if_fail (height > 0 && height <= 1024, NULL);

  data = gimp_drawable_get_thumbnail_data (drawable,
                                           width, height,
                                           &width, &height, &bpp);

  /* For now, convert preview of higher bit depth to 8BPC */
  if (bpp > 4)
    {
      GimpImage *temp_image;
      GList     *layers = NULL;

      g_bytes_unref (data);

      temp_image =
        gimp_image_duplicate (gimp_item_get_image (GIMP_ITEM (drawable)));
      gimp_image_convert_precision (temp_image, GIMP_PRECISION_U8_NON_LINEAR);
      gimp_image_merge_visible_layers (temp_image, GIMP_CLIP_TO_IMAGE);

      layers = gimp_image_list_layers (temp_image);
      data   = gimp_drawable_get_thumbnail_data (GIMP_DRAWABLE (layers->data),
                                                 width, height,
                                                 &width, &height, &bpp);

      g_list_free (layers);
      gimp_image_delete (temp_image);
    }

  switch (bpp)
    {
    case 1:
    case 3:
      format = CAIRO_FORMAT_RGB24;
      break;

    case 2:
    case 4:
      format = CAIRO_FORMAT_ARGB32;
      break;

    default:
      g_assert_not_reached ();
      break;
    }

  surface = cairo_image_surface_create (format, width, height);

  src         = g_bytes_get_data (data, NULL);
  src_stride  = width * bpp;

  dest        = cairo_image_surface_get_data (surface);
  dest_stride = cairo_image_surface_get_stride (surface);

  for (y = 0; y < height; y++)
    {
      const guchar *s = src;
      guchar       *d = dest;
      gint          w = width;

      switch (bpp)
        {
        case 1:
          while (w--)
            {
              GIMP_CAIRO_RGB24_SET_PIXEL (d, s[0], s[0], s[0]);
              s += 1;
              d += 4;
            }
          break;

        case 2:
          while (w--)
            {
              GIMP_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[0], s[0], s[1]);
              s += 2;
              d += 4;
            }
          break;

        case 3:
          while (w--)
            {
              GIMP_CAIRO_RGB24_SET_PIXEL (d, s[0], s[1], s[2]);
              s += 3;
              d += 4;
            }
          break;

        case 4:
          while (w--)
            {
              GIMP_CAIRO_ARGB32_SET_PIXEL (d, s[0], s[1], s[2], s[3]);
              s += 4;
              d += 4;
            }
          break;
        }

      src  += src_stride;
      dest += dest_stride;
    }

  g_bytes_unref (data);

  cairo_surface_mark_dirty (surface);

  return surface;
}

Messung
CHZG
82959992

¤ Dauer der Verarbeitung: 0.10 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.