exifHeader is now using another exif Python module.

This commit is contained in:
Cédric Bonhomme 2016-05-17 15:27:49 +02:00
parent 23abfcf2d7
commit ed3e8560a5
No known key found for this signature in database
GPG key ID: A1CB94DE57B7A70D
6 changed files with 28 additions and 696 deletions

View file

@ -1 +1,2 @@
pillow
piexif

View file

@ -1 +0,0 @@

View file

@ -1,197 +0,0 @@
"""
This module offers one class, MinimalExifReader. Pass jpg filename
to the constructor. Will read minimal exif info from the file. Three
"public" functions available:
imageDescription()--returns Exif ImageDescription tag (0x010e) contents,
or '' if not found.
copyright()--returns Exif copyright tag (0x8298) contents, or '' if not
found.
dateTimeOriginal()--returns Exif DateTimeOriginal tag (0x9003) contents,
or '' if not found. If found, the trailing nul char
is stripped. This function also takes an optional
format string to apply time.strftime-style formatting
to the date time.
Brought to you by Megabyte Rodeo Software.
"""
# Written by Chris Stromberger, 10/2004. Public Domain.
# Much is owed to Thierry Bousch's exifdump.py:
# http://topo.math.u-psud.fr/~bousch/exifdump.py
#---------------------------------------------------------------------
class ExifFormatException(Exception):
pass
#---------------------------------------------------------------------
class MinimalExifReader:
IMAGE_DESCRIPTION_TAG = 0x010e
COPYRIGHT_TAG = 0x8298
EXIF_SUBIFD_TAG = 0x8769
DATE_TIME_ORIGINAL_TAG = 0x9003
#---------------------------------------
def __init__(self, filename):
"""Pass in jpg exif file name to process. Will attempt to find tags
of interest."""
self.tagsToFind = {self.IMAGE_DESCRIPTION_TAG:'',
self.COPYRIGHT_TAG:'',
self.DATE_TIME_ORIGINAL_TAG:''}
# Read first bit of file to see if exif file.
f = open(filename, 'rb')
firstTwoBytes = f.read(2)
if firstTwoBytes != '\xff\xd8':
f.close()
raise ExifFormatException("Missing SOI marker")
appMarker = f.read(2)
# See if there's an APP0 section, which sometimes appears.
if appMarker == '\xff\xe0':
#print "Skipping app0"
# Yes, we have app0. Skip over it.
app0DataLength = ord(f.read(1)) * 256 + ord(f.read(1))
app0 = f.read(app0DataLength - 2)
appMarker = f.read(2)
if appMarker != '\xff\xe1':
raise ExifFormatException("Can't find APP1 marker")
exifHeader = f.read(8)
#import binascii
#print binascii.hexlify(exifHeader)
if (exifHeader[2:6] != 'Exif' or
exifHeader[6:8] != '\x00\x00'):
f.close()
raise ExifFormatException("Malformed APP1")
app1DataLength = ord(exifHeader[0]) * 256 + ord(exifHeader[1])
#print app1DataLength
# Read exif info starting at the beginning of the self.tiff section.
# This is 8 bytes into the app1 section, so subtract 8 from
# app1 length.
self.tiff = f.read(app1DataLength - 8)
f.close()
self.endian = self.tiff[0]
if self.endian not in ('I', 'M'):
raise ExifFormatException("Invalid endianess found: %s" % self.endian)
# Now navigate to the items of interest and get them.
ifdStart = self.getValueAtLocation(4, 4)
self.ifdSearch(ifdStart)
#---------------------------------------
def imageDescription(self):
"""Return image description tag contents or '' if not found."""
return self.tagsToFind[self.IMAGE_DESCRIPTION_TAG].strip('\x20\x00')
#---------------------------------------
def copyright(self):
"""Return copyright tag contents or '' if not found."""
return self.tagsToFind[self.COPYRIGHT_TAG].strip('\x20\x00')
#---------------------------------------
def dateTimeOriginal(self, formatString = None):
"""Pass in optional format string to get time.strftime style formatting,
else get default exif format for date time string (without trailing nul).
Returns '' if tag not found."""
# The datetime should end in nul, get rid of it.
if formatString is None or not self.tagsToFind[self.DATE_TIME_ORIGINAL_TAG]:
return self.tagsToFind[self.DATE_TIME_ORIGINAL_TAG].strip('\x20\x00')
else:
# This will only work if the datetime string is in the standard exif format (i.e., hasn't been altered).
try:
import time
return time.strftime(formatString, time.strptime(self.tagsToFind[self.DATE_TIME_ORIGINAL_TAG].strip('\x20\x00'), '%Y:%m:%d %H:%M:%S'))
except:
return self.tagsToFind[self.DATE_TIME_ORIGINAL_TAG].strip('\x20\x00')
#---------------------------------------
def ifdSearch(self, ifdStart):
numIfdEntries = self.getValueAtLocation(ifdStart, 2)
tagsStart = ifdStart + 2
for entryNum in range(numIfdEntries):
# For my purposes, all files will have either no tags, or
# only our tags of interest, so no need to waste time trying to
# break out of the loop early.
thisTagStart = tagsStart + 12 * entryNum
tagId = self.getValueAtLocation(thisTagStart, 2)
if tagId == self.EXIF_SUBIFD_TAG:
# This is a special tag that points to another ifd. Our
# date time original tag is in the sub ifd.
self.ifdSearch(self.getTagValue(thisTagStart))
elif tagId in self.tagsToFind:
assert(not self.tagsToFind[tagId])
self.tagsToFind[tagId] = self.getTagValue(thisTagStart)
#---------------------------------------
def getValueAtLocation(self, offset, length):
slice = self.tiff[offset:offset + length]
if self.endian == 'I':
val = self.s2n_intel(slice)
else:
val = self.s2n_motorola(slice)
return val
#---------------------------------------
def s2n_motorola(self, str):
x = 0
for c in str:
x = (x << 8) | ord(c)
return x
#---------------------------------------
def s2n_intel(self, str):
x = 0
y = 0
for c in str:
x = x | (ord(c) << y)
y = y + 8
return x
#---------------------------------------
def getTagValue(self, thisTagStart):
datatype = self.getValueAtLocation(thisTagStart + 2, 2)
numBytes = [ 1, 1, 2, 4, 8, 1, 1, 2, 4, 8 ] [datatype-1] * self.getValueAtLocation(thisTagStart + 4, 4)
if numBytes > 4:
offsetToValue = self.getValueAtLocation(thisTagStart + 8, 4)
return self.tiff[offsetToValue:offsetToValue + numBytes]
else:
if datatype == 2 or datatype == 1 or datatype == 7:
return self.tiff[thisTagStart + 8:thisTagStart + 8 + numBytes]
else:
return self.getValueAtLocation(thisTagStart + 8, numBytes)
#---------------------------------------
def __str__(self):
return str(self.tagsToFind)
#---------------------------------------------------------------------
if __name__ == '__main__':
import sys
if len(sys.argv) == 1:
print("Pass jpgs to process.")
sys.exit(1)
for filename in sys.argv[1:]:
try:
f = MinimalExifReader(filename)
print(filename)
print("description: '%s'" % f.imageDescription())
print("copyright: '%s'" % f.copyright())
print("dateTimeOriginal: '%s'" % f.dateTimeOriginal())
print("dateTimeOriginal: '%s'" % f.dateTimeOriginal('%B %d, %Y %I:%M:%S %p'))
print()
except ExifFormatException as ex:
sys.stderr.write("Exif format error: %s\n" % ex)
except:
sys.stderr.write("Unable to process %s\n" % filename)

