forked from AuroraMiddleware/gtk
92006c8e78
Sun Apr 12 18:54:29 PDT 1998 Shawn T. Amundson <amundson@gtk.org> * Changed LGPL address for FSF in all .h and .c files
1631 lines
39 KiB
C
1631 lines
39 KiB
C
/* GTK - The GIMP Toolkit
|
|
* Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/param.h>
|
|
#include "gdk/gdkx.h"
|
|
#include "gtkpreview.h"
|
|
#include "gtksignal.h"
|
|
|
|
|
|
#define IMAGE_SIZE 256
|
|
#define PREVIEW_CLASS(w) GTK_PREVIEW_CLASS (GTK_OBJECT (w)->klass)
|
|
#define COLOR_COMPOSE(r,g,b) (lookup_red[r] | lookup_green[g] | lookup_blue[b])
|
|
|
|
|
|
typedef struct _GtkPreviewProp GtkPreviewProp;
|
|
typedef void (*GtkTransferFunc) (guchar *dest, guchar *src, gint count);
|
|
|
|
struct _GtkPreviewProp
|
|
{
|
|
guint16 ref_count;
|
|
guint16 nred_shades;
|
|
guint16 ngreen_shades;
|
|
guint16 nblue_shades;
|
|
guint16 ngray_shades;
|
|
};
|
|
|
|
|
|
static void gtk_preview_class_init (GtkPreviewClass *klass);
|
|
static void gtk_preview_init (GtkPreview *preview);
|
|
static void gtk_preview_finalize (GtkObject *object);
|
|
static void gtk_preview_realize (GtkWidget *widget);
|
|
static gint gtk_preview_expose (GtkWidget *widget,
|
|
GdkEventExpose *event);
|
|
static void gtk_preview_make_buffer (GtkPreview *preview);
|
|
static void gtk_preview_get_visuals (GtkPreviewClass *klass);
|
|
static void gtk_preview_get_cmaps (GtkPreviewClass *klass);
|
|
static void gtk_preview_dither_init (GtkPreviewClass *klass);
|
|
static void gtk_fill_lookup_array (gulong *array,
|
|
int depth,
|
|
int shift,
|
|
int prec);
|
|
static void gtk_trim_cmap (GtkPreviewClass *klass);
|
|
static void gtk_create_8_bit (GtkPreviewClass *klass);
|
|
|
|
static void gtk_color_8 (guchar *src,
|
|
guchar *data,
|
|
gint x,
|
|
gint y,
|
|
gulong width);
|
|
static void gtk_color_16 (guchar *src,
|
|
guchar *data,
|
|
gulong width);
|
|
static void gtk_color_24 (guchar *src,
|
|
guchar *data,
|
|
gulong width);
|
|
static void gtk_grayscale_8 (guchar *src,
|
|
guchar *data,
|
|
gint x,
|
|
gint y,
|
|
gulong width);
|
|
static void gtk_grayscale_16 (guchar *src,
|
|
guchar *data,
|
|
gulong width);
|
|
static void gtk_grayscale_24 (guchar *src,
|
|
guchar *data,
|
|
gulong width);
|
|
|
|
static gint gtk_get_preview_prop (guint *nred,
|
|
guint *nblue,
|
|
guint *ngreen,
|
|
guint *ngray);
|
|
static void gtk_set_preview_prop (guint nred,
|
|
guint ngreen,
|
|
guint nblue,
|
|
guint ngray);
|
|
|
|
/* transfer functions:
|
|
* destination byte order/source bpp/destination bpp
|
|
*/
|
|
static void gtk_lsbmsb_1_1 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_lsb_2_2 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_msb_2_2 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_lsb_3_3 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_msb_3_3 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_lsb_3_4 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
static void gtk_msb_3_4 (guchar *dest,
|
|
guchar *src,
|
|
gint count);
|
|
|
|
|
|
static GtkWidgetClass *parent_class = NULL;
|
|
static GtkPreviewClass *preview_class = NULL;
|
|
static GtkPreviewInfo *preview_info = NULL;
|
|
static gint install_cmap = FALSE;
|
|
|
|
|
|
guint
|
|
gtk_preview_get_type ()
|
|
{
|
|
static guint preview_type = 0;
|
|
|
|
if (!preview_type)
|
|
{
|
|
GtkTypeInfo preview_info =
|
|
{
|
|
"GtkPreview",
|
|
sizeof (GtkPreview),
|
|
sizeof (GtkPreviewClass),
|
|
(GtkClassInitFunc) gtk_preview_class_init,
|
|
(GtkObjectInitFunc) gtk_preview_init,
|
|
(GtkArgSetFunc) NULL,
|
|
(GtkArgGetFunc) NULL,
|
|
};
|
|
|
|
preview_type = gtk_type_unique (gtk_widget_get_type (), &preview_info);
|
|
}
|
|
|
|
return preview_type;
|
|
}
|
|
|
|
static void
|
|
gtk_preview_class_init (GtkPreviewClass *klass)
|
|
{
|
|
GtkObjectClass *object_class;
|
|
GtkWidgetClass *widget_class;
|
|
|
|
object_class = (GtkObjectClass*) klass;
|
|
widget_class = (GtkWidgetClass*) klass;
|
|
|
|
parent_class = gtk_type_class (gtk_widget_get_type ());
|
|
preview_class = klass;
|
|
|
|
object_class->finalize = gtk_preview_finalize;
|
|
|
|
widget_class->realize = gtk_preview_realize;
|
|
widget_class->expose_event = gtk_preview_expose;
|
|
|
|
if (preview_info)
|
|
klass->info = *preview_info;
|
|
else
|
|
{
|
|
klass->info.visual = NULL;
|
|
klass->info.cmap = NULL;
|
|
|
|
klass->info.color_pixels = NULL;
|
|
klass->info.gray_pixels = NULL;
|
|
klass->info.reserved_pixels = NULL;
|
|
|
|
klass->info.lookup_red = NULL;
|
|
klass->info.lookup_green = NULL;
|
|
klass->info.lookup_blue = NULL;
|
|
|
|
klass->info.dither_red = NULL;
|
|
klass->info.dither_green = NULL;
|
|
klass->info.dither_blue = NULL;
|
|
klass->info.dither_gray = NULL;
|
|
klass->info.dither_matrix = NULL;
|
|
|
|
klass->info.nred_shades = 6;
|
|
klass->info.ngreen_shades = 6;
|
|
klass->info.nblue_shades = 4;
|
|
klass->info.ngray_shades = 24;
|
|
klass->info.nreserved = 0;
|
|
|
|
klass->info.bpp = 0;
|
|
klass->info.cmap_alloced = FALSE;
|
|
klass->info.gamma = 1.0;
|
|
}
|
|
|
|
klass->image = NULL;
|
|
|
|
gtk_preview_get_visuals (klass);
|
|
gtk_preview_get_cmaps (klass);
|
|
gtk_preview_dither_init (klass);
|
|
}
|
|
|
|
void
|
|
gtk_preview_reset (void)
|
|
{
|
|
GtkPreviewInfo *info;
|
|
|
|
if (!preview_class || !preview_info)
|
|
return;
|
|
|
|
info = &preview_class->info;
|
|
|
|
gtk_preview_uninit();
|
|
|
|
if (info->color_pixels)
|
|
{
|
|
gdk_colors_free (info->cmap,
|
|
info->color_pixels,
|
|
info->nred_shades *
|
|
info->ngreen_shades *
|
|
info->nblue_shades,
|
|
0);
|
|
|
|
gdk_colors_free (info->cmap,
|
|
info->gray_pixels,
|
|
info->ngray_shades, 0);
|
|
|
|
g_free (info->color_pixels);
|
|
g_free (info->gray_pixels);
|
|
}
|
|
|
|
if (info->reserved_pixels)
|
|
{
|
|
gdk_colors_free (info->cmap,
|
|
info->reserved_pixels,
|
|
info->nreserved, 0);
|
|
g_free (info->reserved_pixels);
|
|
}
|
|
|
|
if (info->cmap && info->cmap_alloced)
|
|
gdk_colormap_unref (info->cmap);
|
|
|
|
if (info->lookup_red)
|
|
{
|
|
g_free (info->lookup_red);
|
|
g_free (info->lookup_green);
|
|
g_free (info->lookup_blue);
|
|
}
|
|
|
|
if (info->dither_matrix)
|
|
{
|
|
int i, j;
|
|
|
|
for (i= 0 ; i < 8 ; i++)
|
|
{
|
|
for (j = 0; j < 8 ; j++)
|
|
g_free (info->dither_matrix[i][j]);
|
|
g_free (info->dither_matrix[i]);
|
|
}
|
|
g_free (info->dither_matrix);
|
|
g_free (info->dither_red);
|
|
g_free (info->dither_green);
|
|
g_free (info->dither_blue);
|
|
}
|
|
|
|
preview_class->info = *preview_info;
|
|
|
|
gtk_preview_get_visuals (preview_class);
|
|
gtk_preview_get_cmaps (preview_class);
|
|
gtk_preview_dither_init (preview_class);
|
|
}
|
|
|
|
static void
|
|
gtk_preview_init (GtkPreview *preview)
|
|
{
|
|
GTK_WIDGET_SET_FLAGS (preview, GTK_BASIC);
|
|
|
|
preview->buffer = NULL;
|
|
preview->buffer_width = 0;
|
|
preview->buffer_height = 0;
|
|
preview->expand = FALSE;
|
|
}
|
|
|
|
void
|
|
gtk_preview_uninit ()
|
|
{
|
|
GtkPreviewProp *prop;
|
|
GdkAtom property;
|
|
|
|
/* FIXME: need to grab the server here to prevent a race condition */
|
|
|
|
if (preview_class && !install_cmap && preview_class->info.visual &&
|
|
(preview_class->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
|
|
(preview_class->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
|
|
{
|
|
property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
|
|
|
|
if (gdk_property_get (NULL, property, property,
|
|
0, sizeof (GtkPreviewProp), FALSE,
|
|
NULL, NULL, NULL, (guchar**) &prop))
|
|
{
|
|
prop->ref_count = prop->ref_count - 1;
|
|
if (prop->ref_count == 0)
|
|
{
|
|
gdk_property_delete (NULL, property);
|
|
}
|
|
else
|
|
{
|
|
gdk_property_change (NULL, property, property, 16,
|
|
GDK_PROP_MODE_REPLACE,
|
|
(guchar*) prop, 5);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
GtkWidget*
|
|
gtk_preview_new (GtkPreviewType type)
|
|
{
|
|
GtkPreview *preview;
|
|
|
|
preview = gtk_type_new (gtk_preview_get_type ());
|
|
preview->type = type;
|
|
|
|
return GTK_WIDGET (preview);
|
|
}
|
|
|
|
void
|
|
gtk_preview_size (GtkPreview *preview,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
|
|
if ((width != GTK_WIDGET (preview)->requisition.width) ||
|
|
(height != GTK_WIDGET (preview)->requisition.height))
|
|
{
|
|
GTK_WIDGET (preview)->requisition.width = width;
|
|
GTK_WIDGET (preview)->requisition.height = height;
|
|
|
|
if (preview->buffer)
|
|
g_free (preview->buffer);
|
|
preview->buffer = NULL;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_preview_put (GtkPreview *preview,
|
|
GdkWindow *window,
|
|
GdkGC *gc,
|
|
gint srcx,
|
|
gint srcy,
|
|
gint destx,
|
|
gint desty,
|
|
gint width,
|
|
gint height)
|
|
{
|
|
GtkWidget *widget;
|
|
GdkImage *image;
|
|
GdkRectangle r1, r2, r3;
|
|
GtkTransferFunc transfer_func;
|
|
guchar *image_mem;
|
|
guchar *src, *dest;
|
|
gint x, xe, x2;
|
|
gint y, ye, y2;
|
|
guint dest_rowstride;
|
|
guint src_bpp;
|
|
guint dest_bpp;
|
|
gint i;
|
|
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
g_return_if_fail (window != NULL);
|
|
|
|
if (!preview->buffer)
|
|
return;
|
|
|
|
widget = GTK_WIDGET (preview);
|
|
|
|
r1.x = 0;
|
|
r1.y = 0;
|
|
r1.width = preview->buffer_width;
|
|
r1.height = preview->buffer_height;
|
|
|
|
r2.x = srcx;
|
|
r2.y = srcy;
|
|
r2.width = width;
|
|
r2.height = height;
|
|
|
|
if (!gdk_rectangle_intersect (&r1, &r2, &r3))
|
|
return;
|
|
|
|
x2 = r3.x + r3.width;
|
|
y2 = r3.y + r3.height;
|
|
|
|
if (!preview_class->image)
|
|
preview_class->image = gdk_image_new (GDK_IMAGE_FASTEST,
|
|
preview_class->info.visual,
|
|
IMAGE_SIZE, IMAGE_SIZE);
|
|
image = preview_class->image;
|
|
src_bpp = preview_class->info.bpp;
|
|
|
|
image_mem = image->mem;
|
|
dest_bpp = image->bpp;
|
|
dest_rowstride = image->bpl;
|
|
|
|
transfer_func = NULL;
|
|
|
|
switch (dest_bpp)
|
|
{
|
|
case 1:
|
|
switch (src_bpp)
|
|
{
|
|
case 1:
|
|
transfer_func = gtk_lsbmsb_1_1;
|
|
break;
|
|
}
|
|
break;
|
|
case 2:
|
|
switch (src_bpp)
|
|
{
|
|
case 2:
|
|
if (image->byte_order == GDK_MSB_FIRST)
|
|
transfer_func = gtk_msb_2_2;
|
|
else
|
|
transfer_func = gtk_lsb_2_2;
|
|
break;
|
|
case 3:
|
|
break;
|
|
}
|
|
break;
|
|
case 3:
|
|
switch (src_bpp)
|
|
{
|
|
case 3:
|
|
if (image->byte_order == GDK_MSB_FIRST)
|
|
transfer_func = gtk_msb_3_3;
|
|
else
|
|
transfer_func = gtk_lsb_3_3;
|
|
break;
|
|
}
|
|
break;
|
|
case 4:
|
|
switch (src_bpp)
|
|
{
|
|
case 3:
|
|
if (image->byte_order == GDK_MSB_FIRST)
|
|
transfer_func = gtk_msb_3_4;
|
|
else
|
|
transfer_func = gtk_lsb_3_4;
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!transfer_func)
|
|
{
|
|
g_warning ("unsupported byte order/src bpp/dest bpp combination: %s:%d:%d",
|
|
(image->byte_order == GDK_MSB_FIRST) ? "msb" : "lsb", src_bpp, dest_bpp);
|
|
return;
|
|
}
|
|
|
|
for (y = r3.y; y < y2; y += IMAGE_SIZE)
|
|
{
|
|
for (x = r3.x; x < x2; x += IMAGE_SIZE)
|
|
{
|
|
xe = x + IMAGE_SIZE;
|
|
if (xe > x2)
|
|
xe = x2;
|
|
|
|
ye = y + IMAGE_SIZE;
|
|
if (ye > y2)
|
|
ye = y2;
|
|
|
|
for (i = y; i < ye; i++)
|
|
{
|
|
src = preview->buffer + (((gulong) (i - r1.y) * (gulong) preview->buffer_width) +
|
|
(x - r1.x)) * (gulong) src_bpp;
|
|
dest = image_mem + ((gulong) (i - y) * dest_rowstride);
|
|
|
|
if (xe > x)
|
|
(* transfer_func) (dest, src, xe - x);
|
|
}
|
|
|
|
gdk_draw_image (window, gc,
|
|
image, 0, 0,
|
|
destx + (r3.x - srcx) + (x - r3.x),
|
|
desty + (r3.y - srcy) + (y - r3.y),
|
|
xe - x, ye - y);
|
|
gdk_flush ();
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_preview_put_row (GtkPreview *preview,
|
|
guchar *src,
|
|
guchar *dest,
|
|
gint x,
|
|
gint y,
|
|
gint w)
|
|
{
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
g_return_if_fail (src != NULL);
|
|
g_return_if_fail (dest != NULL);
|
|
|
|
switch (preview->type)
|
|
{
|
|
case GTK_PREVIEW_COLOR:
|
|
switch (preview_class->info.visual->depth)
|
|
{
|
|
case 8:
|
|
gtk_color_8 (src, dest, x, y, w);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
gtk_color_16 (src, dest, w);
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
gtk_color_24 (src, dest, w);
|
|
break;
|
|
}
|
|
break;
|
|
case GTK_PREVIEW_GRAYSCALE:
|
|
switch (preview_class->info.visual->depth)
|
|
{
|
|
case 8:
|
|
gtk_grayscale_8 (src, dest, x, y, w);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
gtk_grayscale_16 (src, dest, w);
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
gtk_grayscale_24 (src, dest, w);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_preview_draw_row (GtkPreview *preview,
|
|
guchar *data,
|
|
gint x,
|
|
gint y,
|
|
gint w)
|
|
{
|
|
guchar *dest;
|
|
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
g_return_if_fail (data != NULL);
|
|
g_return_if_fail (preview_class->info.visual != NULL);
|
|
|
|
if ((w <= 0) || (y < 0))
|
|
return;
|
|
|
|
g_return_if_fail (data != NULL);
|
|
|
|
gtk_preview_make_buffer (preview);
|
|
|
|
if (y >= preview->buffer_height)
|
|
return;
|
|
|
|
switch (preview->type)
|
|
{
|
|
case GTK_PREVIEW_COLOR:
|
|
switch (preview_class->info.visual->depth)
|
|
{
|
|
case 8:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
|
|
gtk_color_8 (data, dest, x, y, w);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
|
|
gtk_color_16 (data, dest, w);
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
|
|
gtk_color_24 (data, dest, w);
|
|
break;
|
|
}
|
|
break;
|
|
case GTK_PREVIEW_GRAYSCALE:
|
|
switch (preview_class->info.visual->depth)
|
|
{
|
|
case 8:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x);
|
|
gtk_grayscale_8 (data, dest, x, y, w);
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 2;
|
|
gtk_grayscale_16 (data, dest, w);
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
dest = preview->buffer + ((gulong) y * (gulong) preview->buffer_width + (gulong) x) * 3;
|
|
gtk_grayscale_24 (data, dest, w);
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
gtk_preview_set_expand (GtkPreview *preview,
|
|
gint expand)
|
|
{
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
|
|
preview->expand = (expand != FALSE);
|
|
}
|
|
|
|
void
|
|
gtk_preview_set_gamma (double _gamma)
|
|
{
|
|
if (!preview_info)
|
|
{
|
|
preview_info = g_new0 (GtkPreviewInfo, 1);
|
|
preview_info->nred_shades = 6;
|
|
preview_info->ngreen_shades = 6;
|
|
preview_info->nblue_shades = 4;
|
|
preview_info->ngray_shades = 24;
|
|
}
|
|
|
|
preview_info->gamma = _gamma;
|
|
}
|
|
|
|
void
|
|
gtk_preview_set_color_cube (guint nred_shades,
|
|
guint ngreen_shades,
|
|
guint nblue_shades,
|
|
guint ngray_shades)
|
|
{
|
|
if (!preview_info)
|
|
{
|
|
preview_info = g_new0 (GtkPreviewInfo, 1);
|
|
preview_info->gamma = 1.0;
|
|
}
|
|
|
|
preview_info->nred_shades = nred_shades;
|
|
preview_info->ngreen_shades = ngreen_shades;
|
|
preview_info->nblue_shades = nblue_shades;
|
|
preview_info->ngray_shades = ngray_shades;
|
|
}
|
|
|
|
void
|
|
gtk_preview_set_install_cmap (gint _install_cmap)
|
|
{
|
|
install_cmap = _install_cmap;
|
|
}
|
|
|
|
void
|
|
gtk_preview_set_reserved (gint nreserved)
|
|
{
|
|
if (!preview_info)
|
|
preview_info = g_new0 (GtkPreviewInfo, 1);
|
|
|
|
preview_info->nreserved = nreserved;
|
|
}
|
|
|
|
GdkVisual*
|
|
gtk_preview_get_visual ()
|
|
{
|
|
if (!preview_class)
|
|
preview_class = gtk_type_class (gtk_preview_get_type ());
|
|
|
|
return preview_class->info.visual;
|
|
}
|
|
|
|
GdkColormap*
|
|
gtk_preview_get_cmap ()
|
|
{
|
|
if (!preview_class)
|
|
preview_class = gtk_type_class (gtk_preview_get_type ());
|
|
|
|
return preview_class->info.cmap;
|
|
}
|
|
|
|
GtkPreviewInfo*
|
|
gtk_preview_get_info ()
|
|
{
|
|
if (!preview_class)
|
|
preview_class = gtk_type_class (gtk_preview_get_type ());
|
|
|
|
return &preview_class->info;
|
|
}
|
|
|
|
|
|
static void
|
|
gtk_preview_finalize (GtkObject *object)
|
|
{
|
|
GtkPreview *preview;
|
|
|
|
g_return_if_fail (object != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (object));
|
|
|
|
preview = GTK_PREVIEW (object);
|
|
if (preview->buffer)
|
|
g_free (preview->buffer);
|
|
preview->type = (GtkPreviewType) -1;
|
|
|
|
(* GTK_OBJECT_CLASS (parent_class)->finalize) (object);
|
|
}
|
|
|
|
static void
|
|
gtk_preview_realize (GtkWidget *widget)
|
|
{
|
|
GtkPreview *preview;
|
|
GdkWindowAttr attributes;
|
|
gint attributes_mask;
|
|
|
|
g_return_if_fail (widget != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (widget));
|
|
|
|
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
|
|
preview = GTK_PREVIEW (widget);
|
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
|
attributes.x = widget->allocation.x;
|
|
attributes.y = widget->allocation.y;
|
|
attributes.width = widget->allocation.width;
|
|
attributes.height = widget->allocation.height;
|
|
attributes.wclass = GDK_INPUT_OUTPUT;
|
|
attributes.visual = gtk_widget_get_visual (widget);
|
|
attributes.colormap = gtk_widget_get_colormap (widget);
|
|
attributes.event_mask = gtk_widget_get_events (widget) | GDK_EXPOSURE_MASK;
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP;
|
|
|
|
widget->window = gdk_window_new (gtk_widget_get_parent_window (widget), &attributes, attributes_mask);
|
|
gdk_window_set_user_data (widget->window, widget);
|
|
|
|
widget->style = gtk_style_attach (widget->style, widget->window);
|
|
gtk_style_set_background (widget->style, widget->window, GTK_STATE_NORMAL);
|
|
}
|
|
|
|
static gint
|
|
gtk_preview_expose (GtkWidget *widget,
|
|
GdkEventExpose *event)
|
|
{
|
|
GtkPreview *preview;
|
|
|
|
g_return_val_if_fail (widget != NULL, FALSE);
|
|
g_return_val_if_fail (GTK_IS_PREVIEW (widget), FALSE);
|
|
g_return_val_if_fail (event != NULL, FALSE);
|
|
|
|
if (GTK_WIDGET_DRAWABLE (widget))
|
|
{
|
|
preview = GTK_PREVIEW (widget);
|
|
|
|
gtk_preview_put (GTK_PREVIEW (widget),
|
|
widget->window, widget->style->black_gc,
|
|
event->area.x -
|
|
(widget->allocation.width - preview->buffer_width)/2,
|
|
event->area.y -
|
|
(widget->allocation.height - preview->buffer_height)/2,
|
|
event->area.x, event->area.y,
|
|
event->area.width, event->area.height);
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gtk_preview_make_buffer (GtkPreview *preview)
|
|
{
|
|
GtkWidget *widget;
|
|
gint width;
|
|
gint height;
|
|
|
|
g_return_if_fail (preview != NULL);
|
|
g_return_if_fail (GTK_IS_PREVIEW (preview));
|
|
|
|
widget = GTK_WIDGET (preview);
|
|
|
|
if (preview->expand &&
|
|
(widget->allocation.width != 0) &&
|
|
(widget->allocation.height != 0))
|
|
{
|
|
width = widget->allocation.width;
|
|
height = widget->allocation.height;
|
|
}
|
|
else
|
|
{
|
|
width = widget->requisition.width;
|
|
height = widget->requisition.height;
|
|
}
|
|
|
|
if (!preview->buffer ||
|
|
(preview->buffer_width != width) ||
|
|
(preview->buffer_height != height))
|
|
{
|
|
if (preview->buffer)
|
|
g_free (preview->buffer);
|
|
|
|
preview->buffer_width = width;
|
|
preview->buffer_height = height;
|
|
|
|
preview->buffer = g_new0 (guchar,
|
|
preview->buffer_width *
|
|
preview->buffer_height *
|
|
preview_class->info.bpp);
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_preview_get_visuals (GtkPreviewClass *klass)
|
|
{
|
|
static GdkVisualType types[] =
|
|
{
|
|
GDK_VISUAL_TRUE_COLOR,
|
|
GDK_VISUAL_DIRECT_COLOR,
|
|
GDK_VISUAL_TRUE_COLOR,
|
|
GDK_VISUAL_DIRECT_COLOR,
|
|
GDK_VISUAL_TRUE_COLOR,
|
|
GDK_VISUAL_DIRECT_COLOR,
|
|
GDK_VISUAL_TRUE_COLOR,
|
|
GDK_VISUAL_DIRECT_COLOR,
|
|
GDK_VISUAL_PSEUDO_COLOR
|
|
};
|
|
static gint depths[] = { 24, 24, 32, 32, 16, 16, 15, 15, 8 };
|
|
static gint nvisual_types = sizeof (types) / sizeof (types[0]);
|
|
|
|
int i;
|
|
|
|
g_return_if_fail (klass != NULL);
|
|
|
|
if (!klass->info.visual)
|
|
for (i = 0; i < nvisual_types; i++)
|
|
if ((klass->info.visual = gdk_visual_get_best_with_both (depths[i], types[i])))
|
|
{
|
|
if ((klass->info.visual->type == GDK_VISUAL_TRUE_COLOR) ||
|
|
(klass->info.visual->type == GDK_VISUAL_DIRECT_COLOR))
|
|
{
|
|
klass->info.lookup_red = g_new (gulong, 256);
|
|
klass->info.lookup_green = g_new (gulong, 256);
|
|
klass->info.lookup_blue = g_new (gulong, 256);
|
|
|
|
gtk_fill_lookup_array (klass->info.lookup_red,
|
|
klass->info.visual->depth,
|
|
klass->info.visual->red_shift,
|
|
8 - klass->info.visual->red_prec);
|
|
gtk_fill_lookup_array (klass->info.lookup_green,
|
|
klass->info.visual->depth,
|
|
klass->info.visual->green_shift,
|
|
8 - klass->info.visual->green_prec);
|
|
gtk_fill_lookup_array (klass->info.lookup_blue,
|
|
klass->info.visual->depth,
|
|
klass->info.visual->blue_shift,
|
|
8 - klass->info.visual->blue_prec);
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (!klass->info.visual)
|
|
{
|
|
g_warning ("unable to find a suitable visual for color image display.\n");
|
|
return;
|
|
}
|
|
|
|
switch (klass->info.visual->depth)
|
|
{
|
|
case 8:
|
|
klass->info.bpp = 1;
|
|
break;
|
|
case 15:
|
|
case 16:
|
|
klass->info.bpp = 2;
|
|
break;
|
|
case 24:
|
|
case 32:
|
|
klass->info.bpp = 3;
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_preview_get_cmaps (GtkPreviewClass *klass)
|
|
{
|
|
g_return_if_fail (klass != NULL);
|
|
g_return_if_fail (klass->info.visual != NULL);
|
|
|
|
if ((klass->info.visual->type != GDK_VISUAL_TRUE_COLOR) &&
|
|
(klass->info.visual->type != GDK_VISUAL_DIRECT_COLOR))
|
|
{
|
|
if (install_cmap)
|
|
{
|
|
klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
|
|
klass->info.cmap_alloced = install_cmap;
|
|
|
|
gtk_trim_cmap (klass);
|
|
gtk_create_8_bit (klass);
|
|
}
|
|
else
|
|
{
|
|
guint nred;
|
|
guint ngreen;
|
|
guint nblue;
|
|
guint ngray;
|
|
gint set_prop;
|
|
|
|
klass->info.cmap = gdk_colormap_get_system ();
|
|
|
|
set_prop = TRUE;
|
|
if (gtk_get_preview_prop (&nred, &ngreen, &nblue, &ngray))
|
|
{
|
|
set_prop = FALSE;
|
|
|
|
klass->info.nred_shades = nred;
|
|
klass->info.ngreen_shades = ngreen;
|
|
klass->info.nblue_shades = nblue;
|
|
klass->info.ngray_shades = ngray;
|
|
|
|
if (klass->info.nreserved)
|
|
{
|
|
klass->info.reserved_pixels = g_new (gulong, klass->info.nreserved);
|
|
if (!gdk_colors_alloc (klass->info.cmap, 0, NULL, 0,
|
|
klass->info.reserved_pixels,
|
|
klass->info.nreserved))
|
|
{
|
|
g_free (klass->info.reserved_pixels);
|
|
klass->info.reserved_pixels = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
gtk_trim_cmap (klass);
|
|
}
|
|
|
|
gtk_create_8_bit (klass);
|
|
|
|
if (set_prop)
|
|
gtk_set_preview_prop (klass->info.nred_shades,
|
|
klass->info.ngreen_shades,
|
|
klass->info.nblue_shades,
|
|
klass->info.ngray_shades);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (klass->info.visual == gdk_visual_get_system ())
|
|
klass->info.cmap = gdk_colormap_get_system ();
|
|
else
|
|
{
|
|
klass->info.cmap = gdk_colormap_new (klass->info.visual, FALSE);
|
|
klass->info.cmap_alloced = TRUE;
|
|
}
|
|
|
|
klass->info.nred_shades = 0;
|
|
klass->info.ngreen_shades = 0;
|
|
klass->info.nblue_shades = 0;
|
|
klass->info.ngray_shades = 0;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_preview_dither_init (GtkPreviewClass *klass)
|
|
{
|
|
int i, j, k;
|
|
unsigned char low_shade, high_shade;
|
|
unsigned short index;
|
|
long red_mult, green_mult;
|
|
double red_matrix_width;
|
|
double green_matrix_width;
|
|
double blue_matrix_width;
|
|
double gray_matrix_width;
|
|
double red_colors_per_shade;
|
|
double green_colors_per_shade;
|
|
double blue_colors_per_shade;
|
|
double gray_colors_per_shade;
|
|
gulong *gray_pixels;
|
|
gint shades_r, shades_g, shades_b, shades_gray;
|
|
GtkDitherInfo *red_ordered_dither;
|
|
GtkDitherInfo *green_ordered_dither;
|
|
GtkDitherInfo *blue_ordered_dither;
|
|
GtkDitherInfo *gray_ordered_dither;
|
|
guchar ***dither_matrix;
|
|
guchar DM[8][8] =
|
|
{
|
|
{ 0, 32, 8, 40, 2, 34, 10, 42 },
|
|
{ 48, 16, 56, 24, 50, 18, 58, 26 },
|
|
{ 12, 44, 4, 36, 14, 46, 6, 38 },
|
|
{ 60, 28, 52, 20, 62, 30, 54, 22 },
|
|
{ 3, 35, 11, 43, 1, 33, 9, 41 },
|
|
{ 51, 19, 59, 27, 49, 17, 57, 25 },
|
|
{ 15, 47, 7, 39, 13, 45, 5, 37 },
|
|
{ 63, 31, 55, 23, 61, 29, 53, 21 }
|
|
};
|
|
|
|
if (!klass->info.visual || klass->info.visual->type != GDK_VISUAL_PSEUDO_COLOR)
|
|
return;
|
|
|
|
shades_r = klass->info.nred_shades;
|
|
shades_g = klass->info.ngreen_shades;
|
|
shades_b = klass->info.nblue_shades;
|
|
shades_gray = klass->info.ngray_shades;
|
|
|
|
red_mult = shades_g * shades_b;
|
|
green_mult = shades_b;
|
|
|
|
red_colors_per_shade = 255.0 / (shades_r - 1);
|
|
red_matrix_width = red_colors_per_shade / 64;
|
|
|
|
green_colors_per_shade = 255.0 / (shades_g - 1);
|
|
green_matrix_width = green_colors_per_shade / 64;
|
|
|
|
blue_colors_per_shade = 255.0 / (shades_b - 1);
|
|
blue_matrix_width = blue_colors_per_shade / 64;
|
|
|
|
gray_colors_per_shade = 255.0 / (shades_gray - 1);
|
|
gray_matrix_width = gray_colors_per_shade / 64;
|
|
|
|
/* alloc the ordered dither arrays for accelerated dithering */
|
|
|
|
klass->info.dither_red = g_new (GtkDitherInfo, 256);
|
|
klass->info.dither_green = g_new (GtkDitherInfo, 256);
|
|
klass->info.dither_blue = g_new (GtkDitherInfo, 256);
|
|
klass->info.dither_gray = g_new (GtkDitherInfo, 256);
|
|
|
|
red_ordered_dither = klass->info.dither_red;
|
|
green_ordered_dither = klass->info.dither_green;
|
|
blue_ordered_dither = klass->info.dither_blue;
|
|
gray_ordered_dither = klass->info.dither_gray;
|
|
|
|
dither_matrix = g_new (guchar**, 8);
|
|
for (i = 0; i < 8; i++)
|
|
{
|
|
dither_matrix[i] = g_new (guchar*, 8);
|
|
for (j = 0; j < 8; j++)
|
|
dither_matrix[i][j] = g_new (guchar, 65);
|
|
}
|
|
|
|
klass->info.dither_matrix = dither_matrix;
|
|
|
|
/* setup the ordered_dither_matrices */
|
|
|
|
for (i = 0; i < 8; i++)
|
|
for (j = 0; j < 8; j++)
|
|
for (k = 0; k <= 64; k++)
|
|
dither_matrix[i][j][k] = (DM[i][j] < k) ? 1 : 0;
|
|
|
|
/* setup arrays containing three bytes of information for red, green, & blue */
|
|
/* the arrays contain :
|
|
* 1st byte: low end shade value
|
|
* 2nd byte: high end shade value
|
|
* 3rd & 4th bytes: ordered dither matrix index
|
|
*/
|
|
|
|
gray_pixels = klass->info.gray_pixels;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
|
|
/* setup the red information */
|
|
{
|
|
low_shade = (unsigned char) (i / red_colors_per_shade);
|
|
if (low_shade == (shades_r - 1))
|
|
low_shade--;
|
|
high_shade = low_shade + 1;
|
|
|
|
index = (unsigned short)
|
|
(((double) i - low_shade * red_colors_per_shade) /
|
|
red_matrix_width);
|
|
|
|
low_shade *= red_mult;
|
|
high_shade *= red_mult;
|
|
|
|
red_ordered_dither[i].s[1] = index;
|
|
red_ordered_dither[i].c[0] = low_shade;
|
|
red_ordered_dither[i].c[1] = high_shade;
|
|
}
|
|
|
|
|
|
/* setup the green information */
|
|
{
|
|
low_shade = (unsigned char) (i / green_colors_per_shade);
|
|
if (low_shade == (shades_g - 1))
|
|
low_shade--;
|
|
high_shade = low_shade + 1;
|
|
|
|
index = (unsigned short)
|
|
(((double) i - low_shade * green_colors_per_shade) /
|
|
green_matrix_width);
|
|
|
|
low_shade *= green_mult;
|
|
high_shade *= green_mult;
|
|
|
|
green_ordered_dither[i].s[1] = index;
|
|
green_ordered_dither[i].c[0] = low_shade;
|
|
green_ordered_dither[i].c[1] = high_shade;
|
|
}
|
|
|
|
|
|
/* setup the blue information */
|
|
{
|
|
low_shade = (unsigned char) (i / blue_colors_per_shade);
|
|
if (low_shade == (shades_b - 1))
|
|
low_shade--;
|
|
high_shade = low_shade + 1;
|
|
|
|
index = (unsigned short)
|
|
(((double) i - low_shade * blue_colors_per_shade) /
|
|
blue_matrix_width);
|
|
|
|
blue_ordered_dither[i].s[1] = index;
|
|
blue_ordered_dither[i].c[0] = low_shade;
|
|
blue_ordered_dither[i].c[1] = high_shade;
|
|
}
|
|
|
|
|
|
/* setup the gray information */
|
|
{
|
|
low_shade = (unsigned char) (i / gray_colors_per_shade);
|
|
if (low_shade == (shades_gray - 1))
|
|
low_shade--;
|
|
high_shade = low_shade + 1;
|
|
|
|
index = (unsigned short)
|
|
(((double) i - low_shade * gray_colors_per_shade) /
|
|
gray_matrix_width);
|
|
|
|
gray_ordered_dither[i].s[1] = index;
|
|
gray_ordered_dither[i].c[0] = gray_pixels[low_shade];
|
|
gray_ordered_dither[i].c[1] = gray_pixels[high_shade];
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_fill_lookup_array (gulong *array,
|
|
int depth,
|
|
int shift,
|
|
int prec)
|
|
{
|
|
double one_over_gamma;
|
|
double ind;
|
|
int val;
|
|
int i;
|
|
|
|
if (preview_class->info.gamma != 0.0)
|
|
one_over_gamma = 1.0 / preview_class->info.gamma;
|
|
else
|
|
one_over_gamma = 1.0;
|
|
|
|
for (i = 0; i < 256; i++)
|
|
{
|
|
if (one_over_gamma == 1.0)
|
|
array[i] = ((i >> prec) << shift);
|
|
else
|
|
{
|
|
ind = (double) i / 255.0;
|
|
val = (int) (255 * pow (ind, one_over_gamma));
|
|
array[i] = ((val >> prec) << shift);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_trim_cmap (GtkPreviewClass *klass)
|
|
{
|
|
gulong pixels[256];
|
|
guint nred;
|
|
guint ngreen;
|
|
guint nblue;
|
|
guint ngray;
|
|
guint nreserved;
|
|
guint total;
|
|
guint tmp;
|
|
gint success;
|
|
|
|
nred = klass->info.nred_shades;
|
|
ngreen = klass->info.ngreen_shades;
|
|
nblue = klass->info.nblue_shades;
|
|
ngray = klass->info.ngray_shades;
|
|
nreserved = klass->info.nreserved;
|
|
|
|
success = FALSE;
|
|
while (!success)
|
|
{
|
|
total = nred * ngreen * nblue + ngray + nreserved;
|
|
|
|
if (total <= 256)
|
|
{
|
|
if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
|
|
success = TRUE;
|
|
else
|
|
{
|
|
success = gdk_colors_alloc (klass->info.cmap, 0, NULL, 0, pixels, total);
|
|
if (success)
|
|
{
|
|
if (nreserved > 0)
|
|
{
|
|
klass->info.reserved_pixels = g_new (gulong, nreserved);
|
|
memcpy (klass->info.reserved_pixels, pixels, sizeof (gulong) * nreserved);
|
|
gdk_colors_free (klass->info.cmap, &pixels[nreserved],
|
|
total - nreserved, 0);
|
|
}
|
|
else
|
|
{
|
|
gdk_colors_free (klass->info.cmap, pixels, total, 0);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!success)
|
|
{
|
|
if ((nblue >= nred) && (nblue >= ngreen))
|
|
nblue = nblue - 1;
|
|
else if ((nred >= ngreen) && (nred >= nblue))
|
|
nred = nred - 1;
|
|
else
|
|
{
|
|
tmp = log (ngray) / log (2);
|
|
|
|
if (ngreen >= tmp)
|
|
ngreen = ngreen - 1;
|
|
else
|
|
ngray -= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
if ((nred < 2) || (ngreen < 2) || (nblue < 2) || (ngray < 2))
|
|
{
|
|
g_print ("Unable to allocate sufficient colormap entries.\n");
|
|
g_print ("Try exiting other color intensive applications.\n");
|
|
return;
|
|
}
|
|
|
|
/* If any of the shade values has changed, issue a warning */
|
|
if ((nred != klass->info.nred_shades) ||
|
|
(ngreen != klass->info.ngreen_shades) ||
|
|
(nblue != klass->info.nblue_shades) ||
|
|
(ngray != klass->info.ngray_shades))
|
|
{
|
|
g_print ("Not enough colors to satisfy requested color cube.\n");
|
|
g_print ("Reduced color cube shades from\n");
|
|
g_print ("[%d of Red, %d of Green, %d of Blue, %d of Gray] ==> [%d of Red, %d of Green, %d of Blue, %d of Gray]\n",
|
|
klass->info.nred_shades, klass->info.ngreen_shades,
|
|
klass->info.nblue_shades, klass->info.ngray_shades,
|
|
nred, ngreen, nblue, ngray);
|
|
}
|
|
|
|
klass->info.nred_shades = nred;
|
|
klass->info.ngreen_shades = ngreen;
|
|
klass->info.nblue_shades = nblue;
|
|
klass->info.ngray_shades = ngray;
|
|
}
|
|
|
|
static void
|
|
gtk_create_8_bit (GtkPreviewClass *klass)
|
|
{
|
|
unsigned int r, g, b;
|
|
unsigned int rv, gv, bv;
|
|
unsigned int dr, dg, db, dgray;
|
|
GdkColor color;
|
|
gulong *pixels;
|
|
double one_over_gamma;
|
|
int i;
|
|
|
|
if (!klass->info.color_pixels)
|
|
klass->info.color_pixels = g_new (gulong, 256);
|
|
|
|
if (!klass->info.gray_pixels)
|
|
klass->info.gray_pixels = g_new (gulong, 256);
|
|
|
|
if (klass->info.gamma != 0.0)
|
|
one_over_gamma = 1.0 / klass->info.gamma;
|
|
else
|
|
one_over_gamma = 1.0;
|
|
|
|
dr = klass->info.nred_shades - 1;
|
|
dg = klass->info.ngreen_shades - 1;
|
|
db = klass->info.nblue_shades - 1;
|
|
dgray = klass->info.ngray_shades - 1;
|
|
|
|
pixels = klass->info.color_pixels;
|
|
|
|
for (r = 0, i = 0; r <= dr; r++)
|
|
for (g = 0; g <= dg; g++)
|
|
for (b = 0; b <= db; b++, i++)
|
|
{
|
|
rv = (unsigned int) ((r * klass->info.visual->colormap_size) / dr);
|
|
gv = (unsigned int) ((g * klass->info.visual->colormap_size) / dg);
|
|
bv = (unsigned int) ((b * klass->info.visual->colormap_size) / db);
|
|
color.red = ((int) (255 * pow ((double) rv / 256.0, one_over_gamma))) * 257;
|
|
color.green = ((int) (255 * pow ((double) gv / 256.0, one_over_gamma))) * 257;
|
|
color.blue = ((int) (255 * pow ((double) bv / 256.0, one_over_gamma))) * 257;
|
|
|
|
if (!gdk_color_alloc (klass->info.cmap, &color))
|
|
{
|
|
g_error ("could not initialize 8-bit combined colormap");
|
|
return;
|
|
}
|
|
|
|
pixels[i] = color.pixel;
|
|
}
|
|
|
|
|
|
pixels = klass->info.gray_pixels;
|
|
|
|
for (i = 0; i < (int) klass->info.ngray_shades; i++)
|
|
{
|
|
color.red = (i * klass->info.visual->colormap_size) / dgray;
|
|
color.red = ((int) (255 * pow ((double) color.red / 256.0, one_over_gamma))) * 257;
|
|
color.green = color.red;
|
|
color.blue = color.red;
|
|
|
|
if (!gdk_color_alloc (klass->info.cmap, &color))
|
|
{
|
|
g_error ("could not initialize 8-bit combined colormap");
|
|
return;
|
|
}
|
|
|
|
pixels[i] = color.pixel;
|
|
}
|
|
}
|
|
|
|
|
|
static void
|
|
gtk_color_8 (guchar *src,
|
|
guchar *dest,
|
|
gint x,
|
|
gint y,
|
|
gulong width)
|
|
{
|
|
gulong *colors;
|
|
GtkDitherInfo *dither_red;
|
|
GtkDitherInfo *dither_green;
|
|
GtkDitherInfo *dither_blue;
|
|
GtkDitherInfo r, g, b;
|
|
guchar **dither_matrix;
|
|
guchar *matrix;
|
|
|
|
colors = preview_class->info.color_pixels;
|
|
dither_red = preview_class->info.dither_red;
|
|
dither_green = preview_class->info.dither_green;
|
|
dither_blue = preview_class->info.dither_blue;
|
|
dither_matrix = preview_class->info.dither_matrix[y & 0x7];
|
|
|
|
while (width--)
|
|
{
|
|
r = dither_red[src[0]];
|
|
g = dither_green[src[1]];
|
|
b = dither_blue[src[2]];
|
|
src += 3;
|
|
|
|
matrix = dither_matrix[x++ & 0x7];
|
|
*dest++ = colors[(r.c[matrix[r.s[1]]] +
|
|
g.c[matrix[g.s[1]]] +
|
|
b.c[matrix[b.s[1]]])];
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_color_16 (guchar *src,
|
|
guchar *dest,
|
|
gulong width)
|
|
{
|
|
gulong *lookup_red;
|
|
gulong *lookup_green;
|
|
gulong *lookup_blue;
|
|
gulong val;
|
|
|
|
lookup_red = preview_class->info.lookup_red;
|
|
lookup_green = preview_class->info.lookup_green;
|
|
lookup_blue = preview_class->info.lookup_blue;
|
|
|
|
while (width--)
|
|
{
|
|
val = COLOR_COMPOSE (src[0], src[1], src[2]);
|
|
dest[0] = val;
|
|
dest[1] = val >> 8;
|
|
dest += 2;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_color_24 (guchar *src,
|
|
guchar *dest,
|
|
gulong width)
|
|
{
|
|
gulong *lookup_red;
|
|
gulong *lookup_green;
|
|
gulong *lookup_blue;
|
|
gulong val;
|
|
|
|
lookup_red = preview_class->info.lookup_red;
|
|
lookup_green = preview_class->info.lookup_green;
|
|
lookup_blue = preview_class->info.lookup_blue;
|
|
|
|
while (width--)
|
|
{
|
|
val = COLOR_COMPOSE (src[0], src[1], src[2]);
|
|
dest[0] = val;
|
|
dest[1] = val >> 8;
|
|
dest[2] = val >> 16;
|
|
dest += 3;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_grayscale_8 (guchar *src,
|
|
guchar *dest,
|
|
gint x,
|
|
gint y,
|
|
gulong width)
|
|
{
|
|
GtkDitherInfo *dither_gray;
|
|
GtkDitherInfo gray;
|
|
guchar **dither_matrix;
|
|
guchar *matrix;
|
|
|
|
dither_gray = preview_class->info.dither_gray;
|
|
dither_matrix = preview_class->info.dither_matrix[y & 0x7];
|
|
|
|
while (width--)
|
|
{
|
|
gray = dither_gray[*src++];
|
|
matrix = dither_matrix[x++ & 0x7];
|
|
*dest++ = gray.c[matrix[gray.s[1]]];
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_grayscale_16 (guchar *src,
|
|
guchar *dest,
|
|
gulong width)
|
|
{
|
|
gulong *lookup_red;
|
|
gulong *lookup_green;
|
|
gulong *lookup_blue;
|
|
gulong val;
|
|
|
|
lookup_red = preview_class->info.lookup_red;
|
|
lookup_green = preview_class->info.lookup_green;
|
|
lookup_blue = preview_class->info.lookup_blue;
|
|
|
|
while (width--)
|
|
{
|
|
val = COLOR_COMPOSE (*src, *src, *src);
|
|
dest[0] = val;
|
|
dest[1] = val >> 8;
|
|
dest += 2;
|
|
src += 1;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_grayscale_24 (guchar *src,
|
|
guchar *dest,
|
|
gulong width)
|
|
{
|
|
gulong *lookup_red;
|
|
gulong *lookup_green;
|
|
gulong *lookup_blue;
|
|
gulong val;
|
|
|
|
lookup_red = preview_class->info.lookup_red;
|
|
lookup_green = preview_class->info.lookup_green;
|
|
lookup_blue = preview_class->info.lookup_blue;
|
|
|
|
while (width--)
|
|
{
|
|
val = COLOR_COMPOSE (*src, *src, *src);
|
|
dest[0] = val;
|
|
dest[1] = val >> 8;
|
|
dest[2] = val >> 16;
|
|
dest += 3;
|
|
src += 1;
|
|
}
|
|
}
|
|
|
|
|
|
static gint
|
|
gtk_get_preview_prop (guint *nred,
|
|
guint *ngreen,
|
|
guint *nblue,
|
|
guint *ngray)
|
|
{
|
|
GtkPreviewProp *prop;
|
|
GdkAtom property;
|
|
|
|
/* FIXME: need to grab the server here to prevent a race condition */
|
|
|
|
property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
|
|
|
|
if (gdk_property_get (NULL, property, property,
|
|
0, sizeof (GtkPreviewProp), FALSE,
|
|
NULL, NULL, NULL, (guchar**) &prop))
|
|
{
|
|
*nred = prop->nred_shades;
|
|
*ngreen = prop->ngreen_shades;
|
|
*nblue = prop->nblue_shades;
|
|
*ngray = prop->ngray_shades;
|
|
|
|
prop->ref_count = prop->ref_count + 1;
|
|
gdk_property_change (NULL, property, property, 16,
|
|
GDK_PROP_MODE_REPLACE,
|
|
(guchar*) prop, 5);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
static void
|
|
gtk_set_preview_prop (guint nred,
|
|
guint ngreen,
|
|
guint nblue,
|
|
guint ngray)
|
|
{
|
|
GtkPreviewProp prop;
|
|
GdkAtom property;
|
|
|
|
property = gdk_atom_intern ("GTK_PREVIEW_INFO", FALSE);
|
|
|
|
prop.ref_count = 1;
|
|
prop.nred_shades = nred;
|
|
prop.ngreen_shades = ngreen;
|
|
prop.nblue_shades = nblue;
|
|
prop.ngray_shades = ngray;
|
|
|
|
gdk_property_change (NULL, property, property, 16,
|
|
GDK_PROP_MODE_REPLACE,
|
|
(guchar*) &prop, 5);
|
|
}
|
|
|
|
|
|
static void
|
|
gtk_lsbmsb_1_1 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
memcpy (dest, src, count);
|
|
}
|
|
|
|
static void
|
|
gtk_lsb_2_2 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
memcpy (dest, src, count * 2);
|
|
}
|
|
|
|
static void
|
|
gtk_msb_2_2 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
while (count--)
|
|
{
|
|
dest[0] = src[1];
|
|
dest[1] = src[0];
|
|
dest += 2;
|
|
src += 2;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_lsb_3_3 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
memcpy (dest, src, count * 3);
|
|
}
|
|
|
|
static void
|
|
gtk_msb_3_3 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
while (count--)
|
|
{
|
|
dest[0] = src[2];
|
|
dest[1] = src[1];
|
|
dest[2] = src[0];
|
|
dest += 3;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_lsb_3_4 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
while (count--)
|
|
{
|
|
dest[0] = src[0];
|
|
dest[1] = src[1];
|
|
dest[2] = src[2];
|
|
dest += 4;
|
|
src += 3;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gtk_msb_3_4 (guchar *dest,
|
|
guchar *src,
|
|
gint count)
|
|
{
|
|
while (count--)
|
|
{
|
|
dest[1] = src[2];
|
|
dest[2] = src[1];
|
|
dest[3] = src[0];
|
|
dest += 4;
|
|
src += 3;
|
|
}
|
|
}
|