2015-06-19 16:48:22 +00:00
|
|
|
#!/usr/bin/env python
|
2015-06-05 17:58:41 +00:00
|
|
|
#
|
|
|
|
# Copyright 2013 Google, Inc. All Rights Reserved.
|
|
|
|
#
|
|
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
# you may not use this file except in compliance with the License.
|
|
|
|
# You may obtain a copy of the License at
|
|
|
|
#
|
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
#
|
|
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
# See the License for the specific language governing permissions and
|
|
|
|
# limitations under the License.
|
|
|
|
#
|
|
|
|
# Google Author(s): Behdad Esfahbod
|
|
|
|
#
|
|
|
|
|
2019-07-17 08:33:21 +00:00
|
|
|
import struct
|
|
|
|
import sys
|
|
|
|
if sys.version_info >= (3,0,0): # Python3
|
|
|
|
from io import StringIO
|
|
|
|
else:
|
|
|
|
from StringIO import StringIO
|
2015-06-05 17:58:41 +00:00
|
|
|
|
|
|
|
|
|
|
|
class PNG:
|
|
|
|
|
|
|
|
signature = bytearray ((137,80,78,71,13,10,26,10))
|
|
|
|
|
|
|
|
def __init__ (self, f):
|
|
|
|
|
2019-07-17 08:33:21 +00:00
|
|
|
if (isinstance(f, str) or isinstance(f, type(u''))):
|
2015-06-05 17:58:41 +00:00
|
|
|
f = open (f, 'rb')
|
|
|
|
|
|
|
|
self.f = f
|
|
|
|
self.IHDR = None
|
|
|
|
|
|
|
|
def tell (self):
|
|
|
|
return self.f.tell ()
|
|
|
|
|
|
|
|
def seek (self, pos):
|
|
|
|
self.f.seek (pos)
|
|
|
|
|
|
|
|
def stream (self):
|
|
|
|
return self.f
|
|
|
|
|
|
|
|
def data (self):
|
|
|
|
self.seek (0)
|
2019-07-17 08:33:21 +00:00
|
|
|
if sys.version_info >= (3,0,0): # Python3
|
|
|
|
return bytearray (self.f.read (), 'iso-8859-1')
|
|
|
|
else:
|
|
|
|
return bytearray (self.f.read ())
|
2015-06-05 17:58:41 +00:00
|
|
|
|
|
|
|
class BadSignature (Exception): pass
|
|
|
|
class BadChunk (Exception): pass
|
|
|
|
|
|
|
|
def read_signature (self):
|
|
|
|
header = bytearray (self.f.read (8))
|
|
|
|
if header != PNG.signature:
|
|
|
|
raise PNG.BadSignature
|
|
|
|
return PNG.signature
|
|
|
|
|
|
|
|
def read_chunk (self):
|
2019-07-17 08:33:21 +00:00
|
|
|
buf = self.f.read (4)
|
|
|
|
length = struct.unpack (">I", buf)[0]
|
2015-06-05 17:58:41 +00:00
|
|
|
chunk_type = self.f.read (4)
|
|
|
|
chunk_data = self.f.read (length)
|
|
|
|
if len (chunk_data) != length:
|
|
|
|
raise PNG.BadChunk
|
|
|
|
crc = self.f.read (4)
|
|
|
|
if len (crc) != 4:
|
|
|
|
raise PNG.BadChunk
|
|
|
|
return (chunk_type, chunk_data, crc)
|
|
|
|
|
|
|
|
def read_IHDR (self):
|
|
|
|
(chunk_type, chunk_data, crc) = self.read_chunk ()
|
2019-07-17 08:33:21 +00:00
|
|
|
if chunk_type not in ("IHDR", b"IHDR"):
|
2015-06-05 17:58:41 +00:00
|
|
|
raise PNG.BadChunk
|
|
|
|
# Width: 4 bytes
|
|
|
|
# Height: 4 bytes
|
|
|
|
# Bit depth: 1 byte
|
|
|
|
# Color type: 1 byte
|
|
|
|
# Compression method: 1 byte
|
|
|
|
# Filter method: 1 byte
|
|
|
|
# Interlace method: 1 byte
|
|
|
|
return struct.unpack (">IIBBBBB", chunk_data)
|
|
|
|
|
|
|
|
def read_header (self):
|
|
|
|
self.read_signature ()
|
|
|
|
self.IHDR = self.read_IHDR ()
|
|
|
|
return self.IHDR
|
|
|
|
|
|
|
|
def get_size (self):
|
|
|
|
if not self.IHDR:
|
|
|
|
pos = self.tell ()
|
|
|
|
self.seek (0)
|
|
|
|
self.read_header ()
|
|
|
|
self.seek (pos)
|
|
|
|
return self.IHDR[0:2]
|
|
|
|
|
|
|
|
def filter_chunks (self, chunks):
|
|
|
|
self.seek (0);
|
2019-07-17 08:33:21 +00:00
|
|
|
out = StringIO ()
|
|
|
|
if sys.version_info >= (3,0,0): # Python3
|
|
|
|
out.write (self.read_signature ().decode('iso-8859-1'))
|
|
|
|
else:
|
|
|
|
out.write (self.read_signature ())
|
2015-06-05 17:58:41 +00:00
|
|
|
while True:
|
|
|
|
chunk_type, chunk_data, crc = self.read_chunk ()
|
|
|
|
if chunk_type in chunks:
|
2019-07-17 08:33:21 +00:00
|
|
|
if sys.version_info >= (3,0,0): # Python3
|
|
|
|
out.write (struct.pack (">I", len (chunk_data)).decode('iso-8859-1'))
|
|
|
|
out.write (chunk_type.decode('iso-8859-1'))
|
|
|
|
out.write (chunk_data.decode('iso-8859-1'))
|
|
|
|
out.write (crc.decode('iso-8859-1'))
|
|
|
|
else:
|
|
|
|
out.write (struct.pack (">I", len (chunk_data)))
|
|
|
|
out.write (chunk_type)
|
|
|
|
out.write (chunk_data)
|
|
|
|
out.write (crc)
|
|
|
|
if chunk_type in ("IEND", b"IEND"):
|
2015-06-05 17:58:41 +00:00
|
|
|
break
|
|
|
|
return PNG (out)
|