Initial commit 0.001
authorMarius Gavrilescu <marius@ieval.ro>
Sat, 25 Apr 2015 15:25:06 +0000 (18:25 +0300)
committerMarius Gavrilescu <marius@ieval.ro>
Sat, 25 Apr 2015 15:25:06 +0000 (18:25 +0300)
Changes [new file with mode: 0644]
MANIFEST [new file with mode: 0644]
Makefile.PL [new file with mode: 0644]
README [new file with mode: 0644]
lib/SVG/SpriteMaker.pm [new file with mode: 0644]
svg-spritemaker [new file with mode: 0755]
t/SVG-SpriteMaker.t [new file with mode: 0644]
t/circle.svg [new file with mode: 0644]
t/perlcritic.t [new file with mode: 0644]
t/perlcriticrc [new file with mode: 0644]
t/rect.svg [new file with mode: 0644]

diff --git a/Changes b/Changes
new file mode 100644 (file)
index 0000000..fa1de77
--- /dev/null
+++ b/Changes
@@ -0,0 +1,4 @@
+Revision history for Perl extension SVG::SpriteMaker.
+
+0.001 2015-04-25T18:25+03:00
+ - Initial release
diff --git a/MANIFEST b/MANIFEST
new file mode 100644 (file)
index 0000000..dacf5b4
--- /dev/null
+++ b/MANIFEST
@@ -0,0 +1,11 @@
+Changes
+lib/SVG/SpriteMaker.pm
+Makefile.PL
+MANIFEST
+README
+svg-spritemaker
+t/circle.svg
+t/perlcritic.t
+t/perlcriticrc
+t/rect.svg
+t/SVG-SpriteMaker.t
diff --git a/Makefile.PL b/Makefile.PL
new file mode 100644 (file)
index 0000000..3d950e7
--- /dev/null
@@ -0,0 +1,23 @@
+use 5.014000;
+use ExtUtils::MakeMaker;
+
+WriteMakefile(
+       NAME              => 'SVG::SpriteMaker',
+       VERSION_FROM      => 'lib/SVG/SpriteMaker.pm',
+       ABSTRACT_FROM     => 'lib/SVG/SpriteMaker.pm',
+       AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
+       EXE_FILES         => ['svg-spritemaker'],
+       MIN_PERL_VERSION  => 5.014000,
+       LICENSE           => 'perl',
+       SIGN              => 1,
+       PREREQ_PM         => {
+               qw/SVG         0
+                  SVG::Parser 0/,
+       },
+       META_MERGE         => {
+               dynamic_config => 0,
+               resources      => {
+                       repository => 'https://git.ieval.ro/?p=svg-spritemaker.git'
+               },
+       }
+);
diff --git a/README b/README
new file mode 100644 (file)
index 0000000..dc2011b
--- /dev/null
+++ b/README
@@ -0,0 +1,46 @@
+SVG-SpriteMaker version 0.001
+=============================
+
+This distribution includes:
+* SVG::SpriteMaker, a library for creating SVG sprites
+* svg-spritemaker, a simple command-line interface to the library
+
+A SVG sprite is a SVG image that contains several smaller images that
+can be referred to using fragment identifiers. For example, this HTML
+fragment:
+
+  <img src="/img/cat.svg" alt="A cat">
+  <img src="/img/dog.svg" alt="A dog">
+  <img src="/img/horse.svg" alt="A horse">
+
+Can be replaced with
+
+  <img src="/img/sprite.svg#cat" alt="A cat">
+  <img src="/img/sprite.svg#dog" alt="A dog">
+  <img src="/img/sprite.svg#horse" alt="A horse">
+
+INSTALLATION
+
+To install this module type the following:
+
+   perl Makefile.PL
+   make
+   make test
+   make install
+
+DEPENDENCIES
+
+This module requires these other modules and libraries:
+
+* SVG
+* SVG::Parser
+
+COPYRIGHT AND LICENCE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
diff --git a/lib/SVG/SpriteMaker.pm b/lib/SVG/SpriteMaker.pm
new file mode 100644 (file)
index 0000000..c35399c
--- /dev/null
@@ -0,0 +1,128 @@
+package SVG::SpriteMaker;
+
+use 5.014000;
+use strict;
+use warnings;
+
+our $VERSION = '0.001';
+our @EXPORT = qw/make_sprite make_sprite_prefix/;
+our @EXPORT_OK = @EXPORT;
+
+use parent qw/Exporter/;
+use re '/s';
+
+use Carp;
+use File::Basename;
+
+use SVG -indent => '', -elsep => '';
+use SVG::Parser;
+
+sub make_sprite {
+       my ($prefix, @images) = @_;
+       my $sub = ref $prefix eq 'CODE' ? $prefix : sub {
+               my $base = scalar fileparse $_[0], qr/[.].*/;
+               "$prefix-$base"
+       };
+       my $sprite = SVG->new(-inline => 1);
+       my $parser = SVG::Parser->new;
+       @images = map {[ $sub->($_) => $parser->parse_file($_) ]} @images;
+       my ($x, $mh) = (0, 0);
+
+       for (@images) {
+               my ($img, $doc) = @$_;
+               my $svg = $doc->getFirstChild;
+               my ($w) = $svg->attr('width') =~ /([0-9.]*)/ or carp "Image $img has no width";
+               my ($h) = $svg->attr('height') =~ /([0-9.]*)/ or carp "Image $img has no height";
+               $mh = $h if $h > $mh;
+               $svg->attr(x => $x);
+               $svg->attr(version => undef);
+               my $view = $sprite->view(id => $img, viewBox => "$x 0 $w $h");
+               $x += $w + 5;
+               $view->getParent->insertAfter($svg, $view);
+       }
+
+       # Keep a reference to the documents to prevent garbage collection
+       $sprite->{'--images'} = \@images;
+       $sprite->getFirstChild->attr(viewBox => "0 0 $x $mh");
+       $sprite
+}
+
+1;
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+SVG::SpriteMaker - Combine several SVG images into a single SVG sprite
+
+=head1 SYNOPSIS
+
+  use File::Slurp qw/write_file/;
+  use SVG::SpriteMaker;
+  my $sprite = make_sprite img => '1.svg', '2.svg', '3.svg';
+  write_file 'sprite.svg', $sprite->xmlify;
+  # You can now use <img src="sprite.svg#img-1" alt="...">
+
+  my @images = <dir/*>; # dir/ImageA.svg dir/ImageB.svg
+  $sprite = make_sprite sub {
+    my ($name) = $_[0] =~ m,/([^/.]*),;
+    uc $name
+  }, @images; # Sprite will have identifiers #IMAGEA #IMAGEB
+
+=head1 DESCRIPTION
+
+A SVG sprite is a SVG image that contains several smaller images that
+can be referred to using fragment identifiers. For example, this HTML
+fragment:
+
+  <img src="/img/cat.svg" alt="A cat">
+  <img src="/img/dog.svg" alt="A dog">
+  <img src="/img/horse.svg" alt="A horse">
+
+Can be replaced with
+
+  <img src="/img/sprite.svg#cat" alt="A cat">
+  <img src="/img/sprite.svg#dog" alt="A dog">
+  <img src="/img/sprite.svg#horse" alt="A horse">
+
+This module exports a single function:
+
+=head2 B<make_sprite>(I<$prefix>|I<$coderef>, I<@files>)
+
+Takes a list of filenames, combines them and returns the resulting
+sprite as a L<SVG> object. Each SVG must have width and height
+attributes whose values are in pixels.
+
+If the first argument is a coderef, it will be called with each
+filename as a single argument and it should return the desired
+fragment identifier.
+
+If the first argument is not a coderef, the following coderef will be
+used:
+
+  sub {
+    my $base = scalar fileparse $_[0], qr/\..*/s;
+    "$prefix-$base"
+  };
+
+where I<$prefix> is the value of the first argument.
+
+=head1 SEE ALSO
+
+L<svg-sprite>, L<https://css-tricks.com/svg-fragment-identifiers-work/>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/svg-spritemaker b/svg-spritemaker
new file mode 100755 (executable)
index 0000000..3762063
--- /dev/null
@@ -0,0 +1,80 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use Getopt::Long;
+use SVG::SpriteMaker;
+
+my $prefix = 'sprite';
+my $out;
+
+GetOptions(
+       'prefix|p=s' => \$prefix,
+       'output|out|o=s' => \$out,
+);
+
+my $sprite = make_sprite $prefix, @ARGV;
+if ($out) {
+       open my $fh, '>', $out;
+       select $fh;
+}
+say $sprite->xmlify;
+
+__END__
+
+=encoding utf-8
+
+=head1 NAME
+
+svg-spritemaker - Combine several SVG images into a single SVG sprite
+
+=head1 SYNOPSIS
+
+  svg-spritemaker [-o OUTPUT] [-p PREFIX] FILE...
+
+  svg-spritemaker a.svg b.svg > sprite.svg                 # Standard usage
+  svg-spritemaker -p img a.svg b.svg > sprite.svg          # Custom prefix
+  svg-spritemaker -o sprite.svg dir/*.svg                  # Output file
+  svg-spritemaker --prefix=logo --output=logos.svg logos/* # Long options
+
+=head1 DESCRIPTION
+
+svg-spritemaker takes several SVG images and combines them into a
+single SVG sprite. See L<SVG::SpriteMaker> for more information about
+SVG sprites.
+
+=head1 OPTIONS
+
+=over
+
+=item B<-o> I<file>, B<--out>=I<file>, B<--output>=I<file>
+
+Write the sprite into the following file, overwriting it if necessary.
+By default the sprite is written on STDOUT.
+
+=item B<-p> I<prefix>, B<--prefix>=I<prefix>
+
+Sets the prefix for the fragment identifiers. Default is C<sprite>
+(which results in identifiers C<sprite-a>, C<sprite-b> for the first
+example in the SYNOPSIS).
+
+=back
+
+=head1 SEE ALSO
+
+L<SVG::SpriteMaker>, L<https://css-tricks.com/svg-fragment-identifiers-work/>
+
+=head1 AUTHOR
+
+Marius Gavrilescu, E<lt>marius@ieval.roE<gt>
+
+=head1 COPYRIGHT AND LICENSE
+
+Copyright (C) 2015 by Marius Gavrilescu
+
+This library is free software; you can redistribute it and/or modify
+it under the same terms as Perl itself, either Perl version 5.20.2 or,
+at your option, any later version of Perl 5 you may have available.
+
+
+=cut
diff --git a/t/SVG-SpriteMaker.t b/t/SVG-SpriteMaker.t
new file mode 100644 (file)
index 0000000..b83a939
--- /dev/null
@@ -0,0 +1,12 @@
+#!/usr/bin/perl
+use strict;
+use warnings;
+
+use Test::More tests => 3;
+BEGIN { use_ok('SVG::SpriteMaker') };
+
+my $sprite = make_sprite frag => <t/*.svg>;
+my @elements = $sprite->getFirstChild->getChildren;
+
+ok $sprite->getElementByID('frag-rect'), 'sprite contains #frag-rect';
+ok $sprite->getElementByID('frag-circle'), 'sprite contains #frag-circle';
diff --git a/t/circle.svg b/t/circle.svg
new file mode 100644 (file)
index 0000000..0e1ecb9
--- /dev/null
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 10 10">
+       <circle fill="red" stroke="none" cx="5" cy="5" r="4"/>
+</svg>
diff --git a/t/perlcritic.t b/t/perlcritic.t
new file mode 100644 (file)
index 0000000..79e93dc
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/perl
+use v5.14;
+use warnings;
+
+use Test::More;
+
+BEGIN { plan skip_all => '$ENV{RELEASE_TESTING} is false' unless $ENV{RELEASE_TESTING} }
+use Test::Perl::Critic -profile => 't/perlcriticrc';
+
+all_critic_ok 'lib'
diff --git a/t/perlcriticrc b/t/perlcriticrc
new file mode 100644 (file)
index 0000000..5815f07
--- /dev/null
@@ -0,0 +1,36 @@
+severity = 1
+
+[-BuiltinFunctions::ProhibitComplexMappings]
+[-CodeLayout::RequireTidyCode]
+[-ControlStructures::ProhibitPostfixControls]
+[-ControlStructures::ProhibitUnlessBlocks]
+[-Documentation::PodSpelling]
+[-Documentation::RequirePodLinksIncludeText]
+[-InputOutput::RequireBracedFileHandleWithPrint]
+[-Modules::ProhibitAutomaticExportation]
+[-References::ProhibitDoubleSigils]
+[-RegularExpressions::ProhibitEnumeratedClasses]
+[-RegularExpressions::RequireLineBoundaryMatching]
+[-Subroutines::RequireFinalReturn]
+[-ValuesAndExpressions::ProhibitConstantPragma]
+[-ValuesAndExpressions::ProhibitEmptyQuotes]
+[-ValuesAndExpressions::ProhibitLeadingZeros]
+[-ValuesAndExpressions::ProhibitMagicNumbers]
+[-ValuesAndExpressions::ProhibitNoisyQuotes]
+[-Variables::ProhibitLocalVars]
+[-Variables::ProhibitPackageVars]
+[-Variables::ProhibitPunctuationVars]
+
+[BuiltinFunctions::ProhibitStringyEval]
+allow_includes = 1
+
+[RegularExpressions::RequireExtendedFormatting]
+minimum_regex_length_to_complain_about = 20
+
+[Documentation::RequirePodSections]
+lib_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+script_sections = NAME | SYNOPSIS | DESCRIPTION | AUTHOR | COPYRIGHT AND LICENSE
+
+[Subroutines::RequireArgUnpacking]
+short_subroutine_statements = 5
+allow_subscripts = 1
diff --git a/t/rect.svg b/t/rect.svg
new file mode 100644 (file)
index 0000000..955293d
--- /dev/null
@@ -0,0 +1,3 @@
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" width="200" height="200" viewBox="0 0 10 10">
+       <rect fill="blue" stroke="none" x="1" y="1" width="8" height="8" rx="1" ry="1"/>
+</svg>
This page took 0.017874 seconds and 4 git commands to generate.