Image-Magick-CommandParser

 view release on metacpan or  search on metacpan

lib/Image/Magick/CommandParser.pm  view on Meta::CPAN

package Image::Magick::CommandParser;

use strict;
use warnings;
use warnings  qw(FATAL utf8);    # Fatalize encoding glitches.

use Data::Section::Simple 'get_data_section';

use File::Glob;
use File::Slurper 'read_lines';

use Log::Handler;

use Moo;

use Set::Array;

use Set::FA::Element;

use Types::Standard qw/Any ArrayRef HashRef Str/;

has built_in_images =>
(
	default  => sub{return ''},
	is       => 'rw',
	isa      => Str,
	required => 0,
);

has built_in_patterns =>
(
	default  => sub{return ''},
	is       => 'rw',
	isa      => Str,
	required => 0,
);

has command =>
(
	default  => sub{return ''},
	is       => 'rw',
	isa      => Str,
	required => 0,
);

has dfa =>
(
	default  => sub{return ''},
	is       => 'rw',
	isa      => Any,
	required => 0,
);

has field =>
(
	default  => sub{return []},
	is       => 'rw',
	isa      => ArrayRef,
	required => 0,
);

lib/Image/Magick/CommandParser.pm  view on Meta::CPAN


		if ($k <= $limit)
		{
			splice(@field, $j, $k - $j + 1, join(' ', @field[$j .. $k]) );

			$limit -= $k - $j;
		}
	}

	# Here we jam @field into an attribute of the object because input like @include.me
	# means the contents of that file have to be interpolated into the input stream.
	# The interpolation takes place in function (not method) parameter().
	# And we use $finished to allow for stand-alone 0 to be a field.

	$self -> field([@field]);

	my($finished) = 0;

	my($field);

	while (! $finished)
	{
		$field = shift @{$self -> field};

		if (! defined $field)
		{
			$finished = 1;
		}
		else
		{
			$self -> dfa -> step($field);
		}
	}

	$self -> log(info => '# At end, current state: ' . $self -> dfa -> current);
	$self -> log(info => "# Processed input string: $command");

	if (length($output_file_name) > 0)
	{
		$myself -> stack -> push
		({
			token	=> $output_file_name,
			type	=> 'output_file_name',
		});
	}

	# Return 0 for success and 1 for failure.

	return 0;

} # End of run.

# ------------------------------------------------

1;

=pod

=head1 NAME

C<Image::Magick::CommandParser> - Parse any command line acceptable to convert or mogrify

=head1 Synopsis

This is scripts/synopsis.pl:

	#!/usr/bin/env perl

	use strict;
	use warnings;
	use warnings qw(FATAL utf8);

	use Image::Magick::CommandParser;

	# ----------------------------------------------

	my($command)	= 'convert colors/*s*.png -append output.png';
	my($processor)	= Image::Magick::CommandParser -> new
	(
		command		=> $command,
		maxlevel	=> 'notice',
	);

	$processor -> run;

	print 'Input:  ', $command, "\n";
	print 'Result: ', $processor -> result, "\n";

