Saturday, 29 December 2007

Digital Photo Frames, FAT16 and Directory limits

One problem with FAT16 (Final FAT16) filesystems is the limit on the number of files which can be put into a folder (including the root). The limit is 512 8.3 Files or fewer longer named files. My stepdad had just got a shiny new Philips photo frame and a 2G SD Card and was having a problem with the Card reporting it was full. I now realise why camera cards place the images into folders. All those poor Camera manufacturers are having to create directories in firmware because the FAT16 filestem has been adopted by them. Sigh.



After some deliberation, I decided to install ActiveState Perl, ImageMagick and write a Perl script to do some work:


  • Remove all the whitespace from the filenames.

  • Shrink all the files to 800x600.

  • Convert everything to a JPEG (some bitmaps existed in his photo collection).

  • Place a maximum of 100 files in a directory/folder. Create a number of directories on the fly depending on how many files were being created.

  • Pickup files stored in a flat directory E:/Photos/Frame/INCOMING

  • Place shrunken jpg images in a flat directory E:/Photos/Frame/OUTGOING/FRAMx (where x is a number). These folders can then be dragged and dropped onto the card in a card reader.

  • Ignore .AVI, .MPG and .DB files ( .DB == Picasa directory entries)






#!perl

# Tim Gibbon 2007
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .


use strict;
use warnings;
use Image::Magick;
use File::Path;

my $incoming_directory="E:/Photos/Frame/INCOMING/";
my $outgoing_directory="E:/Photos/Frame/OUTGOING/";
my $directory_name_seed="FRAN";
my $number_of_files_per_dir=100;
my @incoming_files;
my @alldirs;
my $file_counter=0;
my $dir_counter=0;

die "Cannot find Incoming directory $incoming_directory $!\n" unless -e $incoming_directory;

die "Cannot find Outgoing directory $outgoing_directory $!\n" unless -e $outgoing_directory;

opendir (INCOMING,"$incoming_directory");
foreach (readdir(INCOMING)){
chomp;
next if /^\./;
next if /avi$/;
next if /mpg$/;
next if /db$/;
#/

my $incoming_file=$_;
my ($firstportion,$secondportion)=split/\./;
#/
next unless $secondportion;
push (@incoming_files,"$incoming_file");
}
closedir (INCOMING);


my $number_of_incoming_files=$#incoming_files;

print "There are $number_of_incoming_files Incoming files\n";

my $number_of_outgoing_dirs=(int($number_of_incoming_files/$number_of_files_per_dir))+1;
print "Therefore I need $number_of_outgoing_dirs directories\n";

for (1..$number_of_outgoing_dirs){

my $dir_to_make="$outgoing_directory$directory_name_seed$_";
push(@alldirs,$dir_to_make);
print ("Cleaning then Making $dir_to_make\n");
#################BE VERY CAREFUL WITH THE BELOW LINE##############################
#######IT WILL REMOVE ALL FILES AND FOLDERS IN $dir_to_make#######################
rmtree(["$dir_to_make"]);
mkpath(["$dir_to_make"]) or die "Cannot make directory $dir_to_make $!";
}





foreach (@incoming_files){

my ($firstportion,$secondportion)=split/\./;
$firstportion=~s/\W+/_/g;
next unless $secondportion;
print ("File counter $file_counter\n");
$file_counter++;
$dir_counter++ if ((int($file_counter/$number_of_files_per_dir) > $dir_counter));
print ("Dir counter $dir_counter\n");
my $outgoing_sort="$alldirs[$dir_counter]"."/$firstportion\.jpg";
print ("Filename to use is $outgoing_sort\n");

#/
my $image=Image::Magick->new;
$image->Read("$incoming_directory$_");
my ($current_columns,$current_rows)=$image->Get('base-columns','base-rows');

# Do scaling based on Orientation.
if ($current_rows > $current_columns ) {
$image->Scale(geometry => '600x800');
} elsif ($current_columns > $current_rows){
$image->Scale(geometry => '800x600');
} else {
$image->Scale(geometry => '600x800');
}
# $image->(format => "png")
$image->Write("jpg:$outgoing_sort");

}




I placed all my stepdad's photos (4.2G) into INCOMING and it converted the entire lot in a couple of hours and shrank them down to 1G. Not bad for 2 hours work if I do say so.

No comments: