def _getexif(self):
        # Extract EXIF information.  This method is highly experimental,
        # and is likely to be replaced with something better in a future
        # version.
        from PIL import TiffImagePlugin
        import io

        def fixup(value):
            if len(value) == 1:
                return value[0]
            return value

        # The EXIF record consists of a TIFF file embedded in a JPEG
        # application marker (!).
        try:
            data = self.info["exif"]
        except KeyError:
            return None
        file = io.BytesIO(data[6:])
        head = file.read(8)
        exif = {}
        # process dictionary
        info = TiffImagePlugin.ImageFileDirectory(head)
        info.load(file)
        for key, value in info.items():
            exif[key] = fixup(value)
        # get exif extension
        try:
            file.seek(exif[0x8769])
        except KeyError:
            pass
        else:
            info = TiffImagePlugin.ImageFileDirectory(head)
            info.load(file)
            for key, value in info.items():
                exif[key] = fixup(value)
        # get gpsinfo extension
        try:
            file.seek(exif[0x8825])
        except KeyError:
            pass
        else:
            info = TiffImagePlugin.ImageFileDirectory(head)
            info.load(file)
            exif[0x8825] = gps = {}
            for key, value in info.items():
                gps[key] = fixup(value)
        return exif
Example #2
0
def logSpect2Tiff(outimg, fname, scaleinfo=None):
    """ 
    Single channel spectrogram to tiff file normed to [0,1] 
    """
    info = TiffImagePlugin.ImageFileDirectory()

    scale = 80.
    shift = np.amax(outimg)

    if (scaleinfo == None):
        info[270] = str(scale) + ',' + str(shift)
    else:
        info[270] = scaleinfo

    #shift to put max at 0
    shiftimg = outimg - shift
    #scale to map [-80, 0] to  [-1,0]
    outimg = [x / scale for x in outimg]
    #shift to [0,1]
    outimg = [x + 1. for x in outimg]
    #clip anything below 0 (anything originally below -80dB)
    outimg = np.maximum(outimg, 0)  # clip below 0
    #print('logSpect2Tiff: writing image with min ' + str(np.amin(outimg)) + ', and max ' + str(np.amax(outimg)))
    savimg = Image.fromarray(np.flipud(outimg))
    savimg.save(fname, tiffinfo=info)
    return info[270]  # just in case you want it for some reason
    def test_rt_metadata(self):
        """ Test writing arbitrary metadata into the tiff image directory
            Use case is ImageJ private tags, one numeric, one arbitrary
            data.  https://github.com/python-pillow/Pillow/issues/291
            """

        img = hopper()

        textdata = "This is some arbitrary metadata for a text field"
        floatdata = 12.345
        doubledata = 67.89

        info = TiffImagePlugin.ImageFileDirectory()

        info[tag_ids['ImageJMetaDataByteCounts']] = len(textdata)
        info[tag_ids['ImageJMetaData']] = textdata
        info[tag_ids['RollAngle']] = floatdata
        info.tagtype[tag_ids['RollAngle']] = 11

        info[tag_ids['YawAngle']] = doubledata
        info.tagtype[tag_ids['YawAngle']] = 12

        f = self.tempfile("temp.tif")

        img.save(f, tiffinfo=info)

        loaded = Image.open(f)

        self.assertEqual(loaded.tag[50838], (len(textdata), ))
        self.assertEqual(loaded.tag[50839], textdata)
        self.assertAlmostEqual(loaded.tag[tag_ids['RollAngle']][0],
                               floatdata,
                               places=5)
        self.assertAlmostEqual(loaded.tag[tag_ids['YawAngle']][0], doubledata)
Example #4
0
def logSpect2Tiff(outimg, fname, lwinfo=None):
    """ 
    Single channel spectrogram to tiff file normed to [0,1] 
    """
    info = TiffImagePlugin.ImageFileDirectory()

    scale = 80.
    shift = float(np.amax(outimg))

    lwinfo = lwinfo or {}
    lwinfo["scale"] = scale
    lwinfo["shift"] = shift

    #just chose a tag index that appears to be unused: https://www.loc.gov/preservation/digital/formats/content/tiff_tags.shtml
    info[666] = json.dumps(lwinfo)

    #shift to put max at 0
    shiftimg = outimg - shift
    #scale to map [-80, 0] to  [-1,0]
    outimg = [x / scale for x in outimg]
    #shift to [0,1]
    outimg = [x + 1. for x in outimg]
    #clip anything below 0 (anything originally below -80dB)
    outimg = np.maximum(outimg, 0)  # clip below 0
    #print('logSpect2Tiff: writing image with min ' + str(np.amin(outimg)) + ', and max ' + str(np.amax(outimg)))
    savimg = Image.fromarray(np.flipud(outimg))
    savimg.save(fname, tiffinfo=info)
    return info[666]  # just in case you want it for some reason
