1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980 |
- #!/usr/bin/env python
- # $URL: http://pypng.googlecode.com/svn/trunk/code/pnghist $
- # $Rev: 153 $
- # PNG Histogram
- # Only really works on grayscale images.
- from array import array
- import getopt
- import png
- def decidemax(level):
- """Given an array of levels, decide the maximum value to use for the
- histogram. This is normally chosen to be a bit bigger than the 99th
- percentile, but if the 100th percentile is not much more (within a
- factor of 2) then the 100th percentile is chosen.
- """
- truemax = max(level)
- sl = level[:]
- sl.sort(reverse=True)
- i99 = int(round(len(level)*0.01))
- if truemax <= 2*sl[i99]:
- return truemax
- return 1.05*sl[i99]
- def hist(out, inp, verbose=None):
- """Open the PNG file `inp` and generate a histogram."""
- r = png.Reader(file=inp)
- x,y,pixels,info = r.asDirect()
- bitdepth = info['bitdepth']
- level = [0]*2**bitdepth
- for row in pixels:
- for v in row:
- level[v] += 1
- maxlevel = decidemax(level)
- h = 100
- outbitdepth = 8
- outmaxval = 2**outbitdepth - 1
- def genrow():
- for y in range(h):
- y = h-y-1
- # :todo: vary typecode according to outbitdepth
- row = array('B', [0]*len(level))
- fl = y*maxlevel/float(h)
- ce = (y+1)*maxlevel/float(h)
- for x in range(len(row)):
- if level[x] <= fl:
- # Relies on row being initialised to all 0
- continue
- if level[x] >= ce:
- row[x] = outmaxval
- continue
- frac = (level[x] - fl)/(ce - fl)
- row[x] = int(round(outmaxval*frac))
- yield row
- w = png.Writer(len(level), h, gamma=1.0,
- greyscale=True, alpha=False, bitdepth=outbitdepth)
- w.write(out, genrow())
- if verbose: print >>verbose, level
- def main(argv=None):
- import sys
- if argv is None:
- argv = sys.argv
- argv = argv[1:]
- opt,arg = getopt.getopt(argv, '')
- if len(arg) < 1:
- f = sys.stdin
- else:
- f = open(arg[0])
- hist(sys.stdout, f)
- if __name__ == '__main__':
- main()
|