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