View file

@ -1,457 +0,0 @@
"""
Offers one class, MinimalExifWriter, which takes a jpg filename
in the constructor. Allows you to: remove exif section, add
image description, add copyright. Typical usage:
f = MinimalExifWriter('xyz.jpg')
f.newImageDescription('This is a photo of something very interesting!')
f.newCopyright('Jose Blow, All Rights Reserved', addCopyrightYear = 1)
f.process()
Class methods:
newImageDescription(description)--will add Exif ImageDescription to file.
newCopyright(copyright, addSymbol = 0, addYear = 0)--will add Exif Copyright to file.
Will optionally prepend copyright symbol, or copyright symbol and current year.
removeExif()--will obliterate existing exif section.
process()--call after calling one or more of the above. Will remove existing exif
section, optionally saving some existing tags (see below), and insert a new exif
section with only three tags at most: description, copyright and date time original.
If removeExif() not called, existing description (or new description if newDescription()
called), existing copyright (or new copyright if newCopyright() called) and existing
"DateTimeOriginal" (date/time picture taken) tags will be rewritten to the new
minimal exif section.
Run at comand line with no args to see command line usage.
Does not work on unix due to differences in mmap. Not sure what's up there--
don't need it on unix!
Brought to you by Megabyte Rodeo Software.
http://www.fetidcascade.com/pyexif.html
"""
# Written by Chris Stromberger, 10/2004. Public Domain.
# Last updated: 12/3/2004.
DUMP_TIFF = 0
VERBOSE = 0
if VERBOSE:
import binascii
import mmap
import sys
from . import minimal_exif_reader
#---------------------------------------------------------------------
class ExifFormatException(Exception):
pass
#---------------------------------------------------------------------------
class MinimalExifWriter:
SOI_MARKER = '\xff\xd8'
APP0_MARKER = '\xff\xe0'
APP1_MARKER = '\xff\xe1'
# Standard app0 segment that will work for all files. We hope.
# Based on http://www.funducode.com/freec/Fileformats/format3/format3b.htm.
APP0 = '\xff\xe0\x00\x10\x4a\x46\x49\x46\x00\x01\x01\x00\x00\x01\x00\x01\x00\x00'
def __init__(self, filename):
self.filename = filename
self.removeExifSection = 0
self.description = None
self.copyright = None
self.dateTimeOriginal = None
#---------------------------------------------
def newImageDescription(self, description):
self.description = description
#---------------------------------------------
def newCopyright(self, copyright, addSymbol = 0, addYear = 0):
if addYear:
import time
year = time.localtime()[0]
self.copyright = "\xa9 %s %s" % (year, copyright)
elif addSymbol:
self.copyright = "\xa9 %s" % copyright
else:
self.copyright = copyright
#---------------------------------------------
def removeExif(self):
self.removeExifSection = 1
#---------------------------------------------
def process(self):
if not self.removeExifSection:
self.getExistingExifInfo()
if VERBOSE:
print(self)
import os
try:
fd = os.open(self.filename, os.O_RDWR)
except:
sys.stderr.write('Unable to open "%s"\n' % filename)
return
self.m = mmap.mmap(fd, 0)
os.close(fd)
# We only add app0 if all we're doing is removing the exif section.
justRemovingExif = self.description is None and self.copyright is None and self.removeExifSection
if VERBOSE: print('justRemovingExif=%s' % justRemovingExif)
self.removeExifInfo(addApp0 = justRemovingExif)
if justRemovingExif:
self.m.close()
return
# Get here means we are adding new description and/or copyright.
self.removeApp0()
totalTagsToBeAdded = len([_f for _f in (self.description, self.copyright, self.dateTimeOriginal) if _f])
assert(totalTagsToBeAdded > 0)
# Layout will be: firstifd|description|copyright|exififd|datetime.
# First ifd will have tags: desc|copyright|subifd tag.
ifd = [self.twoBytesHexIntel(totalTagsToBeAdded)]
ifdEnd = ['\x00\x00\x00\x00']
NUM_TAGS_LEN = 2
TAG_LEN = 12
NEXT_IFD_OFFSET_LEN = 4
TIFF_HEADER_LENGTH = 8
ifdLength = NUM_TAGS_LEN + TAG_LEN * totalTagsToBeAdded + NEXT_IFD_OFFSET_LEN
# Subifd only has one tag.
SUBIFD_LENGTH = NUM_TAGS_LEN + TAG_LEN + NEXT_IFD_OFFSET_LEN
offsetToEndOfData = ifdLength + TIFF_HEADER_LENGTH
if self.description:
ifd.append(self.descriptionTag(len(self.description), offsetToEndOfData))
ifdEnd.append(self.description)
offsetToEndOfData += len(self.description)
if self.copyright:
ifd.append(self.copyrightTag(len(self.copyright), offsetToEndOfData))
ifdEnd.append(self.copyright)
offsetToEndOfData += len(self.copyright)
if self.dateTimeOriginal:
ifd.append(self.subIfdTag(offsetToEndOfData))
offsetToEndOfData += SUBIFD_LENGTH
ifdEnd.append(self.buildSubIfd(len(self.dateTimeOriginal), offsetToEndOfData))
ifdEnd.append(self.dateTimeOriginal)
app1 = self.buildApp1Section(ifd, ifdEnd)
self.addApp1(app1)
self.m.close()
#---------------------------------------------
# Build exif subifd with one tag for datetime (0x9003).
# Type is ascii (0x0002).
def buildSubIfd(self, lenDateTime, offsetToEndOfData):
return '\x01\x00\x03\x90\x02\x00%s%s\x00\x00\x00\x00' % (self.fourBytesHexIntel(lenDateTime), self.fourBytesHexIntel(offsetToEndOfData))
#---------------------------------------------
def getExistingExifInfo(self):
# Save off the old stuff.
try:
f = minimal_exif_reader.MinimalExifReader(self.filename)
except:
# Assume no existing exif info in the file. We
# don't care.
return
if not self.description:
self.description = f.imageDescription()
if not self.copyright:
self.copyright = f.copyright()
self.dateTimeOriginal = f.dateTimeOriginal()
if self.dateTimeOriginal:
# Restore ending nul.
if self.dateTimeOriginal[-1] != '\x00':
self.dateTimeOriginal += '\x00'
#---------------------------------------------------------------------------
def removeExifInfo(self, addApp0 = 1):
"""Remove the app1 section of the jpg. This removes all exif info and the exif
thumbnail. addApp0 should be 1 to add a minimal app0 section right after soi
to make it a legitimate jpg, I think (various image programs can read the file
without app0, but I think the standard requires one).
"""
# Read first bit of file to see if exif file.
self.m.seek(0)
if self.m.read(2) != self.SOI_MARKER:
self.m.close()
raise ExifFormatException("Missing SOI marker")
app0DataLength = 0
appMarker = self.m.read(2)
# See if there's an APP0 section, which sometimes appears.
if appMarker == self.APP0_MARKER:
if VERBOSE: print('app0 found')
app0DataLength = ord(self.m.read(1)) * 256 + ord(self.m.read(1))
if VERBOSE: print('app0DataLength: %s' % app0DataLength)
# Back up 2 bytes to get the length bytes.
self.m.seek(-2, 1)
existingApp0 = self.m.read(app0DataLength)
appMarker = self.m.read(2)
if appMarker != self.APP1_MARKER:
# We don't care, we'll add our minimal app1 later.
return
exifHeader = self.m.read(8)
if VERBOSE: print('exif header: %s' % binascii.hexlify(exifHeader))
if (exifHeader[2:6] != 'Exif' or
exifHeader[6:8] != '\x00\x00'):
self.m.close()
raise ExifFormatException("Malformed APP1")
app1Length = ord(exifHeader[0]) * 256 + ord(exifHeader[1])
if VERBOSE: print('app1Length: %s' % app1Length)
originalFileSize = self.m.size()
# Shift stuff just past app1 to overwrite app1.
# Start at app1 length bytes in + other bytes not incl in app1 length.
src = app1Length + len(self.SOI_MARKER) + len(self.APP1_MARKER)
if app0DataLength:
src += app0DataLength + len(self.APP0_MARKER)
dest = len(self.SOI_MARKER)
if addApp0:
if app0DataLength != 0:
# We'll re-add the existing app0.
dest += app0DataLength + len(self.APP0_MARKER)
else:
# Add our generic app0.
dest += len(self.APP0)
count = originalFileSize - app1Length - len(self.SOI_MARKER) - len(self.APP1_MARKER)
if app0DataLength:
count -= app0DataLength + len(self.APP0_MARKER)
if VERBOSE: print('self.m.move(%s, %s, %s)' % (dest, src, count))
self.m.move(dest, src, count)
if addApp0:
if app0DataLength != 0:
self.m.resize(originalFileSize - app1Length - len(self.APP1_MARKER))
else:
self.m.seek(len(self.SOI_MARKER))
self.m.write(self.APP0)
self.m.resize(originalFileSize - app1Length - len(self.APP1_MARKER) + len(self.APP0))
else:
self.m.resize(originalFileSize - app1Length - len(self.APP1_MARKER))
#---------------------------------------------------------------------------
def removeApp0(self):
self.m.seek(0)
header = self.m.read(6)
if (header[0:2] != self.SOI_MARKER or
header[2:4] != self.APP0_MARKER):
if VERBOSE: print('no app0 found: %s' % binascii.hexlify(header))
return
originalFileSize = self.m.size()
app0Length = ord(header[4]) * 256 + ord(header[5])
if VERBOSE: print('app0Length:', app0Length)
# Shift stuff to overwrite app0.
# Start at app0 length bytes in + other bytes not incl in app0 length.
src = app0Length + len(self.SOI_MARKER) + len(self.APP0_MARKER)
dest = len(self.SOI_MARKER)
count = originalFileSize - app0Length - len(self.SOI_MARKER) - len(self.APP0_MARKER)
self.m.move(dest, src, count)
if VERBOSE: print('m.move(%s, %s, %s)' % (dest, src, count))
self.m.resize(originalFileSize - app0Length - len(self.APP0_MARKER))
#---------------------------------------------------------------------------
def addApp1(self, app1):
originalFileSize = self.m.size()
# Insert app1 section.
self.m.resize(originalFileSize + len(app1))
src = len(self.SOI_MARKER)
dest = len(app1) + len(self.SOI_MARKER)
count = originalFileSize - len(self.SOI_MARKER)
self.m.move(dest, src, count)
self.m.seek(len(self.SOI_MARKER))
self.m.write(app1)
#---------------------------------------------------------------------------
def fourBytesHexIntel(self, number):
return '%s%s%s%s' % (chr(number & 0x000000ff),
chr((number >> 8) & 0x000000ff),
chr((number >> 16) & 0x000000ff),
chr((number >> 24) & 0x000000ff))
#---------------------------------------------------------------------------
def twoBytesHexIntel(self, number):
return '%s%s' % (chr(number & 0x00ff),
chr((number >> 8) & 0x00ff))
#---------------------------------------------------------------------------
def descriptionTag(self, numChars, loc):
return self.asciiTag('\x0e\x01', numChars, loc)
#---------------------------------------------------------------------------
def copyrightTag(self, numChars, loc):
return self.asciiTag('\x98\x82', numChars, loc)
#---------------------------------------------------------------------------
def subIfdTag(self, loc):
return '\x69\x87\x04\x00\x01\x00\x00\x00%s' % self.fourBytesHexIntel(loc)
#---------------------------------------------------------------------------
def asciiTag(self, tag, numChars, loc):
"""Create ascii tag. Assumes description > 4 chars long."""
return '%s\x02\x00%s%s' % (tag, self.fourBytesHexIntel(numChars), self.fourBytesHexIntel(loc))
#---------------------------------------------------------------------------
def buildApp1Section(self, ifdPieces, ifdEndPieces):
"""Create the APP1 section of an exif jpg. Consists of exif header plus
tiff header + ifd and associated data."""
# Intel byte order, offset to first ifd will be 8.
tiff = 'II\x2a\x00\x08\x00\x00\x00%s%s' % (''.join(ifdPieces), ''.join(ifdEndPieces))
if DUMP_TIFF:
f = open('tiff.dump', 'wb')
f.write(tiff)
f.close()
app1Length = len(tiff) + 8
return '\xff\xe1%s%sExif\x00\x00%s' % (chr((app1Length >> 8) & 0x00ff), chr(app1Length & 0x00ff), tiff)
#---------------------------------------------------------------------------
def __str__(self):
return """filename: %(filename)s
removeExifSection: %(removeExifSection)s
description: %(description)s
copyright: %(copyright)s
dateTimeOriginal: %(dateTimeOriginal)s
""" % self.__dict__
#---------------------------------------------------------------------------
def usage(error = None):
"""Print command line usage and exit"""
if error:
print(error)
print()
print("""This program will remove exif info from an exif jpg, and can optionally
add the ImageDescription exif tag and/or the Copyright tag. But it will always remove
some or all existing exif info (depending on options--see below)!
So don't run this on your original images without a backup.
Options:
-h: shows this message.
-f <file>: jpg to process (required).
-x: remove exif info (including thumbnail).
-d <description or file>: remove exif info (including thumbnail) and then add exif
ImageDescription. Will save the existing copyright tag if present,
as well as the date time original tag (date & time photo taken),
unless -x also passed (-x always means remove all exif info).
It will attempt to open whatever is passed on the
command line as a file; if successful, the contents of the file
are added as the description, else the literal text on the
command line is used as the description.
-c <copyright or file>: remove exif info (including thumbnail) and then add exif
Copyright tag. Will save the existing image description tag if present,
as well as the date time original tag (date & time photo taken),
unless -x also passed (-x always means remove all exif info).
It will attempt to open whatever is passed on the command line as a file;
if successful, the contents of the file are added as the copyright,
else the literal text on the command line is used as the copyright.
-s: prepend copyright symbol to copyright.
-y: prepend copyright symbol and current year to copyright.
The image description and copyright must be > 4 characters long.
This software courtesy of Megabyte Rodeo Software.""")
sys.exit(1)
#---------------------------------------------------------------------------
def parseArgs(args_):
import getopt
try:
opts, args = getopt.getopt(args_, "yshxd:f:c:")
except getopt.GetoptError:
usage()
filename = None
description = ''
copyright = ''
addCopyrightSymbol = 0
addCopyrightYear = 0
removeExif = 0
for o, a in opts:
if o == "-h":
usage()
if o == "-f":
filename = a
if o == "-d":
try:
f = open(a)
description = f.read()
f.close()
except:
description = a
if o == "-c":
try:
f = open(a)
copyright = f.read()
f.close()
except:
copyright = a
if o == '-x':
removeExif = 1
if o == '-s':
addCopyrightSymbol = 1
if o == '-y':
addCopyrightYear = 1
if filename is None:
usage('Missing jpg filename')
if description and (len(description) <= 4 or len(description) > 60000):
usage('Description too short or too long')
if copyright and (len(copyright) <= 4 or len(copyright) > 60000):
usage('Copyright too short or too long')
if not description and not copyright and not removeExif:
usage('Nothing to do!')
return filename, description, copyright, removeExif, addCopyrightSymbol, addCopyrightYear
#---------------------------------------------------------------------------
if __name__ == '__main__':
try:
filename, description, copyright, removeExif, addCopyrightSymbol, addCopyrightYear = parseArgs(sys.argv[1:])
f = MinimalExifWriter(filename)
if description:
f.newImageDescription(description)
if copyright:
f.newCopyright(copyright, addCopyrightSymbol, addCopyrightYear)
if removeExif:
f.removeExif()
f.process()
except ExifFormatException as ex:
sys.stderr.write("Exif format error: %s\n" % ex)
except SystemExit:
pass
except:
sys.stderr.write("Unable to process %s\n" % filename)
raise

