123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172 |
- #!D:\TestPythonProject\TEST\venv\Scripts\python.exe
- # prigreypng
- # Convert image to grey (L, or LA), but only if that involves no colour change.
- import argparse
- import array
- import png
- def as_grey(out, inp):
- """
- Convert image to greyscale, but only when no colour change.
- This works by using the input G channel (green) as
- the output L channel (luminance) and
- checking that every pixel is grey as we go.
- A non-grey pixel will raise an error.
- """
- r = png.Reader(file=inp)
- _, _, rows, info = r.asDirect()
- if info["greyscale"]:
- w = png.Writer(**info)
- return w.write(out, rows)
- planes = info["planes"]
- targetplanes = planes - 2
- alpha = info["alpha"]
- width, height = info["size"]
- typecode = "BH"[info["bitdepth"] > 8]
- # Values per target row
- vpr = width * targetplanes
- def iterasgrey():
- for i, row in enumerate(rows):
- row = array.array(typecode, row)
- targetrow = array.array(typecode, [0] * vpr)
- # Copy G (and possibly A) channel.
- green = row[0::planes]
- if alpha:
- targetrow[0::2] = green
- targetrow[1::2] = row[3::4]
- else:
- targetrow = green
- # Check R and B channel match.
- if green != row[0::planes] or green != row[2::planes]:
- raise ValueError("Row %i contains non-grey pixel." % i)
- yield targetrow
- info["greyscale"] = True
- del info["planes"]
- w = png.Writer(**info)
- return w.write(out, iterasgrey())
- def main(argv=None):
- parser = argparse.ArgumentParser()
- parser.add_argument(
- "input", nargs="?", default="-", type=png.cli_open, metavar="PNG"
- )
- args = parser.parse_args()
- return as_grey(png.binary_stdout(), args.input)
- if __name__ == "__main__":
- import sys
- sys.exit(main())
|