def append(args): """ Append files to an existing container then reconstruct the png with the new keys attached """ keys = generate_nkeys(len(args.files)) random.shuffle(keys) (salt, key) = derive_key(args.key) fernet = Fernet(key) code_chunk = (CD_CHUNK, fernet.encrypt(cPickle.dumps(keys))) salt_chunk = (SL_CHUNK, salt) with open(args.container, "r") as container: reader = png.Reader(file=container) # This of course is horrible # We should use a temp file, but for now it is fine chunks = list(reader.chunks()) (tend, iend) = chunks.pop() if tend != "IEND": print "Muh suck" sys.exit(1) for (file, key) in zip(args.files, keys): with open(file, "r") as hidee: name = file data = hidee.read() iname = (FN_CHUNK, name) fernet = Fernet(key) idata = (DT_CHUNK, fernet.encrypt(zlib.compress(data))) print "Packing %s" % (name) chunks = chunks + [iname] + [idata] with open(args.container + ".out", "w") as out: chunks = chunks + [code_chunk] + [salt_chunk] + [(tend, iend)] png.write_chunks(out, chunks)
def jrm_bake_streams(image_stream, assertion_string, newfile_stream=None): # Get the input stream from the image reader = png.Reader(file=image_stream) # Create a temporary file if no output file specified if newfile_stream is None: newfile_stream = NamedTemporaryFile(suffix='.png') # Build the chunk content with the assertion data chunkheader = "openbadges\x00\x00\x00\x00\x00" chunk_content = chunkheader + assertion_string # We are going to write the chunk in the "iTXt" chunk badge_chunk = (b'iTXt', chunk_content) # Insert our chunk as the second chunk in the image original_chunks = reader.chunks() final_chunks = [] # Insert the first original chunk final_chunks.append(next(original_chunks)) # Insert our chunk final_chunks.append(badge_chunk) # Insert the rest of the original chunks for t,c in original_chunks: final_chunks.append((t,c)) # Write the new chunks into a new PNG file png.write_chunks(newfile_stream, final_chunks) newfile_stream.seek(0) return newfile_stream
def helperFormat(self, f): r = png.Reader(bytes=pngsuite.basn0g01) o = BytesIO() def newchunks(): for chunk in r.chunks(): yield f(chunk) png.write_chunks(o, newchunks()) r = png.Reader(bytes=o.getvalue()) return list(r.asDirect()[2])
def bake(imageFile, assertion_json_string): reader = png.Reader(file=imageFile) filename = '%s.png' % hashlib.md5(str(assertion_json_string)).hexdigest() newfile = ContentFile("", name=filename) newfile.open() chunkheader = 'openbadges\x00\x00\x00\x00\x00' badge_chunk = ('iTXt', bytes(chunkheader + assertion_json_string)) png.write_chunks(newfile, baked_chunks(reader.chunks(), badge_chunk)) newfile.close() return newfile
def insert_text_chunk(src_png, dst_png, text): reader = png.Reader(filename=src_png) chunks = reader.chunks() chunk_list = list(chunks) chunk_item = tuple([b'tEXt', text]) index = 1 chunk_list.insert(index, chunk_item) with open(dst_png, 'wb') as dst_file: png.write_chunks(dst_file, chunk_list)
def insert_text_chunk(target, text, index=1): reader = png.Reader(filename=target) chunks = reader.chunks() chunk_list = list(chunks) # print(chunk_list[0]) # print(chunk_list[1]) # print(chunk_list[2]) chunk_item = generate_text_chunk_tuple(text) chunk_list.insert(index, chunk_item) with open(target, 'wb') as dst_file: png.write_chunks(dst_file, chunk_list)
def insert_text_chunk(png_file,text): with open(text,'r') as text_file: text_content=text_file.read() reader = png.Reader(filename=png_file) chunks = reader.chunks() chunk_list = list(chunks) chunk_item = tuple(['tEXt',bytes(text_content,'utf-8')]) chunk_list.insert(1, chunk_item) #insert tEXt chunk after iHDr with open(png_file,'wb') as dst_file: png.write_chunks(dst_file, chunk_list)
def insert_text_chunk(src_png, dst_png, text): reader = png.Reader(filename=src_png) chunks = reader.chunks() # 创建一个每次返回一个chunk的生成器 chunk_list = list(chunks) # 把生成器的所有元素变成list # print(f"target png total chunks number is {len(chunk_list)}") chunk_item = tuple([b'tEXt', text]) # 第一个chunk是固定的IHDR,我们把tEXt放在第2个chunk index = 1 chunk_list.insert(index, chunk_item) with open(dst_png, 'wb') as dst_file: png.write_chunks(dst_file, chunk_list)
def read_icon(filename): if not os.path.exists(filename): print("ERROR: Cannot find file: {}".format(filename)) sys.exit(1) reader = png.Reader(filename=filename) chunks = [] for name, chunk in reader.chunks(): if name in PNG_CHUNK_WHITELIST: chunks.append((name, chunk)) output = io.BytesIO() png.write_chunks(output, chunks) return base64.b64encode(output.getvalue()).decode('ascii')
def _read_write_chunks_test(): src = r'E:\temp\png\register_02.png' dst = r'E:\temp\png\register_03.png' reader = png.Reader(filename=src) chunks = reader.chunks() chunk_list = list(chunks) print(chunk_list[0]) print(chunk_list[1]) print(chunk_list[2]) chunk_item = generate_text_chunk_tuple('what are you doing?') chunk_list.insert(1, chunk_item) with open(dst, 'wb') as dst_file: png.write_chunks(dst_file, chunk_list) print('from {} generated new png file {}.'.format(src, dst))
def read_modify_chunks(modify_chunk): """Create a temporary PNG file by modifying the chunks of an existing one, then read that temporary file. Each chunk is passed through the function `modify_chunk`. """ r = png.Reader(bytes=pngsuite.basn0g01) o = BytesIO() def newchunks(): for chunk in r.chunks(): yield modify_chunk(chunk) png.write_chunks(o, newchunks()) r = png.Reader(bytes=o.getvalue()) return list(r.asDirect()[2])
def bake(imageFile, assertion_json_string): """ Embeds a serialized representation of a badge instance in a PNG image file. """ reader = png.Reader(file=imageFile) output_filename = "%s.png" % hashlib.md5(str(assertion_json_string)).hexdigest() newfile = ContentFile("", name=output_filename) newfile.open() chunkheader = "openbadges\x00\x00\x00\x00\x00" badge_chunk = ("iTXt", bytes(chunkheader + assertion_json_string)) png.write_chunks(newfile, baked_chunks(reader.chunks(), badge_chunk)) newfile.close() return newfile
def bake(imageFile, assertion_json_string): """ Embeds a serialized representation of a badge instance in a PNG image file. """ reader = png.Reader(file=imageFile) output_filename = '%s.png' % hashlib.md5(str(assertion_json_string)).hexdigest() newfile = ContentFile("", name=output_filename) newfile.open() chunkheader = 'openbadges\x00\x00\x00\x00\x00' badge_chunk = ('iTXt', bytes(chunkheader + assertion_json_string)) png.write_chunks(newfile, baked_chunks(reader.chunks(), badge_chunk)) newfile.close() return newfile
def insert_text_chunk(target, text, index=1): if index < 0: raise Exception('The index value {} less than 0!'.format(index)) reader = png.Reader(filename=target) chunks = reader.chunks() chunk_list = list(chunks) print(chunk_list[0]) print(chunk_list[1]) print(chunk_list[2]) chunk_item = generate_text_chunk_tuple(text) print('chunk_item', chunk_item) chunk_list.insert(index, chunk_item) with open(target, 'wb') as dst_file: png.write_chunks(dst_file, chunk_list)
def bake(imageFile, assertion_string, newfile=None): """ Embeds a serialized representation of a badge instance in a PNG image file. """ encoded_assertion_string = codecs.getwriter('utf-8')(assertion_string) reader = png.Reader(file=imageFile) if newfile is None: newfile = NamedTemporaryFile(suffix='.png') chunkheader = 'openbadges\x00\x00\x00\x00\x00' badge_chunk = ('iTXt', bytes(chunkheader + encoded_assertion_string.stream)) png.write_chunks(newfile, baked_chunks(reader.chunks(), badge_chunk)) newfile.seek(0) return newfile
def insert_text_chunk(target, text, index=1): if index < 0: raise Exception('The index value {} less than 0!'.format(index)) reader = png.Reader(filename=str(target)) chunks = reader.chunks() chunk_list = list(chunks) # add non comment chunks to new list, basically removes all existing comments new_chunk_list = [] for chunk in chunk_list: if b'tEXt' not in chunk[0]: new_chunk_list.append(chunk) # add the new comment with postions chunk_item = generate_text_chunk_tuple(text) new_chunk_list.insert(index, chunk_item) with open(str(target), 'wb') as dst_file: png.write_chunks(dst_file, new_chunk_list)
def helperFormat(self, f, idat_only=True): """ Helper for format tests call `f` function to change chunks """ pngsuite.png["basn0g01"].seek(0) r = png.Reader(pngsuite.png["basn0g01"]) o = BytesIO() def newchunks(): """chunks conversion""" for chunk in r.chunks(): if idat_only and chunk[0] != 'IDAT': yield chunk else: yield f(*chunk) png.write_chunks(o, newchunks()) r = png.Reader(bytes=o.getvalue()) return list(r.asDirect()[2])
def test_plte_bkgd(self): """ Test colortype 3 PNG with bKGD chunk. For coverage. """ k = 'basn3p04' reader = png.Reader(bytes=pngsuite.png[k]) def more_chunks(): for t, v in reader.chunks(): yield t, v if t == b'PLTE': yield b'bKGD', b'\x00' o = BytesIO() png.write_chunks(o, more_chunks()) reader = png.Reader(bytes=o.getvalue()) _, _, rows, info = reader.read() list(rows)
def test_chunk_after_idat(self): """ Test with a PNG that has an ancillary chunk after IDAT chunks. For coverage. """ k = 'f02n0g08' reader = png.Reader(bytes=pngsuite.png[k]) text_chunk = (b'tEXt', b'Comment\x00Test chunk follows IDAT') def more_chunks(): for t, v in reader.chunks(): if t == b'IEND': yield text_chunk yield t, v o = BytesIO() png.write_chunks(o, more_chunks()) reader = png.Reader(bytes=o.getvalue()) _, _, rows, info = reader.read() list(rows)
def bake(image, assertion_string: str, newfile=None): """ Embeds a serialized representation of a badge instance in a PNG image file. """ # encoded_assertion_string = codecs.getwriter('utf-8')(assertion_string) # Prepare to read from the image (could be a file name, a stream or a byte array) reader = png.Reader(image) if newfile is None: newfile = "baked.png" chunkheader = b'openbadges\x00\x00\x00\x00\x00' chunk_content = chunkheader + bytes(assertion_string, encoding="utf-8") badge_chunk = (b'iTXt', chunk_content) with open(newfile, "wb") as newFileStream: png.write_chunks(newFileStream, baked_chunks(reader.chunks(), badge_chunk)) return
def bake_badge(src, dest, url): """ Bake the given PNG file with the given assertion URL. The source and destination can be filenames or file objects. Example: >>> bake_badge('unbaked.png', 'baked.png', 'http://f.org/a.json') """ if isinstance(src, basestring): src = open(src, 'rb') if isinstance(dest, basestring): dest = open(dest, 'wb') reader = png.Reader(file=src) chunks = [ (chunktype, content) for chunktype, content in reader.chunks() if not (chunktype == 'tEXt' and content.startswith('openbadges\x00')) ] chunks.insert(1, ('tEXt', '\x00'.join(('openbadges', url)))) png.write_chunks(dest, chunks)
def save(self, filename): """Save the image. PyPNG doesn't support sBIT chunks with a palette, but this method works around that and adds one anyway. """ # Write to a temporary in-memory PNG temp_png = io.BytesIO() writer = png.Writer(width=self.width, height=self.height, palette=self.palette) writer.write(temp_png, self.pixels) # Read temp PNG's chunks, and insert an sBIT chunk manually temp_png.seek(0) reader = png.Reader(temp_png) chunks = list(reader.chunks()) chunks.insert(1, ('sBIT', b'\x05\x05\x05')) # Write chunks to an actual file with open(filename, 'wb') as png_file: png.write_chunks(png_file, chunks)
def distill(f=None, filename=None): if filename: f = open(filename) if not f: raise ValueError('No file was supplied to distill') reader = png.Reader(f) chunks = [(ct, c) for (ct, c) in reader.chunks()] rebuilt_idat_chunk = build_idat_chunk(chunks) distilled_chunks = reduce(_reduce_chunks, chunks, []) def _remap_chunks(acc, c): if c[0] == 'IDAT': acc.append(rebuilt_idat_chunk) else: acc.append(c) return acc result_chunks = reduce(_remap_chunks, distilled_chunks, []) result = StringIO() png.write_chunks(result, result_chunks) return result
import png #pip install pypng fin = open('odrrere.png', 'rb') image = png.Reader(fin) chunks = [] #initially found is empty found = [0, 12, 8, 4, 9, 10, 6, 7, 3, 5, 2, 11, 1] curr = 3 + len(found) for i in image.chunks(): chunks.append(i) for i in range(0, 13): if i in found and i > 0: continue temp = list(chunks) fout = open('temp/' + str(curr) + '_' + str(i) + '.png', 'wb') for j in range(0, len(found)): temp[3 + j] = chunks[found[j] + 3] temp[curr] = chunks[3 + i] png.write_chunks(fout, temp) fout.close()
def append_json_to_png(filename, data): chunks = list(png.Reader(filename).chunks()) bin_data = zlib.compress(bytes(json.dumps(data), "utf-8")) chunks.insert(len(chunks) - 1, (b"iTXt", bin_data)) with open(filename, 'wb') as file: png.write_chunks(file, chunks)
def chunk(out, inp, l): """Process the input PNG file to the output, chunk by chunk. Chunks can be inserted, removed, replaced, or sometimes edited. Generally, chunks are not inspected, so pixel data (in the ``IDAT`` chunks) cannot be modified. `l` should be a list of (*chunktype*, *content*) pairs. *chunktype* is usually the type of the PNG chunk, specified as a 4-byte Python string, and *content* is the chunk's content, also as a string; if *content* is ``None`` then *all* chunks of that type will be removed. This function *knows* about certain chunk types and will automatically convert from Python friendly representations to string-of-bytes. chunktype 'gamma' 'gAMA' float 'sigbit' 'sBIT' int, or tuple of length 1,2 or 3 Note that the length of the strings used to identify *friendly* chunk types is greater than 4, hence they cannot be confused with canonical chunk types. Chunk types, if specified using the 4-byte syntax, need not be official PNG chunks at all. Non-standard chunks can be created. """ def canonical(p): """Take a pair (*chunktype*, *content*), and return canonical representation (*chunktype*, *content*) where `chunktype` is the 4-byte PNG chunk type and `content` is a string. """ t,v = p if len(t) == 4: return t,v if t == 'gamma': t = 'gAMA' v = int(round(1e5*v)) v = struct.pack('>I', v) elif t == 'sigbit': t = 'sBIT' try: v[0] except TypeError: v = (v,) v = struct.pack('%dB' % len(v), *v) elif t == 'iccprofile': t = 'iCCP' # http://www.w3.org/TR/PNG/#11iCCP v = 'a color profile\x00\x00' + v.encode('zip') else: warnings.warn('Unknown chunk type %r' % t) return t[:4],v l = map(canonical, l) # Some chunks automagically replace ones that are present in the # source PNG. There can only be one of each of these chunk types. # Create a 'replace' dictionary to record these chunks. add = [] delete = set() replacing = set(['gAMA', 'sBIT', 'PLTE', 'tRNS', 'sPLT', 'IHDR']) replace = dict() for t,v in l: if v is None: delete.add(t) elif t in replacing: replace[t] = v else: add.append((t,v)) del l r = png.Reader(file=inp) chunks = r.chunks() def iterchunks(): for t,v in chunks: if t in delete: continue if t in replace: yield t,replace[t] del replace[t] continue if t == 'IDAT' and replace: # Insert into the output any chunks that are on the # replace list. We haven't output them yet, because we # didn't see an original chunk of the same type to # replace. Thus the "replace" is actually an "insert". for u,w in replace.items(): yield u,w del replace[u] if t == 'IDAT' and add: for item in add: yield item del add[:] yield t,v return png.write_chunks(out, iterchunks())
import png #pip install pypng fin = open('odrrere.png','rb') image = png.Reader(fin) chunks = [] #initially found is empty found =[0,12,8,4,9,10,6,7,3,5,2,11,1] curr = 3 + len(found) for i in image.chunks(): chunks.append(i) for i in range(0,13): if i in found and i > 0: continue temp = list(chunks) fout = open('temp/'+str(curr)+'_'+str(i)+'.png','wb') for j in range(0,len(found)): temp[3+j] = chunks[found[j]+3] temp[curr] = chunks[3+i] png.write_chunks(fout,temp) fout.close()
""" from PIL import Image # type: ignore import glob import re import png # type: ignore for sprite in glob.glob("assets/sprites/*.png"): pre_chunk_list = list(png.Reader(sprite).chunks()) img = Image.open(sprite) img.save(sprite, transparency=3, optimize=1) post_chunk_list = list(png.Reader(sprite).chunks()) for chunk in pre_chunk_list: if re.compile(b"..Xt").match(chunk[0]): post_chunk_list.insert(2, chunk) with open(sprite, "wb") as out_sprite: png.write_chunks(out_sprite, post_chunk_list) for ui_piece in glob.glob("assets/ui/*.png"): pre_chunk_list = list(png.Reader(ui_piece).chunks()) img = Image.open(ui_piece) img.save(ui_piece, transparency=3, optimize=1) post_chunk_list = list(png.Reader(ui_piece).chunks()) for chunk in pre_chunk_list: if re.compile(b"..Xt").match(chunk[0]): post_chunk_list.insert(2, chunk) with open(ui_piece, "wb") as out_ui_piece: png.write_chunks(out_ui_piece, post_chunk_list)
def extract_png(image): # TODO: Maybe just use APNG: https://pypi.org/project/apng/ img = APNG.open(image.veritas.file_name) if len(img.frames) == 1: logger.debug('Only one frame detected.') return print("Extracting {} PNG frames.".format(len(img.frames))) for i, (png, control) in enumerate(img.frames): outfile = os.path.join( image.veritas.results_directory, '{}_frame_{}.png'.format(os.path.basename(image.veritas.file_name), i)) png.save(outfile) return ### Below is some original work before finding that library # PIL apparently can't handle this. Neither can ffmpeg. ImageMagick can be fooled. # Time to write my own animated png extractor img = png.Reader(image.veritas.file_name) chunks = list(img.chunks()) num_frames = len(list(x for x in chunks if x[0] in [b'fcTL'])) """ actl = next(x for x in chunks if x[0] == b'acTL') # How many frames does the image claim to have given_num_frames, _ = unpack('>II', actl[1]) if given_num_frames != num_frames: print('Image only claims {} frames, but I discovered {}'.format(given_num_frames, num_frames)) print('Patching and attempting to extract the frames') new_actl = (b'acTL', pack('>II',num_frames,0)) new_chunks = [] frame_number = 0 for t,v in chunks: if t == b'acTL': new_chunks.append(new_actl) elif t == b'fcTL': new_chunks.append((t, pack('>I', frame_number) + v[4:])) frame_number += 1 else: new_chunks.append((t,v)) with open('blerg.png','wb') as f: png.write_chunks(f, new_chunks) return """ ####### if num_frames == 1: logger.debug('Only one frame discovered.') return print('Discovered multuple PNG frames. Attempting to extract them...') header_chunk = next(x for x in chunks if x[0] in [b'IHDR']) end_chunk = (b'IEND', b'') actl_chunk = (b'acTL', b'\x00\x00\x00\x01\x00\x00\x00\x00' ) # looping, 1 frame new_image = [] num_frames = 0 # Type and value for the chunks for t, val in chunks: print(t) # We're done with this image if t in [b'fcTL', b'IEND']: # We have something to save if new_image != []: # Put propper chunks in place new_image.insert(0, copy(actl_chunk)) new_header_chunk = list(copy(header_chunk)) #new_header_chunk[1] = pack('>II', width, height) + new_header_chunk[1][8:] #new_header_chunk[1] = width_height + new_header_chunk[1][8:] new_header_chunk = tuple(new_header_chunk) new_image.insert(0, new_header_chunk) #new_image.insert(0, copy(header_chunk)) new_image.append(copy(end_chunk)) print(new_image) outfile = os.path.join( image.veritas.results_directory, '{}_frame_{}.png'.format( os.path.basename(image.veritas.file_name), num_frames)) print(outfile) with open(outfile, 'wb') as f: png.write_chunks(f, new_image) #new_image = [(t, val)] new_image = [] num_frames += 1 if t == b'fcTL': # Update our frame size #width, height = unpack('>II', val[4:12]) #print('width and height: ' + str(width) + ' ' + str(height)) #width_height = val[4:12] #new_image.append((t, b'\x00\x00\x00\x00' + val[4:])) new_image.append((t, val)) # Nothing to save, just add our header in #else: # new_image.append((t, val)) elif t == b'IDAT': new_image.append((t, val)) elif t == b'fdAT': # fdAT is simply IDAT with 4 bytes at the beginning new_image.append((b'IDAT', val[4:])) """