web2png
上传用户:sorock1981
上传日期:2007-01-06
资源大小:73k
文件大小:11k
源码类别:

图片显示

开发平台:

Unix_Linux

  1. #!/usr/bin/env python
  2. """web2png -- convert a web hierarchy from using GIFs to using PNGs.
  3. This script is a front end for gif2png that assists you in converting an
  4. entire website.  Requires gif2png 1.1.0 or later.  Requires python 1.5.2
  5. or later. Requires Unix.
  6. by Eric S. Raymond <esr@thyrsus.com>
  7. """
  8. __version__="$Revision: 1.21 $" 
  9. # Future library code -- I'm going to submit this for Python 1.6
  10. import sys, os, sys
  11. from stat import *
  12. if sys.version[:5] < "1.5.2":
  13.     print "This program requires Python 1.5.2 or later."
  14.     sys.exit(1)
  15. FTW_FILE    = 0 # Item is a normal file
  16. FTW_DIR     = 1 # Item is a directory
  17. FTW_CHRDEV  = 2 # Item is a character special device file
  18. FTW_BLKDEV  = 3 # Item is a block special device file
  19. FTW_FIFO    = 4 # Item is a FIFO
  20. FTW_SYMLINK = 5 # Item is a symbolic link
  21. FTW_SOCKET  = 6 # Item is a socket
  22. FTW_NOSTAT = -1 # stat failed on item
  23. FTW_DNR    = -2 # item was an unreadable directory
  24. class FTWException(Exception):
  25. pass
  26. def ftw_inner(func, path=".", extra=[]):
  27.     try:
  28.         st = os.stat(path)
  29.     except:
  30.         return FTW_NOSTAT
  31.     mode = st[ST_MODE]
  32.     if S_ISDIR(mode):
  33.         try:
  34.             subdirs = os.listdir(path)
  35.         except:
  36.             return FTW_DNR
  37.     if S_ISREG(mode):  ftype = FTW_FILE
  38.     if S_ISDIR(mode):  ftype = FTW_DIR
  39.     if S_ISBLK(mode):  ftype = FTW_BLKDEV
  40.     if S_ISCHR(mode):  ftype = FTW_CHRDEV
  41.     if S_ISFIFO(mode): ftype = FTW_FIFO
  42.     if S_ISLNK(mode):  ftype = FTW_SYMLINK
  43.     if S_ISSOCK(mode): ftype = FTW_SOCKET
  44.     terminate = apply(func, tuple([path, st, ftype] + list(extra)))
  45.     if terminate < 0:
  46.         raise FTWException, terminate
  47.     if S_ISDIR(mode) and not terminate:
  48.         for f in subdirs:
  49.             ftw_inner(func, os.path.join(path, f), extra)
  50. def ftw(func, path=".", *extra):
  51.     """Python tree-walker -- like ftw(3), but more capable."""
  52.     try:
  53.         ftw_inner(func, path, extra)
  54.     except FTWException, val:
  55.         return val
  56.     return 0
  57. def find(dir=".", regexp=None):
  58.    """Return a tuple list of entries beneath dir matching a given pattern."""
  59.    def findhook(path, st, ftype, r, fl):
  60.        if not r or r.search(path):
  61.            fl.append((path, ftype))
  62.        return 0
  63.    flist=[]
  64.    ftw(findhook, dir, regexp, flist)
  65.    return flist
  66. def findfiles(dir=".", regexp=None):
  67.     """Return a list of files beneath dir matching a given pattern."""
  68.     return map(lambda x: os.path.normpath(x[0]),
  69.                filter(lambda t: t[1]==FTW_FILE, find(dir, regexp)))
  70. def cmp(f1, f2, blocksize=1):
  71.     # print "Comparing %s with %s" % (f1, f2)
  72.     # st1 = os.stat(f1); print st1
  73.     # st2 = os.stat(f2); print st2
  74.     f1 = open(f1, "r")
  75.     f2 = open(f2, "r")
  76.     blocknum = 0
  77.     try:
  78.         while 1:
  79.             blocknum = blocknum + 1
  80.             s1 = f1.read(blocksize);
  81.             s2 = f2.read(blocksize);
  82.             if not s1 and not s2:
  83.                 break
  84.             elif s1 != s2:
  85.                 return blocknum
  86.     finally:
  87.         f1.close()
  88.         f2.close()
  89.     return None
  90. # End future library code
  91. import re, getopt, commands, string, shutil, urllib
  92. nochange = all = None
  93. gifre = re.compile(r".gif$", re.IGNORECASE)
  94. pngre = re.compile(r".png$", re.IGNORECASE)
  95. pagere = re.compile(r".s?html$|.php$|.inc$|.css$|.js$", re.IGNORECASE)
  96. bakre = re.compile(r".bak$", re.IGNORECASE)
  97. # Possible left delimiters of these matches are =, ", (, s
  98. # Possible right delimiters of these matches are ", >, ), s
  99. # .?"? parts deal with the possibility that the optional " might be backslashed
  100. delim = r'(?:\?")?' # Optional double quote, possibly preceded by backslash
  101. gif = delim + '([^">]*.gif)' + delim
  102. imgre = re.compile(r'SRC=' + gif, re.IGNORECASE)
  103. hrefre = re.compile(r'<A HREF=' + gif + '>', re.IGNORECASE)
  104. backre = re.compile(r'BACKGROUND=' + gif, re.IGNORECASE)
  105. basere = re.compile(r'<BASE HREF=' + gif + '>', re.IGNORECASE)
  106. cssurlre = re.compile(r'url(' + gif + ')', re.IGNORECASE)
  107. def version_controlled(page):
  108.     # Is given page under version control?
  109.     return os.path.exists(page + ",v") 
  110.            or os.path.exists(os.path.join("RCS", page) + ",v")
  111. def web2png(directory):
  112.     # Convert a web hierarchy rooted on the given directory
  113.     gifs = findfiles(directory, gifre)
  114.     htmls = findfiles(directory, pagere)
  115.     # There's a standard max on the number of arguments we can feed gif2png.
  116.     # if we see more than these, 
  117.     if len(gifs) > 5120:
  118.         "web2png: Too many GIFs.  Try converting some subtrees first."
  119.         system.exit(1)
  120.     print "This web subtree has", len(gifs), "GIFs and", len(htmls), "pages."
  121.     # Display information on files we won't convert
  122.     rejects = 
  123. commands.getoutput("gif2png -w "+string.join(gifs," ")+" >/dev/null")
  124.     rejects = re.sub("gif2png: ", " ", rejects)
  125.     if rejects:
  126.         if all:
  127.             print "You are forcing conversion of these GIFs:"
  128.         else:
  129.             print "The following GIFs will not be converted:"
  130.         print rejects
  131.     # Figure out which files are eligible for conversion
  132.     if all:
  133.         giflist = gifs
  134.     else:
  135.         giflist = 
  136.                 string.split(commands.getoutput("gif2png -w "+string.join(gifs," ")+" 2>/dev/null"))
  137.     if verbose: print "Giflist: " + repr(giflist)
  138.     convert_gifs = []
  139.     for gif in giflist:
  140.         png = re.sub(r".gif$", r".png", gif)
  141.         if os.path.exists(png):
  142.             print "t%s already has a PNG equivalent" % (gif,)
  143.         else:
  144.             convert_gifs.append(gif)
  145.     # Display information on files we will convert
  146.     if convert_gifs:
  147.         print "The following GIFs will be converted:nt" + 
  148. string.join(convert_gifs, "nt")
  149.     if not convert_gifs:
  150.         print "All eligible GIFs seem to have been converted already."
  151.     # Create a dictionary mapping pages to sets of references to be mapped
  152.     print "Checking for HTML, PHP JavaScript and include pages that need conversion..."
  153.     pagecount = 0
  154.     page_conversions = {}
  155.     for file in htmls:
  156.         fp = open(file, "r")
  157.         contents = fp.read()
  158.         fp.close()
  159.         basedir = basere.search(contents)
  160.         if basedir:
  161.             basedir = base.group(1)
  162.         else:
  163.             basedir = os.path.dirname(file)
  164.         matches = imgre.findall(contents) + hrefre.findall(contents) + backre.findall(contents) + cssurlre.findall(contents)
  165.         if verbose:
  166.     print "Found %d .gif image(s) references in %s."%(len(matches),file)
  167.         convert_refs = []
  168.         gif_basenames = map(os.path.basename, giflist)
  169.         for ref in matches:
  170.             withbase = os.path.join(basedir, ref)
  171.             # Simple case -- it's a filename, we presume it's local
  172.             if withbase[:5] != "http:" and withbase[1:] != os.sep:
  173.                 target = os.path.normpath(withbase)
  174.                 if not target in giflist:
  175.                     if verbose: print "Won't replace %s. Not on my list."%target
  176.                     continue
  177.             # Tricky case -- compare by basename and content
  178.             else:
  179.                 basename = os.path.basename(withbase[7:])
  180.                 if not basename in gif_basenames:
  181.                     print "No local match by basename for %s" % (ref,)
  182.                     continue
  183.                 target = giflist[gif_basenames.index(basename)]
  184.                 (data, headers) = urllib.urlretrieve(withbase)
  185.                 not_equal = cmp(data, target)
  186.                 os.remove(data)
  187.                 if not_equal:
  188.                     print "Data of %s and %s don't match at offset %d" % (ref, target, not_equal)
  189.                     continue
  190.             ref = ref[:-4]
  191.             convert_refs.append((ref, target))
  192.         if convert_refs:
  193.             print "tIn %s, I see: %s" % (file, string.join(map(lambda x: x[0]+".gif", convert_refs)," "))
  194.             page_conversions[file] = convert_refs
  195.     pagecount = pagecount + 1
  196.     print "%d HTML or PHP page(s) need conversion." % (pagecount,)
  197.     # Unless user is willing to make changes, we're done now
  198.     if nochange:
  199.         return
  200.     # Convert gifs verbosely
  201.     if convert_gifs:
  202.         print "GIF conversions begin:"
  203.         os.system("gif2png -v -O " + string.join(convert_gifs, " "))
  204.         # print "GIF conversions complete"
  205.     # Now check to see which conversions did not take
  206.     failures = []
  207.     for gif in convert_gifs:
  208.         png = re.sub(r".gif$", r".png", gif)
  209.         if not os.path.exists(png):
  210.             failures.append(gif)
  211.     if failures:
  212.         print "Some conversions failed:", string.join(failures)
  213.     # Now hack the references in the web pages
  214.     for page in page_conversions.keys():
  215.         print "Converting %s..." % (page,)
  216.         if version_controlled(page):
  217.             os.system("co -l " + page)
  218.         else:
  219.             shutil.copyfile(page, page + ".bak")
  220.         fp = open(page, "r")
  221.         contents = fp.read()
  222.         fp.close()
  223.         basedir = basere.search(contents)
  224.         if basedir:
  225.             basedir = base.group(1)
  226.         else:
  227.             basedir = ""
  228.         for (ref, target) in page_conversions[page]:
  229.             if target in giflist and not target in failures:
  230.                 source = '(?P<g1>[="(s])' + ref + r'.gif(?P<g2>[s"\>)])'
  231.                 target = r"g<g1>" + ref + r".pngg<g2>"
  232.                 print "Source: %s, target %s" % (source, target)
  233.                 contents = re.sub(source, target, contents)
  234.         fp = open(page, "w")
  235.         fp.write(contents)
  236.         fp.close()
  237.     print "Page conversions complete."
  238. def cleanup(directory):
  239.     # Clean up superfluous .gif and .bak files left over after a conversion
  240.     map(os.unlink, findfiles(directory, bakre))
  241.     pnglist = findfiles(directory, pngre)
  242.     for png in pnglist:
  243.         gif = png[:-4] + ".gif"
  244.         if os.path.exists(gif):
  245.             os.remove(gif)
  246. def unconvert(directory):
  247.     # Reverse a conversion    
  248.     pnglist = findfiles(directory, pngre)
  249.     for png in pnglist:
  250.         gif = png[:-4] + ".gif"
  251.         if os.path.exists(gif):
  252.             os.unlink(png)
  253.     htmls = findfiles(directory, pagere)
  254.     for page in htmls:
  255.         if os.path.exists(page + ".bak"):
  256.             os.rename(page + ".bak", page)
  257.         elif version_controlled(page):
  258.             os.system("rcs -u " + page)
  259. if __name__ == '__main__': 
  260.     delete = nochange = reverse = verbose = 0
  261.     (options, arguments) = getopt.getopt(sys.argv[1:], "adnrv")
  262.     if not arguments:
  263.         arguments = ['.']
  264.     for (switch, val) in options:
  265.         if switch == '-a':
  266.             all = 1
  267.         elif switch == '-d':
  268.             delete = 1
  269.         elif switch == '-n':
  270.             nochange = 1
  271.         elif switch == '-r':
  272.             reverse = 1
  273.         elif switch == '-v':
  274.             verbose = 1
  275.     if delete:
  276.         map(cleanup, arguments)
  277.     elif reverse:
  278.         map(unconvert, arguments)
  279.     else:
  280.         map(web2png, arguments)
  281. # The following sets edit modes for GNU EMACS
  282. # Local Variables:
  283. # mode:python
  284. # End: