CSS-SpriteBuilder

 view release on metacpan or  search on metacpan

lib/CSS/SpriteBuilder/Sprite.pm  view on Meta::CPAN

package CSS::SpriteBuilder::Sprite;

use warnings;
use strict;
use File::Glob ":glob";
use File::Spec;
use Cwd ();
use CSS::SpriteBuilder::Constants;
use CSS::SpriteBuilder::SpriteItem;
use base 'CSS::SpriteBuilder::ImageDriver::Auto';

sub max { $_[ $_[0] < $_[1] ] }

sub new {
    my ($class, @args) = @_;

    my $self = $class->SUPER::new(
        source_dir          => undef,
        source_images       => undef,
        target_file         => undef,

        image_quality       => DEF_IMAGE_QUALITY,
        max_image_size      => DEF_MAX_IMAGE_SIZE,
        max_image_width     => DEF_MAX_IMAGE_WIDTH,
        max_image_height    => DEF_MAX_IMAGE_HEIGHT,
        max_sprite_width    => DEF_MAX_SPRITE_WIDTH,
        max_sprite_height   => DEF_MAX_SPRITE_HEIGHT,
        margin              => DEF_MARGIN,
        transparent_color   => undef,
        is_background       => 0,
        layout              => DEF_LAYOUT,
        css_selector_prefix => DEF_CSS_SELECTOR_PREFIX,
        css_url_prefix      => '',
        is_add_timestamp    => 1,

        _sprite_no          => 1,
        _repeated_images    => [],
        _sprites            => {},
        _x                  => 0,
        _y                  => 0,

        @args,
    );

    unless ( grep { $_ eq $self->{layout} } @{ LAYOUT_LIST() } ) {
        die "Invalid 'layout' parameter: $self->{layout}";
    }

    return $self;
}

sub target_file    { sprintf( $_[0]->{target_file}, $_[0]->{_sprite_no} )                }

sub _init {
    my ($self, $image) = @_;

    die "The 'target_file' parameter is not defined"    unless $self->{target_file};
    die "The 'source_images' parameter is not defined"  unless $self->{source_images};

    $self->SUPER::_init($image);

    $self->{_x} = $self->{_y} = 0;

    return;
}

sub build {
    my ($self) = @_;

    my $images = $self->search_images();
    foreach my $image (@$images) {
        $self->process_image($image);
    }

    $self->write();

    return $self->{_sprites};
}

sub search_images {
    my ($self) = @_;

    my $save_dir;
    if ( $self->{source_dir} ) {
        $save_dir = Cwd::getcwd();
        chdir $self->{source_dir} or die "Cannot chdir to $self->{source_dir}: $!\n";
    }

    my @images = grep {

lib/CSS/SpriteBuilder/Sprite.pm  view on Meta::CPAN


    return;
}

sub save_info {
    my ($self, $image) = @_;

    my (undef, undef, $filename) = File::Spec->splitpath( $self->target_file() );
    my $sprite_image = $self->{css_url_prefix} . $filename;

    $sprite_image .= '?' . time() if $self->{is_add_timestamp};

    push @{ $self->{_sprites}{$sprite_image} }, {
        image           => $image->source_file(),
        width           => $image->width(),
        height          => $image->height(),
        x               => $self->{_x},
        y               => $self->{_y},
        selector        => $image->get_css_selector( $self->{css_selector_prefix} ),
        is_background   => (
            defined $image->is_background()
                ? $image->is_background()
                : $self->{is_background}
        ) ? 1 : 0,
        repeat          => $self->{layout} ne PACKED_LAYOUT && $image->is_repeat()
            ? $self->{layout} eq HORIZONTAL_LAYOUT ? 'y' : 'x'
            : 'no'
        ,
    };

    return;
}

sub save_repeated_images {
    my ($self, $image) = @_;

    push @{ $self->{_repeated_images} }, {
        image => $image,
        x     => $self->{_x},
        y     => $self->{_y},
    };

    return;
}

sub post_process {
    my ($self, $image) = @_;

    $self->{ $self->{layout} eq VERTICAL_LAYOUT ? '_y' : '_x' } += $image->width;

    return;
}

sub write {
    my ($self) = @_;

    return if $self->is_blank();

    $self->process_repeated_images();

    $self->set_transparent_color( $self->{transparent_color} )
        if $self->{transparent_color};

    $self->set_quality( $self->{image_quality} );

    $self->SUPER::write( $self->target_file() );

    $self->{_sprite_no}++;

    $self->reset();

    return;
}

sub process_repeated_images {
    my ($self) = @_;

    return unless scalar @{ $self->{_repeated_images} };

    my $meter                = $self->{layout} eq VERTICAL_LAYOUT ? 'width' : 'height';
    my $original_sprite_size = $self->$meter();
    my $max_sprite_size      = $self->{ $self->{layout} eq VERTICAL_LAYOUT ? 'max_sprite_width' : 'max_sprite_height' };
    my @images_size          = reverse sort map { $_->{image}->$meter() } @{ $self->{_repeated_images} };
    my $max_image_size       = shift @images_size;

    for (
        my $k = int($original_sprite_size / $max_image_size) + ($original_sprite_size % $max_image_size ? 1 : 0);
        $k * $max_image_size <= $max_sprite_size;
        $k++
    ) {
        my $extented_sprite_size = $k * $max_image_size;
        unless (grep { $extented_sprite_size % $_ } @images_size) {
            $self->extent(
                $meter eq 'width'
                    ? ( $extented_sprite_size, $self->height()        )
                    : ( $self->width()       , $extented_sprite_size  )
            );

            foreach my $image_info (@{ $self->{_repeated_images} }) {
                my $image = $image_info->{image};
                my $size  = $image->$meter();

                while (($image_info->{ $self->{layout} eq VERTICAL_LAYOUT ? 'x' : 'y' } += $size) < $extented_sprite_size) {
                    $self->composite( $image, $image_info->{x}, $image_info->{y} )
                }
            }

            return;
        }
    }

    $self->{_repeated_images} = [];

    die "Can't process repeated images";
}

1;



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