added new functions color_region_mask() which works like color_region()

2003-09-27  Michael Natterer  <mitch@gimp.org>

	* app/paint-funcs/paint-funcs.[ch]: added new functions
	color_region_mask() which works like color_region() but takes an
	additional maskPR parameters and pattern_region() which fills
	destPR with a TempBuf of *matching color depth*.

	* app/paint-funcs/paint-funcs-generic.h: added corresponding
	color_pixels_mask() and pattern_pixels().

	* app/core/gimpimage.[ch] (gimp_image_transform_temp_buf): new
	function which transforms a TempBuf to a specified drawable's
	color space.

	* app/core/gimpdrawable-bucket-fill.c: the functions were factored
	out here. Removed them and use the new stuff.

	* app/core/core-enums.[ch]: added enum GimpStrokeStyle which can
	be one of { SOLID, PATTERN }.

	* app/core/gimpstrokeoptions.[ch]: added "GimpStrokeStyle style"
	property, cleanup.

	* app/core/gimpdrawable-stroke.c: honor the new "style" property
	and call the new color_region_mask() and pattern_region()
	functions accordingly, cleanup.

	* app/widgets/gimpstrokeeditor.c: added a GUI for the stroke
	style. Ugly but works.

	* app/gui/stroke-dialog.c: undefine "foreground" and "pattern" and
	set the user context as parent context so we get these properties
	from the global settings.
This commit is contained in:
Michael Natterer 2003-09-27 20:04:07 +00:00 committed by Michael Natterer
parent fcb29af719
commit ab34b3ee94
15 changed files with 543 additions and 352 deletions

View File

@ -1,3 +1,37 @@
2003-09-27 Michael Natterer <mitch@gimp.org>
* app/paint-funcs/paint-funcs.[ch]: added new functions
color_region_mask() which works like color_region() but takes an
additional maskPR parameters and pattern_region() which fills
destPR with a TempBuf of *matching color depth*.
* app/paint-funcs/paint-funcs-generic.h: added corresponding
color_pixels_mask() and pattern_pixels().
* app/core/gimpimage.[ch] (gimp_image_transform_temp_buf): new
function which transforms a TempBuf to a specified drawable's
color space.
* app/core/gimpdrawable-bucket-fill.c: the functions were factored
out here. Removed them and use the new stuff.
* app/core/core-enums.[ch]: added enum GimpStrokeStyle which can
be one of { SOLID, PATTERN }.
* app/core/gimpstrokeoptions.[ch]: added "GimpStrokeStyle style"
property, cleanup.
* app/core/gimpdrawable-stroke.c: honor the new "style" property
and call the new color_region_mask() and pattern_region()
functions accordingly, cleanup.
* app/widgets/gimpstrokeeditor.c: added a GUI for the stroke
style. Ugly but works.
* app/gui/stroke-dialog.c: undefine "foreground" and "pattern" and
set the user context as parent context so we get these properties
from the global settings.
2003-09-27 Sven Neumann <sven@gimp.org>
* themes/Default/images/Makefile.am

View File

@ -254,6 +254,25 @@ gimp_grid_style_get_type (void)
}
static const GEnumValue gimp_stroke_style_enum_values[] =
{
{ GIMP_STROKE_STYLE_SOLID, N_("Solid"), "solid" },
{ GIMP_STROKE_STYLE_PATTERN, N_("Pattern"), "pattern" },
{ 0, NULL, NULL }
};
GType
gimp_stroke_style_get_type (void)
{
static GType enum_type = 0;
if (!enum_type)
enum_type = g_enum_register_static ("GimpStrokeStyle", gimp_stroke_style_enum_values);
return enum_type;
}
static const GEnumValue gimp_join_style_enum_values[] =
{
{ GIMP_JOIN_MITER, N_("Miter"), "miter" },

View File

@ -195,6 +195,17 @@ typedef enum /*< pdb-skip >*/
} GimpGridStyle;
#define GIMP_TYPE_STROKE_STYLE (gimp_stroke_style_get_type ())
GType gimp_stroke_style_get_type (void) G_GNUC_CONST;
typedef enum /*< pdb-skip >*/
{
GIMP_STROKE_STYLE_SOLID, /*< desc="Solid" >*/
GIMP_STROKE_STYLE_PATTERN /*< desc="Pattern" >*/
} GimpStrokeStyle;
#define GIMP_TYPE_JOIN_STYLE (gimp_join_style_get_type ())
GType gimp_join_style_get_type (void) G_GNUC_CONST;

View File

@ -44,32 +44,6 @@
#include "gimp-intl.h"
/* local function prototypes */
static void gimp_drawable_bucket_fill_region (GimpBucketFillMode fill_mode,
PixelRegion *bufPR,
PixelRegion *maskPR,
guchar *col,
TempBuf *pattern,
gint off_x,
gint off_y,
gboolean has_alpha);
static void gimp_drawable_bucket_fill_line_color (guchar *buf,
guchar *mask,
guchar *col,
gboolean has_alpha,
gint bytes,
gint width);
static void gimp_drawable_bucket_fill_line_pattern (guchar *buf,
guchar *mask,
TempBuf *pattern,
gboolean has_alpha,
gint bytes,
gint x,
gint y,
gint width);
/* public functions */
void
@ -178,59 +152,8 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
}
else if (fill_mode == GIMP_PATTERN_BUCKET_FILL)
{
/* If the pattern doesn't match the image in terms of color type,
* transform it. (ie pattern is RGB, image is indexed)
*/
if (((pattern->mask->bytes == 3 || pattern->mask->bytes == 4 ) && ! gimp_drawable_is_rgb (drawable)) ||
((pattern->mask->bytes == 1 || pattern->mask->bytes == 2 ) && ! gimp_drawable_is_gray (drawable)))
{
guchar *d1, *d2;
gint size, in_bytes, out_bytes;
if ((pattern->mask->bytes == 2) && gimp_drawable_is_rgb (drawable))
pat_buf = temp_buf_new (pattern->mask->width,
pattern->mask->height,
4, 0, 0, NULL);
else if ((pattern->mask->bytes == 1) && gimp_drawable_is_rgb (drawable))
pat_buf = temp_buf_new (pattern->mask->width,
pattern->mask->height,
3, 0, 0, NULL);
else if ((pattern->mask->bytes == 4) && gimp_drawable_is_gray (drawable))
pat_buf = temp_buf_new (pattern->mask->width,
pattern->mask->height,
2, 0, 0, NULL);
else
pat_buf = temp_buf_new (pattern->mask->width,
pattern->mask->height,
1, 0, 0, NULL);
d1 = temp_buf_data (pattern->mask);
d2 = temp_buf_data (pat_buf);
size = pattern->mask->width * pattern->mask->height;
in_bytes = pattern->mask->bytes;
out_bytes = pat_buf->bytes;
while (size--)
{
gimp_image_transform_color (gimage, drawable, d2,
(in_bytes == 3 ||
in_bytes == 4) ?
GIMP_RGB : GIMP_GRAY, d1);
/* Handle alpha */
if (in_bytes == 4 ||
in_bytes == 2 )
d2[out_bytes - 1] = d1[in_bytes - 1];
d1 += in_bytes;
d2 += out_bytes;
}
new_buf = TRUE;
}
else
{
pat_buf = pattern->mask;
}
pat_buf = gimp_image_transform_temp_buf (gimage, drawable,
pattern->mask, &new_buf);
}
else
{
@ -244,8 +167,8 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
has_alpha = gimp_drawable_has_alpha (drawable);
selection = gimp_drawable_mask_bounds (drawable, &x1, &y1, &x2, &y2);
/* Do a seed bucket fill...To do this, calculate a new
* contiguous region. If there is a selection, calculate the
/* Do a seed bucket fill...To do this, calculate a new
* contiguous region. If there is a selection, calculate the
* intersection of this region with the existing selection.
*/
if (do_seed_fill)
@ -289,7 +212,7 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
x2 = CLAMP (x2, off_x, (off_x + gimp_item_width (item)));
y2 = CLAMP (y2, off_y, (off_y + gimp_item_height (item)));
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)),
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)),
x1, y1, (x2 - x1), (y2 - y1), TRUE);
/* translate mask bounds to drawable coords */
@ -300,7 +223,7 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
}
else
{
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)),
pixel_region_init (&maskPR, gimp_drawable_data (GIMP_DRAWABLE (mask)),
x1, y1, (x2 - x1), (y2 - y1), TRUE);
}
@ -317,7 +240,7 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
else if (fill_mode == GIMP_PATTERN_BUCKET_FILL &&
(pat_buf->bytes == 2 || pat_buf->bytes == 4))
{
/* If pattern being applied has an alpha channel,
/* If pattern being applied has an alpha channel,
* add one to the temp buffer from the image too.
*/
if (! has_alpha)
@ -330,18 +253,20 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
buf_tiles = tile_manager_new ((x2 - x1), (y2 - y1), bytes);
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), TRUE);
if (mask)
gimp_drawable_bucket_fill_region (fill_mode,
&bufPR, &maskPR,
col, pat_buf,
x1, y1,
has_alpha);
else
gimp_drawable_bucket_fill_region (fill_mode,
&bufPR, NULL,
col, pat_buf,
x1, y1,
has_alpha);
switch (fill_mode)
{
case GIMP_FG_BUCKET_FILL:
case GIMP_BG_BUCKET_FILL:
if (mask)
color_region_mask (&bufPR, &maskPR, col);
else
color_region (&bufPR, col);
break;
case GIMP_PATTERN_BUCKET_FILL:
pattern_region (&bufPR, mask ? &maskPR : NULL, pat_buf, x1, y1);
break;
}
/* Apply it to the image */
pixel_region_init (&bufPR, buf_tiles, 0, 0, (x2 - x1), (y2 - y1), FALSE);
@ -363,146 +288,3 @@ gimp_drawable_bucket_fill_full (GimpDrawable *drawable,
gimp_unset_busy (gimage->gimp);
}
/* private functions */
static void
gimp_drawable_bucket_fill_region (GimpBucketFillMode fill_mode,
PixelRegion *bufPR,
PixelRegion *maskPR,
guchar *col,
TempBuf *pattern,
gint off_x,
gint off_y,
gboolean has_alpha)
{
guchar *s, *m;
gint y;
void *pr;
for (pr = pixel_regions_register (2, bufPR, maskPR);
pr != NULL;
pr = pixel_regions_process (pr))
{
s = bufPR->data;
if (maskPR)
m = maskPR->data;
else
m = NULL;
for (y = 0; y < bufPR->h; y++)
{
switch (fill_mode)
{
case GIMP_FG_BUCKET_FILL:
case GIMP_BG_BUCKET_FILL:
gimp_drawable_bucket_fill_line_color (s, m,
col,
has_alpha,
bufPR->bytes, bufPR->w);
break;
case GIMP_PATTERN_BUCKET_FILL:
gimp_drawable_bucket_fill_line_pattern (s, m,
pattern,
has_alpha,
bufPR->bytes,
off_x + bufPR->x,
off_y + y + bufPR->y,
bufPR->w);
break;
}
s += bufPR->rowstride;
if (maskPR)
m += maskPR->rowstride;
}
}
}
static void
gimp_drawable_bucket_fill_line_color (guchar *buf,
guchar *mask,
guchar *col,
gboolean has_alpha,
gint bytes,
gint width)
{
gint alpha, b;
alpha = (has_alpha) ? bytes - 1 : bytes;
while (width--)
{
for (b = 0; b < alpha; b++)
buf[b] = col[b];
if (has_alpha)
{
if (mask)
buf[alpha] = *mask++;
else
buf[alpha] = OPAQUE_OPACITY;
}
buf += bytes;
}
}
static void
gimp_drawable_bucket_fill_line_pattern (guchar *buf,
guchar *mask,
TempBuf *pattern,
gboolean has_alpha,
gint bytes,
gint x,
gint y,
gint width)
{
guchar *pat, *p;
gint alpha, b;
gint i;
/* Get a pointer to the appropriate scanline of the pattern buffer */
pat = temp_buf_data (pattern) +
(y % pattern->height) * pattern->width * pattern->bytes;
alpha = (has_alpha) ? bytes - 1 : bytes;
/*
* image data = pattern data for all but alpha
*
* If (image has alpha)
* if (there's a mask)
* image data = mask for alpha;
* else
* image data = opaque for alpha.
*
* if (pattern has alpha)
* multiply existing alpha channel by pattern alpha
* (normalised to (0..1))
*/
for (i = 0; i < width; i++)
{
p = pat + ((i + x) % pattern->width) * pattern->bytes;
for (b = 0; b < alpha; b++)
buf[b] = p[b];
if (has_alpha)
{
if (mask)
buf[alpha] = *mask++;
else
buf[alpha] = OPAQUE_OPACITY;
if (pattern->bytes == 2 || pattern->bytes == 4)
{
buf[alpha] =
(guchar)(buf[alpha] *
(p[alpha]/(gdouble)OPAQUE_OPACITY));
}
}
buf += bytes;
}
}

