Write PNG file to `outfile`. `rows` should be an iterator that yields each packed row; a packed row being a sequence of packed bytes. The rows have a filter byte prefixed and are then compressed into one or more IDAT chunks. They are not processed an
(self, outfile, rows)
| 707 | return self.write_packed(outfile, rows) |
| 708 | |
| 709 | def write_packed(self, outfile, rows): |
| 710 | """ |
| 711 | Write PNG file to `outfile`. |
| 712 | `rows` should be an iterator that yields each packed row; |
| 713 | a packed row being a sequence of packed bytes. |
| 714 | |
| 715 | The rows have a filter byte prefixed and |
| 716 | are then compressed into one or more IDAT chunks. |
| 717 | They are not processed any further, |
| 718 | so if bitdepth is other than 1, 2, 4, 8, 16, |
| 719 | the pixel values should have been scaled |
| 720 | before passing them to this method. |
| 721 | |
| 722 | This method does work for interlaced images but it is best avoided. |
| 723 | For interlaced images, the rows should be |
| 724 | presented in the order that they appear in the file. |
| 725 | """ |
| 726 | |
| 727 | self.write_preamble(outfile) |
| 728 | |
| 729 | # http://www.w3.org/TR/PNG/#11IDAT |
| 730 | if self.compression is not None: |
| 731 | compressor = zlib.compressobj(self.compression) |
| 732 | else: |
| 733 | compressor = zlib.compressobj() |
| 734 | |
| 735 | # data accumulates bytes to be compressed for the IDAT chunk; |
| 736 | # it's compressed when sufficiently large. |
| 737 | data = bytearray() |
| 738 | |
| 739 | for i, row in enumerate(rows): |
| 740 | # Add "None" filter type. |
| 741 | # Currently, it's essential that this filter type be used |
| 742 | # for every scanline as |
| 743 | # we do not mark the first row of a reduced pass image; |
| 744 | # that means we could accidentally compute |
| 745 | # the wrong filtered scanline if we used |
| 746 | # "up", "average", or "paeth" on such a line. |
| 747 | data.append(0) |
| 748 | data.extend(row) |
| 749 | if len(data) > self.chunk_limit: |
| 750 | compressed = compressor.compress(data) |
| 751 | if len(compressed): |
| 752 | write_chunk(outfile, b"IDAT", compressed) |
| 753 | data = bytearray() |
| 754 | |
| 755 | compressed = compressor.compress(bytes(data)) |
| 756 | flushed = compressor.flush() |
| 757 | if len(compressed) or len(flushed): |
| 758 | write_chunk(outfile, b"IDAT", compressed + flushed) |
| 759 | # http://www.w3.org/TR/PNG/#11IEND |
| 760 | write_chunk(outfile, b"IEND") |
| 761 | return i + 1 |
| 762 | |
| 763 | def write_preamble(self, outfile): |
| 764 | # http://www.w3.org/TR/PNG/#5PNG-file-signature |
no test coverage detected