]> thyrsus.com Git - imgsizer.git/commitdiff
Ready to ship 2.0.
authorEric S. Raymond <esr@thyrsus.com>
Wed, 11 Jul 2001 19:27:45 +0000 (19:27 +0000)
committerEric S. Raymond <esr@thyrsus.com>
Wed, 11 Jul 2001 19:27:45 +0000 (19:27 +0000)
Makefile
README
imgsizer
imgsizer.xml

index 5ac50f852ae1f211702ddc8b14782d18cc65e701..ec8a05d886e8e2ca31b9bca4df28de8445364b13 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,12 +1,12 @@
 # Makefile for the imgsizer distribution
-VERS=1.8
+VERS=1.2
 
 # These choices are correct for Linux.  Season to taste.
 BINDIR = /usr/bin
 MANDIR = /usr/man/man1
 
 install:
-       cp imgsizer httpget $(BINDIR)
+       cp imgsizer $(BINDIR)
        cp imgsizer.man $(MANDIR)/imgsizer.1
 
 uninstall:
@@ -16,7 +16,7 @@ clean:
        rm -f *~ 
        rm -f imgsizer-*-1.noarch.rpm imgsizer-*-1.noarch.rpm imgsizer-*.tar.gz
 
-SOURCES = READ.ME Makefile imgsizer httpget imgsizer.man imgsizer.lsm  
+SOURCES = READ.ME Makefile imgsizer imgsizer.man imgsizer.lsm  
 imgsizer-$(VERS).tar.gz: $(SOURCES)
        mkdir imgsizer-$(VERS)
        cp $(SOURCES) imgsizer-$(VERS)
diff --git a/README b/README
index a475831eda7f1ebdaad8ec0d744d479f02695c53..17410dda77578c3253028a046813827327e89642 100644 (file)
--- a/README
+++ b/README
@@ -9,12 +9,11 @@ Files in this directory:
        READ.ME         -- this file
        imgsizer        -- the utility
        imgsizer.man    -- manual page
-       httpget         -- required for fetching remote images
        Makefile        -- installation and packaging productions 
        imgsizer.lsm    -- Linux Software Map description.
 
-Put imgsizer and httpget on your execution path and
-the man page in a man source directory somewhere.  That's it.
+Put imgsizer on your execution path and the man page in a man source
+directory somewhere.  That's it.
 
 You will need identify(1) from the ImageMagick tools suite to make this
 work.  If you are using Linux or any of the free BSDs it is probably
index c41b998214804d9eff1f6ce3b8806bdeeb146f9c..8b22a35028f80c274a039ca64b707dcf2d925157 100755 (executable)
--- a/imgsizer
+++ b/imgsizer
@@ -1,4 +1,4 @@
-#!/usr/bin/perl
+#!/usr/bin/python
 #
 # imgsizer -- correct image sizes in WWW pages
 # by Eric S. Raymond <esr@thyrsus.com>
@@ -8,7 +8,7 @@
 # a decent file(1) and rdjpgcom(1).  To fix up sizes for non-local images
 # it requires the httpget(1) script.
 # 
-# Works with either Perl4 or Perl5, Perl4 is much faster.
+# Works with Python 1.5.2
 #
 # Copy, use, and redistribute freely, but don't take my name off it and
 # clearly mark an altered version.  Fixes and enhancements cheerfully 
 #    the line number an error occurred due to the input record separator
 #    being set to ">".
 #
+# Rewritten in Python by Eric S. Raymond <esr@thyrsus.com> 11 July 2001
+#
+#    Time to get rid of the dependency on httpget.  The -l option is cone, too;
+#    instead, we deduce the right case by looking at the leading tag.  -q
+#    is gone; we always emit without quotes.  -m is gone too, instead we
+#    try commands in least to most expensive order, and notice when a command
+#    returns not to try it again.
+#
+import sys, os, getopt, filecmp, string, re, urllib, commands
 
