/ adafruit_imageload / pnm / __init__.py
__init__.py
  1  # The MIT License (MIT)
  2  #
  3  # Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
  4  #
  5  # Permission is hereby granted, free of charge, to any person obtaining a copy
  6  # of this software and associated documentation files (the "Software"), to deal
  7  # in the Software without restriction, including without limitation the rights
  8  # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  9  # copies of the Software, and to permit persons to whom the Software is
 10  # furnished to do so, subject to the following conditions:
 11  #
 12  # The above copyright notice and this permission notice shall be included in
 13  # all copies or substantial portions of the Software.
 14  #
 15  # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 16  # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 17  # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 18  # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 19  # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 20  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 21  # THE SOFTWARE.
 22  """
 23  `adafruit_imageload.pnm`
 24  ====================================================
 25  
 26  Load pixel values (indices or colors) into a bitmap and colors into a palette.
 27  
 28  * Author(s): Matt Land, Brooke Storm, Sam McGahan
 29  
 30  """
 31  # pylint: disable=import-outside-toplevel
 32  
 33  __version__ = "0.0.0-auto.0"
 34  __repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"
 35  
 36  
 37  def load(file, header, *, bitmap=None, palette=None):
 38      """
 39      Scan for netpbm format info, skip over comments, and and delegate to a submodule
 40      to do the actual data loading.
 41      Formats P1, P4 have two space padded pieces of information: width and height.
 42      All other formats have three: width, height, and max color value.
 43      This load function will move the file stream pointer to the start of data in all cases.
 44      """
 45      # pylint: disable=too-many-branches
 46      magic_number = header[:2]
 47      file.seek(2)
 48      pnm_header = []
 49      next_value = bytearray()
 50      while True:
 51          # We have all we need at length 3 for formats P2, P3, P5, P6
 52          if len(pnm_header) == 3:
 53              if magic_number in [b"P2", b"P5"]:
 54                  from . import pgm
 55  
 56                  return pgm.load(
 57                      file, magic_number, pnm_header, bitmap=bitmap, palette=palette
 58                  )
 59  
 60              if magic_number == b"P3":
 61                  from . import ppm_ascii
 62  
 63                  return ppm_ascii.load(
 64                      file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
 65                  )
 66  
 67              if magic_number == b"P6":
 68                  from . import ppm_binary
 69  
 70                  return ppm_binary.load(
 71                      file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
 72                  )
 73  
 74          if len(pnm_header) == 2 and magic_number in [b"P1", b"P4"]:
 75              bitmap = bitmap(pnm_header[0], pnm_header[1], 1)
 76              if palette:
 77                  palette = palette(1)
 78                  palette[0] = b"\xFF\xFF\xFF"
 79              if magic_number.startswith(b"P1"):
 80                  from . import pbm_ascii
 81  
 82                  return pbm_ascii.load(
 83                      file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
 84                  )
 85  
 86              from . import pbm_binary
 87  
 88              return pbm_binary.load(
 89                  file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
 90              )
 91  
 92          next_byte = file.read(1)
 93          if next_byte == b"":
 94              raise RuntimeError("Unsupported image format {}".format(magic_number))
 95          if next_byte == b"#":  # comment found, seek until a newline or EOF is found
 96              while file.read(1) not in [b"", b"\n"]:  # EOF or NL
 97                  pass
 98          elif not next_byte.isdigit():  # boundary found in header data
 99              if next_value:
100                  # pull values until space is found
101                  pnm_header.append(int("".join(["%c" % char for char in next_value])))
102                  next_value = bytearray()  # reset the byte array
103          else:
104              next_value += next_byte  # push the digit into the byte array