Example #5
0
 def test_empty_metadata(self):
     f = io.BytesIO(b'II*\x00\x08\x00\x00\x00')
     head = f.read(8)
     info = TiffImagePlugin.ImageFileDirectory(head)
     try:
         self.assert_warning(UserWarning, lambda: info.load(f))
     except struct.error:
         self.fail("Should not be struct errors there.")
Example #6
0
    def test_rt_metadata(self):
        """ Test writing arbitrary metadata into the tiff image directory
            Use case is ImageJ private tags, one numeric, one arbitrary
            data.  https://github.com/python-pillow/Pillow/issues/291
            """

        img = hopper()

        # Behaviour change: re #1416
        # Pre ifd rewrite, ImageJMetaData was being written as a string(2),
        # Post ifd rewrite, it's defined as arbitrary bytes(7). It should
        # roundtrip with the actual bytes, rather than stripped text
        # of the premerge tests.
        #
        # For text items, we still have to decode('ascii','replace') because
        # the tiff file format can't take 8 bit bytes in that field.

        basetextdata = "This is some arbitrary metadata for a text field"
        bindata = basetextdata.encode('ascii') + b" \xff"
        textdata = basetextdata + " " + chr(255)
        reloaded_textdata = basetextdata + " ?"
        floatdata = 12.345
        doubledata = 67.89
        info = TiffImagePlugin.ImageFileDirectory()

        ImageJMetaData = tag_ids['ImageJMetaData']
        ImageJMetaDataByteCounts = tag_ids['ImageJMetaDataByteCounts']
        ImageDescription = tag_ids['ImageDescription']

        info[ImageJMetaDataByteCounts] = len(bindata)
        info[ImageJMetaData] = bindata
        info[tag_ids['RollAngle']] = floatdata
        info.tagtype[tag_ids['RollAngle']] = 11
        info[tag_ids['YawAngle']] = doubledata
        info.tagtype[tag_ids['YawAngle']] = 12

        info[ImageDescription] = textdata

        f = self.tempfile("temp.tif")

        img.save(f, tiffinfo=info)

        loaded = Image.open(f)

        self.assertEqual(loaded.tag[ImageJMetaDataByteCounts],
                         (len(bindata), ))
        self.assertEqual(loaded.tag_v2[ImageJMetaDataByteCounts], len(bindata))

        self.assertEqual(loaded.tag[ImageJMetaData], bindata)
        self.assertEqual(loaded.tag_v2[ImageJMetaData], bindata)

        self.assertEqual(loaded.tag[ImageDescription], (reloaded_textdata, ))
        self.assertEqual(loaded.tag_v2[ImageDescription], reloaded_textdata)

        loaded_float = loaded.tag[tag_ids['RollAngle']][0]
        self.assertAlmostEqual(loaded_float, floatdata, places=5)
        loaded_double = loaded.tag[tag_ids['YawAngle']][0]
        self.assertAlmostEqual(loaded_double, doubledata)
Example #7
0
def add_comment(filename, comment):

    tags = TiffImagePlugin.ImageFileDirectory()
    tags[270] = comment
    tags.tagtype['Description'] = 2

    Image.DEBUG = False
    TiffImagePlugin.WRITE_LIBTIFF = True

    return tags
Example #8
0
    def test_load_float(self):
        # Arrange
        ifd = TiffImagePlugin.ImageFileDirectory()
        data = b"abcdabcd"

        # Act
        ret = ifd.load_float(data)

        # Assert
        self.assertEqual(ret, (1.6777999408082104e+22, 1.6777999408082104e+22))
Example #9
0
    def test_load_double(self):
        # Arrange
        ifd = TiffImagePlugin.ImageFileDirectory()
        data = b"abcdefghabcdefgh"

        # Act
        ret = ifd.load_double(data)

        # Assert
        self.assertEqual(ret, (8.540883223036124e+194, 8.540883223036124e+194))