With its output (after running in the distro dir, with access to colors/*.png):

	Input:  convert colors/*s*.png -append output.png
	Result: convert colors/fuchsia.png colors/silver.png -append output.png

=head1 Description

C<Image::Magick::CommandParser> is a stand-alone parser for command lines acceptable to the
L<Imagemagick|https://imagemagick.org> programs C<convert> and C<mogrify>.

It aims to handle all constructs supported by Imagemagick itself, but it's vital to understand
that this module does not use any component of Imagemagick. Hence the I<stand-alone> just above.

In particular the output is a stack, accessible via the C<< $object -> stack >> method, which
returns an array of hashrefs.

The stack is managed by an object of type L<Set::Array>. See the L</FAQ> for details.

The result - as a space-separated string of tokens detected in the command - is returned by
L</result()>.

The actual parsing is done with L<Set::FA::Element>.

Consult the L</FAQ> and t/test.t for specific examples of command line options supported. A few of
them are included here:

=over 4

=item o All command options of the form [-+][a-zA-Z]+

=item o Redirecting input from files

=over 4

=item o convert magick:rose -label @t/label.1.txt -format "%l label" rose.png

=back

=item o File globbing

=over 4

=item o convert colors/*s*.png -append output.png

=back

=item o Explicit image format

=over 4

=item o convert rgb:camera.image -size 320x85 output.png

=back

=item o Built-in images and patterns

=over 4

=item o convert pattern:bricks -size 320x85 output.png

=back

=item o Standard input and output

=over 4

=item o convert gif:- -size 320x85 output.png

lib/Image/Magick/CommandParser.pm  view on Meta::CPAN


=item o The apparently endless variations of the geometry parameter

Samples:

=over 4

=item o 320x85

=item o 50%

=item o 60%x40

=item o 320x85+0+0

=item o 60x40%+0+0

=item o 50%!+0+0

=back

=item o Built-in special files

Samples:

=over 4

=item o logo:

=item o magick:rose

=back

=item o Output label format strings

=over 4

=item o convert magick:rose -label "%wx%h" -format "%l label" rose.png

=back

=item o The image stack and cloning

=over 4

=item o convert label.gif ( +clone -shade 110x90 -normalize -negate +clone -compose Plus -composite ) button.gif

=item o convert label.gif +clone 0,4,5 button.gif

=back

=back

Imagemagick has a web page, L<http://imagemagick.org/script/command-line-processing.php>, dedicated
to the features available in its command line processing code. Please report any cases where this
module does not support one of those features. But see L</Trouble-shooting> before reporting an
issue, since there I list a few special cases.

=head1 Installation

Install C<Image::Magick::CommandParser> as you would for any C<Perl> module:

Run:

	cpanm Image::Magick::CommandParser

or run:

	sudo cpan Image::Magick::CommandParser

or unpack the distro, and then:

	perl Makefile.PL
	make (or dmake or nmake)
	make test
	make install

=head1 Constructor and Initialization

Call C<new()> as C<< my($parser) = Image::Magick::CommandParser -> new(k1 => v1, k2 => v2, ...) >>.

It returns a new object of type C<Image::Magick::CommandParser>.

Key-value pairs accepted in the parameter list (see also the corresponding methods
[e.g. L</command([$string])>]):

=over 4

=item o command => $string

The command string to process.

Default: ''.

=item o logger => $logger_object

Specify a logger object.

The default value triggers creation of an object of type L<Log::Handler> which outputs to the
screen.

To disable logging, just set I<logger> to the empty string.

Default: undef.

=item o maxlevel => $level

This option is only used if an object of type L<Log::Handler> is created. See I<logger> above.

See also L<Log::Handler::Levels>.

Nothing is printed by default.

Default: 'notice'. Typical value is 'debug' and 'info'.

=item o minlevel => $level

This option is only used if an object of type L<Log::Handler> is created. See I<logger> above.

See also L<Log::Handler::Levels>.

Default: 'error'.

No lower levels are used.

=back

=head1 Methods

=head2 command([$string])

Here, the [] indicate an optional parameter.

Get or set the command line string to be processed.

=head2 log($level, $s)

Calls $self -> logger -> log($level => $s) if ($self -> logger).

=head2 logger([$logger_object])

Here, the [] indicate an optional parameter.

lib/Image/Magick/CommandParser.pm  view on Meta::CPAN

See L</result()> just above for how to use this object.

=head1 FAQ

=head2 What is the format of stack items?

They are hashrefs, with these keys:

=over 4

=item o token

This is the token extracted from the command line.

Note: In the cases of file globbing and redirection of input from a file, these tokens are I<after>
expansion of such items.

=item o type

This is my classification of the type of token detected. The values taken by C<type> are:

=over 4

=item o action

=item o close_parenthesis

=item o command

=item o done

In this case, the C<token> will be the empty string.

=item o input_file

This is used for both explicit file names and for each file name produced by expanding globs.

=item o open_parenthesis

=item o output_file

=item o operator

=item o parameter

=back

=back

=head2 Why do you use pairs of states such as 'action' and 'action_1'?

The way L<Set::FA::Element> was designed, it will not move from a state to the same state when the
input matches. So, to trigger the entry or exit subs, I have to rock back-and-forth between 2
states which are more-or-less identical.

=head1 Trouble-shooting

=head2 Installation failure

I had a failure when installing the module on my laptop for the 1st time. The problem was that,
somehow, during the installation of L<Image::Magick>, root had become the owner of a directory
under the control of perlbrew. To fix this, I had to do:

	sudo chown ron:ron /home/ron/perl5/perlbrew/perls/perl-5.20.2/lib/site_perl/5.20.2/x86_64-linux/auto/Image/Magick

=head2 Regions specified as '@100000' are not supported

So, you must put the '@' at the end of the region:

	convert magick:logo -resize '10000@' wiz10000.png

=head2 Frame references are not supported

So, this won't work:

	convert 'images.gif[0]' image.png

=head1 See Also

L<Imager>

L<Image::Magick::Chart>

L<Image::Magick::PolyText>

L<Image::Magick::Tiler>

L<Set::Array>

L<Set::FA::Element>

=head1 Machine-Readable Change Log

The file Changes was converted into Changelog.ini by L<Module::Metadata::Changes>.

=head1 Version Numbers

Version numbers < 1.00 represent development versions. From 1.00 up, they are production versions.

=head1 Repository

L<https://github.com/ronsavage/Image-Magick-CommandParser>

=head1 Support

Email the author, or log a bug on RT:

L<https://rt.cpan.org/Public/Dist/Display.html?Name=Image::Magick::CommandParser>.

=head1 Author

C<Image::Magick::CommandParser> was written by Ron Savage I<E<lt>ron@savage.net.auE<gt>> in 2016.

My homepage: L<http://savage.net.au/>

=head1 Copyright

Australian copyright (c) 2016, Ron Savage.

	All Programs of mine are 'OSI Certified Open Source Software';
	you can redistribute them and/or modify them under the terms of
	The Perl License, a copy of which is available at:
	http://dev.perl.org/licenses/

=cut

__DATA__
@@ built_in_images
granite
logo
netscape
rose
wizard

@@ built_in_patterns
bricks
checkerboard
circles
crosshatch
crosshatch30
crosshatch45
fishscales
gray0
gray5
gray10
gray15
gray20
gray25
gray30
gray35
gray40
gray45
gray50
gray55
gray60
gray65
gray70
gray75
gray80
gray85
gray90
gray95
gray100
hexagons
horizontal
horizontal2
horizontal3
horizontalsaw
hs_bdiagonal
hs_cross
hs_diagcross
hs_fdiagonal



( run in 1.329 second using v1.01-cache-2.11-cpan-39bf76dae61 )