App-ImageMagickUtils

 view release on metacpan or  search on metacpan

lib/App/ImageMagickUtils.pm  view on Meta::CPAN

    ],
};
sub downsize_image {
    require File::Which;
    require Image::Size;
    require IPC::System::Options;
    #require Filename::Type::Image;

    my %args = @_;

    my $convert_path = File::Which::which("convert");
    my $downsize_to = $args{downsize_to};
    my $skip_whatsapp = $args{skip_whatsapp} // 1;
    my $skip_downsized = $args{skip_downsized} // 1;

    unless ($args{-dry_run}) {
        return [400, "Cannot find convert in path"] unless defined $convert_path;
        return [400, "convert path $convert_path is not executable"] unless -x $convert_path;
    }

    my ($num_files, $num_success) = (0, 0);
    my $trash;
  FILE:
    for my $file (@{$args{files}}) {
        log_info "Processing file %s ...", $file;
        $num_files++;

        unless (-f $file) {
            log_error "No such file %s, skipped", $file;
            next FILE;
        }

        #my $res = Filename::Type::Image::check_image_filename(filename => $file);
        my ($width, $height, $fmt) = Image::Size::imgsize($file);
        unless ($width) {
            log_error "Filename '%s' is not image (%s), skipped", $file, $fmt;
            next FILE;
        }

        if ($skip_whatsapp) {
            require Regexp::Pattern::Filename::Type::Image::WhatsApp;
            if ($file =~ $Regexp::Pattern::Filename::Type::Image::WhatsApp::RE{filename_type_image_whatsapp}{pat}) {
                log_info "Filename '%s' looks like a WhatsApp image, skip downsizing due to --skip-whatsapp option is in effect", $file;
                next FILE;
            }
        }

        if ($skip_downsized) {
            if ($file =~ /\.(?:\d+p?-)?q(?:\d{1,3})\.\w+\z/) {
                log_info "Filename '%s' looks like it's already downsized, skip downsizing due to --skip-downsized option is in effect", $file;
                next FILE;
            }
        }

        my $q = $args{quality} // 40;
        my @convert_args = (
            $file,
        );

        my $downsized;
        #say "D:downsize_to=<$downsize_to>, width=<$width>, height=<$height>, q=<$q>";
      DOWNSIZE: {
            last unless $downsize_to;
            my $ratio;
            my $shortest_side = $width > $height ? $height : $width;
            last unless $shortest_side > $downsize_to;
            $downsized++;
            push @convert_args, "-resize", "$downsize_to^>";
        } # DOWNSIZE

        push @convert_args, "-quality", $q;

        my $output_file = $file;
        my $ext = $downsized ? ".$downsize_to-q$q.jpg" : ".q$q.jpg";
        $output_file =~ s/(\.\w{3,4})?\z/($1 eq ".jpg" ? "" : $1) . $ext/e;

        push @convert_args, (
            $output_file,
        );

        if ($args{-dry_run}) {
            log_info "[DRY-RUN] Running $convert_path with args %s ...", \@convert_args;
            $num_success++;
            next FILE;
        }

        log_info "Running $convert_path with args %s ...", \@convert_args;
        IPC::System::Options::system(
            $convert_path, @convert_args,
        );
        if ($?) {
            my ($exit_code, $signal, $core_dump) = ($? < 0 ? $? : $? >> 8, $? & 127, $? & 128);
            log_error "convert for $file failed: exit_code=$exit_code, signal=$signal, core_dump=$core_dump";
        } else {
            if ($args{trash_original}) {
                require File::Trash::FreeDesktop;
                $trash //= File::Trash::FreeDesktop->new;
                log_info "Trashing original file %s ...", $file;
                # will die upon failure, currently we don't trap
                $trash->trash($file);
            } elsif ($args{delete_original}) {
                # currently we ignore the results
                log_info "Deleting original file %s ...", $file;
                unlink $file;
            }
            $num_success++;
        }
    }

    $num_success == 0 ? [500, "All files failed"] : [200];
}

$SPEC{convert_image_to} = {
    v => 1.1,
    summary => 'Convert images using ImageMagick\'s \'convert\' utility, with multiple file support and automatic output naming',
    description => <<'MARKDOWN',

This is a simple wrapper to ImageMagick's `convert` utility to let you process
multiple files using a single command:

    % convert-image-to --to pdf *.jpg



( run in 1.530 second using v1.01-cache-2.11-cpan-d7a12ab2c7f )