#!/usr/bin/perl -w # Copyright © 2000, 2001, 2002 Jamie Zawinski # # Permission to use, copy, modify, distribute, and sell this software and its # documentation for any purpose is hereby granted without fee, provided that # the above copyright notice appear in all copies and that both that # copyright notice and this permission notice appear in supporting # documentation. No representations are made about the suitability of this # software for any purpose. It is provided "as is" without express or # implied warranty. # # jpegdiff.pl --- compares two or more JPEG files and says whether they differ # non-trivally. Exits with 0 if the first JPEG is a member of # the set of the remaining JPEGs, and exits with 1 if not. # In other words, exits with 0 if the first image is a # duplicate of *any* of the subsequent JPEGs. # # For example: jpegdiff A B C D ==> 1 # jpegdiff A B C A ==> 0 # jpegdiff A B B C ==> 1 # # Created: 14-Sep-2000. require 5; use diagnostics; use strict; my $progname = $0; $progname =~ s@.*/@@g; my $version = q{ $Revision: 1.8 $ }; $version =~ s/^[^0-9]+([0-9.]+).*$/$1/; my $verbose = 0; my $debug = 0; my $usage = "usage: $progname [ --verbose ] [ --debug ] file1 files ...\n" . "Exit status is 0 if file1 and any fileN are the same;\n" . "else exits with non-zero (meaning file1 is not duplicated\n" . "by any of the other files.)\n"; sub compare { my @files = @_; my $file1 = shift @files; my $shrink_cmd ="djpeg | pnmscale -width 128 -height 96 | ppmtopgm | " . "pnmcut 6 6 116 85"; my $tmp1 = "/tmp/jpgdiff$$.1.pgm"; my $tmp2 = "/tmp/jpgdiff$$.2.pgm"; if (! -f $file1) { # # If the first file doesn't exist, exit with 1 (the null file is not # considered to be duplicated by any other file.) # print STDERR "$progname: $file1 does not exist\n"; return 1; } system "($shrink_cmd) < $file1 > $tmp1 2>/dev/null"; my $differ = 0; my $which = 1; foreach my $file2 (@files) { if (! -f $file2) { # Just ignore any of the other files that don't exist. print STDERR "$progname: warning: $file2 does not exist\n"; next; } print STDERR "$progname: comparing $file1 and $file2...\n" if ($verbose || $debug); system "($shrink_cmd) < $file2 > $tmp2 2>/dev/null"; # Just ignore errors here: this means that if an image is corrupted, # it will be considered a match on all images. I'm not totally sure # what the implications of that are... But I do know I'm tired of # getting mail from cron that say "pnmarith: EOF / read error reading # magic number". # my $cmp = `pnmarith -difference $tmp1 $tmp2 2>/dev/null`; unlink $tmp2; my $ocmp = ($debug ? $cmp : undef); $cmp =~ s/^P.\n\d+ \d+\n\d+\n//s; # take off pbm header $cmp =~ s/[\000-\031]//g; # nuke low-valued pixels $differ = (length($cmp) > 100); $differ = 0 unless $differ; if ($debug || $verbose) { print STDERR "$progname: images " . ($differ ? "differ" : "do not differ"); print ".\n" unless $debug; } if ($debug) { if (!$differ) { print "\n"; } else { print "; running xv on delta...\n"; $_ = $ocmp; my ($oh) = m/^(P.\n\d+ \d+\n\d+\n)/; # save pbm header s/^(P.\n\d+ \d+\n\d+\n)//; # take off pbm header s/[\000-\031]/\000/g; # nuke low-valued pixels $_ = $oh . $_; # put header back open (OUT, "|xv -"); print OUT $_; close OUT; } } # bug out when we reach the first file that is identical. last if (! $differ); $which++; } unlink $tmp1; print "$progname: returning $differ\n" if ($verbose > 1); return $differ; } sub main { my @files; while ($_ = $ARGV[0]) { shift @ARGV; if ($_ eq "--verbose") { $verbose++; } elsif (m/^-v+$/) { $verbose += length($_)-1; } elsif ($_ eq "--debug") { $debug++; } elsif (m/^-/) { print STDERR $usage; exit -1; } else { push @files, $_; } } if ($#files < 1) { print STDERR $usage; exit -1; } return compare (@files); } exit (main());