View File

@ -31,20 +31,19 @@
#include "base/temp-buf.h"
#include "base/tile-manager.h"
#include "core/gimpitem.h"
#include "core/gimpscanconvert.h"
#include "core/gimpstrokeoptions.h"
#include "core/gimpunit.h"
#include "vectors/gimpstroke.h"
#include "vectors/gimpvectors.h"
#include "paint-funcs/paint-funcs.h"
#include "gimp.h"
#include "gimpdrawable.h"
#include "gimpdrawable-stroke.h"
#include "gimpimage.h"
#include "gimppattern.h"
#include "gimpscanconvert.h"
#include "gimpstrokeoptions.h"
#include "gimpunit.h"
#include "vectors/gimpstroke.h"
#include "vectors/gimpvectors.h"
#include "gimp-intl.h"
@ -58,8 +57,8 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
{
/* Stroke options */
gdouble opacity;
GimpRGB *color;
GimpLayerModeEffects paint_mode;
GimpStrokeStyle style;
gdouble width;
GimpJoinStyle join;
GimpCapStyle cap;
@ -69,33 +68,32 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
gint num_coords = 0;
GimpStroke *stroke;
GimpImage *gimage;
GimpScanConvert *scan_convert;
TileManager *base;
TileManager *mask;
gint x1, x2, y1, y2, bytes, w, h;
guchar ucolor[4] = { 0, 0, 0, 255 };
guchar bg[1] = { 0, };
guchar *src_bytes;
PixelRegion maskPR, basePR;
/* get the options from the GimpStrokeOptions */
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
g_return_if_fail (GIMP_IS_VECTORS (vectors));
g_return_if_fail (GIMP_IS_STROKE_OPTIONS (options));
g_object_get (options,
"opacity", &opacity,
"foreground", &color,
"paint-mode", &paint_mode,
"style", &style,
"width", &width,
"join-style", &join,
"cap-style", &cap,
"antialias", &antialias,
NULL);
gimage = gimp_item_get_image (GIMP_ITEM (drawable));
if (options->width_unit != GIMP_UNIT_PIXEL)
{
GimpImage *gimage = gimp_item_get_image (GIMP_ITEM (drawable));
width = (width *
_gimp_unit_get_factor (gimage->gimp,
options->width_unit) *
@ -113,7 +111,8 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
scan_convert = gimp_scan_convert_new (w, h, antialias);
/* For each Stroke in the vector, interpolate it, and add it to the
* ScanConvert */
* ScanConvert
*/
for (stroke = gimp_vectors_stroke_get_next (vectors, NULL);
stroke;
stroke = gimp_vectors_stroke_get_next (vectors, stroke))
@ -124,7 +123,8 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
gint i;
/* Get the interpolated version of this stroke, and add it to our
* scanconvert. */
* scanconvert.
*/
coords = gimp_stroke_interpolate (stroke, 1, &closed);
if (coords && coords->len)
@ -160,7 +160,8 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
0.0, dash_array);
/* fill a 1-bpp Tilemanager with black, this will describe the shape
* of the stroke. */
* of the stroke.
*/
mask = tile_manager_new (w, h, 1);
tile_manager_set_offsets (mask, x1+x2, y1+y2);
pixel_region_init (&maskPR, mask, 0, 0, w, h, TRUE);
@ -175,26 +176,53 @@ gimp_drawable_stroke_vectors (GimpDrawable *drawable,
if (!gimp_drawable_has_alpha (drawable))
bytes++;
src_bytes = g_malloc0 (bytes);
/* Fill a TileManager with the stroke color */
gimp_rgb_get_uchar (color, ucolor + 0, ucolor + 1, ucolor + 2);
g_free (color);
src_bytes[bytes - 1] = OPAQUE_OPACITY;
gimp_image_transform_color (GIMP_ITEM (drawable)->gimage, drawable,
src_bytes, GIMP_RGB, ucolor);
base = tile_manager_new (w, h, bytes);
tile_manager_set_offsets (base, x1+x2, y1+y2);
pixel_region_init (&basePR, base, 0, 0, w, h, TRUE);
color_region (&basePR, src_bytes);
g_free (src_bytes);
/* combine mask and stroke color TileManager */
tile_manager_set_offsets (base, x1 + x2, y1 + y2);
pixel_region_init (&basePR, base, 0, 0, w, h, TRUE);
pixel_region_init (&maskPR, mask, 0, 0, w, h, FALSE);
apply_mask_to_region (&basePR, &maskPR, OPAQUE_OPACITY);
switch (style)
{
case GIMP_STROKE_STYLE_SOLID:
{
GimpRGB *color;
guchar ucolor[4] = { 0, 0, 0, OPAQUE_OPACITY };
guchar *src_bytes;
g_object_get (options, "foreground", &color, NULL);
gimp_rgb_get_uchar (color, ucolor + 0, ucolor + 1, ucolor + 2);
g_free (color);
src_bytes = g_malloc0 (bytes);
src_bytes[bytes - 1] = OPAQUE_OPACITY;
gimp_image_transform_color (GIMP_ITEM (drawable)->gimage, drawable,
src_bytes, GIMP_RGB, ucolor);
color_region_mask (&basePR, &maskPR, src_bytes);
g_free (src_bytes);
}
break;
case GIMP_STROKE_STYLE_PATTERN:
{
GimpPattern *pattern;
TempBuf *pat_buf;
gboolean new_buf;
g_object_get (options, "pattern", &pattern, NULL);
pat_buf = gimp_image_transform_temp_buf (gimage, drawable,
pattern->mask, &new_buf);
g_object_unref (pattern);
pattern_region (&basePR, &maskPR, pat_buf, x1, y1);
if (new_buf)
temp_buf_free (pat_buf);
}
break;
}
/* Apply to drawable */
pixel_region_init (&basePR, base, 0, 0, w, h, FALSE);

View File

@ -1762,6 +1762,88 @@ gimp_image_transform_color (const GimpImage *dest_gimage,
}
}
TempBuf *
gimp_image_transform_temp_buf (const GimpImage *dest_image,
const GimpDrawable *dest_drawable,
TempBuf *temp_buf,
gboolean *new_buf)
{
TempBuf *ret_buf;
g_return_val_if_fail (GIMP_IMAGE (dest_image), NULL);
g_return_val_if_fail (GIMP_DRAWABLE (dest_drawable), NULL);
g_return_val_if_fail (temp_buf != NULL, NULL);
g_return_val_if_fail (new_buf != NULL, NULL);
/* If the pattern doesn't match the image in terms of color type,
* transform it. (ie pattern is RGB, image is indexed)
*/
if (((temp_buf->bytes == 3 || temp_buf->bytes == 4) &&
! gimp_drawable_is_rgb (dest_drawable)) ||
((temp_buf->bytes == 1 || temp_buf->bytes == 2) &&
! gimp_drawable_is_gray (dest_drawable)))
{
guchar *d1, *d2;
gint size, in_bytes, out_bytes;
if (temp_buf->bytes == 2 && gimp_drawable_is_rgb (dest_drawable))
{
ret_buf = temp_buf_new (temp_buf->width,
temp_buf->height,
4, 0, 0, NULL);
}
else if (temp_buf->bytes == 1 && gimp_drawable_is_rgb (dest_drawable))
{
ret_buf = temp_buf_new (temp_buf->width,
temp_buf->height,
3, 0, 0, NULL);
}
else if (temp_buf->bytes == 4 && gimp_drawable_is_gray (dest_drawable))
{
ret_buf = temp_buf_new (temp_buf->width,
temp_buf->height,
2, 0, 0, NULL);
}
else
{
ret_buf = temp_buf_new (temp_buf->width,
temp_buf->height,
1, 0, 0, NULL);
}
d1 = temp_buf_data (temp_buf);
d2 = temp_buf_data (ret_buf);
size = temp_buf->width * temp_buf->height;
in_bytes = temp_buf->bytes;
out_bytes = ret_buf->bytes;
while (size--)
{
gimp_image_transform_color (dest_image, dest_drawable, d2,
(in_bytes == 3 || in_bytes == 4) ?
GIMP_RGB : GIMP_GRAY, d1);
/* Handle alpha */
if (in_bytes == 4 || in_bytes == 2 )
d2[out_bytes - 1] = d1[in_bytes - 1];
d1 += in_bytes;
d2 += out_bytes;
}
*new_buf = TRUE;
}
else
{
ret_buf = temp_buf;
*new_buf = FALSE;
}
return ret_buf;
}
/* shadow tiles */

View File

@ -331,6 +331,10 @@ void gimp_image_transform_color (const GimpImage *dest_gimag
guchar *dest,
GimpImageBaseType src_type,
const guchar *src);
TempBuf * gimp_image_transform_temp_buf (const GimpImage *dest_gimage,
const GimpDrawable *dest_drawable,
TempBuf *temp_buf,
gboolean *new_buf);
/* shadow tiles */

View File

@ -34,6 +34,7 @@
enum
{
PROP_0,
PROP_STYLE,
PROP_WIDTH,
PROP_WIDTH_UNIT,
PROP_CAP_STYLE,
@ -46,7 +47,7 @@ enum
};
static void gimp_stroke_options_class_init (GimpStrokeOptionsClass *options_class);
static void gimp_stroke_options_class_init (GimpStrokeOptionsClass *klass);
static void gimp_stroke_options_set_property (GObject *object,
guint property_id,
@ -102,6 +103,11 @@ gimp_stroke_options_class_init (GimpStrokeOptionsClass *klass)
object_class->set_property = gimp_stroke_options_set_property;
object_class->get_property = gimp_stroke_options_get_property;
GIMP_CONFIG_INSTALL_PROP_ENUM (object_class, PROP_STYLE,
"style", NULL,
GIMP_TYPE_STROKE_STYLE,
GIMP_STROKE_STYLE_SOLID,
0);
GIMP_CONFIG_INSTALL_PROP_DOUBLE (object_class, PROP_WIDTH,
"width", NULL,
0.0, 2000.0, 5.0,
@ -151,16 +157,13 @@ gimp_stroke_options_set_property (GObject *object,
const GValue *value,
GParamSpec *pspec)
{
GimpStrokeOptions *options;
GValueArray *val_array;
GValue *item;
gint i;
gdouble val;
options = GIMP_STROKE_OPTIONS (object);
GimpStrokeOptions *options = GIMP_STROKE_OPTIONS (object);
switch (property_id)
{
case PROP_STYLE:
options->style = g_value_get_enum (value);
break;
case PROP_WIDTH:
options->width = g_value_get_double (value);
break;
@ -186,32 +189,39 @@ gimp_stroke_options_set_property (GObject *object,
options->dash_offset = g_value_get_double (value);
break;
case PROP_DASH_INFO:
if (options->dash_info)
g_array_free (options->dash_info, TRUE);
{
GValueArray *val_array;
GValue *item;
gint i;
gdouble val;
val_array = g_value_get_boxed (value);
if (val_array == NULL || val_array->n_values == 0)
{
options->dash_info = NULL;
}
else
{
options->dash_info = g_array_sized_new (FALSE, FALSE,
sizeof (gdouble),
val_array->n_values);
if (options->dash_info)
g_array_free (options->dash_info, TRUE);
val_array = g_value_get_boxed (value);
if (val_array == NULL || val_array->n_values == 0)
{
options->dash_info = NULL;
}
else
{
options->dash_info = g_array_sized_new (FALSE, FALSE,
sizeof (gdouble),
val_array->n_values);
for (i=0; i < val_array->n_values; i++)
{
item = g_value_array_get_nth (val_array, i);
for (i=0; i < val_array->n_values; i++)
{
item = g_value_array_get_nth (val_array, i);
g_return_if_fail (G_VALUE_HOLDS_DOUBLE (item));
g_return_if_fail (G_VALUE_HOLDS_DOUBLE (item));
val = g_value_get_double (item);
val = g_value_get_double (item);
options->dash_info = g_array_append_val (options->dash_info, val);
}
}
options->dash_info = g_array_append_val (options->dash_info,
val);
}
}
}
break;
default:
@ -226,15 +236,13 @@ gimp_stroke_options_get_property (GObject *object,
GValue *value,
GParamSpec *pspec)
{
GimpStrokeOptions *options;
GValueArray *val_array;
GValue item;
gint i;
options = GIMP_STROKE_OPTIONS (object);
GimpStrokeOptions *options = GIMP_STROKE_OPTIONS (object);
switch (property_id)
{
case PROP_STYLE:
g_value_set_enum (value, options->style);
break;
case PROP_WIDTH:
g_value_set_double (value, options->width);
break;
@ -260,27 +268,34 @@ gimp_stroke_options_get_property (GObject *object,
g_value_set_double (value, options->dash_offset);
break;
case PROP_DASH_INFO:
if (options->dash_info)
g_array_free (options->dash_info, TRUE);
{
GValueArray *val_array;
GValue item;
gint i;
if (options->dash_info == NULL || options->dash_info->len == 0)
{
g_value_set_boxed (value, NULL);
}
else
{
val_array = g_value_array_new (options->dash_info->len);
if (options->dash_info)
g_array_free (options->dash_info, TRUE);
for (i=0; i < options->dash_info->len; i++)
{
g_value_set_double (&item, g_array_index (options->dash_info,
gdouble,
i));
if (options->dash_info == NULL || options->dash_info->len == 0)
{
g_value_set_boxed (value, NULL);
}
else
{
val_array = g_value_array_new (options->dash_info->len);
g_value_array_append (val_array, &item);
}
g_value_set_boxed (value, val_array);
}
for (i=0; i < options->dash_info->len; i++)
{
g_value_set_double (&item, g_array_index (options->dash_info,
gdouble,
i));
g_value_array_append (val_array, &item);
}
g_value_set_boxed (value, val_array);
}
}
break;
default:
@ -288,6 +303,3 @@ gimp_stroke_options_get_property (GObject *object,
break;
}
}

View File

@ -38,21 +38,23 @@ typedef struct _GimpStrokeOptionsClass GimpStrokeOptionsClass;
struct _GimpStrokeOptions
{
GimpContext parent_instance;
GimpContext parent_instance;
gdouble width;
GimpUnit width_unit;
GimpStrokeStyle style;
GimpCapStyle cap_style;
GimpJoinStyle join_style;
gdouble width;
GimpUnit width_unit;
gdouble miter;
GimpCapStyle cap_style;
GimpJoinStyle join_style;
gboolean antialias;
gdouble miter;
GimpUnit dash_unit;
gdouble dash_offset;
GArray *dash_info;
gboolean antialias;
GimpUnit dash_unit;
gdouble dash_offset;
GArray *dash_info;
};
struct _GimpStrokeOptionsClass
@ -61,6 +63,7 @@ struct _GimpStrokeOptionsClass
};
GType gimp_stroke_options_get_type (void) G_GNUC_CONST;
GType gimp_stroke_options_get_type (void) G_GNUC_CONST;
#endif /* __GIMP_STROKE_OPTIONS_H__ */

View File

@ -81,6 +81,13 @@ stroke_dialog_new (GimpItem *item,
"gimp", image->gimp,
NULL);
gimp_context_set_parent (GIMP_CONTEXT (options),
gimp_get_user_context (image->gimp));
gimp_context_define_properties (GIMP_CONTEXT (options),
GIMP_CONTEXT_FOREGROUND_MASK |
GIMP_CONTEXT_PATTERN_MASK,
FALSE);
/* the dialog */
dialog =
gimp_viewable_dialog_new (GIMP_VIEWABLE (item),

View File

@ -81,6 +81,13 @@ stroke_dialog_new (GimpItem *item,
"gimp", image->gimp,
NULL);
gimp_context_set_parent (GIMP_CONTEXT (options),
gimp_get_user_context (image->gimp));
gimp_context_define_properties (GIMP_CONTEXT (options),
GIMP_CONTEXT_FOREGROUND_MASK |
GIMP_CONTEXT_PATTERN_MASK,
FALSE);
/* the dialog */
dialog =
gimp_viewable_dialog_new (GIMP_VIEWABLE (item),

View File

@ -164,6 +164,118 @@ color_pixels (guchar *dest,
}
}
void
color_pixels_mask (guchar *dest,
guchar *mask,
const guchar *color,
guint w,
guint bytes)
{
guchar c0, c1, c2;
gint alpha;
alpha = HAS_ALPHA (bytes) ? bytes - 1 : bytes;
switch (bytes)
{
case 1:
memset (dest, *color, w);
break;
case 2:
c0 = color[0];
while (w--)
{
dest[0] = c0;
dest[1] = *mask++;
dest += 2;
}
break;
case 3:
c0 = color[0];
c1 = color[1];
c2 = color[2];
while (w--)
{
dest[0] = c0;
dest[1] = c1;
dest[2] = c2;
dest += 3;
}
break;
case 4:
c0 = color[0];
c1 = color[1];
c2 = color[2];
while (w--)
{
dest[0] = c0;
dest[1] = c1;
dest[2] = c2;
dest[3] = *mask++;
dest += 4;
}
break;
}
}
void
pattern_pixels_mask (guchar *dest,
guchar *mask,
TempBuf *pattern,
guint w,
guint bytes,
gint x,
gint y)
{
guchar *pat, *p;
gint alpha, b;
gint i;
/* Get a pointer to the appropriate scanline of the pattern buffer */
pat = (temp_buf_data (pattern) +
(y % pattern->height) * pattern->width * pattern->bytes);
alpha = HAS_ALPHA (bytes) ? bytes - 1 : bytes;
/*
* image data = pattern data for all but alpha
*
* If (image has alpha)
* if (there's a mask)
* image data = mask for alpha;
* else
* image data = opaque for alpha.
*
* if (pattern has alpha)
* multiply existing alpha channel by pattern alpha
* (normalised to (0..1))
*/
for (i = 0; i < w; i++)
{
p = pat + ((i + x) % pattern->width) * pattern->bytes;
for (b = 0; b < alpha; b++)
dest[b] = p[b];
if (HAS_ALPHA (bytes))
{
if (mask)
dest[alpha] = *mask++;
else
dest[alpha] = OPAQUE_OPACITY;
if (HAS_ALPHA (pattern->bytes))
dest[alpha] = (guchar) (dest[alpha] *
p[alpha] / (gdouble) OPAQUE_OPACITY);
}
dest += bytes;
}
}
inline void
blend_pixels (const guchar *src1,

View File

@ -31,6 +31,7 @@
#include "base/pixel-processor.h"
#include "base/pixel-region.h"
#include "base/temp-buf.h"
#include "base/tile-manager.h"
#include "base/tile.h"
@ -2017,24 +2018,97 @@ color_region (PixelRegion *dest,
h = dest->h;
s = dest->data;
if (dest->w*dest->bytes == dest->rowstride)
if (dest->w * dest->bytes == dest->rowstride)
{
/* do it all in one function call if we can */
/* this hasn't been tested to see if it is a
signifigant speed gain yet */
color_pixels (s, col, dest->w*h, dest->bytes);
/* do it all in one function call if we can
* this hasn't been tested to see if it is a
* signifigant speed gain yet
*/
color_pixels (s, col, dest->w * h, dest->bytes);
}
else
{
while (h--)
{
color_pixels (s, col, dest->w, dest->bytes);
color_pixels (s, col, dest->w, dest->bytes);
s += dest->rowstride;
}
}
}
}
void
color_region_mask (PixelRegion *dest,
PixelRegion *mask,
const guchar *col)
{
gint h;
guchar *d;
guchar *m;
void *pr;
for (pr = pixel_regions_register (2, dest, mask);
pr != NULL;
pr = pixel_regions_process (pr))
{
h = dest->h;
d = dest->data;
m = mask->data;
if (dest->w * dest->bytes == dest->rowstride &&
mask->w * mask->bytes == mask->rowstride)
{
/* do it all in one function call if we can
* this hasn't been tested to see if it is a
* signifigant speed gain yet
*/
color_pixels_mask (d, m, col, dest->w * h, dest->bytes);
}
else
{
while (h--)
{
color_pixels_mask (d, m, col, dest->w, dest->bytes);
d += dest->rowstride;
m += mask->rowstride;
}
}
}
}
void
pattern_region (PixelRegion *dest,
PixelRegion *mask,
TempBuf *pattern,
gint off_x,
gint off_y)
{
gint y;
guchar *d;
guchar *m = NULL;
void *pr;
for (pr = pixel_regions_register (2, dest, mask);
pr != NULL;
pr = pixel_regions_process (pr))
{
d = dest->data;
if (mask)
m = mask->data;
for (y = 0; y < dest->h; y++)
{
pattern_pixels_mask (d, m, pattern, dest->w, dest->bytes,
off_x + dest->x,
off_y + dest->y + y);
d += dest->rowstride;
if (mask)
m += mask->rowstride;
}
}
}
void
blend_region (PixelRegion *src1,
@ -3846,7 +3920,7 @@ border_region (PixelRegion *src,
{
guchar color[] = "\0\0\0\0";
color_region(src, color);
color_region (src, color);
return;
}

View File

@ -268,9 +268,17 @@ void extract_from_indexed_pixels (guchar *src,
/* Region functions */
void color_region (PixelRegion *dest,
void color_region (PixelRegion *dest,
const guchar *color);
void color_region_mask (PixelRegion *dest,
PixelRegion *mask,
const guchar *color);
void pattern_region (PixelRegion *dest,
PixelRegion *mask,
TempBuf *pattern,
gint off_x,
gint off_y);
void blend_region (PixelRegion *, PixelRegion *,
PixelRegion *, int);

View File

@ -167,12 +167,20 @@ gimp_stroke_editor_constructor (GType type,
g_assert (editor->options != NULL);
table = gtk_table_new (4, 3, FALSE);
table = gtk_table_new (5, 3, FALSE);
gtk_table_set_col_spacings (GTK_TABLE (table), 2);
gtk_table_set_row_spacings (GTK_TABLE (table), 4);
gtk_box_pack_start (GTK_BOX (editor), table, FALSE, FALSE, 0);
gtk_widget_show (table);
box = gimp_prop_enum_radio_frame_new (G_OBJECT (editor->options), "style",
_("Style"), 0, 0);
gtk_table_attach (GTK_TABLE (table), box, 0, 3, row, row + 1,
GTK_SHRINK | GTK_FILL, GTK_SHRINK | GTK_FILL, 0, 0);
gtk_widget_show (box);
row++;
digits = gimp_unit_get_digits (editor->options->width_unit);
spinbutton = gimp_prop_spin_button_new (G_OBJECT (editor->options), "width",
1.0, 10.0, digits);