Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

pypng >= 0.0.20 Removed 3D support from_array #54

Open
gentaman opened this issue Nov 6, 2022 · 1 comment
Open

pypng >= 0.0.20 Removed 3D support from_array #54

gentaman opened this issue Nov 6, 2022 · 1 comment

Comments

@gentaman
Copy link

gentaman commented Nov 6, 2022

I found the error while I was running the bellow like code with jupyter-innotater==0.2.2.

import io

import png
import numpy as np

print(png.__version__, np.__version__)

npim = np.zeros((256, 256, 3), dtype=np.uint8)
npim[:, :, 0] = 255
npim[:, ::8, 1] = 255
npim[:, 1::8, 1] = 255
npim[:, 2::8, 1] = 255

pngbytes = io.BytesIO()
pngmode = 'L' # Greyscale
if len(npim.shape) == 3:
    if npim.shape[2] > 4:
        raise Exception("Image numpy array appears to have more than 4 channels")
    pngmode = ('L','LA','RGB','RGBA')[npim.shape[2]-1]
else:
    npim = np.expand_dims(npim, axis=-1) # Need a third axis for channel
   

pngim = png.from_array(npim, mode=pngmode) # Don't have BGR available so flipped to RGB above
pngim.write(pngbytes) if hasattr(pngim, 'write') else pngim.save(pngbytes) # PyPNG API due to change after v0.0.19
pixel_value = pngbytes.getvalue()
pngbytes.close()
png.__version__='0.20220715.0' np.__version__='1.23.4'

---------------------------------------------------------------------------
ProtocolError                             Traceback (most recent call last)
Cell In [11], line 20
     16 # h, w, ch = npim.shape
     17 # npim = npim.reshape(h, w * ch)
     19 pngim = png.from_array(npim, mode=pngmode) # Don't have BGR available so flipped to RGB above
---> 20 pngim.write(pngbytes) if hasattr(pngim, 'write') else pngim.save(pngbytes) # PyPNG API due to change after v0.0.19
     21 pixel_value = pngbytes.getvalue()
     22 pngbytes.close()

File /app/venv/lib/python3.9/site-packages/png.py:1320, in Image.write(self, file)
   1309 """Write the image to the open file object.
   1310 
   1311 See `.save()` if you have a filename.
   (...)
   1316 cannot be streamed again.
   1317 """
   1319 w = Writer(**self.info)
-> 1320 w.write(file, self.rows)

File /app/venv/lib/python3.9/site-packages/png.py:668, in Writer.write(self, outfile, rows)
    665     a = array(fmt, itertools.chain(*check_rows(rows)))
    666     return self.write_array(outfile, a)
--> 668 nrows = self.write_passes(outfile, check_rows(rows))
    669 if nrows != self.height:
    670     raise ProtocolError(
    671         "rows supplied (%d) does not match height (%d)" %
    672         (nrows, self.height))

File /app/venv/lib/python3.9/site-packages/png.py:703, in Writer.write_passes(self, outfile, rows)
    700 elif self.bitdepth == 16:
    701     rows = unpack_rows(rows)
--> 703 return self.write_packed(outfile, rows)

File /app/venv/lib/python3.9/site-packages/png.py:738, in Writer.write_packed(self, outfile, rows)
    735 # raise i scope out of the for loop. set to -1, because the for loop
    736 # sets i to 0 on the first pass
    737 i = -1
--> 738 for i, row in enumerate(rows):
    739     # Add "None" filter type.
    740     # Currently, it's essential that this filter type be used
    741     # for every scanline as
    742     # we do not mark the first row of a reduced pass image;
    743     # that means we could accidentally compute
    744     # the wrong filtered scanline if we used
    745     # "up", "average", or "paeth" on such a line.
    746     data.append(0)
    747     data.extend(row)

File /app/venv/lib/python3.9/site-packages/png.py:658, in Writer.write.<locals>.check_rows(rows)
    655     wrong_length = False
    656 if wrong_length:
    657     # Note: row numbers start at 0.
--> 658     raise ProtocolError(
    659         "Expected %d values but got %d values, in row %d" %
    660         (vpr, len(row), i))
    661 yield row

ProtocolError: ProtocolError: Expected 255 values but got 256 values, in row 0

I checked that latest pypng.from_array is unsupported 3D ndarray.

https://gitlab.com/drj11/pypng/#release-0020

So I made a simple patch code and check that it work.

print(f"{png.__version__=} {np.__version__=}")

npim = np.zeros((256, 256, 3), dtype=np.uint8)
npim[:, :, 0] = 255
npim[:, ::8, 1] = 255
npim[:, 1::8, 1] = 255
npim[:, 2::8, 1] = 255

pngbytes = io.BytesIO()
pngmode = 'L' # Greyscale
if len(npim.shape) == 3:
    if npim.shape[2] > 4:
        raise Exception("Image numpy array appears to have more than 4 channels")
    pngmode = ('L','LA','RGB','RGBA')[npim.shape[2]-1]
else:
    npim = np.expand_dims(npim, axis=-1) # Need a third axis for channel
    
h, w, ch = npim.shape
npim = npim.reshape(h, w * ch)
npim = np.ascontiguousarray(npim)

pngim = png.from_array(npim, mode=pngmode) # Don't have BGR available so flipped to RGB above
pngim.write(pngbytes) if hasattr(pngim, 'write') else pngim.save(pngbytes) # PyPNG API due to change after v0.0.19
pixel_value = pngbytes.getvalue()
pngbytes.close()

This error only occurs when opencv-python was not installed.

If you want to fix the error, I think that you need to fix the pypng version to 0.0.19 or fix the jupyter_innotater/data.py .

@danlester
Copy link
Member

Thank you for letting everyone know!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants