Add HEIC/HEIF EXIF metadata support for PowerRename
Summary of the Pull Request
This PR enables PowerRename to extract EXIF metadata from HEIC/HEIF images (Apple's photo format) for use in file renaming patterns.
References and Relevant Issues
Fixes #43758
Detailed Description of the Pull Request / Additional comments
Root Cause Analysis
HEIC/HEIF files store EXIF metadata under a different path structure than JPEG/TIFF files:
- JPEG/TIFF:
/app1/ifd/exif/{ushort=...}and/app1/ifd/gps/{ushort=...} - HEIC/HEIF:
/ifd/exif/{ushort=...}and/ifd/gps/{ushort=...}
The existing implementation only queried the standard JPEG/TIFF paths, so HEIC metadata was not found.
Changes Made
- Helpers.cpp: Added
.heicand.heifto thesupportedExtensionsset inisMetadataUsed()function - WICMetadataExtractor.cpp:
- Added 23 HEIC-specific metadata query paths (18 EXIF + 5 GPS)
- Added 4 fallback methods:
ReadDateTimeWithFallback,ReadStringWithFallback,ReadIntegerWithFallback,ReadDoubleWithFallback - Updated
ExtractAllEXIFFields()to use fallback methods (try standard path first, then HEIC path) - Updated
ExtractGPSData()to use fallback paths for GPS data
- WICMetadataExtractor.h: Added declarations for the 4 fallback methods
Testing
- Tested with HEIC images from iPhone containing EXIF data
- Verified that standard JPEG/TIFF metadata extraction still works correctly
Validation Steps Performed
- Built and verified no compilation errors
- Tested metadata extraction from HEIC files
- Tested that JPEG/TIFF extraction still works (no regression)
@microsoft-github-policy-service agree
@daverayment Thank you for the detailed feedback! I've completely refactored the implementation based on your suggestions.
Changes Made
1. Extensible Path System (DRY Principle)
- Separated EXIF tag IDs from root paths: Each tag ID (e.g.,
{ushort=36867}for DateTimeOriginal) is now declared once - Created root path vectors:
IFD_ROOT_PATHS,EXIF_ROOT_PATHS,GPS_ROOT_PATHSthat can be easily extended - Added
BuildMetadataPaths()helper: Combines root paths with tag IDs to build full query paths
// Root paths for EXIF sub-IFD metadata
const std::vector<std::wstring> EXIF_ROOT_PATHS = {
L"/app1/ifd/exif", // JPEG (APP1 marker)
L"/ifd/exif" // HEIC/HEIF/TIFF
};
// Tag IDs (identical across formats)
const std::wstring TAG_DATE_TAKEN = L"{ushort=36867}";
2. Multi-Path Reading Methods
- Added
ReadDateTimeFromPaths(),ReadStringFromPaths(),ReadIntegerFromPaths(),ReadDoubleFromPaths(),ReadMetadataFromPaths() - These methods iterate through all paths until metadata is found
- Removed the repetitive
WithFallbackmethods
3. Future Extensibility
To add support for new formats (PNG, WebP, etc.), you simply:
- Add new root paths to the vectors
- No changes needed to extraction logic
4. Unit Tests for HEIC/HEIF
- Added
ExtractHEICMetadataTeststest class - Tests gracefully skip when HEIC test files aren't available
- Tests handle missing HEIF Image Extensions gracefully
Note: I didn't include HEIC test files because:
- Need to find/create properly licensed test images
- HEIC testing requires Microsoft's HEIF Image Extensions to be installed
Would you like me to:
- Create a simple HEIC test image with known metadata?
- Add any additional test cases?
Thank you again for the guidance on making this more maintainable!
@ThanhNguyxn You've marked this as being ready for another review, but you keep force-pushing changes. I cannot review this while this is happening because each time you force push, I have to restart the review process.
sorry bro i didn't pay attention before so i updated everything so it wouldn't be out of date
There's no need to keep a PR "up to date" by pushing the same files repeatedly. If it needs to be updated to the latest version of the main branch, one of the maintainers would let you know after the review process is complete and before your contribution is merged in. If you have your own changes to add (like new features or bug fixes) while a review is in progress, please mention it in a comment first.
I'm a bit confused that you're now saying that you don't have test files. You mentioned in the original PR description that you'd tested the solution with HEIC file(s). Was that incorrect, or is the issue that they cannot be shared because of the project's particular open source licence? If it's the latter, could you please at least share some screenshots to show that the tests are passing with your test file(s), and then source some files which can be used to review your code. As you say, we may not be able to use them in the CI build because the build machines may not have the codecs installed, but we must still have a set of test files for manual testing that are comprehensive and consistent so the unit tests are repeatable and accurate.
There are also some concerns (possibly unfounded!) that I have about treating HEIC/HEIF and JPEG the same. We may need some custom handling, or at least some research into whether the format differences are anything to worry about. HEIC/HEIF are more complex in terms of their structure and capabilities and we'd need to be certain that (for example) we can extract metadata from multi-frame files and also from different devices, not just iPhones, where the format is likely most popular.