Files
EricRollei-AAA_Metadata_System/eric_metadata/utils/hash_utils.py
T

173 lines
5.4 KiB
Python

"""
Hash Utility Functions - Perceptual image hashing utilities for duplicate detection
This module provides functions for calculating perceptual image hashes
and storing them in metadata.
Author: Eric Hiss (GitHub: EricRollei)
Contact: [eric@historic.camera, eric@rollei.us]
License: Dual License (Non-Commercial and Commercial Use)
Copyright (c) 2025 Eric Hiss. All rights reserved.
Dual License:
1. Non-Commercial Use: This software is licensed under the terms of the
Creative Commons Attribution-NonCommercial 4.0 International License.
To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/
2. Commercial Use: For commercial use, a separate license is required.
Please contact Eric Hiss at [eric@historic.camera, eric@rollei.us] for licensing options.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT.
"""
import os
from datetime import datetime
from PIL import Image
# Check for imagehash library
try:
import imagehash
IMAGEHASH_AVAILABLE = True
except ImportError:
print("Warning: imagehash library not installed. To enable image hash functionality:")
print("pip install imagehash")
IMAGEHASH_AVAILABLE = False
def calculate_image_hash(image, hash_algorithm="phash"):
"""
Calculate perceptual hash for an image
Args:
image: PIL Image object
hash_algorithm: Hash algorithm to use ('phash', 'dhash', 'average_hash', 'whash-haar')
Returns:
str: String representation of the hash, or None if error
"""
if not IMAGEHASH_AVAILABLE:
return None
try:
# Calculate hash based on selected algorithm
hash_value = None
if hash_algorithm == "phash":
hash_value = imagehash.phash(image)
elif hash_algorithm == "dhash":
hash_value = imagehash.dhash(image)
elif hash_algorithm == "whash-haar":
hash_value = imagehash.whash(image)
else: # default to average_hash
hash_value = imagehash.average_hash(image)
# Return string representation
return str(hash_value)
except Exception as e:
print(f"Error calculating image hash: {e}")
return None
def calculate_hash_from_file(file_path, hash_algorithm="phash"):
"""
Calculate perceptual hash for an image file
Args:
file_path: Path to image file
hash_algorithm: Hash algorithm to use
Returns:
str: String representation of the hash, or None if error
"""
if not IMAGEHASH_AVAILABLE:
return None
try:
# Open image
img = Image.open(file_path)
# Calculate hash
return calculate_image_hash(img, hash_algorithm)
except Exception as e:
print(f"Error calculating hash from file {file_path}: {e}")
return None
def save_hash_to_metadata(file_path, hash_value, hash_algorithm, metadata_service):
"""
Save hash value to image metadata
Args:
file_path: Path to image file
hash_value: String representation of hash
hash_algorithm: Hash algorithm used
metadata_service: Initialized metadata service
Returns:
bool: True if successful, False otherwise
"""
if not metadata_service:
return False
try:
# Create hash metadata
hash_metadata = {
'eiqa': {
'technical': {
'hashes': {
hash_algorithm: hash_value,
'hash_time': datetime.now().isoformat()
}
}
}
}
# Set resource identifier
filename = os.path.basename(file_path)
resource_uri = f"file:///{filename}"
metadata_service.set_resource_identifier(resource_uri)
# Write hash metadata
metadata_service.write_metadata(
file_path,
hash_metadata,
targets=['embedded', 'xmp', 'database']
)
return True
except Exception as e:
print(f"Error saving hash to metadata: {e}")
return False
def calculate_and_save_hash(image_or_path, file_path, metadata_service, hash_algorithm="phash"):
"""
Calculate image hash and save to metadata
Args:
image_or_path: PIL Image or path to image file
file_path: Path where image is/will be saved
metadata_service: Initialized metadata service
hash_algorithm: Hash algorithm to use
Returns:
str: String representation of the hash or None if error
"""
try:
# Calculate hash
hash_value = None
if isinstance(image_or_path, str):
# It's a file path
hash_value = calculate_hash_from_file(image_or_path, hash_algorithm)
else:
# It's a PIL Image
hash_value = calculate_image_hash(image_or_path, hash_algorithm)
if hash_value:
# Save to metadata
save_hash_to_metadata(file_path, hash_value, hash_algorithm, metadata_service)
return hash_value
except Exception as e:
print(f"Error in calculate_and_save_hash: {e}")
return None