1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
#!/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()
|