Example #10
0
    def test_load_string(self):
        # Arrange
        ifd = TiffImagePlugin.ImageFileDirectory()
        data = b"abc\0"

        # Act
        ret = ifd.load_string(data)

        # Assert
        self.assertEqual(ret, "abc")
Example #11
0
    def test_load_byte(self):
        # Arrange
        from PIL import TiffImagePlugin
        ifd = TiffImagePlugin.ImageFileDirectory()
        data = b"abc"

        # Act
        ret = ifd.load_byte(data)

        # Assert
        self.assertEqual(ret, b"abc")
Example #12
0
    def __generate_master__(self):
        """
        create a master file from the original already in the package and set all metadata
        """
        # open original
        # capture existing ICC profile (if there is one)
        # if no ICC profile, assign sRGB
        # if ICC profile and != sRGB, convert to sRGB
        # save as uncompressed TIFF

        logger = logging.getLogger(sys._getframe().f_code.co_name)

        profile_srgb2 = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'icc',
            'sRGB_IEC61966-2-1_black_scaled.icc')
        profile_srgb4 = os.path.join(
            os.path.dirname(os.path.abspath(__file__)), 'icc',
            'sRGB_v4_ICC_preference.icc')
        original_path = os.path.join(self.path, self.original)
        original_image = Image.open(original_path)
        try:
            raw_profile = original_image.info['icc_profile']
        except KeyError:
            raw_profile = getOpenProfile(profile_srgb2).tobytes()
            logger.warning(
                '{original} does not have an internal ICC color profile'.
                format(original=self.original))
        else:
            logger.debug(
                'detected internal ICC color profile in {original}'.format(
                    original=self.original))
        original_profile = getOpenProfile(BytesIO(raw_profile))
        original_profile_name = getProfileName(original_profile).strip()
        target_profile = getOpenProfile(profile_srgb4)
        target_profile_name = getProfileName(target_profile).strip()
        logger.debug(
            'attempting to convert from "{original}" to "{target}"'.format(
                original=original_profile_name, target=target_profile_name))
        converted_image = profileToProfile(original_image, original_profile,
                                           target_profile)
        master_path = os.path.join(self.path, 'master.tif')
        tiffinfo = TiffImagePlugin.ImageFileDirectory()
        tiffinfo[TiffImagePlugin.ICCPROFILE] = target_profile.tobytes()
        tiffinfo.tagtype[
            TiffImagePlugin.ICCPROFILE] = 1  # byte according to TiffTags.TYPES
        converted_image.DEBUG = True
        converted_image.save(master_path, tiffinfo=tiffinfo)
        hash_master = hash_of_file(master_path)
        logger.debug('saved converted master image to {master}'.format(
            master=master_path))
        self.__append_event__(
            'created master.tif file at {master}'.format(master=master_path))
        self.manifest.set('master.tif', hash_master)
Example #13
0
def test_undefined_zero(tmp_path):
    # Check that the tag has not been changed since this test was created
    tag = TiffTags.TAGS_V2[45059]
    assert tag.type == TiffTags.UNDEFINED
    assert tag.length == 0

    info = TiffImagePlugin.ImageFileDirectory(b"II*\x00\x08\x00\x00\x00")
    info[45059] = b"test"

    # Assert that the tag value does not change by setting it to itself
    original = info[45059]
    info[45059] = info[45059]
    assert info[45059] == original
Example #14
0
def scale_img(fname, basewidth, baseheight=None, info=None):
    """
    rescale images according to specified basewidth in terms of pixels. Maintains aspect ratio.
    """
    if (info == None):
        info = TiffImagePlugin.ImageFileDirectory()
    img = Image.open(fname)
    if (baseheight == None):
        wpercent = (basewidth / float(img.size[0]))
        hsize = int((float(img.size[1]) * float(wpercent)))
        img = img.resize((basewidth, hsize), Image.ANTIALIAS)
    else:
        img = img.resize((basewidth, baseheight), Image.ANTIALIAS)
    img.save(fname, tiffinfo=info)
    return img.size
