pnghist 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  1. #!/usr/bin/env python
  2. # $URL: http://pypng.googlecode.com/svn/trunk/code/pnghist $
  3. # $Rev: 153 $
  4. # PNG Histogram
  5. # Only really works on grayscale images.
  6. from array import array
  7. import getopt
  8. import png
  9. def decidemax(level):
  10. """Given an array of levels, decide the maximum value to use for the
  11. histogram. This is normally chosen to be a bit bigger than the 99th
  12. percentile, but if the 100th percentile is not much more (within a
  13. factor of 2) then the 100th percentile is chosen.
  14. """
  15. truemax = max(level)
  16. sl = level[:]
  17. sl.sort(reverse=True)
  18. i99 = int(round(len(level)*0.01))
  19. if truemax <= 2*sl[i99]:
  20. return truemax
  21. return 1.05*sl[i99]
  22. def hist(out, inp, verbose=None):
  23. """Open the PNG file `inp` and generate a histogram."""
  24. r = png.Reader(file=inp)
  25. x,y,pixels,info = r.asDirect()
  26. bitdepth = info['bitdepth']
  27. level = [0]*2**bitdepth
  28. for row in pixels:
  29. for v in row:
  30. level[v] += 1
  31. maxlevel = decidemax(level)
  32. h = 100
  33. outbitdepth = 8
  34. outmaxval = 2**outbitdepth - 1
  35. def genrow():
  36. for y in range(h):
  37. y = h-y-1
  38. # :todo: vary typecode according to outbitdepth
  39. row = array('B', [0]*len(level))
  40. fl = y*maxlevel/float(h)
  41. ce = (y+1)*maxlevel/float(h)
  42. for x in range(len(row)):
  43. if level[x] <= fl:
  44. # Relies on row being initialised to all 0
  45. continue
  46. if level[x] >= ce:
  47. row[x] = outmaxval
  48. continue
  49. frac = (level[x] - fl)/(ce - fl)
  50. row[x] = int(round(outmaxval*frac))
  51. yield row
  52. w = png.Writer(len(level), h, gamma=1.0,
  53. greyscale=True, alpha=False, bitdepth=outbitdepth)
  54. w.write(out, genrow())
  55. if verbose: print >>verbose, level
  56. def main(argv=None):
  57. import sys
  58. if argv is None:
  59. argv = sys.argv
  60. argv = argv[1:]
  61. opt,arg = getopt.getopt(argv, '')
  62. if len(arg) < 1:
  63. f = sys.stdin
  64. else:
  65. f = open(arg[0])
  66. hist(sys.stdout, f)
  67. if __name__ == '__main__':
  68. main()