-$version = "1.9, 23 Feb 2001";
+version = "2.0, 11 July 2001";
 
-$splash = <<EOT;
-imgsizer version $version, Eric  S. Raymond <esr\@thyrsus.com>
-See my home page at <http://www.tuxedo.org/~esr> for updates.
-EOT
+splash = """imgsizer version %s, Eric S. Raymond <esr@thyrsus.com>
+See <http://www.tuxedo.org/~esr/software.html> for updates."""
 
-$usage = <<EOT;
-Usage: imgsizer [OPTIONS] [HTML File]
+usage = """Usage: imgsizer [OPTIONS] [HTML File]
 
 Options:
 
-    -v, --version
+    -V, --version
 
         Display version information and exit.
 
@@ -67,289 +73,193 @@ Options:
 
         Display usage information.
 
-    -m, --no-magick
-
-        Use file(1) and rdjpgcom(1) to determine the image size, instead
-        of identify(1) from the ImageMagick suite, which is the default.
-
     -d <directory>, --document-root <directory>
 
-        Directory where aboslute image filenames (i.e, ones which contain
+        Directory where absolute image filenames (i.e, ones which contain
         a leading "/") may be found.
 
-    -l, --lowercase
+    -n, --no-overwrite
 
-        Output HTML tag attributes imgsizer generates in lowercase.
+        Don't overwrite existing width and heigbt tags if both are present.
 
-    -q, --no-quotes
+"""
 
-        Omit the quotes in HTML tag attributes imgsizer generates.
-EOT
+def attrformat(xc, dim):
+    if lower:
+        res = " " + dim
+    else:
+        res = " " + string.upper(dim)
+    res = res + '=' + str(xc)
+    return res
 
