From 0e3460ce4ee17fb0d78c3b949c876b0ff3b0c1ee Mon Sep 17 00:00:00 2001 From: Niles Rogoff Date: Wed, 30 Nov 2016 19:40:57 -0500 Subject: [PATCH] Readme written --- __pycache__/libpme.cpython-35.pyc | Bin 0 -> 5522 bytes libpme.py | 16 +++--- readme.md | 81 ++++++++++++++++++++++++++++++ 3 files changed, 89 insertions(+), 8 deletions(-) create mode 100644 __pycache__/libpme.cpython-35.pyc create mode 100644 readme.md diff --git a/__pycache__/libpme.cpython-35.pyc b/__pycache__/libpme.cpython-35.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ad64c905acc7521dae4358bbcc523219218408d0 GIT binary patch literal 5522 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 YIL1PJh{@ftKSSQ-*b}Q=Qj5WV0a)_=5C8xG literal 0 HcmV?d00001 diff --git a/libpme.py b/libpme.py index 3d58d90..940405b 100644 --- a/libpme.py +++ b/libpme.py @@ -1,14 +1,14 @@ #!/usr/bin/env python3 # PNG Metadata Editor # Niles Rogoff 2016 -import struct, zlib, copy +import zlib, copy +class color_types(object): + GREYSCALE = 0 + RGB = 2 + PALETTE = 3 + GREYSCALE_WITH_ALPHA = 4 + RGB_WITH_ALPHA = 6 class PME(object): - class color_types(object): - GREYSCALE = 0 - RGB = 2 - PALETTE = 3 - GREYSCALE_WITH_ALPHA = 4 - RGB_WITH_ALPHA = 6 def _int(self, binary): return int.from_bytes(binary, byteorder="big") def _bytes(self, integer, length): @@ -40,7 +40,7 @@ class PME(object): ] self.width = self.height = 0 # the user can decide self.bit_depth = 8 # a sane default - self.color_type = self.color_types.RGB_WITH_ALPHA + self.color_type = color_types.RGB_WITH_ALPHA self.compression_method = 0 self.filter_method = 0 # The only one as far as I know self.interlace_method = 0 diff --git a/readme.md b/readme.md new file mode 100644 index 0000000..b33f2c2 --- /dev/null +++ b/readme.md @@ -0,0 +1,81 @@ +# PNG Metadata Editor + +This library was written for a competition between me and Ethan, who was going to write this same thing in Java. He failed. + +You can initialize a PME instance by passing it a filename to an already existing file, or no arguments, like this: + + img = new libpme.PME("test.png"); + # or + img = new libpme.PME(); + +If the file is not valid, it will throw an exception + +## Properties + +These are the values that you can access or change. Most are self explanatory. Changing any of these will automatically call `recalculate_IHDR`. If you really want to suppress this behavior, just back up the IHDR chunk before changing the value. The defaults for an object created with no filename are displayed in parenthesis + + width (0) + height (0) + bit_depth (8) + color_type (color_types.RGB_WITH_ALPHA (6)) + compression_method (0) + filter_method (0) + interlace_method (0) + +## Methods +Here are the methods you can call on an image, in no particular order + +### `recalculate_properties` +This simply recalculates the seven properties listed above from the data currently in the IHDR chunk. + + img.height = 400 + img.chunks[0][2] = b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x06\x00\x00\x00' + # img.height remains unchanged at 400 + img.recalculate_properties() + # img.height is now set to 0 + +### `recalculate_IHDR` +This takes the seven properties listed above and destructively replaces the first chunk's data and crc with updated fields + + img.width = 0 + # img.chunks[0][2] is now set to b'\x00\x00\x00\x00\x00\x00\x00\x00\x08\x06\x00\x00\x00' + img.width = 400 + img.recalculate_IHDR() + # img.chunks[0][2] is now set to b'\x00\x00\x01\x90\x00\x00\x00\x00\x08\x06\x00\x00\x00' + +### `recalculate_crc` +This takes an index of a chunk (see below) and overwrites the crc in that chunk with a newly calculated crc based on that chunk's label and data + + img.color_type = libpme.color_types.RGB + img.width = img.height = 1 + img.chunks[1][2] = b'\x00\xFF\x00\x00' # a 1x1 red image, assuming that the second chunk is the only IDAT chunk + img.recalculate_crc(1) # img.chunks[1][3] is now set to b'T\xbb\xd3\xea' + +### `recalculate_length` +This takes an index of a chunk (see below) and updates the length of that chunk with a newly calculated length based on that chunk's data + + img.color_type = libpme.color_types.RGB + img.width = img.height = 1 + img.chunks[1][2] = img.compress(b'\x00\xFF\x00\x00') # a 1x1 red image, assuming that the second chunk is the only IDAT chunk + img.recalculate_length(1) # img.chunks[1][0] is now set to b'\x00\x00\x00\x04' + +### `save` +This saves the image to the disk, overwriting a file if it was already there. If the object was created from an existing file and no arguments are passed, it will use the original file. + + img.save("red1.png") + img.save() # Only if the object was created from an existing file. + +### `get_concatenated_idat_data` +Concatenates the (still compressed) data of each IDAT chunk, then returns it. + + img.width = 2 + img.chunks.insert(2, [b'\x00\x00\x00\x03', b'IDAT', img.compress(b'\x00\xFF\x00'), b'j\xee\xb3\xd0']) # making it a 2x1 image with a red and a green pixel + img.decompress(img.get_concatenated_idat_data()) # returns '\x00\xFF\x00\x00\x00\xFF\x00'; + +### `write_raw_idat_data` +Deletes all IDAT chunks except the first one, then sets that chunk's data to the argument it was passed, and recalculates its crc and length. + + img.write_raw_idat_data(img.compress(b'\x00\x00\x00\xFF\x00\x00\xFF')) # a 2x1 image with all blue pixels + +## Indexes +Any function that takes an index can be passed either the numerical index of the chunk (so 0 for IDAT, 1 for the second chunk, -1 for the last chunk, etc..), or a list that exists in `img.chunks`, or a 4-length bytes object that is equal to the label of one of the chunks in the image. If a chunk with that label appears more than once, the first one will be used