Skip to content

Commit

Permalink
Merge pull request #12 from crookedstorm/feature-tests
Browse files Browse the repository at this point in the history
Working P1-P6 formats
  • Loading branch information
matt-land authored May 22, 2019
2 parents e4c04af + 115716d commit 74b287c
Show file tree
Hide file tree
Showing 29 changed files with 1,500 additions and 8 deletions.
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,7 @@ _build
.env
build*
bundles
.idea/
venv/

.vscode
2 changes: 1 addition & 1 deletion .pylintrc
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ extension-pkg-whitelist=

# Add files or directories to the blacklist. They should be base names, not
# paths.
ignore=CVS
ignore=CVS,adafruit_imageload/tests

# Add files or directories matching the regex patterns to the blacklist. The
# regex matches against base names, not paths.
Expand Down
1 change: 1 addition & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ install:
- pip install --force-reinstall pylint==1.9.2

script:
- pytest adafruit_imageload
- pylint adafruit_imageload/**
- ([[ ! -d "examples" ]] || pylint --disable=missing-docstring,invalid-name,bad-whitespace examples/*.py)
- circuitpython-build-bundles --filename_prefix adafruit-circuitpython-imageload --library_location .
Expand Down
5 changes: 4 additions & 1 deletion adafruit_imageload/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,11 @@ def load(filename, *, bitmap=None, palette=None):
"""
with open(filename, "rb") as file:
header = file.read(3)
file.seek(0)
if header.startswith(b"BM"):
from . import bmp
file.seek(0)
return bmp.load(file, bitmap=bitmap, palette=palette)
if header.startswith(b"P"):
from . import pnm
return pnm.load(file, header, bitmap=bitmap, palette=palette)
raise RuntimeError("Unsupported image format")
12 changes: 6 additions & 6 deletions adafruit_imageload/bmp/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,9 +56,9 @@ def load(file, *, bitmap=None, palette=None):

if colors == 0 and color_depth >= 16:
raise NotImplementedError("True color BMP unsupported")
else:
if colors == 0:
colors = 2 ** color_depth
from . import indexed
return indexed.load(file, width, height, data_start, colors, color_depth, bitmap=bitmap,
palette=palette)

if colors == 0:
colors = 2 ** color_depth
from . import indexed
return indexed.load(file, width, height, data_start, colors, color_depth, bitmap=bitmap,
palette=palette)
103 changes: 103 additions & 0 deletions adafruit_imageload/pnm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_imageload.pnm`
====================================================
Load pixel values (indices or colors) into a bitmap and colors into a palette.
* Author(s): Matt Land, Brooke Storm, Sam McGahan
"""

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"


def load(file, header, *, bitmap=None, palette=None):
"""
Scan for netpbm format info, skip over comments, and and delegate to a submodule
to do the actual data loading.
Formats P1, P4 have two space padded pieces of information: width and height.
All other formats have three: width, height, and max color value.
This load function will move the file stream pointer to the start of data in all cases.
"""
# pylint: disable=too-many-branches
magic_number = header[:2]
file.seek(2)
pnm_header = []
next_value = bytearray()
while True:
# We have all we need at length 3 for formats P2, P3, P5, P6
if len(pnm_header) == 3:
if magic_number in [b"P2", b"P5"]:
from . import pgm

return pgm.load(
file, magic_number, pnm_header, bitmap=bitmap, palette=palette
)

if magic_number == b"P3":
from . import ppm_ascii

return ppm_ascii.load(
file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
)

if magic_number == b"P6":
from . import ppm_binary

return ppm_binary.load(
file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
)

if len(pnm_header) == 2 and magic_number in [b"P1", b"P4"]:
bitmap = bitmap(pnm_header[0], pnm_header[1], 1)
if palette:
palette = palette(1)
palette[0] = b"\xFF\xFF\xFF"
if magic_number.startswith(b"P1"):
from . import pbm_ascii

return pbm_ascii.load(
file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
)

from . import pbm_binary

return pbm_binary.load(
file, pnm_header[0], pnm_header[1], bitmap=bitmap, palette=palette
)

next_byte = file.read(1)
if next_byte == b"":
raise RuntimeError("Unsupported image format {}".format(magic_number))
if next_byte == b"#": # comment found, seek until a newline or EOF is found
while file.read(1) not in [b"", b"\n"]: # EOF or NL
pass
elif not next_byte.isdigit(): # boundary found in header data
if next_value:
# pull values until space is found
pnm_header.append(int("".join(["%c" % char for char in next_value])))
next_value = bytearray() # reset the byte array
else:
next_value += next_byte # push the digit into the byte array
52 changes: 52 additions & 0 deletions adafruit_imageload/pnm/pbm_ascii.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_imageload.pnm.pbm_ascii`
====================================================
Load pixel values (indices or colors) into a bitmap and for an ascii ppm,
return None for pallet.
* Author(s): Matt Land, Brooke Storm, Sam McGahan
"""

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"


def load(file, width, height, bitmap=None, palette=None):
"""
Load a P1 'PBM' ascii image into the displayio.Bitmap
"""
next_byte = True
for y in range(height):
x = 0
while next_byte:
next_byte = file.read(1)
if not next_byte.isdigit():
continue
bitmap[x, y] = 1 if next_byte == b"1" else 0
if x == width - 1:
break
x += 1
return bitmap, palette
74 changes: 74 additions & 0 deletions adafruit_imageload/pnm/pbm_binary.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_imageload.pnm.pbm_binary`
====================================================
Load pixel values (indices or colors) into a bitmap and for an ascii ppm,
return None for pallet.
* Author(s): Matt Land, Brooke Storm, Sam McGahan
"""

__version__ = "0.0.0-auto.0"
__repo__ = "https://github.com/adafruit/Adafruit_CircuitPython_ImageLoad.git"


def load(file, width, height, bitmap=None, palette=None):
"""
Load a P4 'PBM' binary image into the displayio.Bitmap
"""
x = 0
y = 0
while True:
next_byte = file.read(1)
if not next_byte:
break # out of bits
for bit in iterbits(next_byte):
bitmap[x, y] = bit
x += 1
if x > width - 1:
y += 1
x = 0
if y > height - 1:
break
return bitmap, palette


def iterbits(b):
"""
generator to iterate over the bits in a byte (character)
"""
in_char = reverse(int.from_bytes(b, "little"))
for i in range(8):
yield (in_char >> i) & 1


def reverse(b):
"""
reverse bit order so the iterbits works
"""
b = (b & 0xF0) >> 4 | (b & 0x0F) << 4
b = (b & 0xCC) >> 2 | (b & 0x33) << 2
b = (b & 0xAA) >> 1 | (b & 0x55) << 1
return b
52 changes: 52 additions & 0 deletions adafruit_imageload/pnm/pgm/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
# The MIT License (MIT)
#
# Copyright (c) 2018 Scott Shawcroft for Adafruit Industries LLC
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
"""
`adafruit_imageload.pnm.pgm`
====================================================
Load pixel values (indices or colors) into a bitmap and colors into a palette.
* Author(s): Matt Land, Brooke Storm, Sam McGahan
"""


def load(file, magic_number, header, *, bitmap=None, palette=None):
"""
Perform the load of Netpbm greyscale images (P2, P5)
"""
if header[2] > 256:
raise NotImplementedError("16 bit files are not supported")
width = header[0]
height = header[1]

if magic_number == b"P2": # To handle ascii PGM files.
from . import ascii as pgm_ascii

return pgm_ascii.load(file, width, height, bitmap=bitmap, palette=palette)

if magic_number == b"P5": # To handle binary PGM files.
from . import binary

return binary.load(file, width, height, bitmap=bitmap, palette=palette)

raise NotImplementedError("Was not able to send image")
Loading

0 comments on commit 74b287c

Please sign in to comment.