mirror of https://github.com/GNOME/gimp.git
Added Sven's patch for the scale and resize dialogs
Added Raph's patch for the transperancy blur problem
This commit is contained in:
parent
ff7139d37f
commit
7d148f0288
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
@ -518,6 +581,176 @@ height_update (GtkWidget *w,
|
|||
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)
|
||||
{
|
||||
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
|
||||
|
|
|
@ -34,6 +34,8 @@ struct _Resize
|
|||
ResizeType type;
|
||||
int width;
|
||||
int height;
|
||||
double ratio_x;
|
||||
double ratio_y;
|
||||
int off_x;
|
||||
int off_y;
|
||||
|
||||
|
|
120
app/gimage.c
120
app/gimage.c
|
@ -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)
|
||||
|
|
|
@ -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 *,
|
||||
|
|
|
@ -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);
|
||||
|
@ -518,6 +581,176 @@ height_update (GtkWidget *w,
|
|||
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)
|
||||
{
|
||||
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
|
||||
|
|
|
@ -34,6 +34,8 @@ struct _Resize
|
|||
ResizeType type;
|
||||
int width;
|
||||
int height;
|
||||
double ratio_x;
|
||||
double ratio_y;
|
||||
int off_x;
|
||||
int off_y;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
|
@ -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
|
||||
|
|
103
app/paint_core.c
103
app/paint_core.c
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 *);
|
||||
|
|
247
app/resize.c
247
app/resize.c
|
@ -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);
|
||||
|
@ -518,6 +581,176 @@ height_update (GtkWidget *w,
|
|||
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)
|
||||
{
|
||||
resize->off_x = resize_bound_off_x (resize, (resize->width - private->old_width) / 2);
|
||||
|
|
|
@ -34,6 +34,8 @@ struct _Resize
|
|||
ResizeType type;
|
||||
int width;
|
||||
int height;
|
||||
double ratio_x;
|
||||
double ratio_y;
|
||||
int off_x;
|
||||
int off_y;
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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__ */
|
||||
|
|
Loading…
Reference in New Issue