-# Anything that can fetch a URL defined on the command line 
-# and dump it to stdout will do here.  We try a number of
-# alternatives and crap out if we can't find any of them
-%fetchers = {"curl":"curl", "httpget":"httpget", "lynx":"lynx -source"}
-$fetcher = ""
-for $trythis in keys(fetchers) {
-    if (system(`whereis $trythis >/dev/null`) == 0) {
-       $fetcher = $fetchers{trythis}
-    }
-unless ($fetcher)
-    die("Can't find a remote URL fetcher.\n")
+def sizefix(infp, outfp):
+# Apply attrfix to the attributes in each image tag
+    global lower
+    while 1:
+        ch = infp.read(1)
+        if ch == '':
+            return
+        outfp.write(ch)
+        if ch == '<':
+            # within an HTML tag
+            lead = infp.read(3)
+            if ch == '':
+                return
+            outfp.write(lead)
+            if lead.find('>') > -1:
+                continue
+            if not lead in ("img", "IMG"):
+                continue
+            # within an image tag
+            lower = (lead == 'img')
+            state = suppress = 0
+            attributes = ""
+            while 1:
+                ch = infp.read(1)
+                if ch == '':
+                    return
+                if ch == '>':
+                    break
+                attributes = attributes + ch
+            outfp.write(transform(attributes) + ">")
+
+x_match = re.compile (r" ([0-9]+) *x *([0-9]+) ")
+rdjpg_match = re.compile (r" ([0-9]+)w *\* *([0-9]+)h ")
+
+def imgsize(src):
+    "Return the image size in pixels for a given image source."
+    global magick, rdjpgcom
+    try:
+        (filename, headers) = urllib.urlretrieve(src)
+    except IOError:
+        return None
+    # Now let's see if we can get a size for the retrieved image.
+    # Try file(1) first -- cheapest, as it doesn't read the whole image
+    (status, output) = commands.getstatusoutput("file " + filename)
+    if status == 0:
+        # file(1) works for every common image format other than JPEG
+        if string.find(output, "JPEG") == -1:
+            sizes = x_match.search(output)
+            if sizes:
+                return (sizes.group(1), sizes.group(2))
+        elif rdjpgcom:
+            # Use rdjpcom(1) to handle JPEGs
+            (status, output) = commands.getstatusoutput("rdjpcom " + filename)
+            sizes = rdjpg_match.search(output)
+            if sizes:
+                return (sizes.group(1), sizes.group(2))
+            elif status == 127:
+                rdjpgcom = 0
+    # Next try identify(1), more expensive nut bulletproof
+    if magick:
+        (status, output) = commands.getstatusoutput("identify " + filename)
+        if status == 0:
+            sizes = x_match.search(output)
+            if sizes:
+                return (sizes.group(1), sizes.group(2))
+        elif status == 127:
+            magick = 0
+    # All attempts failed
+    sys.stderr.write("imgsizer: couldn't analyze " + src)
+
+source  = re.compile('SRC="?([^" \t\n]*)"?', re.I)
+awidth  = re.compile(' *WIDTH="?[0-9]*"?', re.I)
+aheight = re.compile(' *HEIGHT="?[0-9]*"?', re.I)
+pwidth  = re.compile('WIDTH="?[0-9]*%"?', re.I)
+pheight = re.compile('HEIGHT="?[0-9]*%"?', re.I)
+
+def transform(attr):
+    src = source.search(attr)
+    # Must have a source part and no percents in existing width or height
+    if not src or pwidth.search(attr) or pheight.search(attr):
+        return attr
+    if no_overwrite and awidth.search(attr) and aheight.search(attr):
+        return attr
+    # Correct the url for documentation root, if present
+    url = src.group(1)
+    if url[0] == '/' and root:
+        url = os.path.join(root, url)
+    # OK, get the size tuple if possible
+    dimensions = imgsize(url)
+    if not dimensions:
+        return attr
+    else:
+        # Nuke any old size attr
+        if not no_overwrite:
+            attr = re.sub(awidth, "", attr)
+            attr = re.sub(aheight, "", attr)
+        # Compute image dimensions
+        (xc, yc) = dimensions
+        # Plug in the new attr
+        return attr + attrformat(xc, "width") + attrformat(yc, "height") 
 
 # Output uppercase tags, surrounded by quotes, by default.
-$lower = 0;
-$quotes = 1;
+lower = 0
+quotes = 1
 
 # Set the default DocumentRoot to the current working directory.
-$root = ".";
-
-$out = "imgsizer-out$$";
-$dir = ".";    # NOTE: if you are doing <yourfile , make sure that pwd is correct! 
-$magick = 1;   # using ImageMagick by default
-$/='>';                # define INPUT_RECORD_SEPARATOR to split on HTML marker boundaries
-
-# Look in IMGSIZER environmental variable for additional command line options
-unshift @ARGV, split /\s+/, $ENV{IMGSIZER}
-       if ($ENV{IMGSIZER});
-
-while ($i = shift @ARGV)
-{
-       last if ($i eq "--");
-
-       unless ($i =~ /^-/)
-       {
-               unshift @ARGV, $i;
-               last;
-       }
-
-       if ($i =~ /^-(\w{2,})$/i)
-       {
-               # Hack to parse "-foo" as "-f -o -o"
-               unshift  @ARGV, map { "-$_" } split //, $1;
-               next;
-       }
-
-       if ($i =~ /^(--ver(sion)?|-v)$/i)
-       {
-               die "\n$splash\n";
-       }
-
-       if ($i =~ /^(--help|--usage|-h)$/i)
-       {
-               die "\n$splash\n$usage\n";
-       }
-
-       if ($i =~ /^(--no-?magick|-m)$/i)
-       {
-               $magick = 0;
-               next;
-       }
-
-       if ($i =~ /^(--document-?root(=.*)?|-d)$/i)
-       {
-               if ($2 =~ /^=(.*)/)
-               {
-                       $root = $1;
-               }
-
-               else
-               {
-                       die "Error: --document-root requires a directory name\n"
-                               unless (@ARGV);
-
-                       $root = shift @ARGV;
-               }
-
-               die "Error: --document-root, \"$root\", is not a directory ",
-                       "or does not exist\n"
-                               unless (-d $root);
-               next;
-       }
-
-       if ($i =~ /^(--lower-?(case)?|-l)$/i)
-       {
-               $lower = 1;
-               next;
-       }
-
-       if ($i =~ /^(--no-?quotes?|-q)$/i)
-       {
-               $quotes = 0;
-               next;
-       }
-
-       die "Error: Unknown option: $i\n";
-}
-
-if (@ARGV) {           
-       foreach $x (@ARGV) {
-               $file = $x;
-               $dir = &dirname($x);
-               open(TEMP, ">$out")
-                       || die("imgsizer: couldn't open tempfile $out \n");
-               close(STDIN);
-               if (!open(STDIN, "$file")) {
-                       print STDERR "imgsize: couldn't open $x for input\n";
-               } else {
-                       select(TEMP);
-                       &sizefix;
-                       close(TEMP);
-                       if (`cmp $out $file` && system("cp $out $file")) {
-                               print STDERR "imgsize: couldn't replace ${file}\n}";
-                       }
-               }
-       }
-       unlink($out);
-}
-else {
-       $file = "stdin";
-       &sizefix;
-}
-
-sub dirname
-# return filename with the basename part stripped away
-{
-       local($file) = @_;
-       if ($file =~ /\//) {
-               $file =~ s:/[^/]*$::;
-       } else {
-               $file = ".";
-       }
-       return($file);
-}
-
-sub sizefix
-# Apply attrfix to the attributes in each image tag
-{
-       local $line = 1;
-
-       while (<STDIN>) {
-
-               $line += scalar @{[ /[\n\r]/g ]};
-
-               if (/(<IMG\s+)(.*)>/is) {
-                       print $`; print $1;
-                       $tag = $2;
-                       print &attrfix($tag);
-                       print ">";
-               }
-               else {
-                       print $_;
-               }
-       }
-}
-
-sub error
-{
-       print STDERR "\"$file\", line $line: $_[0]\n";
-}
-
-sub attrfix
-# fix up a space-separated sequence of image attributes 
-{
-       $attribs = $_[0];
-
-       unless ( ($attribs =~ /SRC=([^\s]+)/is)
-               || ($attribs =~ /SRC\s*=\s*\"([^"]*)\"/is) )
-       {
-               &error("image \"${attribs}\"' has no SRC attribute");
-               return $attribs;
-       }
-
-       $url = $1;
-
-       # fetch the image
-       if ($url =~ /^http:/) {
-               $image = "imgsizer-tmp$$";
-               $status = system("$fetcher ${url} >${image}");
-               if ($status) {
-                       &error("can't fetch $1");
-                       unlink("imgsizer-tmp$$");
-                       return $attribs;
-               }
-       }
-        elsif ($url =~ m!^"?/!) {
-              $image = $root . $url;  # This catches local files that are in
-                                     # virtual root, assuming we're called
-                                     # from /var/www or equivalent.
-        }
-        elsif (!($url =~ /^[a-z]+:/)) {
-                $image = "$dir/$url";   # This catches local files
-       }
-
-       # Don't try to fix up percent sizes
-       if ($attribs =~ /[0-9]%/s) {
-               return $attribs;
-       }
-
-       if ($magick) {
-               ($name, $size) = split(' ', `identify ${image}`);
-               unlink("imgsizer-tmp$$");
-               if ($name =~ /:/) {
-                       &error("can't analyze included image ${image}");
-                       return $attribs;
-               }
-               if (!($size=~ /([0-9]+)x([0-9]+)/)) {
-                       &error("size field ${size} is ill-formed");
-                       return $attribs;
-               }
-               $xc = $1;
-               $yc = $2;
-       }
-
-       else {
-               $result = `file ${image}`;
-               if ($result =~ /JPEG/) {
-                       $result = `rdjpgcom -verbose ${image}`;
-                       unlink("imgsizer-tmp$$");
-                       if ($result =~ /rdjpgcom:/) {
-                               &error("can't analyze included image ${image}");
-                               return $attribs;
-                       }
-                       else {
-                               $result =~ /(\d+)w \* (\d+)h/;
-                               $xc = $1;
-                               $yc = $2;
-                       }
-               }
-               else {
-                       unlink("imgsizer-tmp$$");
-                       if ($result !~ /(\d+) x (\d+)/) {
-                               &error("can't analyze included image ${image}");
-                               return $attribs;
-                       }
-                       else {
-                               $xc = $1;
-                               $yc = $2;
-                       }
-               }
-       }
-
-       if ($attribs =~ /WIDTH\s*=\s*["0123456789]+/is) {
-               $attribs = $` . &widthstring . $';
-       } else {
-               $attribs .= " " . &widthstring;
-       }
-
-       if ($attribs =~ /HEIGHT\s*=\s*["0123456789]+/is) {
-               $attribs = $` . &heightstring . $';
-       } else {
-               $attribs .= " " . &heightstring;
-       }
-
-       return $attribs;
-}
-
-sub widthstring        
-{
-       return ($lower ? "width=" : "WIDTH=")
-               . ($quotes ? '"' : '') . $xc . ($quotes ? '"' : '');
-}
-
-sub heightstring
-{
-       return ($lower ? "height=" : "HEIGHT=")
-               . ($quotes ? '"' : '') . $yc . ($quotes ? '"' : '');
-}
+root = "."
+
+out = "imgsizer-out$$"
+dir = "."      # NOTE: if you are doing <yourfile , make sure that pwd is correct! 
+
+# Optimization latches -- if an attempt  to invoke a command returns 127
+# "not found" there will turn off and that command won't be tried again.
+magick = 1     # using ImageMagick by default
+rdjpgcom = 1   # using rdjpcom by default
+
+# Collect options from the environment first, then the command line
+options = os.environ.get("IMGSIZER")
+if options:
+    options = string.split(options)
+else:
+    options = []
+options = options + sys.argv[1:]
+
+# Process options
+(options, arguments) = getopt.getopt(options, "Vhd:n",
+                            ('version', 'help', 'usage', 'document=', 'no-overwrite'))
+no_overwrite = 0
+for (switch, val) in options:
+    if switch in ('-V', '--version'):
+        print splash % version
+        raise SystemExit
+    elif switch in ('-h', '--help', '--usage'):
+        print splash + "\n\n" + usage
+        raise SystemExit
+    elif switch in ('-d', '--document'):
+        root = val
+        if not os.path.isdir(root):
+            print "Document root isn't a directory"
+            raise SystemExit, 1
+    elif switch in ('-n', '--no-overwrite'):
+        no_overwrite = 1
+
+if not arguments:
+    sizefix(sys.stdin, sys.stdout)
+else:
+    for file in arguments:
+        base = os.path.basename(file) 
+        dir  = os.path.dirname(file) 
+        try:
+            infp = open(file)
+        except:
+            print "imgsizer: can't open input file", file
+            raise SystemExit, 1
+        tempfile = file + ".~imgsizer-%d~" % os.getpid()
+        try:
+            outfp = open(tempfile)
+        except OSError:
+            print "imgsizer: can't open tempfile"
+            raise SystemExit, 1
+        sizefix(infp, outfp)
+        if filecmp.cmp(file, tempfile):
+            os.remove(tempfile)
+        else:
+            try:
+                os.rename(tempfile, file)
+            except OSError:
+                sys.stderr.write("imgsize: couldn't replace " + file)
+                os.remove(tempfile)
+
+# End
index 15c0b583ca583b40d44dc02978773eff9d50e2cd..10d7b7a66de4e21bb4822a6df5712f606bb14a99 100644 (file)
@@ -7,25 +7,18 @@ imgsizer \- automatically splice in height and width params for HTML IMG tags
 .PP
 .SH OPTIONS
 .TP
-.B \-v, \-\-version
+.B \-V, \-\-version
 Display version information and exit.
 .TP
 .B \-h, \-\-help
 Display usage information.
 .TP
-.B \-m, \-\-no\-magick
-Use file(1) and rdjpgcom(1) to determine the image size, instead
-of identify(1) from the ImageMagick suite, which is the default.
-.TP
 .B \-d <directory>, \-\-document\-root <directory>
 Directory where aboslute image filenames (i.e, ones which contain
 a leading "/") may be found.
 .TP
-.B \-l, \-\-lowercase
-Output HTML tag attributes imgsizer generates in lowercase.
+.B \-n, \-\-no-overwwrite
 .TP
-.B \-q, \-\-no\-quotes
-Omit the quotes in HTML tag attributes imgsizer generates.
 .SH DESCRIPTION
 The 
 .B imgsizer
@@ -49,38 +42,38 @@ arguments, it will attempt to transform each file in place.  Each
 argument file is not actually modified until the script completes a
 successful conversion pass.
 .PP
-The \-q option suppresses generation of string quotes in generated
-attributes.  The \-l option generates attributes in lower case.
 The \-d <directory> option sets the DocumentRoot, which images with an
 absolute filename (i.e., ones which contain a leading "/") may be found.
 If none is specified, the DocumentRoot defaults to the current working
 directory.
 .PP
+The \-n (no-overwrite) opion prevents the program from overwriting 
+existing width and height tags if both are present.
+.PP
 Additional options may also be specified in the environmental variable
-"IMGSIZER".  For example, to avoid typing "imgsizer -options ..." each
+"IMGSIZER".  For example, to avoid typing "imgsizer -d /var/www/docs" each
 time imgsizer is invoked, you might tell sh (or one of its descendants):
 .PP
 .RS
-IMGSIZER="\-options"; export IMGSIZER
+IMGSIZER="\-d /var/www/docs"; export IMGSIZER
 .RE
 .PP
 or, if you use csh:
 .PP
 .RS
-setenv IMGSIZER "\-options"
+setenv IMGSIZER "\-d /var/www/docs"
 .RE
 .PP
-This script is written in Perl, and thus requires a Perl interpreter
+This script is written in Python, and thus requires a Python interpreter
 on the host system.  It also requires either the 
 .IR identify (1)
-utility distributed in the freeware ImageMagick suite of image-display
+utility distributed in the open-source ImageMagick suite of image-display
 and manipulation tools, or, with the \-\-no\-magick option, a modern
 version of
 .IR file (1)
 and 
-.IR rdjpgcom (1)
-(the --no-magick mode is faster).  These 
-utilities are used to extract sizes from the images;
+.IR rdjpgcom (1).
+These  utilities are used to extract sizes from the images;
 .B imgsizer
 itself has no knowledge of graphics formats.  The script will handle any
 image format known to 
@@ -88,20 +81,14 @@ image format known to
 including PNG, GIF, JPEG, XBM, XPM, PostScript, BMP, TIFF, and anything else
 even remotely likely to show up as an inline image.
 .PP
-In order for
-.B imgsizer
-to correctly interpret remote URLs, the freeware script 
-.IR httpget (1)
-must be executable and present in your execution path;
-.B imgsizer
-will complain and fail if either the required size-reporting tools or
-.IR httpget (1)
-are needed and not present.
+.SH NOTE
+The -q, -l, and -m options of the 1.0 versions are gone.  What they
+used to do has been made unnecessary by smarter logic.
 .SH AUTHOR
 Originally created by Eric\ S.\ Raymond\ <esr@thyrsus.com>.  Additional code
 contributed by Erik\ Rossen and Michael\ C.\ Toren\ <michael@toren.net>.
-.SH AVAILABILITY
 For updates, see <http://www.tuxedo.org/~esr>
 .SH SEE ALSO
 .IR identify (1),
-.IR httpget (1).
+.IR file (1),
+.IR rdjpgcom(1).