Added Sven's patch for the scale and resize dialogs

Added Raph's patch for the transperancy blur problem
This commit is contained in:
Manish Singh 1997-12-08 01:13:10 +00:00
parent ff7139d37f
commit 7d148f0288
21 changed files with 1514 additions and 29 deletions

View File

@ -1,3 +1,11 @@
Sun Dec 7 17:05:32 PST 1997
* added Sven Neumann's patch to the scale and resize dialogs for ratio input fields (app/resize.h, app/resize.c)
* added Raph Levien's patch for the transperancy blur problem
(app/convolve.c, app/gimage.h, app/gimage.c, paint_core.h,
paint_core.c, paint_funcs.h, paint_funcs.c)
Sun Dec 7 15:27:14 EST 1997 Adrian Likins <adrian@gimp.org>
* fixed refract.c to look for megawidget.h in the proper place

View File

@ -266,6 +266,11 @@ convolve_motion (PaintCore *paint_core,
/* if the source has no alpha, then add alpha pixels */
if (!drawable_has_alpha (drawable_id))
{
/* note: this architecture needlessly convolves the totally-
opaque alpha channel. A faster approach would be to keep
tempPR the same number of bytes as srcPR, and extend the
paint_core_replace_canvas API to handle non-alpha images. */
tempPR.bytes = srcPR.bytes + 1;
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
@ -287,6 +292,13 @@ convolve_motion (PaintCore *paint_core,
tempPR.data = temp_data;
copy_region (&srcPR, &tempPR);
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
tempPR.h = area->height;
tempPR.data = temp_data;
multiply_alpha_region (&tempPR);
}
tempPR.x = 0; tempPR.y = 0;
@ -298,6 +310,9 @@ convolve_motion (PaintCore *paint_core,
convolve_region (&tempPR, &destPR, matrix, matrix_size,
matrix_divisor, NORMAL);
if (drawable_has_alpha (drawable_id))
separate_alpha_region (&destPR);
/* Free the allocated temp space */
g_free (temp_data);
}
@ -311,9 +326,9 @@ convolve_motion (PaintCore *paint_core,
}
/* paste the newly painted canvas to the gimage which is being worked on */
paint_core_paste_canvas (paint_core, drawable_id, OPAQUE,
paint_core_replace_canvas (paint_core, drawable_id, OPAQUE,
(int) (get_brush_opacity () * 255),
NORMAL_MODE, SOFT, INCREMENTAL);
SOFT, INCREMENTAL);
}
static void

View File

@ -31,6 +31,8 @@ struct _ResizePrivate
{
GtkWidget *width_text;
GtkWidget *height_text;
GtkWidget *ratio_x_text;
GtkWidget *ratio_y_text;
GtkWidget *off_x_text;
GtkWidget *off_y_text;
GtkWidget *drawing_area;
@ -50,6 +52,8 @@ static void off_x_update (GtkWidget *w, gpointer data);
static void off_y_update (GtkWidget *w, gpointer data);
static void width_update (GtkWidget *w, gpointer data);
static void height_update (GtkWidget *w, gpointer data);
static void ratio_x_update (GtkWidget *w, gpointer data);
static void ratio_y_update (GtkWidget *w, gpointer data);
static void constrain_update (GtkWidget *w, gpointer data);
static gint resize_events (GtkWidget *area, GdkEvent *event);
@ -68,6 +72,7 @@ resize_widget_new (ResizeType type,
GtkWidget *constrain;
GtkWidget *table;
char size[12];
char ratio_text[12];
table = NULL;
@ -77,6 +82,8 @@ resize_widget_new (ResizeType type,
resize->private_part = private;
resize->width = width;
resize->height = height;
resize->ratio_x = 1.0;
resize->ratio_y = 1.0;
resize->off_x = 0;
resize->off_y = 0;
private->old_width = width;
@ -95,11 +102,11 @@ resize_widget_new (ResizeType type,
{
case ScaleWidget:
resize->resize_widget = gtk_frame_new ("Scale");
table = gtk_table_new (2, 2, TRUE);
table = gtk_table_new (4, 2, TRUE);
break;
case ResizeWidget:
resize->resize_widget = gtk_frame_new ("Resize");
table = gtk_table_new (4, 2, TRUE);
table = gtk_table_new (6, 2, TRUE);
break;
}
gtk_frame_set_shadow_type (GTK_FRAME (resize->resize_widget), GTK_SHADOW_ETCHED_IN);
@ -146,17 +153,51 @@ resize_widget_new (ResizeType type,
resize);
gtk_widget_show (private->height_text);
/* the x scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_x);
label = gtk_label_new ("X ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_x_text, 1, 2, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_x_text), "changed",
(GtkSignalFunc) ratio_x_update,
resize);
gtk_widget_show (private->ratio_x_text);
/* the y scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_y);
label = gtk_label_new ("Y ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_y_text, 1, 2, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_y_text), "changed",
(GtkSignalFunc) ratio_y_update,
resize);
gtk_widget_show (private->ratio_y_text);
if (type == ResizeWidget)
{
/* the off_x label and entry */
sprintf (size, "%d", 0);
label = gtk_label_new ("X Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 2, 3,
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
@ -169,11 +210,11 @@ resize_widget_new (ResizeType type,
sprintf (size, "%d", 0);
label = gtk_label_new ("Y Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 3, 4,
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
@ -425,6 +466,7 @@ width_update (GtkWidget *w,
double ratio;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -432,6 +474,14 @@ width_update (GtkWidget *w,
resize->width = atoi (str);
ratio = (double) resize->width / (double) private->old_width;
resize->ratio_x = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
@ -445,7 +495,6 @@ width_update (GtkWidget *w,
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
ratio = (double) resize->width / (double) private->old_width;
new_height = (int) (private->old_height * ratio);
if (new_height == 0) new_height = 1;
@ -458,6 +507,12 @@ width_update (GtkWidget *w,
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
resize->ratio_y = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -485,6 +540,7 @@ height_update (GtkWidget *w,
double ratio;
int new_width;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -492,6 +548,13 @@ height_update (GtkWidget *w,
resize->height = atoi (str);
ratio = (double) resize->height / (double) private->old_height;
resize->ratio_y = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -517,6 +580,176 @@ height_update (GtkWidget *w,
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
resize->ratio_x = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_x_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_x = atof (str);
new_width = (int) ((double) private->old_width * resize->ratio_x);
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", new_width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
resize->ratio_y = resize->ratio_x;
new_height = (int) (private->old_height * resize->ratio_y);
if (new_height == 0) new_height = 1;
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", resize->height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_y_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_y = atof (str);
new_height = (int) ((double) private->old_height * resize->ratio_y);
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", new_height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
if (private->constrain && resize->height != 0)
{
private->constrain = FALSE;
resize->ratio_x = resize->ratio_y;
new_width = (int) (private->old_width * resize->ratio_x);
if (new_width == 0) new_width = 1;
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", resize->width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{

View File

@ -34,6 +34,8 @@ struct _Resize
ResizeType type;
int width;
int height;
double ratio_x;
double ratio_y;
int off_x;
int off_y;

View File

@ -584,6 +584,126 @@ gimage_apply_image (GImage *gimage, int drawable_id, PixelRegion *src2PR,
opacity, mode, active, operation);
}
/* Similar to gimage_apply_image but works in "replace" mode (i.e.
transparent pixels in src2 make the result transparent rather
than opaque.
Takes an additional mask pixel region as well.
*/
void
gimage_replace_image (GImage *gimage, int drawable_id, PixelRegion *src2PR,
int undo, int opacity,
PixelRegion *maskPR,
int x, int y)
{
Channel * mask;
int x1, y1, x2, y2;
int offset_x, offset_y;
PixelRegion src1PR, destPR;
PixelRegion mask2PR, tempPR;
unsigned char *temp_data;
int operation;
int active [MAX_CHANNELS];
/* get the selection mask if one exists */
mask = (gimage_mask_is_empty (gimage)) ?
NULL : gimage_get_mask (gimage);
/* configure the active channel array */
gimage_get_active_channels (gimage, drawable_id, active);
/* determine what sort of operation is being attempted and
* if it's actually legal...
*/
operation = valid_combinations [drawable_type (drawable_id)][src2PR->bytes];
if (operation == -1)
{
warning ("gimage_apply_image sent illegal parameters\n");
return;
}
/* get the layer offsets */
drawable_offsets (drawable_id, &offset_x, &offset_y);
/* make sure the image application coordinates are within gimage bounds */
x1 = BOUNDS (x, 0, drawable_width (drawable_id));
y1 = BOUNDS (y, 0, drawable_height (drawable_id));
x2 = BOUNDS (x + src2PR->w, 0, drawable_width (drawable_id));
y2 = BOUNDS (y + src2PR->h, 0, drawable_height (drawable_id));
if (mask)
{
/* make sure coordinates are in mask bounds ...
* we need to add the layer offset to transform coords
* into the mask coordinate system
*/
x1 = BOUNDS (x1, -offset_x, mask->width - offset_x);
y1 = BOUNDS (y1, -offset_y, mask->height - offset_y);
x2 = BOUNDS (x2, -offset_x, mask->width - offset_x);
y2 = BOUNDS (y2, -offset_y, mask->height - offset_y);
}
/* If the calling procedure specified an undo step... */
if (undo)
drawable_apply_image (drawable_id, x1, y1, x2, y2, NULL, FALSE);
/* configure the pixel regions
* If an alternative to using the drawable's data as src1 was provided...
*/
pixel_region_init (&src1PR, drawable_data (drawable_id), x1, y1, (x2 - x1), (y2 - y1), FALSE);
pixel_region_init (&destPR, drawable_data (drawable_id), x1, y1, (x2 - x1), (y2 - y1), TRUE);
pixel_region_resize (src2PR, src2PR->x + (x1 - x), src2PR->y + (y1 - y), (x2 - x1), (y2 - y1));
if (mask)
{
int mx, my;
/* configure the mask pixel region
* don't use x1 and y1 because they are in layer
* coordinate system. Need mask coordinate system
*/
mx = x1 + offset_x;
my = y1 + offset_y;
pixel_region_init (&mask2PR, mask->tiles, mx, my, (x2 - x1), (y2 - y1), FALSE);
tempPR.bytes = 1;
tempPR.x = 0;
tempPR.y = 0;
tempPR.w = x2 - x1;
tempPR.h = y2 - y1;
tempPR.rowstride = mask2PR.rowstride;
temp_data = g_malloc (tempPR.h * tempPR.rowstride);
tempPR.data = temp_data;
copy_region (&mask2PR, &tempPR);
/* apparently, region operations can mutate some PR data. */
tempPR.x = 0;
tempPR.y = 0;
tempPR.w = x2 - x1;
tempPR.h = y2 - y1;
tempPR.data = temp_data;
apply_mask_to_region (&tempPR, maskPR, OPAQUE);
tempPR.x = 0;
tempPR.y = 0;
tempPR.w = x2 - x1;
tempPR.h = y2 - y1;
tempPR.data = temp_data;
combine_regions_replace (&src1PR, src2PR, &destPR, &tempPR, NULL,
opacity, active, operation);
g_free (temp_data);
}
else
combine_regions_replace (&src1PR, src2PR, &destPR, maskPR, NULL,
opacity, active, operation);
}
void
gimage_get_foreground (GImage *gimage, int drawable_id, unsigned char *fg)

View File

@ -163,6 +163,8 @@ void gimage_free_shadow (GImage *);
void gimage_delete (GImage *);
void gimage_apply_image (GImage *, int, PixelRegion *, int, int, int,
TileManager *, int, int);
void gimage_replace_image (GImage *, int, PixelRegion *, int, int,
PixelRegion *, int, int);
void gimage_get_foreground (GImage *, int, unsigned char *);
void gimage_get_background (GImage *, int, unsigned char *);
void gimage_get_color (GImage *, int, unsigned char *,

View File

@ -31,6 +31,8 @@ struct _ResizePrivate
{
GtkWidget *width_text;
GtkWidget *height_text;
GtkWidget *ratio_x_text;
GtkWidget *ratio_y_text;
GtkWidget *off_x_text;
GtkWidget *off_y_text;
GtkWidget *drawing_area;
@ -50,6 +52,8 @@ static void off_x_update (GtkWidget *w, gpointer data);
static void off_y_update (GtkWidget *w, gpointer data);
static void width_update (GtkWidget *w, gpointer data);
static void height_update (GtkWidget *w, gpointer data);
static void ratio_x_update (GtkWidget *w, gpointer data);
static void ratio_y_update (GtkWidget *w, gpointer data);
static void constrain_update (GtkWidget *w, gpointer data);
static gint resize_events (GtkWidget *area, GdkEvent *event);
@ -68,6 +72,7 @@ resize_widget_new (ResizeType type,
GtkWidget *constrain;
GtkWidget *table;
char size[12];
char ratio_text[12];
table = NULL;
@ -77,6 +82,8 @@ resize_widget_new (ResizeType type,
resize->private_part = private;
resize->width = width;
resize->height = height;
resize->ratio_x = 1.0;
resize->ratio_y = 1.0;
resize->off_x = 0;
resize->off_y = 0;
private->old_width = width;
@ -95,11 +102,11 @@ resize_widget_new (ResizeType type,
{
case ScaleWidget:
resize->resize_widget = gtk_frame_new ("Scale");
table = gtk_table_new (2, 2, TRUE);
table = gtk_table_new (4, 2, TRUE);
break;
case ResizeWidget:
resize->resize_widget = gtk_frame_new ("Resize");
table = gtk_table_new (4, 2, TRUE);
table = gtk_table_new (6, 2, TRUE);
break;
}
gtk_frame_set_shadow_type (GTK_FRAME (resize->resize_widget), GTK_SHADOW_ETCHED_IN);
@ -146,17 +153,51 @@ resize_widget_new (ResizeType type,
resize);
gtk_widget_show (private->height_text);
/* the x scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_x);
label = gtk_label_new ("X ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_x_text, 1, 2, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_x_text), "changed",
(GtkSignalFunc) ratio_x_update,
resize);
gtk_widget_show (private->ratio_x_text);
/* the y scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_y);
label = gtk_label_new ("Y ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_y_text, 1, 2, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_y_text), "changed",
(GtkSignalFunc) ratio_y_update,
resize);
gtk_widget_show (private->ratio_y_text);
if (type == ResizeWidget)
{
/* the off_x label and entry */
sprintf (size, "%d", 0);
label = gtk_label_new ("X Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 2, 3,
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
@ -169,11 +210,11 @@ resize_widget_new (ResizeType type,
sprintf (size, "%d", 0);
label = gtk_label_new ("Y Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 3, 4,
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
@ -425,6 +466,7 @@ width_update (GtkWidget *w,
double ratio;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -432,6 +474,14 @@ width_update (GtkWidget *w,
resize->width = atoi (str);
ratio = (double) resize->width / (double) private->old_width;
resize->ratio_x = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
@ -445,7 +495,6 @@ width_update (GtkWidget *w,
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
ratio = (double) resize->width / (double) private->old_width;
new_height = (int) (private->old_height * ratio);
if (new_height == 0) new_height = 1;
@ -458,6 +507,12 @@ width_update (GtkWidget *w,
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
resize->ratio_y = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -485,6 +540,7 @@ height_update (GtkWidget *w,
double ratio;
int new_width;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -492,6 +548,13 @@ height_update (GtkWidget *w,
resize->height = atoi (str);
ratio = (double) resize->height / (double) private->old_height;
resize->ratio_y = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -517,6 +580,176 @@ height_update (GtkWidget *w,
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
resize->ratio_x = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_x_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_x = atof (str);
new_width = (int) ((double) private->old_width * resize->ratio_x);
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", new_width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
resize->ratio_y = resize->ratio_x;
new_height = (int) (private->old_height * resize->ratio_y);
if (new_height == 0) new_height = 1;
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", resize->height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_y_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_y = atof (str);
new_height = (int) ((double) private->old_height * resize->ratio_y);
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", new_height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
if (private->constrain && resize->height != 0)
{
private->constrain = FALSE;
resize->ratio_x = resize->ratio_y;
new_width = (int) (private->old_width * resize->ratio_x);
if (new_width == 0) new_width = 1;
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", resize->width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{

View File

@ -34,6 +34,8 @@ struct _Resize
ResizeType type;
int width;
int height;
double ratio_x;
double ratio_y;
int off_x;
int off_y;

View File

@ -94,6 +94,10 @@ static int * make_curve (double, int *);
static void run_length_encode (unsigned char *, int *, int, int);
static void draw_segments (PixelRegion *, BoundSeg *, int, int, int, int);
static double cubic (double, int, int, int, int);
static void apply_layer_mode_replace (unsigned char *, unsigned char *,
unsigned char *, unsigned char *,
int, int, int,
int, int, int, int *);
static unsigned char *
@ -850,6 +854,59 @@ dissolve_pixels (unsigned char *src,
}
}
void
replace_pixels (unsigned char *src1,
unsigned char *src2,
unsigned char *dest,
unsigned char *mask,
int length,
int opacity,
int *affect,
int b1,
int b2)
{
int alpha;
int b;
double a_val, a_recip, mask_val;
double norm_opacity;
int s1_a, s2_a;
int new_val;
if (b1 != b2)
{
g_warning ("replace_pixels only works on commensurate pixel regions");
return;
}
alpha = b1 - 1;
norm_opacity = opacity * (1.0 / 65025.0);
while (length --)
{
mask_val = mask[0] * norm_opacity;
/* calculate new alpha first. */
s1_a = src1[alpha];
s2_a = src2[alpha];
a_val = s1_a + mask_val * (s2_a - s1_a);
if (a_val == 0)
a_recip = 0;
else
a_recip = 1.0 / a_val;
/* possible optimization: fold a_recip into s1_a and s2_a */
for (b = 0; b < alpha; b++)
{
new_val = 0.5 + a_recip * (src1[b] * s1_a + mask_val *
(src2[b] * s2_a - src1[b] * s1_a));
dest[b] = affect[b] ? MIN (new_val, 255) : src1[b];
}
dest[alpha] = affect[alpha] ? a_val + 0.5: s1_a;
src1 += b1;
src2 += b2;
dest += b2;
mask++;
}
}
void
swap_pixels (unsigned char *src,
@ -2544,6 +2601,78 @@ convolve_region (PixelRegion *srcR,
}
}
/* Convert from separated alpha to premultiplied alpha. Only works on
non-tiled regions! */
void
multiply_alpha_region (PixelRegion *srcR)
{
unsigned char *src, *s;
int x, y;
int width, height;
int b, bytes;
double alpha_val;
width = srcR->w;
height = srcR->h;
bytes = srcR->bytes;
src = srcR->data;
for (y = 0; y < height; y++)
{
s = src;
for (x = 0; x < width; x++)
{
alpha_val = s[bytes - 1] * (1.0 / 255.0);
for (b = 0; b < bytes - 1; b++)
s[b] = 0.5 + s[b] * alpha_val;
s += bytes;
}
src += srcR->rowstride;
}
}
/* Convert from premultiplied alpha to separated alpha. Only works on
non-tiled regions! */
void
separate_alpha_region (PixelRegion *srcR)
{
unsigned char *src, *s;
int x, y;
int width, height;
int b, bytes;
double alpha_recip;
int new_val;
width = srcR->w;
height = srcR->h;
bytes = srcR->bytes;
src = srcR->data;
for (y = 0; y < height; y++)
{
s = src;
for (x = 0; x < width; x++)
{
/* predicate is equivalent to:
(((s[bytes - 1] - 1) & 255) + 2) & 256
*/
if (s[bytes - 1] != 0 && s[bytes - 1] != 255)
{
alpha_recip = 255.0 / s[bytes - 1];
for (b = 0; b < bytes - 1; b++)
{
new_val = 0.5 + s[b] * alpha_recip;
new_val = MIN (new_val, 255);
s[b] = new_val;
}
}
s += bytes;
}
src += srcR->rowstride;
}
}
void
gaussian_blur_region (PixelRegion *srcR,
@ -3792,6 +3921,43 @@ combine_regions (PixelRegion *src1,
}
}
void
combine_regions_replace (PixelRegion *src1,
PixelRegion *src2,
PixelRegion *dest,
PixelRegion *mask,
unsigned char *data,
int opacity,
int *affect,
int type)
{
int h;
unsigned char * s1, * s2;
unsigned char * d, * m;
void * pr;
for (pr = pixel_regions_register (4, src1, src2, dest, mask); pr != NULL; pr = pixel_regions_process (pr))
{
s1 = src1->data;
s2 = src2->data;
d = dest->data;
m = mask->data;
for (h = 0; h < src1->h; h++)
{
/* Now, apply the paint mode */
apply_layer_mode_replace (s1, s2, d, m, src1->x, src1->y + h, opacity, src1->w,
src1->bytes, src2->bytes, affect);
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
m += mask->rowstride;
}
}
}
/*********************************
* color conversion routines *
@ -4246,3 +4412,19 @@ apply_indexed_layer_mode (unsigned char *src1,
return combine;
}
static void
apply_layer_mode_replace (unsigned char *src1,
unsigned char *src2,
unsigned char *dest,
unsigned char *mask,
int x,
int y,
int opacity,
int length,
int b1, /* bytes */
int b2, /* bytes */
int *affect)
{
replace_pixels (src1, src2, dest, mask, length, opacity, affect, b1, b2);
}

View File

@ -324,6 +324,10 @@ void extract_from_region (PixelRegion *, PixelRegion *,
void convolve_region (PixelRegion *, PixelRegion *,
int *, int, int, int);
void multiply_alpha_region (PixelRegion *);
void separate_alpha_region (PixelRegion *);
void gaussian_blur_region (PixelRegion *, double);
void border_region (PixelRegion *, void *,
@ -402,6 +406,11 @@ void combine_regions (PixelRegion *, PixelRegion *,
unsigned char *, int,
int, int *, int);
void combine_regions_replace (PixelRegion *, PixelRegion *,
PixelRegion *, PixelRegion *,
unsigned char *,
int, int *, int);
/* Color conversion routines */
void rgb_to_hsv (int *, int *, int *);

View File

@ -266,6 +266,11 @@ convolve_motion (PaintCore *paint_core,
/* if the source has no alpha, then add alpha pixels */
if (!drawable_has_alpha (drawable_id))
{
/* note: this architecture needlessly convolves the totally-
opaque alpha channel. A faster approach would be to keep
tempPR the same number of bytes as srcPR, and extend the
paint_core_replace_canvas API to handle non-alpha images. */
tempPR.bytes = srcPR.bytes + 1;
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
@ -287,6 +292,13 @@ convolve_motion (PaintCore *paint_core,
tempPR.data = temp_data;
copy_region (&srcPR, &tempPR);
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
tempPR.h = area->height;
tempPR.data = temp_data;
multiply_alpha_region (&tempPR);
}
tempPR.x = 0; tempPR.y = 0;
@ -298,6 +310,9 @@ convolve_motion (PaintCore *paint_core,
convolve_region (&tempPR, &destPR, matrix, matrix_size,
matrix_divisor, NORMAL);
if (drawable_has_alpha (drawable_id))
separate_alpha_region (&destPR);
/* Free the allocated temp space */
g_free (temp_data);
}
@ -311,9 +326,9 @@ convolve_motion (PaintCore *paint_core,
}
/* paste the newly painted canvas to the gimage which is being worked on */
paint_core_paste_canvas (paint_core, drawable_id, OPAQUE,
paint_core_replace_canvas (paint_core, drawable_id, OPAQUE,
(int) (get_brush_opacity () * 255),
NORMAL_MODE, SOFT, INCREMENTAL);
SOFT, INCREMENTAL);
}
static void

View File

@ -43,6 +43,7 @@ static MaskBuf * paint_core_subsample_mask (MaskBuf *, double, double);
static MaskBuf * paint_core_solidify_mask (MaskBuf *);
static MaskBuf * paint_core_get_brush_mask (PaintCore *, int);
static void paint_core_paste (PaintCore *, MaskBuf *, int, int, int, int, int);
static void paint_core_replace (PaintCore *, MaskBuf *, int, int, int, int);
static void paint_to_canvas_tiles (PaintCore *, MaskBuf *, int);
static void paint_to_canvas_buf (PaintCore *, MaskBuf *, int);
static void set_undo_tiles (int, int, int, int, int);
@ -638,6 +639,29 @@ paint_core_paste_canvas (paint_core, drawable_id, brush_opacity, image_opacity,
brush_opacity, image_opacity, paint_mode, mode);
}
/* Similar to paint_core_paste_canvas, but replaces the alpha channel
rather than using it to composite (i.e. transparent over opaque
becomes transparent rather than opauqe. */
void
paint_core_replace_canvas (paint_core, drawable_id, brush_opacity, image_opacity,
brush_hardness, mode)
PaintCore *paint_core;
int drawable_id;
int brush_opacity;
int image_opacity;
int brush_hardness;
int mode;
{
MaskBuf *brush_mask;
/* get the brush mask */
brush_mask = paint_core_get_brush_mask (paint_core, brush_hardness);
/* paste the canvas buf */
paint_core_replace (paint_core, brush_mask, drawable_id,
brush_opacity, image_opacity, mode);
}
/************************************************************
* LOCAL FUNCTION DEFINITIONS *
************************************************************/
@ -834,6 +858,85 @@ paint_core_paste (paint_core, brush_mask, drawable_id, brush_opacity, image_opac
canvas_buf->width, canvas_buf->height);
}
/* This works similarly to paint_core_paste. However, instead of combining
the canvas to the paint core drawable using one of the combination
modes, it uses a "replace" mode (i.e. transparent pixels in the
canvas erase the paint core drawable).
When not drawing on alpha-enabled images, it just paints using NORMAL
mode.
*/
static void
paint_core_replace (paint_core, brush_mask, drawable_id, brush_opacity, image_opacity, mode)
PaintCore *paint_core;
MaskBuf *brush_mask;
int drawable_id;
int brush_opacity;
int image_opacity;
int mode;
{
GImage *gimage;
PixelRegion srcPR, maskPR;
int offx, offy;
if (!drawable_has_alpha (drawable_id))
{
paint_core_paste (paint_core, brush_mask, drawable_id,
brush_opacity, image_opacity, NORMAL_MODE,
mode);
return;
}
if (mode != INCREMENTAL)
{
g_warning ("paint_core_replace only works in INCREMENTAL mode");
return;
}
if (! (gimage = drawable_gimage (drawable_id)))
return;
/* set undo blocks */
set_undo_tiles (drawable_id,
canvas_buf->x, canvas_buf->y,
canvas_buf->width, canvas_buf->height);
maskPR.bytes = 1;
maskPR.x = 0; maskPR.y = 0;
maskPR.w = srcPR.w;
maskPR.h = srcPR.h;
maskPR.rowstride = maskPR.bytes * brush_mask->width;
maskPR.data = mask_buf_data (brush_mask);
/* intialize canvas buf source pixel regions */
srcPR.bytes = canvas_buf->bytes;
srcPR.x = 0; srcPR.y = 0;
srcPR.w = canvas_buf->width;
srcPR.h = canvas_buf->height;
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
srcPR.data = temp_buf_data (canvas_buf);
/* apply the paint area to the gimage */
gimage_replace_image (gimage, drawable_id, &srcPR,
FALSE, image_opacity,
&maskPR,
canvas_buf->x, canvas_buf->y);
/* Update the undo extents */
paint_core->x1 = MINIMUM (paint_core->x1, canvas_buf->x);
paint_core->y1 = MINIMUM (paint_core->y1, canvas_buf->y);
paint_core->x2 = MAXIMUM (paint_core->x2, (canvas_buf->x + canvas_buf->width));
paint_core->y2 = MAXIMUM (paint_core->y2, (canvas_buf->y + canvas_buf->height));
/* Update the gimage--it is important to call gdisplays_update_area
* instead of drawable_update because we don't want the drawable
* preview to be constantly invalidated
*/
drawable_offsets (drawable_id, &offx, &offy);
gdisplays_update_area (gimage->ID, canvas_buf->x + offx, canvas_buf->y + offy,
canvas_buf->width, canvas_buf->height);
}
static void
paint_to_canvas_tiles (paint_core, brush_mask, brush_opacity)
PaintCore *paint_core;

View File

@ -96,6 +96,7 @@ void paint_core_cleanup (void);
TempBuf * paint_core_get_paint_area (PaintCore *, int);
TempBuf * paint_core_get_orig_image (PaintCore *, int, int, int, int, int);
void paint_core_paste_canvas (PaintCore *, int, int, int, int, int, int);
void paint_core_replace_canvas (PaintCore *, int, int, int, int, int);
#endif /* __PAINT_CORE_H__ */

View File

@ -94,6 +94,10 @@ static int * make_curve (double, int *);
static void run_length_encode (unsigned char *, int *, int, int);
static void draw_segments (PixelRegion *, BoundSeg *, int, int, int, int);
static double cubic (double, int, int, int, int);
static void apply_layer_mode_replace (unsigned char *, unsigned char *,
unsigned char *, unsigned char *,
int, int, int,
int, int, int, int *);
static unsigned char *
@ -850,6 +854,59 @@ dissolve_pixels (unsigned char *src,
}
}
void
replace_pixels (unsigned char *src1,
unsigned char *src2,
unsigned char *dest,
unsigned char *mask,
int length,
int opacity,
int *affect,
int b1,
int b2)
{
int alpha;
int b;
double a_val, a_recip, mask_val;
double norm_opacity;
int s1_a, s2_a;
int new_val;
if (b1 != b2)
{
g_warning ("replace_pixels only works on commensurate pixel regions");
return;
}
alpha = b1 - 1;
norm_opacity = opacity * (1.0 / 65025.0);
while (length --)
{
mask_val = mask[0] * norm_opacity;
/* calculate new alpha first. */
s1_a = src1[alpha];
s2_a = src2[alpha];
a_val = s1_a + mask_val * (s2_a - s1_a);
if (a_val == 0)
a_recip = 0;
else
a_recip = 1.0 / a_val;
/* possible optimization: fold a_recip into s1_a and s2_a */
for (b = 0; b < alpha; b++)
{
new_val = 0.5 + a_recip * (src1[b] * s1_a + mask_val *
(src2[b] * s2_a - src1[b] * s1_a));
dest[b] = affect[b] ? MIN (new_val, 255) : src1[b];
}
dest[alpha] = affect[alpha] ? a_val + 0.5: s1_a;
src1 += b1;
src2 += b2;
dest += b2;
mask++;
}
}
void
swap_pixels (unsigned char *src,
@ -2544,6 +2601,78 @@ convolve_region (PixelRegion *srcR,
}
}
/* Convert from separated alpha to premultiplied alpha. Only works on
non-tiled regions! */
void
multiply_alpha_region (PixelRegion *srcR)
{
unsigned char *src, *s;
int x, y;
int width, height;
int b, bytes;
double alpha_val;
width = srcR->w;
height = srcR->h;
bytes = srcR->bytes;
src = srcR->data;
for (y = 0; y < height; y++)
{
s = src;
for (x = 0; x < width; x++)
{
alpha_val = s[bytes - 1] * (1.0 / 255.0);
for (b = 0; b < bytes - 1; b++)
s[b] = 0.5 + s[b] * alpha_val;
s += bytes;
}
src += srcR->rowstride;
}
}
/* Convert from premultiplied alpha to separated alpha. Only works on
non-tiled regions! */
void
separate_alpha_region (PixelRegion *srcR)
{
unsigned char *src, *s;
int x, y;
int width, height;
int b, bytes;
double alpha_recip;
int new_val;
width = srcR->w;
height = srcR->h;
bytes = srcR->bytes;
src = srcR->data;
for (y = 0; y < height; y++)
{
s = src;
for (x = 0; x < width; x++)
{
/* predicate is equivalent to:
(((s[bytes - 1] - 1) & 255) + 2) & 256
*/
if (s[bytes - 1] != 0 && s[bytes - 1] != 255)
{
alpha_recip = 255.0 / s[bytes - 1];
for (b = 0; b < bytes - 1; b++)
{
new_val = 0.5 + s[b] * alpha_recip;
new_val = MIN (new_val, 255);
s[b] = new_val;
}
}
s += bytes;
}
src += srcR->rowstride;
}
}
void
gaussian_blur_region (PixelRegion *srcR,
@ -3792,6 +3921,43 @@ combine_regions (PixelRegion *src1,
}
}
void
combine_regions_replace (PixelRegion *src1,
PixelRegion *src2,
PixelRegion *dest,
PixelRegion *mask,
unsigned char *data,
int opacity,
int *affect,
int type)
{
int h;
unsigned char * s1, * s2;
unsigned char * d, * m;
void * pr;
for (pr = pixel_regions_register (4, src1, src2, dest, mask); pr != NULL; pr = pixel_regions_process (pr))
{
s1 = src1->data;
s2 = src2->data;
d = dest->data;
m = mask->data;
for (h = 0; h < src1->h; h++)
{
/* Now, apply the paint mode */
apply_layer_mode_replace (s1, s2, d, m, src1->x, src1->y + h, opacity, src1->w,
src1->bytes, src2->bytes, affect);
s1 += src1->rowstride;
s2 += src2->rowstride;
d += dest->rowstride;
m += mask->rowstride;
}
}
}
/*********************************
* color conversion routines *
@ -4246,3 +4412,19 @@ apply_indexed_layer_mode (unsigned char *src1,
return combine;
}
static void
apply_layer_mode_replace (unsigned char *src1,
unsigned char *src2,
unsigned char *dest,
unsigned char *mask,
int x,
int y,
int opacity,
int length,
int b1, /* bytes */
int b2, /* bytes */
int *affect)
{
replace_pixels (src1, src2, dest, mask, length, opacity, affect, b1, b2);
}

View File

@ -324,6 +324,10 @@ void extract_from_region (PixelRegion *, PixelRegion *,
void convolve_region (PixelRegion *, PixelRegion *,
int *, int, int, int);
void multiply_alpha_region (PixelRegion *);
void separate_alpha_region (PixelRegion *);
void gaussian_blur_region (PixelRegion *, double);
void border_region (PixelRegion *, void *,
@ -402,6 +406,11 @@ void combine_regions (PixelRegion *, PixelRegion *,
unsigned char *, int,
int, int *, int);
void combine_regions_replace (PixelRegion *, PixelRegion *,
PixelRegion *, PixelRegion *,
unsigned char *,
int, int *, int);
/* Color conversion routines */
void rgb_to_hsv (int *, int *, int *);

View File

@ -31,6 +31,8 @@ struct _ResizePrivate
{
GtkWidget *width_text;
GtkWidget *height_text;
GtkWidget *ratio_x_text;
GtkWidget *ratio_y_text;
GtkWidget *off_x_text;
GtkWidget *off_y_text;
GtkWidget *drawing_area;
@ -50,6 +52,8 @@ static void off_x_update (GtkWidget *w, gpointer data);
static void off_y_update (GtkWidget *w, gpointer data);
static void width_update (GtkWidget *w, gpointer data);
static void height_update (GtkWidget *w, gpointer data);
static void ratio_x_update (GtkWidget *w, gpointer data);
static void ratio_y_update (GtkWidget *w, gpointer data);
static void constrain_update (GtkWidget *w, gpointer data);
static gint resize_events (GtkWidget *area, GdkEvent *event);
@ -68,6 +72,7 @@ resize_widget_new (ResizeType type,
GtkWidget *constrain;
GtkWidget *table;
char size[12];
char ratio_text[12];
table = NULL;
@ -77,6 +82,8 @@ resize_widget_new (ResizeType type,
resize->private_part = private;
resize->width = width;
resize->height = height;
resize->ratio_x = 1.0;
resize->ratio_y = 1.0;
resize->off_x = 0;
resize->off_y = 0;
private->old_width = width;
@ -95,11 +102,11 @@ resize_widget_new (ResizeType type,
{
case ScaleWidget:
resize->resize_widget = gtk_frame_new ("Scale");
table = gtk_table_new (2, 2, TRUE);
table = gtk_table_new (4, 2, TRUE);
break;
case ResizeWidget:
resize->resize_widget = gtk_frame_new ("Resize");
table = gtk_table_new (4, 2, TRUE);
table = gtk_table_new (6, 2, TRUE);
break;
}
gtk_frame_set_shadow_type (GTK_FRAME (resize->resize_widget), GTK_SHADOW_ETCHED_IN);
@ -146,17 +153,51 @@ resize_widget_new (ResizeType type,
resize);
gtk_widget_show (private->height_text);
/* the x scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_x);
label = gtk_label_new ("X ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_x_text, 1, 2, 2, 3,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_x_text), "changed",
(GtkSignalFunc) ratio_x_update,
resize);
gtk_widget_show (private->ratio_x_text);
/* the y scale ratio label and entry */
sprintf (ratio_text, "%0.4f", resize->ratio_y);
label = gtk_label_new ("Y ratio:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->ratio_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->ratio_y_text, 1, 2, 3, 4,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->ratio_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_connect (GTK_OBJECT (private->ratio_y_text), "changed",
(GtkSignalFunc) ratio_y_update,
resize);
gtk_widget_show (private->ratio_y_text);
if (type == ResizeWidget)
{
/* the off_x label and entry */
sprintf (size, "%d", 0);
label = gtk_label_new ("X Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_x_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 2, 3,
gtk_table_attach (GTK_TABLE (table), private->off_x_text, 1, 2, 4, 5,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_x_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
@ -169,11 +210,11 @@ resize_widget_new (ResizeType type,
sprintf (size, "%d", 0);
label = gtk_label_new ("Y Offset:");
gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 3, 4,
gtk_table_attach (GTK_TABLE (table), label, 0, 1, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_show (label);
private->off_y_text = gtk_entry_new ();
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 3, 4,
gtk_table_attach (GTK_TABLE (table), private->off_y_text, 1, 2, 5, 6,
GTK_SHRINK | GTK_FILL, GTK_SHRINK, 2, 2);
gtk_widget_set_usize (private->off_y_text, TEXT_WIDTH, 25);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
@ -425,6 +466,7 @@ width_update (GtkWidget *w,
double ratio;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -432,6 +474,14 @@ width_update (GtkWidget *w,
resize->width = atoi (str);
ratio = (double) resize->width / (double) private->old_width;
resize->ratio_x = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
@ -445,7 +495,6 @@ width_update (GtkWidget *w,
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
ratio = (double) resize->width / (double) private->old_width;
new_height = (int) (private->old_height * ratio);
if (new_height == 0) new_height = 1;
@ -458,6 +507,12 @@ width_update (GtkWidget *w,
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
resize->ratio_y = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -485,6 +540,7 @@ height_update (GtkWidget *w,
double ratio;
int new_width;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
@ -492,6 +548,13 @@ height_update (GtkWidget *w,
resize->height = atoi (str);
ratio = (double) resize->height / (double) private->old_height;
resize->ratio_y = ratio;
sprintf (ratio_text, "%0.4f", ratio);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
@ -517,6 +580,176 @@ height_update (GtkWidget *w,
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
resize->ratio_x = ratio;
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_x_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_x = atof (str);
new_width = (int) ((double) private->old_width * resize->ratio_x);
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", new_width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
if (resize->type == ResizeWidget)
{
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
sprintf (size, "%d", resize->off_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_x_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_x_text), data);
}
}
if (private->constrain && resize->width != 0)
{
private->constrain = FALSE;
resize->ratio_y = resize->ratio_x;
new_height = (int) (private->old_height * resize->ratio_y);
if (new_height == 0) new_height = 1;
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", resize->height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_y_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_y_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
private->constrain = TRUE;
}
resize_draw (resize);
}
static void
ratio_y_update (GtkWidget *w,
gpointer data)
{
Resize *resize;
ResizePrivate *private;
char *str;
int new_width;
int new_height;
char size[12];
char ratio_text[12];
resize = (Resize *) data;
private = (ResizePrivate *) resize->private_part;
str = gtk_entry_get_text (GTK_ENTRY (w));
resize->ratio_y = atof (str);
new_height = (int) ((double) private->old_height * resize->ratio_y);
if (new_height != resize->height)
{
resize->height = new_height;
sprintf (size, "%d", new_height);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->height_text), data);
gtk_entry_set_text (GTK_ENTRY (private->height_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->height_text), data);
if (resize->type == ResizeWidget)
{
resize->off_y = resize_bound_off_y (resize, (resize->height - private->old_height) / 2);
sprintf (size, "%d", resize->off_y);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->off_y_text), data);
gtk_entry_set_text (GTK_ENTRY (private->off_y_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->off_y_text), data);
}
}
if (private->constrain && resize->height != 0)
{
private->constrain = FALSE;
resize->ratio_x = resize->ratio_y;
new_width = (int) (private->old_width * resize->ratio_x);
if (new_width == 0) new_width = 1;
if (new_width != resize->width)
{
resize->width = new_width;
sprintf (size, "%d", resize->width);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->width_text), data);
gtk_entry_set_text (GTK_ENTRY (private->width_text), size);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->width_text), data);
sprintf (ratio_text, "%0.4f", resize->ratio_x);
gtk_signal_handler_block_by_data (GTK_OBJECT (private->ratio_x_text), data);
gtk_entry_set_text (GTK_ENTRY (private->ratio_x_text), ratio_text);
gtk_signal_handler_unblock_by_data (GTK_OBJECT (private->ratio_x_text), data);
if (resize->type == ResizeWidget)
{

View File

@ -34,6 +34,8 @@ struct _Resize
ResizeType type;
int width;
int height;
double ratio_x;
double ratio_y;
int off_x;
int off_y;

View File

@ -266,6 +266,11 @@ convolve_motion (PaintCore *paint_core,
/* if the source has no alpha, then add alpha pixels */
if (!drawable_has_alpha (drawable_id))
{
/* note: this architecture needlessly convolves the totally-
opaque alpha channel. A faster approach would be to keep
tempPR the same number of bytes as srcPR, and extend the
paint_core_replace_canvas API to handle non-alpha images. */
tempPR.bytes = srcPR.bytes + 1;
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
@ -287,6 +292,13 @@ convolve_motion (PaintCore *paint_core,
tempPR.data = temp_data;
copy_region (&srcPR, &tempPR);
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
tempPR.h = area->height;
tempPR.data = temp_data;
multiply_alpha_region (&tempPR);
}
tempPR.x = 0; tempPR.y = 0;
@ -298,6 +310,9 @@ convolve_motion (PaintCore *paint_core,
convolve_region (&tempPR, &destPR, matrix, matrix_size,
matrix_divisor, NORMAL);
if (drawable_has_alpha (drawable_id))
separate_alpha_region (&destPR);
/* Free the allocated temp space */
g_free (temp_data);
}
@ -311,9 +326,9 @@ convolve_motion (PaintCore *paint_core,
}
/* paste the newly painted canvas to the gimage which is being worked on */
paint_core_paste_canvas (paint_core, drawable_id, OPAQUE,
paint_core_replace_canvas (paint_core, drawable_id, OPAQUE,
(int) (get_brush_opacity () * 255),
NORMAL_MODE, SOFT, INCREMENTAL);
SOFT, INCREMENTAL);
}
static void

View File

@ -266,6 +266,11 @@ convolve_motion (PaintCore *paint_core,
/* if the source has no alpha, then add alpha pixels */
if (!drawable_has_alpha (drawable_id))
{
/* note: this architecture needlessly convolves the totally-
opaque alpha channel. A faster approach would be to keep
tempPR the same number of bytes as srcPR, and extend the
paint_core_replace_canvas API to handle non-alpha images. */
tempPR.bytes = srcPR.bytes + 1;
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
@ -287,6 +292,13 @@ convolve_motion (PaintCore *paint_core,
tempPR.data = temp_data;
copy_region (&srcPR, &tempPR);
tempPR.x = 0; tempPR.y = 0;
tempPR.w = area->width;
tempPR.h = area->height;
tempPR.data = temp_data;
multiply_alpha_region (&tempPR);
}
tempPR.x = 0; tempPR.y = 0;
@ -298,6 +310,9 @@ convolve_motion (PaintCore *paint_core,
convolve_region (&tempPR, &destPR, matrix, matrix_size,
matrix_divisor, NORMAL);
if (drawable_has_alpha (drawable_id))
separate_alpha_region (&destPR);
/* Free the allocated temp space */
g_free (temp_data);
}
@ -311,9 +326,9 @@ convolve_motion (PaintCore *paint_core,
}
/* paste the newly painted canvas to the gimage which is being worked on */
paint_core_paste_canvas (paint_core, drawable_id, OPAQUE,
paint_core_replace_canvas (paint_core, drawable_id, OPAQUE,
(int) (get_brush_opacity () * 255),
NORMAL_MODE, SOFT, INCREMENTAL);
SOFT, INCREMENTAL);
}
static void

View File

@ -43,6 +43,7 @@ static MaskBuf * paint_core_subsample_mask (MaskBuf *, double, double);
static MaskBuf * paint_core_solidify_mask (MaskBuf *);
static MaskBuf * paint_core_get_brush_mask (PaintCore *, int);
static void paint_core_paste (PaintCore *, MaskBuf *, int, int, int, int, int);
static void paint_core_replace (PaintCore *, MaskBuf *, int, int, int, int);
static void paint_to_canvas_tiles (PaintCore *, MaskBuf *, int);
static void paint_to_canvas_buf (PaintCore *, MaskBuf *, int);
static void set_undo_tiles (int, int, int, int, int);
@ -638,6 +639,29 @@ paint_core_paste_canvas (paint_core, drawable_id, brush_opacity, image_opacity,
brush_opacity, image_opacity, paint_mode, mode);
}
/* Similar to paint_core_paste_canvas, but replaces the alpha channel
rather than using it to composite (i.e. transparent over opaque
becomes transparent rather than opauqe. */
void
paint_core_replace_canvas (paint_core, drawable_id, brush_opacity, image_opacity,
brush_hardness, mode)
PaintCore *paint_core;
int drawable_id;
int brush_opacity;
int image_opacity;
int brush_hardness;
int mode;
{
MaskBuf *brush_mask;
/* get the brush mask */
brush_mask = paint_core_get_brush_mask (paint_core, brush_hardness);
/* paste the canvas buf */
paint_core_replace (paint_core, brush_mask, drawable_id,
brush_opacity, image_opacity, mode);
}
/************************************************************
* LOCAL FUNCTION DEFINITIONS *
************************************************************/
@ -834,6 +858,85 @@ paint_core_paste (paint_core, brush_mask, drawable_id, brush_opacity, image_opac
canvas_buf->width, canvas_buf->height);
}
/* This works similarly to paint_core_paste. However, instead of combining
the canvas to the paint core drawable using one of the combination
modes, it uses a "replace" mode (i.e. transparent pixels in the
canvas erase the paint core drawable).
When not drawing on alpha-enabled images, it just paints using NORMAL
mode.
*/
static void
paint_core_replace (paint_core, brush_mask, drawable_id, brush_opacity, image_opacity, mode)
PaintCore *paint_core;
MaskBuf *brush_mask;
int drawable_id;
int brush_opacity;
int image_opacity;
int mode;
{
GImage *gimage;
PixelRegion srcPR, maskPR;
int offx, offy;
if (!drawable_has_alpha (drawable_id))
{
paint_core_paste (paint_core, brush_mask, drawable_id,
brush_opacity, image_opacity, NORMAL_MODE,
mode);
return;
}
if (mode != INCREMENTAL)
{
g_warning ("paint_core_replace only works in INCREMENTAL mode");
return;
}
if (! (gimage = drawable_gimage (drawable_id)))
return;
/* set undo blocks */
set_undo_tiles (drawable_id,
canvas_buf->x, canvas_buf->y,
canvas_buf->width, canvas_buf->height);
maskPR.bytes = 1;
maskPR.x = 0; maskPR.y = 0;
maskPR.w = srcPR.w;
maskPR.h = srcPR.h;
maskPR.rowstride = maskPR.bytes * brush_mask->width;
maskPR.data = mask_buf_data (brush_mask);
/* intialize canvas buf source pixel regions */
srcPR.bytes = canvas_buf->bytes;
srcPR.x = 0; srcPR.y = 0;
srcPR.w = canvas_buf->width;
srcPR.h = canvas_buf->height;
srcPR.rowstride = canvas_buf->width * canvas_buf->bytes;
srcPR.data = temp_buf_data (canvas_buf);
/* apply the paint area to the gimage */
gimage_replace_image (gimage, drawable_id, &srcPR,
FALSE, image_opacity,
&maskPR,
canvas_buf->x, canvas_buf->y);
/* Update the undo extents */
paint_core->x1 = MINIMUM (paint_core->x1, canvas_buf->x);
paint_core->y1 = MINIMUM (paint_core->y1, canvas_buf->y);
paint_core->x2 = MAXIMUM (paint_core->x2, (canvas_buf->x + canvas_buf->width));
paint_core->y2 = MAXIMUM (paint_core->y2, (canvas_buf->y + canvas_buf->height));
/* Update the gimage--it is important to call gdisplays_update_area
* instead of drawable_update because we don't want the drawable
* preview to be constantly invalidated
*/
drawable_offsets (drawable_id, &offx, &offy);
gdisplays_update_area (gimage->ID, canvas_buf->x + offx, canvas_buf->y + offy,
canvas_buf->width, canvas_buf->height);
}
static void
paint_to_canvas_tiles (paint_core, brush_mask, brush_opacity)
PaintCore *paint_core;

View File

@ -96,6 +96,7 @@ void paint_core_cleanup (void);
TempBuf * paint_core_get_paint_area (PaintCore *, int);
TempBuf * paint_core_get_orig_image (PaintCore *, int, int, int, int, int);
void paint_core_paste_canvas (PaintCore *, int, int, int, int, int, int);
void paint_core_replace_canvas (PaintCore *, int, int, int, int, int);
#endif /* __PAINT_CORE_H__ */