Created
August 16, 2010 16:55
-
-
Save klang/527284 to your computer and use it in GitHub Desktop.
change size and quality of jpg/bmp pictures while keeping exifdata. The script makes a 'lightweight' version of original off-the-camera jpg pictures. The copy can be used for picture frames without taking up too much space.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/perl | |
use Getopt::Long; | |
use strict; | |
my $src = $ENV{'PWD'}; | |
my $dst = "/cygdrive/c/pictures/export/digital"; | |
my $quality = 75; | |
sub usage { | |
print STDERR "$0\n"; | |
print STDERR " [--verbose]\twrites everything that happens (2 levels)\n"; | |
print STDERR " [--dry]\tdo NOT execute any commands\n"; | |
print STDERR " [--quality]\treduce pictures to this jpg quality (default: $quali | |
ty)\n"; | |
print STDERR " [--dst]\talt. destination (default: $dst)\n"; | |
print STDERR " [--src]\talt. source (default: $src)\n\n"; | |
print STDERR " [--exif]\twill check destination files for exif data and move if | |
missing\t"; | |
print STDERR "the command can be run without commands to reduce quality to $qual | |
ity\n"; | |
print STDERR "using current directory as source and default as destination\n\n"; | |
} | |
my ($help, $verbose , $dry, $moveExifData); | |
GetOptions( 'help|?' => \$help, | |
"verbose+" => \$verbose, | |
"quality:$quality" => \$quality, | |
"src:s" => \$src, | |
"dst:s" => \$dst, | |
"dry!" => \$dry, | |
"exif!" => \$moveExifData, | |
); | |
if ($help) { | |
usage(); | |
exit; | |
} | |
print "Reading from: $src".$/; | |
print "Exporting to: $dst".$/; | |
if ($moveExifData) { | |
print "checking EXIF data in all exported files (and moving missing data from so | |
urce)\n"; | |
moveExifData($src); | |
}else{ | |
print "converting source files to ${quality}% quality and moving EXIF data\n"; | |
convert($src);; | |
} | |
exit; | |
sub convert { | |
my $dir = shift; | |
local *DIR; | |
makeDestinationDir($dir); | |
print "$dir$/" or print "error - $!"; | |
opendir DIR, $dir or die "opendir $dir: $!"; | |
my $found = 0; | |
while ($_ = readdir DIR) { | |
next if /^\.{1,2}$/; | |
#next if -f $path $_!~/JPG$/i || $_ !~ /BMP$/i; | |
my $path = "$dir/$_"; | |
reduceJPGQuality($path) if -f $path && /JPG$/i; | |
reduceBMPQuality($path) if -f $path && /BMP$/i; | |
convert($path) if -d $path; | |
} | |
closedir DIR; | |
} | |
# http://www.mactricksandtips.com/2008/07/convert-images-using-terminal.html | |
sub moveExifData { | |
my $dir = shift; | |
local *DIR; | |
makeDestinationDir($dir); | |
print "$dir$/" or print "error - $!"; | |
opendir DIR, $dir or die "opendir $dir: $!"; | |
my $found = 0; | |
while ($_ = readdir DIR) { | |
next if /^\.{1,2}$/; | |
my $path = "$dir/$_"; | |
if ( -f $path && /JPG$/i ) { | |
my $file = relativePath($path); | |
my $exiflines = `exiftool '$dst$file' | wc -l`; | |
chomp($exiflines); | |
if ( $exiflines <= 13 ) { | |
moveEXIFdata($path); | |
} else { | |
print " EXIF OK for $dst$file\n" if $verbose > 1; | |
} | |
} | |
moveExifData($path) if -d $path; | |
} | |
closedir DIR; | |
} | |
### *** TODO *** ### | |
# rsync -varuHpogt --filter='+ Picasa.ini' --filter='- *.*' /cygdrive/g/pictures/d40 | |
x /cygdrive/c/pictures/export/digital/d40x | |
# rsync -varuHpogt --filter='+ Picasa.ini' --filter='- *.*' /cygdrive/g/pictures/dig | |
ital /cygdrive/c/pictures/export/digital | |
sub movePicasaData { | |
my $dir = shift; | |
local *DIR; | |
makeDestinationDir($dir); | |
print "$dir$/" or print "error - $!"; | |
opendir DIR, $dir or die "opendir $dir: $!"; | |
my $found = 0; | |
while ($_ = readdir DIR) { | |
next if /^\.{1,2}$/; | |
my $path = "$dir/$_"; | |
if ( -f $path && /INI$/i ) { | |
my $file = relativePath($path); | |
# check date of $dst$file | |
# move the newest file | |
my $exiflines = `exiftool '$dst$file' | wc -l`; | |
chomp($exiflines); | |
if ( $exiflines <= 13 ) { | |
movePicasadata($path); | |
} else { | |
print " EXIF OK for $dst$file\n" if $verbose > 1; | |
} | |
} | |
movePicasaData($path) if -d $path; | |
} | |
closedir DIR; | |
} | |
sub makeDestinationDir { | |
my $dir = relativePath(shift); | |
if (! -e "$dst$dir" ) { | |
print "mkdir -p $dst$dir".$/ if $verbose > 2; | |
mkdir("$dst$dir", 0755) || `mkdir -m 0755 -p $dst$dir`; | |
die "Can not mkdir $dst$dir: $!" if ! -e "$dst$dir"; | |
} else { | |
print "$dst$dir exists$/" if $verbose > 2; | |
} | |
} | |
sub filename { | |
my $file = shift; | |
$file =~ s/.*\/(.+\.JPG)/\1/; | |
return $file; | |
} | |
sub relativePath { | |
my $relative = shift; | |
$relative =~ s/$src//e; | |
return $relative; | |
} | |
sub reduceJPGQuality { | |
my $file = relativePath(shift); | |
my $filename = filename($file); | |
if ( ! -e "$dst$file" && $file =~ /JPG$/i ) { | |
print " $filename quality reduced to $quality%$/"; | |
print "djpeg '$src$file' | cjpeg -verbose -quality $quality -outfile '$dst$f | |
ile'".$/ if $dry || $verbose > 2; | |
`djpeg '$src$file' | cjpeg -verbose -quality $quality -outfile '$dst$file' 2 | |
>/dev/null` if !$dry; | |
moveEXIFdata($file); | |
} else { | |
print " $filename already converted$/" if $verbose > 1; | |
} | |
} | |
sub reduceJPGsize { | |
my $file = relativePath(shift); | |
my $filename = filename($file); | |
if ( ! -e "$dst$file" && $file =~ /JPG$/i ) { | |
print " $filename quality reduced to $quality%$/"; | |
print "djpeg '$src$file' | cjpeg -verbose -quality $quality -outfile '$dst$f | |
ile'".$/ if $dry || $verbose > 2; | |
`djpeg -fast -scale 1/8 '$src$file' | cjpeg -verbose -quality $quality -outf | |
ile '$dst$file' 2>/dev/null` if !$dry; | |
moveEXIFdata($file); | |
} else { | |
print " $filename already converted$/" if $verbose > 1; | |
} | |
} | |
sub moveEXIFdata { | |
my $file = relativePath(shift); | |
if ( -e "$dst$file" ) { | |
print " moving EXIF data$/"; | |
print "exiftool -TagsFromFile '$src$file' -all:all '$dst$file'$/" if $dry || | |
$verbose > 2; | |
# exiftool -TagsFromFile src.jpg -all:all dst.jpg | |
# Copy the values of all writable tags from "src.jpg" to "dst.jpg", | |
# preserving the original tag groups. | |
`exiftool -TagsFromFile '$src$file' -all:all '$dst$file'` if !$dry; | |
unlink("$dst$file"."_original") if !$dry; | |
} | |
} | |
sub reduceBMPQuality { | |
my $file = relativePath(shift); | |
my $filename = filename($file); | |
my $jpgfile = $file; $jpgfile =~ s/BMP$/jpg/; | |
if ( ! -e "$dst$jpgfile" && $file =~ /BMP$/i ) { | |
print " $filename quality reduced to $quality%$/"; | |
print "cjpeg -verbose -quality $quality -outfile '$dst$file' '$src$file'".$/ | |
if $dry || $verbose > 2; | |
`cjpeg -verbose -quality $quality -outfile '$dst$jpgfile' '$src$file' 2>/dev | |
/null` if !$dry; | |
} else { | |
print " $filename already converted$/" if $verbose > 1; | |
} | |
} | |
sub nef2jpg { | |
my $file = relativePath(shift); | |
if ( ! -e "$dst$file" && $file =~ /NEF$/i ) { | |
print "\tcreating jpg file$/"; | |
print "\t\t$/"; | |
# dcraw -c -w crw_0001.crw | cjpeg > crw_0001.jpeg | |
# print "djpeg '$src$file' | cjpeg -verbose -quality $quality -outfile '$dst$f | |
ile'".$/ if $dry || $verbose; | |
# `djpeg '$src$file' | cjpeg -verbose -quality $quality -outfile '$dst$file'` | |
if !$dry; | |
moveEXIFdata($file); | |
} | |
} | |
__END__; | |
=head1 NAME | |
exportjpg | |
=head1 SYNOPSIS | |
Create a lightweight copy of large photo collections while maintaining EXIF data. Or | |
, how to anoy the family with endless slideshows in viewable quality. | |
=head1 DESCRIPTION | |
Normally, when working on pictures using C<djpeg>, C<djpeg> or similar, EXIF data is | |
not copied to the resulting files. I found that anoying as I have all my pictues on | |
my portable computer (limited space, always limited space) for easy and fast refere | |
nce. | |
It is possible to check the existence of EXIF data in exported (by exportjpg) jpgs. | |
During implementation of this program, I fucked up and did not know which exported f | |
iles contained EXIF data and which did not. The B<--exif> option checks the copies t | |
o determine the presence of a full set of EXIF data. If something is missing in the | |
copy, the program will find the data in the original file. | |
=head1 USAGE | |
exportjpg | |
exportjpg --exif | |
exportjpg --verbose --verbose --dry | |
=head1 DEPENDENCIES | |
djpeg - http://www.linuxcommand.org/man_pages/djpeg1.html | |
cjpeg - http://www.linuxcommand.org/man_pages/cjpeg1.html | |
exiftool - http://www.sno.phy.queensu.ca/~phil/exiftool/ | |
Windows users will benefit greatly form B<Cygwin> http://www.cygwin.com/ | |
=head1 OPTIONS | |
=over 4 | |
=item B<no options> - normal operation | |
cd to the directory containing the folders with pictures you want to export. Write C | |
<exportjpg>, wait. | |
=item B<--verbose> - verbose | |
several uses of B<verbose> is possible (and when I say 'several' I mean, two.) | |
=item B<--dry> - dry run | |
do not execute any time consuming commands (conversions or exif inspections) | |
=item B<--exif> - exif tester | |
if an execution of the command produced errors, it is possible to recheck the presen | |
ce of the exif data in the exported files with this option. When running in B<exif> | |
mode, nothing else is done (no conversions) | |
=item B<--src> - source directory | |
If source directory is not the current directory. | |
=item B<--dst> - destination directory | |
To change the destination directory specified in the $dst variable on the fly. | |
=item B<--help> - help | |
short option help | |
[--verbose] writes everything that happens (2 levels) | |
[--dry] do NOT execute any commands | |
[--quality] reduce pictures to this jpg quality (default: 75) | |
[--dst] alt. destination (default: $dst) | |
[--src] alt. source (default: $ENV{'PWD'}) | |
[--exif] will check destination files for exif data and move | |
if missing | |
the command can be run without commands to reduce quality to 75 using current direct | |
ory as source and default as destination | |
=back | |
=head TODO | |
Extend the program to accept RAW files as input using C<dcraw>. | |
Finish the BMP section (bmp2jpg) and add options for this | |
=head1 AUTHOR | |
Karsten Lang Pedersen <karsten@lang.dk> | |
=head1 COPYRIGHT | |
Copyright 2006 by Karsten Lang Pedersen (karsten@lang.dk). All rights reserved. | |
=cut |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment