At the risk of just dumping irrelevant code, here's a Perl program that I used for a similar purpose - transferring images to a printer with a card reader (before I was able to locate the printer near enough to use its USB connection). It has some built-in assumptions (that card filesystems are user-mountable under /media/card/<card-type>
) but you should be able to discard the mount
/umount
part if it's not relevant to you. (If I were writing it again from scratch, I'd probably use pmount
instead.)
There's also an attempt to give non-JPEG images a suitable thumbnail file as prescribed by DCIM; I can confirm that this works on my Canon DSLR, but I can't remember whether I tested it on a Fuji. If I did, it would be on a F30 or F60 compact.
FWIW, my card-reading script (not shown) deletes each image from the card filesystem when it has been correctly written to my archive directory (and marked readonly). I have a --keep
option to override that, which is useful when testing changes to the script. I never re-format the cards.
The code
#!/usr/bin/perl
use strict;
use Getopt::Long;
# Usage: write-image.pl file... dest
# dest is a dcf root directory - i.e. it contains a dcim subdir.
my $verbose = '';
my $rotate = '';
my $clear = '';
GetOptions ("clear!" => \$clear,
"rotate!" => \$rotate,
"verbose!" => \$verbose);
my $basedir = "/media/card";
if (@ARGV < 2) {
die "not enough arguments\n";
}
my $dest = pop;
$dest = "$basedir/$dest" unless $dest =~ /^\//;
my $mounted = -d "$dest/dcim";
unless ($mounted) {
print "mount $dest\n" if $verbose;
system("mount", "$dest") == 0 or die;
}
if ($clear && -d "$dest/dcim") {
clear(<$dest/dcim/*>);
}
# scan image directories
my $dirno = 99;
my $destdir;
foreach (<$dest/dcim/*>) {
$dirno = $1 if /\/([1-9][0-9][0-9])/;;
$destdir = $_ if /\/([1-9][0-9][0-9])linux$/;
}
unless ($destdir) {
die if ++$dirno > 999;
$destdir = "$dest/dcim/${dirno}linux";
print "Adding new directory $destdir\n" if $verbose;
-d "$dest/dcim" or mkdir"$dest/dcim" or die;
mkdir $destdir or die;
}
# scan files
my $fileno = 0;
foreach (<$destdir/????[0-9][0-9][0-9][0-9].*>) {
/\/....([0-9][0-9][0-9][0-9])\..*/;
$fileno = $1 if $1 > $fileno;
}
sub clear(@) {
my $f;
foreach $f (@_) {
if (-d $f) {
&clear(<$f/*>);
#print STDERR "rmdir $f\n";
rmdir $f;
} else {
#print STDERR "unlink $f\n";
unlink $f;
}
}
}
#do it
foreach (@ARGV) {
if (++$fileno > 9999) {
die if ++$dirno > 999;
$fileno = 1;
$destdir = "$dest/dcim/${dirno}linux";
mkdir $destdir or die;
}
my $destfile = sprintf "$destdir/img_%04d", $fileno;
my $suffix = "";
if (/\.[^.]+\Z/) {
$suffix = $&;
}
#print "$_ -> $destfile$suffix\n" if $verbose;
print "$_: " if $verbose; # no newline!
if ("$suffix" eq ".jpg") {
if ($rotate) {
system("( jpegtran -rot 90 -perfect $_ || djpeg $_ | pnmflip -cw | cjpeg -quality 95 -dct float -sample 1x1 ) > $destfile.jpg && exiftran -g -i $destfile.jpg") == 0 || die;
} else {
system("exiftran", "-g", "-o", "$destfile.jpg", "$_") == 0 || die;
print sprintf(" -> img_%04d$suffix\n", $fileno) if $verbose;
}
} else {
system("/bin/cp $_ $destfile$suffix") == 0 || die "$!\n";
system("anytopnm $_ 2>&- | pnmscale -xysize 160 120 | pnmpad -width 160 -height 120 | pnmtojpeg >$destfile.thm") ==0 || die "$!\n";
print "\n" if $verbose;
}
}
unless ($mounted) {
print "umount $dest\n" if $verbose;
system("umount", "$dest") == 0 or die;
}
Again, I apologise for the length. But it should now be clear where to write the image in the card's filesystem: in particular, according to the DCIM standard, it must be in DCIM/nnnAAAAA/AAAAnnnn.ext
, where n
is numeric, A
is any character¹, and ext
is JPG
or THM
depending on whether it's the object itself or a separate thumbnail. If the name doesn't fit this pattern, the camera will likely ignore it.
Note also the use of exiftran -g
to add an EXIF thumbnail (of the correct size) to an image that doesn't have one. That is likely important for your use, as cameras tend to rely on the thumbnail for image preview. The one created by GIMP is probably the wrong size, and may cause your camera to ignore the image, display a placeholder or even report a read error.
¹ That is, any character within the quite restricted set allowed by DCIM: 123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_
.