Example #15
0
    def test_rt_metadata(self):
        """ Test writing arbitray metadata into the tiff image directory
            Use case is ImageJ private tags, one numeric, one arbitrary
            data.  https://github.com/python-pillow/Pillow/issues/291
            """

        img = lena()

        textdata = "This is some arbitrary metadata for a text field"
        info = TiffImagePlugin.ImageFileDirectory()

        info[tag_ids['ImageJMetaDataByteCounts']] = len(textdata)
        info[tag_ids['ImageJMetaData']] = textdata

        f = self.tempfile("temp.tif")

        img.save(f, tiffinfo=info)

        loaded = Image.open(f)

        self.assertEqual(loaded.tag[50838], (len(textdata),))
        self.assertEqual(loaded.tag[50839], textdata)
Example #16
0
def save_image(image, fname, scaleinfo=None):
	print('save_image: shape is ' + str(image.shape))
	if (height==1) : # orientation is freq bins in channels
		print('saving image in channel orientation')
		image = np.transpose(image, [2,1,0])[:,:,0]
	else :
		print('saving image in image orientation')
		image = image[:,:,0]
	
	print('AFTER reshaping, save_image: shape is ' + str(image.shape))


	
	print('image max is ' + str(np.amax(image) ))
	print('image min is ' + str(np.amin(image) ))
	# Output should add back the mean pixels we subtracted at the beginning

	# [0,80db] -> [0, 255]
	# after style transfer, images range outside of [0,255].
	# To preserve scale, and mask low values, we shift by (255-max), then clip at 0 and then have all bins in the top 80dB.
	image = np.clip(image-np.amax(image)+255, 0, 255).astype('uint8')

	info = TiffImagePlugin.ImageFileDirectory()
    
	if (scaleinfo == None) :
	    info[270] = '80, 0'
	else :
	    info[270] = scaleinfo

	#scipy.misc.imsave(path, image)

	bwarray=np.asarray(image)/255.

	savimg = Image.fromarray(np.float64(bwarray)) #==============================
	savimg.save(fname, tiffinfo=info)
	#print('RGB2TiffGray : tiffinfo is ' + str(info))
	return info[270] # just in case you want it for some reason
Example #17
0
 def test_empty_metadata(self):
     f = io.BytesIO(b'II*\x00\x08\x00\x00\x00')
     head = f.read(8)
     info = TiffImagePlugin.ImageFileDirectory(head)
     # Should not raise struct.error.
     self.assert_warning(UserWarning, info.load, f)
def _getmp(self):
    # Extract MP information.  This method was inspired by the "highly
    # experimental" _getexif version that's been in use for years now,
    # itself based on the ImageFileDirectory class in the TIFF plug-in.

    # The MP record essentially consists of a TIFF file embedded in a JPEG
    # application marker.
    try:
        data = self.info["mp"]
    except KeyError:
        return None
    file_contents = io.BytesIO(data)
    head = file_contents.read(8)
    endianness = '>' if head[:4] == b'\x4d\x4d\x00\x2a' else '<'
    mp = {}
    # process dictionary
    info = TiffImagePlugin.ImageFileDirectory(head)
    info.load(file_contents)
    for key, value in info.items():
        mp[key] = _fixup(value)
    # it's an error not to have a number of images
    try:
        quant = mp[0xB001]
    except KeyError:
        raise SyntaxError("malformed MP Index (no number of images)")
    # get MP entries
    try:
        mpentries = []
        for entrynum in range(0, quant):
            rawmpentry = mp[0xB002][entrynum * 16:(entrynum + 1) * 16]
            unpackedentry = unpack('{0}LLLHH'.format(endianness), rawmpentry)
            labels = ('Attribute', 'Size', 'DataOffset', 'EntryNo1',
                      'EntryNo2')
            mpentry = dict(zip(labels, unpackedentry))
            mpentryattr = {
                'DependentParentImageFlag':
                bool(mpentry['Attribute'] & (1 << 31)),
                'DependentChildImageFlag':
                bool(mpentry['Attribute'] & (1 << 30)),
                'RepresentativeImageFlag':
                bool(mpentry['Attribute'] & (1 << 29)),
                'Reserved': (mpentry['Attribute'] & (3 << 27)) >> 27,
                'ImageDataFormat': (mpentry['Attribute'] & (7 << 24)) >> 24,
                'MPType': mpentry['Attribute'] & 0x00FFFFFF
            }
            if mpentryattr['ImageDataFormat'] == 0:
                mpentryattr['ImageDataFormat'] = 'JPEG'
            else:
                raise SyntaxError("unsupported picture format in MPO")
            mptypemap = {
                0x000000: 'Undefined',
                0x010001: 'Large Thumbnail (VGA Equivalent)',
                0x010002: 'Large Thumbnail (Full HD Equivalent)',
                0x020001: 'Multi-Frame Image (Panorama)',
                0x020002: 'Multi-Frame Image: (Disparity)',
                0x020003: 'Multi-Frame Image: (Multi-Angle)',
                0x030000: 'Baseline MP Primary Image'
            }
            mpentryattr['MPType'] = mptypemap.get(mpentryattr['MPType'],
                                                  'Unknown')
            mpentry['Attribute'] = mpentryattr
            mpentries.append(mpentry)
        mp[0xB002] = mpentries
    except KeyError:
        raise SyntaxError("malformed MP Index (bad MP Entry)")
    # Next we should try and parse the individual image unique ID list;
    # we don't because I've never seen this actually used in a real MPO
    # file and so can't test it.
    return mp
Example #19
0
def test_empty_metadata():
    f = io.BytesIO(b"II*\x00\x08\x00\x00\x00")
    head = f.read(8)
    info = TiffImagePlugin.ImageFileDirectory(head)
    # Should not raise struct.error.
    pytest.warns(UserWarning, info.load, f)
Example #20
0
def test_rt_metadata(tmp_path):
    """ Test writing arbitrary metadata into the tiff image directory
        Use case is ImageJ private tags, one numeric, one arbitrary
        data.  https://github.com/python-pillow/Pillow/issues/291
        """

    img = hopper()

    # Behaviour change: re #1416
    # Pre ifd rewrite, ImageJMetaData was being written as a string(2),
    # Post ifd rewrite, it's defined as arbitrary bytes(7). It should
    # roundtrip with the actual bytes, rather than stripped text
    # of the premerge tests.
    #
    # For text items, we still have to decode('ascii','replace') because
    # the tiff file format can't take 8 bit bytes in that field.

    basetextdata = "This is some arbitrary metadata for a text field"
    bindata = basetextdata.encode("ascii") + b" \xff"
    textdata = basetextdata + " " + chr(255)
    reloaded_textdata = basetextdata + " ?"
    floatdata = 12.345
    doubledata = 67.89
    info = TiffImagePlugin.ImageFileDirectory()

    ImageJMetaData = TAG_IDS["ImageJMetaData"]
    ImageJMetaDataByteCounts = TAG_IDS["ImageJMetaDataByteCounts"]
    ImageDescription = TAG_IDS["ImageDescription"]

    info[ImageJMetaDataByteCounts] = len(bindata)
    info[ImageJMetaData] = bindata
    info[TAG_IDS["RollAngle"]] = floatdata
    info.tagtype[TAG_IDS["RollAngle"]] = 11
    info[TAG_IDS["YawAngle"]] = doubledata
    info.tagtype[TAG_IDS["YawAngle"]] = 12

    info[ImageDescription] = textdata

    f = str(tmp_path / "temp.tif")

    img.save(f, tiffinfo=info)

    with Image.open(f) as loaded:

        assert loaded.tag[ImageJMetaDataByteCounts] == (len(bindata), )
        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (len(bindata), )

        assert loaded.tag[ImageJMetaData] == bindata
        assert loaded.tag_v2[ImageJMetaData] == bindata

        assert loaded.tag[ImageDescription] == (reloaded_textdata, )
        assert loaded.tag_v2[ImageDescription] == reloaded_textdata

        loaded_float = loaded.tag[TAG_IDS["RollAngle"]][0]
        assert round(abs(loaded_float - floatdata), 5) == 0
        loaded_double = loaded.tag[TAG_IDS["YawAngle"]][0]
        assert round(abs(loaded_double - doubledata), 7) == 0

    # check with 2 element ImageJMetaDataByteCounts, issue #2006

    info[ImageJMetaDataByteCounts] = (8, len(bindata) - 8)
    img.save(f, tiffinfo=info)
    with Image.open(f) as loaded:

        assert loaded.tag[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)
        assert loaded.tag_v2[ImageJMetaDataByteCounts] == (8, len(bindata) - 8)