View file

@ -24,39 +24,33 @@ __version__ = "$Revision: 0.2 $"
__date__ = "$Date: 2016/05/17 $"
__license__ = "GPLv3"
# Thanks to: http://www.julesberman.info/spec2img.htm
from PIL import Image
import piexif
def hide(img, img_enc, copyright="https://github.com/cedricbonhomme/Stegano", \
secret_message = None, secret_file = None):
def hide(img, img_enc, secret_message = None, secret_file = None):
"""
"""
import shutil
import datetime
from zlib import compress
from zlib import decompress
from base64 import b64encode
from .exif.minimal_exif_writer import MinimalExifWriter
if secret_file != None:
with open(secret_file, "r") as f:
secret_file_content = f.read()
if secret_file != None:
text = compress(b64encode(secret_file_content))
text = compress(b64encode(bytes(secret_file_content, "utf-8")))
else:
text = compress(b64encode(secret_message))
text = compress(b64encode(bytes(secret_message, "utf-8")))
try:
shutil.copy(img, img_enc)
except Exception as e:
print(("Impossible to copy image:", e))
return
f = MinimalExifWriter(img_enc)
f.removeExif()
f.newImageDescription(text)
if copyright:
f.newCopyright(copyright, addYear = 1)
f.process()
img = Image.open(img)
if "exif" in img.info:
exif_dict = piexif.load(img.info["exif"])
else:
exif_dict = {}
exif_dict["0th"] = {}
exif_dict["0th"][piexif.ImageIFD.ImageDescription] = text
exif_bytes = piexif.dump(exif_dict)
img.save(img_enc, exif=exif_bytes)
img.close()
def reveal(img):
@ -64,16 +58,10 @@ def reveal(img):
"""
from base64 import b64decode
from zlib import decompress
from .exif.minimal_exif_reader import MinimalExifReader
try:
g = MinimalExifReader(img)
except:
print("Impossible to read description.")
return
return b64decode(decompress(g.imageDescription()))
#print((b64decode(decompress(g.imageDescription()))))
#print(("\nCopyright " + g.copyright()))
#print g.dateTimeOriginal()
exif_dict = piexif.load(img)
encoded_message = exif_dict["0th"][piexif.ImageIFD.ImageDescription]
return b64decode(decompress(encoded_message))
if __name__ == "__main__":

View file

@ -36,31 +36,29 @@ class TestEXIFHeader(unittest.TestCase):
Test hiding the empty string.
"""
secret = exifHeader.hide("./examples/pictures/Elisha-Cuthbert.jpg",
"./image.png", copyright="", secret_message="")
"./image.jpg", secret_message="")
#secret.save(""./image.png"")
clear_message = exifHeader.reveal("./image.png")
#print(clear_message)
self.assertEqual("", clear_message)
clear_message = exifHeader.reveal("./image.jpg")
self.assertEqual(b"", clear_message)
def test_hide_and_reveal(self):
messages_to_hide = ["a", "foo", "Hello World!", ":Python:"]
for message in messages_to_hide:
secret = exifHeader.hide("./examples/pictures/Elisha-Cuthbert.jpg",
"./image.png", copyright="",
secret_message=message)
"./image.jpg", secret_message=message)
clear_message = exifHeader.reveal("./image.png")
clear_message = exifHeader.reveal("./image.jpg")
self.assertEqual(message, clear_message)
self.assertEqual(message, message)
def tearDown(self):
try:
os.unlink("./image.png")
os.unlink("./image.jpg")
except:
pass
if __name__ == '__main__':
unittest.main()