From b1b509f4862aedc4a3388c6ba25e800c0aa4ccd1 Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Sat, 25 Apr 2015 18:25:06 +0300 Subject: [PATCH 1/1] Initial commit --- Changes | 4 ++ MANIFEST | 11 ++++ Makefile.PL | 23 ++++++++ README | 46 +++++++++++++++ lib/SVG/SpriteMaker.pm | 128 +++++++++++++++++++++++++++++++++++++++++ svg-spritemaker | 80 ++++++++++++++++++++++++++ t/SVG-SpriteMaker.t | 12 ++++ t/circle.svg | 3 + t/perlcritic.t | 10 ++++ t/perlcriticrc | 36 ++++++++++++ t/rect.svg | 3 + 11 files changed, 356 insertions(+) create mode 100644 Changes create mode 100644 MANIFEST create mode 100644 Makefile.PL create mode 100644 README create mode 100644 lib/SVG/SpriteMaker.pm create mode 100755 svg-spritemaker create mode 100644 t/SVG-SpriteMaker.t create mode 100644 t/circle.svg create mode 100644 t/perlcritic.t create mode 100644 t/perlcriticrc create mode 100644 t/rect.svg diff --git a/Changes b/Changes new file mode 100644 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 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 index 0000000..3d950e7 --- /dev/null +++ b/Makefile.PL @@ -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 ', + 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 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: + + A cat + A dog + A horse + +Can be replaced with + + A cat + A dog + 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 index 0000000..c35399c --- /dev/null +++ b/lib/SVG/SpriteMaker.pm @@ -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 ... + + my @images = ; # 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: + + A cat + A dog + A horse + +Can be replaced with + + A cat + A dog + A horse + +This module exports a single function: + +=head2 B(I<$prefix>|I<$coderef>, I<@files>) + +Takes a list of filenames, combines them and returns the resulting +sprite as a L 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, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 index 0000000..3762063 --- /dev/null +++ b/svg-spritemaker @@ -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 for more information about +SVG sprites. + +=head1 OPTIONS + +=over + +=item B<-o> I, B<--out>=I, B<--output>=I + +Write the sprite into the following file, overwriting it if necessary. +By default the sprite is written on STDOUT. + +=item B<-p> I, B<--prefix>=I + +Sets the prefix for the fragment identifiers. Default is C +(which results in identifiers C, C for the first +example in the SYNOPSIS). + +=back + +=head1 SEE ALSO + +L, L + +=head1 AUTHOR + +Marius Gavrilescu, Emarius@ieval.roE + +=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 index 0000000..b83a939 --- /dev/null +++ b/t/SVG-SpriteMaker.t @@ -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 => ; +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 index 0000000..0e1ecb9 --- /dev/null +++ b/t/circle.svg @@ -0,0 +1,3 @@ + + + diff --git a/t/perlcritic.t b/t/perlcritic.t new file mode 100644 index 0000000..79e93dc --- /dev/null +++ b/t/perlcritic.t @@ -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 index 0000000..5815f07 --- /dev/null +++ b/t/perlcriticrc @@ -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 index 0000000..955293d --- /dev/null +++ b/t/rect.svg @@ -0,0 +1,3 @@ + + + -- 2.39.2