see plug-ins/perl/Changes
This commit is contained in:
@ -1,5 +1,13 @@
|
|||||||
Revision history for Gimp-Perl extension.
|
Revision history for Gimp-Perl extension.
|
||||||
|
|
||||||
|
- Gimp::Fu does no longer display the returned image when it
|
||||||
|
is the same as the one passed in.
|
||||||
|
- append imagenumber to "Untitled"-images in widget.
|
||||||
|
- removed publicly-visible non-PDB pixelfunctions.
|
||||||
|
"uuuuuse peedee-ell or dieieie".
|
||||||
|
- implemented Gimp::Fu::PF_RADIO.
|
||||||
|
- added blowinout.pl.
|
||||||
|
|
||||||
1.055 Mon Feb 22 22:38:44 CET 1999
|
1.055 Mon Feb 22 22:38:44 CET 1999
|
||||||
- applied seth's script changes.
|
- applied seth's script changes.
|
||||||
- gimp11ified some plug-ins.
|
- gimp11ified some plug-ins.
|
||||||
|
@ -12,7 +12,7 @@ use base qw(DynaLoader);
|
|||||||
|
|
||||||
require DynaLoader;
|
require DynaLoader;
|
||||||
|
|
||||||
$VERSION = 1.055;
|
$VERSION = 1.06;
|
||||||
|
|
||||||
@_param = qw(
|
@_param = qw(
|
||||||
PARAM_BOUNDARY PARAM_CHANNEL PARAM_COLOR PARAM_DISPLAY PARAM_DRAWABLE
|
PARAM_BOUNDARY PARAM_CHANNEL PARAM_COLOR PARAM_DISPLAY PARAM_DRAWABLE
|
||||||
@ -312,6 +312,16 @@ sub AUTOLOAD {
|
|||||||
if (exists $ignore_function{$sub}) {
|
if (exists $ignore_function{$sub}) {
|
||||||
*{$AUTOLOAD} = sub { () };
|
*{$AUTOLOAD} = sub { () };
|
||||||
goto &$AUTOLOAD;
|
goto &$AUTOLOAD;
|
||||||
|
} elsif (UNIVERSAL::can(Gimp::Util,$sub)) {
|
||||||
|
my $ref = \&{"Gimp::Util::$sub"};
|
||||||
|
*{$AUTOLOAD} = sub {
|
||||||
|
shift unless ref $_[0];
|
||||||
|
# goto &$ref # does not always work, PERLBUG! #FIXME
|
||||||
|
my @r = eval { &$ref };
|
||||||
|
_croak $@ if $@;
|
||||||
|
wantarray ? @r : $r[0];
|
||||||
|
};
|
||||||
|
goto &$AUTOLOAD;
|
||||||
} elsif (UNIVERSAL::can($interface_pkg,$sub)) {
|
} elsif (UNIVERSAL::can($interface_pkg,$sub)) {
|
||||||
my $ref = \&{"${interface_pkg}::$sub"};
|
my $ref = \&{"${interface_pkg}::$sub"};
|
||||||
*{$AUTOLOAD} = sub {
|
*{$AUTOLOAD} = sub {
|
||||||
@ -333,16 +343,6 @@ sub AUTOLOAD {
|
|||||||
goto &$AUTOLOAD;
|
goto &$AUTOLOAD;
|
||||||
} elsif (defined(*{"${interface_pkg}::$sub"}{CODE})) {
|
} elsif (defined(*{"${interface_pkg}::$sub"}{CODE})) {
|
||||||
die "safety net $interface_pkg :: $sub (REPORT THIS!!)";#d#
|
die "safety net $interface_pkg :: $sub (REPORT THIS!!)";#d#
|
||||||
} elsif (UNIVERSAL::can(Gimp::Util,$sub)) {
|
|
||||||
my $ref = \&{"Gimp::Util::$sub"};
|
|
||||||
*{$AUTOLOAD} = sub {
|
|
||||||
shift unless ref $_[0];
|
|
||||||
# goto &$ref # does not always work, PERLBUG! #FIXME
|
|
||||||
my @r = eval { &$ref };
|
|
||||||
_croak $@ if $@;
|
|
||||||
wantarray ? @r : $r[0];
|
|
||||||
};
|
|
||||||
goto &$AUTOLOAD;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# for performance reasons: supply a DESTROY method
|
# for performance reasons: supply a DESTROY method
|
||||||
|
@ -79,6 +79,7 @@ sub PF_ADJUSTMENT(){ PARAM_END+5 }; # compatibility fix for script-fu _ONLY_
|
|||||||
sub PF_BRUSH () { PARAM_END+6 };
|
sub PF_BRUSH () { PARAM_END+6 };
|
||||||
sub PF_PATTERN () { PARAM_END+7 };
|
sub PF_PATTERN () { PARAM_END+7 };
|
||||||
sub PF_GRADIENT () { PARAM_END+8 };
|
sub PF_GRADIENT () { PARAM_END+8 };
|
||||||
|
sub PF_RADIO () { PARAM_END+9 };
|
||||||
|
|
||||||
sub PF_BOOL () { PF_TOGGLE };
|
sub PF_BOOL () { PF_TOGGLE };
|
||||||
sub PF_INT () { PF_INT32 };
|
sub PF_INT () { PF_INT32 };
|
||||||
@ -101,6 +102,7 @@ sub Gimp::RUN_FULLINTERACTIVE (){ Gimp::RUN_INTERACTIVE+100 }; # you don't want
|
|||||||
&PF_SLIDER => 'integer',
|
&PF_SLIDER => 'integer',
|
||||||
&PF_SPINNER => 'integer',
|
&PF_SPINNER => 'integer',
|
||||||
&PF_ADJUSTMENT => 'integer',
|
&PF_ADJUSTMENT => 'integer',
|
||||||
|
&PF_RADIO => 'string',
|
||||||
&PF_IMAGE => 'NYI',
|
&PF_IMAGE => 'NYI',
|
||||||
&PF_LAYER => 'NYI',
|
&PF_LAYER => 'NYI',
|
||||||
&PF_CHANNEL => 'NYI',
|
&PF_CHANNEL => 'NYI',
|
||||||
@ -111,7 +113,7 @@ sub Gimp::RUN_FULLINTERACTIVE (){ Gimp::RUN_INTERACTIVE+100 }; # you don't want
|
|||||||
PF_STRING PF_COLOR PF_COLOUR PF_TOGGLE PF_IMAGE
|
PF_STRING PF_COLOR PF_COLOUR PF_TOGGLE PF_IMAGE
|
||||||
PF_DRAWABLE PF_FONT PF_LAYER PF_CHANNEL PF_BOOL
|
PF_DRAWABLE PF_FONT PF_LAYER PF_CHANNEL PF_BOOL
|
||||||
PF_SLIDER PF_INT PF_SPINNER PF_ADJUSTMENT
|
PF_SLIDER PF_INT PF_SPINNER PF_ADJUSTMENT
|
||||||
PF_BRUSH PF_PATTERN PF_GRADIENT);
|
PF_BRUSH PF_PATTERN PF_GRADIENT PF_RADIO);
|
||||||
|
|
||||||
@EXPORT = (qw(register main),@_params);
|
@EXPORT = (qw(register main),@_params);
|
||||||
@EXPORT_OK = qw(interact $run_mode save_image);
|
@EXPORT_OK = qw(interact $run_mode save_image);
|
||||||
@ -280,6 +282,25 @@ sub interact($$$@) {
|
|||||||
push(@setvals,sub{set_state $a ($_[0] ? 1 : 0)});
|
push(@setvals,sub{set_state $a ($_[0] ? 1 : 0)});
|
||||||
push(@getvals,sub{state $a eq "active"});
|
push(@getvals,sub{state $a eq "active"});
|
||||||
|
|
||||||
|
} elsif($type == PF_RADIO) {
|
||||||
|
my $b = new Gtk::HBox 0,5;
|
||||||
|
my($r,$prev);
|
||||||
|
my $prev_sub = sub { $r = $_[0] };
|
||||||
|
for (@$extra) {
|
||||||
|
my ($label,$value)=@$_;
|
||||||
|
my $radio = new Gtk::RadioButton $label;
|
||||||
|
$radio->set_group ($prev) if $prev;
|
||||||
|
$b->pack_start ($radio,1,0,5);
|
||||||
|
$radio->signal_connect(clicked => sub { $r = $value });
|
||||||
|
my $prev_sub_my = $prev_sub;
|
||||||
|
$prev_sub = sub { $radio->set_active ($_[0] == $value); &$prev_sub_my };
|
||||||
|
$prev = $radio;
|
||||||
|
}
|
||||||
|
$a = new Gtk::Frame;
|
||||||
|
$a->add($b);
|
||||||
|
push(@setvals,$prev_sub);
|
||||||
|
push(@getvals,sub{$r});
|
||||||
|
|
||||||
} elsif($type == PF_IMAGE) {
|
} elsif($type == PF_IMAGE) {
|
||||||
my $res;
|
my $res;
|
||||||
$a=new Gtk::HBox (0,5);
|
$a=new Gtk::HBox (0,5);
|
||||||
@ -443,6 +464,7 @@ sub string2pf($$) {
|
|||||||
|| $type==PF_FONT
|
|| $type==PF_FONT
|
||||||
|| $type==PF_PATTERN
|
|| $type==PF_PATTERN
|
||||||
|| $type==PF_BRUSH
|
|| $type==PF_BRUSH
|
||||||
|
|| $type==PF_RADIO # for now! #d#
|
||||||
|| $type==PF_GRADIENT) {
|
|| $type==PF_GRADIENT) {
|
||||||
$s;
|
$s;
|
||||||
} elsif($type==PF_INT8
|
} elsif($type==PF_INT8
|
||||||
@ -553,6 +575,7 @@ sub query {
|
|||||||
$_->[0]=PARAM_INT32 if $_->[0] == PF_SLIDER;
|
$_->[0]=PARAM_INT32 if $_->[0] == PF_SLIDER;
|
||||||
$_->[0]=PARAM_INT32 if $_->[0] == PF_SPINNER;
|
$_->[0]=PARAM_INT32 if $_->[0] == PF_SPINNER;
|
||||||
$_->[0]=PARAM_INT32 if $_->[0] == PF_ADJUSTMENT;
|
$_->[0]=PARAM_INT32 if $_->[0] == PF_ADJUSTMENT;
|
||||||
|
$_->[0]=PARAM_INT32 if $_->[0] == PF_RADIO;
|
||||||
$_->[0]=PARAM_STRING if $_->[0] == PF_FONT;
|
$_->[0]=PARAM_STRING if $_->[0] == PF_FONT;
|
||||||
$_->[0]=PARAM_STRING if $_->[0] == PF_BRUSH;
|
$_->[0]=PARAM_STRING if $_->[0] == PF_BRUSH;
|
||||||
$_->[0]=PARAM_STRING if $_->[0] == PF_PATTERN;
|
$_->[0]=PARAM_STRING if $_->[0] == PF_PATTERN;
|
||||||
@ -703,6 +726,19 @@ Default values will be substitued for missing entries, like in:
|
|||||||
|
|
||||||
The same as PF_SLIDER, except that this one uses a spinbutton instead of a scale.
|
The same as PF_SLIDER, except that this one uses a spinbutton instead of a scale.
|
||||||
|
|
||||||
|
=item PF_RADIO
|
||||||
|
|
||||||
|
In addition to a default value, an extra argument describing the various
|
||||||
|
options I<must> be provided. That extra argument must be a reference
|
||||||
|
to an array filled with ["Option-Name", integer-value] pairs. Gimp::Fu
|
||||||
|
will then generate a horizontal frame with radio buttons, one for each
|
||||||
|
alternative. For example:
|
||||||
|
|
||||||
|
[PF_RADIO, "direction", "the direction to move to", 5, [["Left",5],["Right",7]]]
|
||||||
|
|
||||||
|
draws two buttons, when the first (the default, "Left") is activated, 5
|
||||||
|
will be returned. If the second is activated, 7 is returned.
|
||||||
|
|
||||||
=item PF_FONT
|
=item PF_FONT
|
||||||
|
|
||||||
Lets the user select a font and returns a X Logical Font Descriptor (XLFD).
|
Lets the user select a font and returns a X Logical Font Descriptor (XLFD).
|
||||||
@ -737,7 +773,7 @@ sub register($$$$$$$$$;@) {
|
|||||||
|
|
||||||
*$function = sub {
|
*$function = sub {
|
||||||
$run_mode=shift; # global!
|
$run_mode=shift; # global!
|
||||||
my(@pre,@defaults,@lastvals);
|
my(@pre,@defaults,@lastvals,$input_image);
|
||||||
if ($menupath=~/^<Image>\//) {
|
if ($menupath=~/^<Image>\//) {
|
||||||
@_ >= 2 or die "<Image> plug-in called without an image and drawable!\n";
|
@_ >= 2 or die "<Image> plug-in called without an image and drawable!\n";
|
||||||
@pre = (shift,shift);
|
@pre = (shift,shift);
|
||||||
@ -779,6 +815,8 @@ sub register($$$$$$$$$;@) {
|
|||||||
} else {
|
} else {
|
||||||
die "run_mode must be INTERACTIVE, NONINTERACTIVE or WITH_LAST_VALS\n";
|
die "run_mode must be INTERACTIVE, NONINTERACTIVE or WITH_LAST_VALS\n";
|
||||||
}
|
}
|
||||||
|
$input_image = $_[0] if ref $_[0] eq "Gimp::Image";
|
||||||
|
$input_image = $pre[0] if ref $pre[0] eq "Gimp::Image";
|
||||||
|
|
||||||
$Gimp::Data{"$function/_fu_data"}=Dumper([@_]);
|
$Gimp::Data{"$function/_fu_data"}=Dumper([@_]);
|
||||||
|
|
||||||
@ -802,7 +840,7 @@ sub register($$$$$$$$$;@) {
|
|||||||
save_image($img,$path);
|
save_image($img,$path);
|
||||||
$img->delete;
|
$img->delete;
|
||||||
} elsif ($run_mode != &Gimp::RUN_NONINTERACTIVE) {
|
} elsif ($run_mode != &Gimp::RUN_NONINTERACTIVE) {
|
||||||
$img->display_new;
|
$img->display_new unless $input_image && $$img == $$input_image;
|
||||||
}
|
}
|
||||||
} elsif (!@$results) {
|
} elsif (!@$results) {
|
||||||
warn "WARNING: $function returned something that is not an image: \"$img\"\n";
|
warn "WARNING: $function returned something that is not an image: \"$img\"\n";
|
||||||
|
@ -1539,7 +1539,7 @@ gimp_pixel_rgn_resize(sv, x, y, width, height)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SV *
|
SV *
|
||||||
gimp_pixel_rgn_get_pixel(pr, x, y)
|
_gimp_pixel_rgn_get_pixel(pr, x, y)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
int x
|
int x
|
||||||
int y
|
int y
|
||||||
@ -1552,7 +1552,7 @@ gimp_pixel_rgn_get_pixel(pr, x, y)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
SV *
|
SV *
|
||||||
gimp_pixel_rgn_get_row(pr, x, y, width)
|
_gimp_pixel_rgn_get_row(pr, x, y, width)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
int x
|
int x
|
||||||
int y
|
int y
|
||||||
@ -1566,7 +1566,7 @@ gimp_pixel_rgn_get_row(pr, x, y, width)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
SV *
|
SV *
|
||||||
gimp_pixel_rgn_get_col(pr, x, y, height)
|
_gimp_pixel_rgn_get_col(pr, x, y, height)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
int x
|
int x
|
||||||
int y
|
int y
|
||||||
@ -1580,7 +1580,7 @@ gimp_pixel_rgn_get_col(pr, x, y, height)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
SV *
|
SV *
|
||||||
gimp_pixel_rgn_get_rect(pr, x, y, width, height)
|
_gimp_pixel_rgn_get_rect(pr, x, y, width, height)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
int x
|
int x
|
||||||
int y
|
int y
|
||||||
@ -1595,7 +1595,7 @@ gimp_pixel_rgn_get_rect(pr, x, y, width, height)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_pixel_rgn_set_pixel(pr, data, x, y)
|
_gimp_pixel_rgn_set_pixel(pr, data, x, y)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
SV * data
|
SV * data
|
||||||
int x
|
int x
|
||||||
@ -1608,7 +1608,7 @@ gimp_pixel_rgn_set_pixel(pr, data, x, y)
|
|||||||
gimp_pixel_rgn_set_pixel (pr, SvPV(data, dc), x, y);
|
gimp_pixel_rgn_set_pixel (pr, SvPV(data, dc), x, y);
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_pixel_rgn_set_row(pr, data, x, y)
|
_gimp_pixel_rgn_set_row(pr, data, x, y)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
SV * data
|
SV * data
|
||||||
int x
|
int x
|
||||||
@ -1621,7 +1621,7 @@ gimp_pixel_rgn_set_row(pr, data, x, y)
|
|||||||
gimp_pixel_rgn_set_row (pr, SvPV(data, dc), x, y, SvCUR (data) / pr->bpp);
|
gimp_pixel_rgn_set_row (pr, SvPV(data, dc), x, y, SvCUR (data) / pr->bpp);
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_pixel_rgn_set_col(pr, data, x, y)
|
_gimp_pixel_rgn_set_col(pr, data, x, y)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
SV * data
|
SV * data
|
||||||
int x
|
int x
|
||||||
@ -1634,7 +1634,7 @@ gimp_pixel_rgn_set_col(pr, data, x, y)
|
|||||||
gimp_pixel_rgn_set_col (pr, SvPV(data, dc), x, y, SvCUR (data) / pr->bpp);
|
gimp_pixel_rgn_set_col (pr, SvPV(data, dc), x, y, SvCUR (data) / pr->bpp);
|
||||||
|
|
||||||
void
|
void
|
||||||
gimp_pixel_rgn_set_rect(pr, data, x, y, width)
|
_gimp_pixel_rgn_set_rect(pr, data, x, y, width)
|
||||||
GPixelRgn * pr
|
GPixelRgn * pr
|
||||||
SV * data
|
SV * data
|
||||||
int x
|
int x
|
||||||
@ -1663,7 +1663,7 @@ PROTOTYPES: DISABLE
|
|||||||
# construction/destruction.
|
# construction/destruction.
|
||||||
|
|
||||||
SV *
|
SV *
|
||||||
get_data(tile)
|
_get_data(tile)
|
||||||
GTile * tile
|
GTile * tile
|
||||||
CODE:
|
CODE:
|
||||||
gimp_tile_ref (tile);
|
gimp_tile_ref (tile);
|
||||||
@ -1673,7 +1673,7 @@ get_data(tile)
|
|||||||
RETVAL
|
RETVAL
|
||||||
|
|
||||||
void
|
void
|
||||||
set_data(tile, data)
|
_set_data(tile, data)
|
||||||
GTile * tile
|
GTile * tile
|
||||||
SV * data
|
SV * data
|
||||||
CODE:
|
CODE:
|
||||||
|
@ -11,87 +11,71 @@ require AutoLoader;
|
|||||||
|
|
||||||
@EXPORT = ();
|
@EXPORT = ();
|
||||||
|
|
||||||
$old_w = $^W; $^W = 0;
|
sub Gimp::Tile::set_data($) {
|
||||||
|
|
||||||
*old_set_data = \&Gimp::Tile::set_data;
|
|
||||||
*Gimp::Tile::set_data = sub {
|
|
||||||
(my $p = byte $_[1])->make_physical;
|
(my $p = byte $_[1])->make_physical;
|
||||||
old_set_data($_[0],${$p->get_dataref});
|
Gimp::Tile::_set_data($_[0],${$p->get_dataref});
|
||||||
};
|
};
|
||||||
|
|
||||||
*old_get_data = \&Gimp::Tile::get_data;
|
sub Gimp::Tile::get_data($) {
|
||||||
*Gimp::Tile::get_data = sub {
|
|
||||||
my($tile)=@_;
|
my($tile)=@_;
|
||||||
my($pdl)=new_from_specification PDL (byte,width(),height(),
|
my($pdl)=new_from_specification PDL (byte,width(),height(),
|
||||||
$tile->bpp > 1 ? $tile->bpp : ());
|
$tile->bpp > 1 ? $tile->bpp : ());
|
||||||
${$pdl->get_dataref} = old_get_data($tile);
|
${$pdl->get_dataref} = &Gimp::Tile::_get_data;
|
||||||
$pdl->upd_data;
|
$pdl->upd_data;
|
||||||
return $pdl;
|
return $pdl;
|
||||||
};
|
};
|
||||||
|
|
||||||
# this tries to overwrite a function with another one. this is quite tricky
|
sub Gimp::PixelRgn::get_pixel {
|
||||||
# (almost impossible in general), we only overwrite Gimp::<iface>::function
|
|
||||||
# and hope no other references are around.
|
|
||||||
sub rep ($&) {
|
|
||||||
my($name,$sub)=@_;
|
|
||||||
*{"old_$name"}=\&{"${Gimp::interface_pkg}::gimp_pixel_rgn_$name"};
|
|
||||||
undef *{"${Gimp::interface_pkg}::gimp_pixel_rgn_$name"};
|
|
||||||
*{"${Gimp::interface_pkg}::gimp_pixel_rgn_$name"}=$sub;
|
|
||||||
}
|
|
||||||
|
|
||||||
rep "get_pixel", sub($$$) {
|
|
||||||
my($rgn)=@_;
|
my($rgn)=@_;
|
||||||
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp);
|
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp);
|
||||||
${$pdl->get_dataref} = &old_get_pixel;
|
${$pdl->get_dataref} = &Gimp::PixelRgn::_get_pixel;
|
||||||
$pdl->upd_data;
|
$pdl->upd_data;
|
||||||
return $pdl;
|
return $pdl;
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "get_col", sub($$$$) {
|
sub Gimp::PixelRgn::get_col {
|
||||||
my($rgn)=@_;
|
my($rgn)=@_;
|
||||||
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3]);
|
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3]);
|
||||||
${$pdl->get_dataref} = &old_get_col;
|
${$pdl->get_dataref} = &Gimp::PixelRgn::__get_col;
|
||||||
$pdl->upd_data;
|
$pdl->upd_data;
|
||||||
return $pdl;
|
return $pdl;
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "get_row", sub($$$$) {
|
sub Gimp::PixelRgn::get_row {
|
||||||
my($rgn)=@_;
|
my($rgn)=@_;
|
||||||
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3]);
|
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3]);
|
||||||
${$pdl->get_dataref} = &old_get_row;
|
${$pdl->get_dataref} = &Gimp::PixelRgn::_get_row;
|
||||||
$pdl->upd_data;
|
$pdl->upd_data;
|
||||||
return $pdl;
|
return $pdl;
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "get_rect", sub($$$$$) {
|
sub Gimp::PixelRgn::get_rect {
|
||||||
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3],$_[4]);
|
my($pdl)=new_from_specification PDL (byte,$_[0]->bpp,$_[3],$_[4]);
|
||||||
${$pdl->get_dataref} = &old_get_rect;
|
${$pdl->get_dataref} = &Gimp::PixelRgn::_get_rect;
|
||||||
$pdl->upd_data;
|
$pdl->upd_data;
|
||||||
return $pdl;
|
return $pdl;
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "set_pixel", sub($$$$) {
|
sub Gimp::PixelRgn::set_pixel {
|
||||||
(my $p = byte $_[1])->make_physical;
|
(my $p = byte $_[1])->make_physical;
|
||||||
old_set_pixel($_[0],${$p->get_dataref},$_[2],$_[3]);
|
Gimp::PixelRgn::_set_pixel($_[0],${$p->get_dataref},$_[2],$_[3]);
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "set_col", sub($$$$) {
|
sub Gimp::PixelRgn::set_col {
|
||||||
(my $p = byte $_[1])->make_physical;
|
(my $p = byte $_[1])->make_physical;
|
||||||
old_set_col($_[0],${$p->get_dataref},$_[2],$_[3]);
|
Gimp::PixelRgn::_set_col($_[0],${$p->get_dataref},$_[2],$_[3]);
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "set_row", sub($$$$) {
|
sub Gimp::PixelRgn::set_row {
|
||||||
(my $p = byte $_[1])->make_physical;
|
(my $p = byte $_[1])->make_physical;
|
||||||
old_set_row($_[0],${$p->get_dataref},$_[2],$_[3]);
|
Gimp::PixelRgn::_set_row($_[0],${$p->get_dataref},$_[2],$_[3]);
|
||||||
};
|
};
|
||||||
|
|
||||||
rep "set_rect", sub($$$$) {
|
sub Gimp::PixelRgn::set_rect {
|
||||||
(my $p = byte $_[1])->make_physical;
|
(my $p = byte $_[1])->make_physical;
|
||||||
old_set_rect($_[0],${$p->get_dataref},$_[2],$_[3],($_[1]->dims)[1]);
|
Gimp::PixelRgn::_set_rect($_[0],${$p->get_dataref},$_[2],$_[3],($_[1]->dims)[1]);
|
||||||
};
|
};
|
||||||
|
|
||||||
$^W = $old_w; undef $old_w;
|
|
||||||
|
|
||||||
1;
|
1;
|
||||||
__END__
|
__END__
|
||||||
|
|
||||||
@ -102,15 +86,15 @@ Gimp::PDL - Overwrite Tile/Region functions to work with piddles.
|
|||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
use Gimp;
|
use Gimp;
|
||||||
use Gimp::PDL; # must be use'd _after_ Gimp!
|
use Gimp::PDL;
|
||||||
use PDL;
|
use PDL;
|
||||||
|
|
||||||
=head1 DESCRIPTION
|
=head1 DESCRIPTION
|
||||||
|
|
||||||
This module overwrites all methods of Gimp::Tile and Gimp::PixelRgn. The new
|
This module overwrites some methods of Gimp::Tile and Gimp::PixelRgn. The
|
||||||
functions return and accept piddles instead of strings for pixel values. The
|
new functions return and accept piddles. The last argument (height) of
|
||||||
last argument (height) of C<gimp_pixel_rgn_set_rect> is calculated from the
|
C<gimp_pixel_rgn_set_rect> is calculated from the piddle. There is no
|
||||||
piddle.
|
other way to access the raw pixeldata in Gimp.
|
||||||
|
|
||||||
Some exmaples:
|
Some exmaples:
|
||||||
|
|
||||||
|
@ -4,7 +4,9 @@ Gimp::Pixel - how to operate on raw pixels
|
|||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
use Gimp; # all you need is in Gimp.
|
use Gimp;
|
||||||
|
use Gimp::PDL; # you need Gimp::PDL for pixel access
|
||||||
|
use PDL; # to make sensible things with the pixels
|
||||||
|
|
||||||
# Gimp::GDrawable - The GDrawable structure
|
# Gimp::GDrawable - The GDrawable structure
|
||||||
# Gimp::Tile - The Tile family of functions.
|
# Gimp::Tile - The Tile family of functions.
|
||||||
@ -57,8 +59,8 @@ expects pixel coordinates and will return the tile that pixel is in:
|
|||||||
|
|
||||||
The C<data> method returns and sets the raw pixel data.
|
The C<data> method returns and sets the raw pixel data.
|
||||||
|
|
||||||
$packed_data = $tile->data; # you don't want this, use Gimp::PDL
|
$piddle = $tile->data; # get the tile data as a piddle
|
||||||
$tile->data($packed_data); # and modify the tile
|
$tile->data($piddle); # and modify the tile
|
||||||
|
|
||||||
=head1 PIXELREGIONS
|
=head1 PIXELREGIONS
|
||||||
|
|
||||||
@ -83,20 +85,20 @@ which method you choose is purely a question of style...
|
|||||||
The following functions return packed pixel data (see L<Gimp::PDL> for an
|
The following functions return packed pixel data (see L<Gimp::PDL> for an
|
||||||
easier way to manipulate on image data):
|
easier way to manipulate on image data):
|
||||||
|
|
||||||
$packed_data = $region->get_pixel(45,60); # return the pixel at (45|60)
|
$piddle = $region->get_pixel(45,60); # return the pixel at (45|60)
|
||||||
$packed_data = $region->get_row(45,60,10); # return ten horizontal pixels
|
$piddle = $region->get_row(45,60,10); # return ten horizontal pixels
|
||||||
$packed_data = $region->get_col(45,60,10); # same but vertically
|
$piddle = $region->get_col(45,60,10); # same but vertically
|
||||||
$packed_data = $region->get_rect(45,60,10,12); # a 10x12 rectangle
|
$piddle = $region->get_rect(45,60,10,12); # a 10x12 rectangle
|
||||||
|
|
||||||
To modify pixels, the dirty bit of the region must be set (I believe, but I
|
To modify pixels, the dirty bit of the region must be set (I believe, but I
|
||||||
don't see the reason what the dirty bit in a region is for so I might be
|
don't see the reason what the dirty bit in a region is for so I might be
|
||||||
wrong), and you can write pixel data to the region with the following
|
wrong), and you can write pixel data to the region with the following
|
||||||
functions, each one corresponding to a get-function:
|
functions, each one corresponding to a get-function:
|
||||||
|
|
||||||
$region->set_pixel($packed_data,45,60); # set pixel at (45|60)
|
$region->set_pixel($piddle,45,60); # set pixel at (45|60)
|
||||||
$region->set_row($packed_data,45,60); # set a row
|
$region->set_row($piddle,45,60); # set a row
|
||||||
$region->set_col($packed_data,45,60); # set a column
|
$region->set_col($piddle,45,60); # set a column
|
||||||
$region->set_rect($packed_data,45,60,10); # a 10 pixel wide rectangle
|
$region->set_rect($piddle,45,60,10); # a 10 pixel wide rectangle
|
||||||
|
|
||||||
Please note that (different to the C functions they call), the last
|
Please note that (different to the C functions they call), the last
|
||||||
parameter (width or height) is missing, it can be calculcated from the perl
|
parameter (width or height) is missing, it can be calculcated from the perl
|
||||||
@ -112,3 +114,4 @@ Marc Lehmann <pcg@goof.com>
|
|||||||
perl(1), Gimp(1).
|
perl(1), Gimp(1).
|
||||||
|
|
||||||
=cut
|
=cut
|
||||||
|
|
||||||
|
@ -41,22 +41,28 @@ reimplement all of it in perl.
|
|||||||
@Gimp::UI::ChannelMenu::ISA =qw(Gimp::UI);
|
@Gimp::UI::ChannelMenu::ISA =qw(Gimp::UI);
|
||||||
@Gimp::UI::DrawableMenu::ISA=qw(Gimp::UI);
|
@Gimp::UI::DrawableMenu::ISA=qw(Gimp::UI);
|
||||||
|
|
||||||
|
sub image_name {
|
||||||
|
my $name = $_[0]->get_filename;
|
||||||
|
$name.="-".${$_[0]} if $name eq "Untitled";
|
||||||
|
$name;
|
||||||
|
}
|
||||||
|
|
||||||
sub Gimp::UI::ImageMenu::_items {
|
sub Gimp::UI::ImageMenu::_items {
|
||||||
map [[$_],$_,$_->get_filename],
|
map [[$_],$_,image_name($_)],
|
||||||
Gimp->list_images ();
|
Gimp->list_images ();
|
||||||
}
|
}
|
||||||
sub Gimp::UI::LayerMenu::_items {
|
sub Gimp::UI::LayerMenu::_items {
|
||||||
map { my $i = $_; map [[$i,$_],$_,$i->get_filename."/".$_->get_name],$i->get_layers }
|
map { my $i = $_; map [[$i,$_],$_,image_name($i)."/".$_->get_name],$i->get_layers }
|
||||||
Gimp->list_images ();
|
Gimp->list_images ();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Gimp::UI::ChannelMenu::_items {
|
sub Gimp::UI::ChannelMenu::_items {
|
||||||
map { my $i = $_; map [[$i,$_],$_,$i->get_filename."/".$_->get_name],$i->get_channels }
|
map { my $i = $_; map [[$i,$_],$_,image_name($i)."/".$_->get_name],$i->get_channels }
|
||||||
Gimp->list_images ();
|
Gimp->list_images ();
|
||||||
}
|
}
|
||||||
|
|
||||||
sub Gimp::UI::DrawableMenu::_items {
|
sub Gimp::UI::DrawableMenu::_items {
|
||||||
map { my $i = $_; map [[$i,$_],$_,$i->get_filename."/".$_->get_name],($i->get_layers, $i->get_channels) }
|
map { my $i = $_; map [[$i,$_],$_,image_name($i)."/".$_->get_name],($i->get_layers, $i->get_channels) }
|
||||||
Gimp->list_images ();
|
Gimp->list_images ();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,7 +222,7 @@ sub layer_add_layer_as_mask {
|
|||||||
1;
|
1;
|
||||||
|
|
||||||
##############################################################################
|
##############################################################################
|
||||||
# all functions below are originally for the chart module
|
# all functions below are by Marc Lehmann
|
||||||
=pod
|
=pod
|
||||||
|
|
||||||
=item C<gimp_text_wh $text,$fontname>
|
=item C<gimp_text_wh $text,$fontname>
|
||||||
@ -236,6 +236,22 @@ sub gimp_text_wh {
|
|||||||
|
|
||||||
=pod
|
=pod
|
||||||
|
|
||||||
|
=item C<gimp_image_layertype $alpha>
|
||||||
|
|
||||||
|
returns the corresponding layer type for an image, alpha controls wether the layer type
|
||||||
|
is with alpha or not. Example: imagetype: RGB -> RGB_IMAGE (or RGBA_IMAGE).
|
||||||
|
|
||||||
|
=cut
|
||||||
|
sub gimp_image_layertype {
|
||||||
|
my $type = $_[0]->base_type;
|
||||||
|
$type == RGB ? $alpha ? RGBA_IMAGE : RGB_IMAGE :
|
||||||
|
$type == GRAY ? $alpha ? GRAYA_IMAGE : GRAY_IMAGE :
|
||||||
|
$type == INDEXED ? $alpha ? INDEXEDA_IMAGE : INDEXED_IMAGE :
|
||||||
|
die;
|
||||||
|
}
|
||||||
|
|
||||||
|
=pod
|
||||||
|
|
||||||
=back
|
=back
|
||||||
|
|
||||||
=head1 AUTHOR
|
=head1 AUTHOR
|
||||||
|
@ -56,3 +56,5 @@ examples/feedback.pl
|
|||||||
examples/xachlego.pl
|
examples/xachlego.pl
|
||||||
examples/xachshadow.pl
|
examples/xachshadow.pl
|
||||||
examples/parasite-editor
|
examples/parasite-editor
|
||||||
|
examples/scratches.pl
|
||||||
|
examples/blowinout.pl
|
||||||
|
@ -116,7 +116,8 @@ EOF
|
|||||||
|
|
||||||
@examples =
|
@examples =
|
||||||
qw(windy.pl prep4gif.pl webify.pl PDB alpha2color.pl tex-to-float ditherize.pl
|
qw(windy.pl prep4gif.pl webify.pl PDB alpha2color.pl tex-to-float ditherize.pl
|
||||||
border.pl view3d.pl feedback.pl xachlego.pl xachshadow.pl parasite-editor);
|
border.pl view3d.pl feedback.pl xachlego.pl xachshadow.pl parasite-editor
|
||||||
|
scratches.pl blowinout.pl);
|
||||||
@shebang = (map("examples/$_",@examples),
|
@shebang = (map("examples/$_",@examples),
|
||||||
qw(Perl-Server scm2perl scm2scm examples/example-net.pl examples/homepage-logo.pl
|
qw(Perl-Server scm2perl scm2scm examples/example-net.pl examples/homepage-logo.pl
|
||||||
examples/example-fu.pl));
|
examples/example-fu.pl));
|
||||||
|
@ -10,14 +10,13 @@ make test TEST_VERBOSE=1
|
|||||||
|
|
||||||
bugs
|
bugs
|
||||||
|
|
||||||
[DONE] * auto-edit shebang
|
|
||||||
[XXXX] * only install plug-ins that really work
|
|
||||||
* perl_fu_webify in homepage-logo.pl
|
* perl_fu_webify in homepage-logo.pl
|
||||||
* wait for working gimp_file_load (or do it myself?)
|
* wait for working gimp_file_load (or do it myself?)
|
||||||
[DONE] * Gimp::import should croak on importing "garbage".
|
|
||||||
|
|
||||||
important issues
|
important issues
|
||||||
|
|
||||||
|
* fix auto-edit shebang for check-ins
|
||||||
|
* gimp-tiles are not accessible in any way..
|
||||||
* register dummy function to calm gimp down
|
* register dummy function to calm gimp down
|
||||||
* paths in module(!)
|
* paths in module(!)
|
||||||
* gimp->object_id, drawable_object_id remove!
|
* gimp->object_id, drawable_object_id remove!
|
||||||
@ -44,7 +43,7 @@ important issues
|
|||||||
* create working progress when Net and $verbose
|
* create working progress when Net and $verbose
|
||||||
* require Storable soon(!)
|
* require Storable soon(!)
|
||||||
* Gimp::Fu::command(?)
|
* Gimp::Fu::command(?)
|
||||||
* Untitled/0 Untitled/1 etc..
|
[DONE] * Untitled/0 Untitled/1 etc..
|
||||||
* default parameters at end(!)
|
* default parameters at end(!)
|
||||||
* try to deduce default parameters
|
* try to deduce default parameters
|
||||||
|
|
||||||
|
108
plug-ins/perl/examples/blowinout.pl
Executable file
108
plug-ins/perl/examples/blowinout.pl
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
# Blow In/Out
|
||||||
|
# John Pitney
|
||||||
|
|
||||||
|
use Gimp;
|
||||||
|
use Gimp::Fu;
|
||||||
|
|
||||||
|
# print "hello there\n";
|
||||||
|
|
||||||
|
# Gimp::set_trace(TRACE_CALL);
|
||||||
|
|
||||||
|
|
||||||
|
sub blowinout {
|
||||||
|
my ($img, $drawable, $angle, $nsteps, $distance, $inmode, $arithmode) = @_;
|
||||||
|
# bail out if $drawable isn't a layer
|
||||||
|
# print "Starting\n";
|
||||||
|
if( gimp_selection_is_empty($img) == 0) { return };
|
||||||
|
# if ($nsteps == 0) return;
|
||||||
|
eval { $img->undo_push_group_start };
|
||||||
|
# save the background color for later restoration
|
||||||
|
my $oldbg = gimp_palette_get_background();
|
||||||
|
#get the drawable dimensions
|
||||||
|
my $xsize = gimp_drawable_width($drawable);
|
||||||
|
my $ysize = gimp_drawable_height($drawable);
|
||||||
|
|
||||||
|
# Set background color to 128, for clearing dm
|
||||||
|
gimp_palette_set_background([128,128,128]);
|
||||||
|
|
||||||
|
# Create a grayscale workspace image for displacement map
|
||||||
|
my $dm = gimp_image_new($xsize, $ysize, 1);
|
||||||
|
eval { $dm->undo_push_group_start($dm) };
|
||||||
|
# It needs to have 2 layers
|
||||||
|
my $dmlayer = gimp_layer_new($dm, $xsize, $ysize, GRAY_IMAGE, "newlayer",
|
||||||
|
100, NORMAL_MODE);
|
||||||
|
gimp_image_add_layer($dm, $dmlayer, 0);
|
||||||
|
|
||||||
|
# Create the layers, one-by-one
|
||||||
|
my $i = 1;
|
||||||
|
my $xdist = ($arithmode) ?
|
||||||
|
$i * $distance / $nsteps * -cos($angle * 3.14159 / 180) :
|
||||||
|
$distance ** ($i/$nsteps) * -cos($angle * 3.14159 / 180);
|
||||||
|
my $ydist = ($arithmode) ?
|
||||||
|
$i * $distance / $nsteps * sin($angle * 3.14159 / 180) :
|
||||||
|
$distance ** ($i/$nsteps) * sin($angle * 3.14159 / 180);
|
||||||
|
gimp_edit_clear($dmlayer);
|
||||||
|
plug_in_noisify(1, $dm, $dmlayer, 0, 255, 255, 255, 0);
|
||||||
|
gimp_levels($dmlayer, 0, 0, 255, 1.0, 128, 255);
|
||||||
|
$drawable = gimp_layer_copy($drawable, 0);
|
||||||
|
gimp_image_add_layer($img, $drawable, -1);
|
||||||
|
plug_in_displace(1, $img, $drawable, $xdist, $ydist, 1, 1, $dmlayer,
|
||||||
|
$dmlayer, 1);
|
||||||
|
if ( $inmode == 1 )
|
||||||
|
{
|
||||||
|
gimp_image_lower_layer($img, $drawable);
|
||||||
|
};
|
||||||
|
for ( $i = 2; $i <= $nsteps; $i++ ) {
|
||||||
|
$xdist = ($arithmode) ?
|
||||||
|
$i * $distance / $nsteps * -cos($angle * 3.14159 / 180) :
|
||||||
|
$distance ** ($i/$nsteps) * -cos($angle * 3.14159 / 180);
|
||||||
|
$ydist = ($arithmode) ?
|
||||||
|
$i * $distance / $nsteps * sin($angle * 3.14159 / 180) :
|
||||||
|
$distance ** ($i/$nsteps) * sin($angle * 3.14159 / 180);
|
||||||
|
gimp_edit_clear($dmlayer);
|
||||||
|
plug_in_noisify(1, $dm, $dmlayer, 0, 255, 255, 255, 0);
|
||||||
|
gimp_levels($dmlayer, 0, 0, 255, 1.0, 128, 255);
|
||||||
|
$drawable = gimp_layer_copy($drawable, 0);
|
||||||
|
gimp_image_add_layer($img, $drawable, -1);
|
||||||
|
plug_in_displace(1, $img, $drawable, $xdist, $ydist, 1, 1, $dmlayer,
|
||||||
|
$dmlayer, 1);
|
||||||
|
if ( $inmode == 1 )
|
||||||
|
{
|
||||||
|
gimp_image_lower_layer($img, $drawable);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
eval { $dm->undo_push_group_end };
|
||||||
|
# gimp_image_remove_layer($dm, $dmlayer);
|
||||||
|
# gimp_image_delete ($dm);
|
||||||
|
gimp_palette_set_background($oldbg);
|
||||||
|
eval { $img->undo_push_group_end };
|
||||||
|
# gimp_displays_flush(); unneccessary (and dangerous ;)
|
||||||
|
|
||||||
|
(); # I like smileys ;)
|
||||||
|
}
|
||||||
|
|
||||||
|
register
|
||||||
|
"blowinout",
|
||||||
|
"Blow selected layer inout",
|
||||||
|
"Generates an animation thats blows the selected layer in or out",
|
||||||
|
"John Pitney",
|
||||||
|
"John Pitney <pitney\@students.uiuc.edu>",
|
||||||
|
"1999-02-24",
|
||||||
|
"<Image>/Filters/Distorts/BlowInOut",
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
[PF_INT32, "angle", "Wind Angle, 0 is left", 120],
|
||||||
|
[PF_INT32, "steps", "Number of Steps/Layers", 5],
|
||||||
|
[PF_VALUE, "distance", "How far to blow",30],
|
||||||
|
# What I really need here are radio buttons! Maybe they even exist...
|
||||||
|
# You wanted them...
|
||||||
|
[PF_RADIO, "direction", "Blow direction", 0, [["In", 1],["Out", 0]]],
|
||||||
|
[PF_RADIO, "series", "Kind of series", 1, [["Arithmetic",1],["Geometric",0]]]
|
||||||
|
],
|
||||||
|
\&blowinout;
|
||||||
|
|
||||||
|
exit main;
|
||||||
|
|
66
plug-ins/perl/examples/scratches.pl
Executable file
66
plug-ins/perl/examples/scratches.pl
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
#!/usr/bin/perl
|
||||||
|
|
||||||
|
use Gimp;
|
||||||
|
use Gimp::Fu;
|
||||||
|
use Gimp::Util;
|
||||||
|
use Gimp::PDL;
|
||||||
|
|
||||||
|
sub new_scratchlayer {
|
||||||
|
my($image,$length,$gamma,$angle)=@_;
|
||||||
|
my $type=$image->layertype(0);
|
||||||
|
my($layer)=$image->layer_new ($image->width, $image->height, $image->layertype(0),
|
||||||
|
"displace layer ($angle)", 100, NORMAL_MODE);
|
||||||
|
$layer->add_layer(-1);
|
||||||
|
$layer->fill (WHITE_IMAGE_FILL);
|
||||||
|
$layer->noisify (0, 1, 1, 1, 0);
|
||||||
|
$layer->mblur (0, $length, $angle);
|
||||||
|
$layer->levels (VALUE, 120, 255, $gamma, 0, 255);
|
||||||
|
|
||||||
|
$layer;
|
||||||
|
}
|
||||||
|
|
||||||
|
register "scratches",
|
||||||
|
"Create a scratch effect",
|
||||||
|
"Add scratches to an existing image. Works best on a metallic-like background.",
|
||||||
|
"Marc Lehmann",
|
||||||
|
"Marc Lehmann <pcg\@goof.com>",
|
||||||
|
"19990223",
|
||||||
|
"<Image>/Filters/Distorts/Scratches",
|
||||||
|
"*",
|
||||||
|
[
|
||||||
|
[PF_SLIDER , "angle_x" , "The horizontal angle" , 30, [ 0, 360]],
|
||||||
|
[PF_SLIDER , "angle_y" , "The vertical angle" , 70, [ 0, 360]],
|
||||||
|
[PF_SLIDER , "gamma" , "Scratch map gamma" , 0.3, [0.1, 10, 0.05]],
|
||||||
|
[PF_SPINNER , "smoothness" , "The scratch smoothness" , 15, [ 0, 400]],
|
||||||
|
[PF_SPINNER , "length" , "The scratch length" , 10, [ 0, 400]],
|
||||||
|
#[PF_BOOL, , "bump_map" , "Use bump map instead of displace", 0],
|
||||||
|
],
|
||||||
|
sub {
|
||||||
|
my($image,$drawable,$anglex,$angley,$gamma,$length,$width)=@_;
|
||||||
|
|
||||||
|
$image->undo_push_group_start;
|
||||||
|
|
||||||
|
my $layer1 = new_scratchlayer ($image, $length, $gamma, $anglex);
|
||||||
|
my $layer2 = new_scratchlayer ($image, $length, $gamma, $angley);
|
||||||
|
|
||||||
|
$drawable->displace ($width, $width, 1, 1, $layer1, $layer2, WRAP);
|
||||||
|
|
||||||
|
$layer1->remove_layer;
|
||||||
|
$layer2->remove_layer;
|
||||||
|
|
||||||
|
$image->undo_push_group_end;
|
||||||
|
|
||||||
|
$image;
|
||||||
|
};
|
||||||
|
|
||||||
|
exit main;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
Reference in New Issue
Block a user