From: Eric S. Raymond Date: Wed, 11 Jul 2001 19:27:45 +0000 (+0000) Subject: Ready to ship 2.0. X-Git-Tag: 2.0~1 X-Git-Url: http://thyrsus.com/gitweb/?a=commitdiff_plain;h=ad57b41916e602dd3ae6d1910b5770122b7c1585;p=imgsizer.git Ready to ship 2.0. --- diff --git a/Makefile b/Makefile index 5ac50f8..ec8a05d 100644 --- 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 a475831..17410dd 100644 --- 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 diff --git a/imgsizer b/imgsizer index c41b998..8b22a35 100755 --- 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 @@ -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 @@ -46,20 +46,26 @@ # the line number an error occurred due to the input record separator # being set to ">". # +# Rewritten in Python by Eric S. Raymond 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 = < -See my home page at for updates. -EOT +splash = """imgsizer version %s, Eric S. Raymond +See for updates.""" -$usage = <, --document-root - 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 '; # 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 () { - - $line += scalar @{[ /[\n\r]/g ]}; - - if (/(/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 , \-\-document\-root 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 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\ . Additional code contributed by Erik\ Rossen and Michael\ C.\ Toren\ . -.SH AVAILABILITY For updates, see .SH SEE ALSO .IR identify (1), -.IR httpget (1). +.IR file (1), +.IR rdjpgcom(1).