Files
PowerToys/src/modules/powerrename/lib/MetadataFormatHelper.h
moooyo 70e1177a6a [PowerRename] Support using photo metadata to replace in the PowerRename (#41728)
<!-- Enter a brief description/summary of your PR here. What does it
fix/what does it change/how was it tested (even manually, if necessary)?
-->
## Summary of the Pull Request
1. Introduce WIC for power rename and add new class WICMetadataExtractor
to use WIC to extract metadata.
2. Add some patterns for metadata extract.
3. Support XMP and EXIF metadata extract.
4. Add test data for xmp and exif extractor
5. Add attribution for the test data uploader.

UI:
<img width="2052" height="1415" alt="image"
src="https://github.com/user-attachments/assets/9051b12e-4e66-4fdc-a4d4-3bada661c235"
/>
<img width="284" height="170" alt="image"
src="https://github.com/user-attachments/assets/2fd67193-77a7-48f0-a5ac-08a69fe64e55"
/>
<img width="715" height="1160" alt="image"
src="https://github.com/user-attachments/assets/5fa68a8c-d129-44dd-b747-099dfbcded12"
/>

demo:


https://github.com/user-attachments/assets/e90bc206-62e5-4101-ada2-3187ee7e2039



<!-- Please review the items on the PR checklist before submitting-->
## PR Checklist

- [x] Closes: #5612
- [x] **Communication:** I've discussed this with core contributors
already. If the work hasn't been agreed, this work might be rejected
- [x] **Tests:** Added/updated and all pass
- [x] **Localization:** All end-user-facing strings can be localized
- [ ] **Dev docs:** Added/updated
- [ ] **New binaries:** Added on the required places
- [ ] [JSON for
signing](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ESRPSigning_core.json)
for new binaries
- [ ] [WXS for
installer](https://github.com/microsoft/PowerToys/blob/main/installer/PowerToysSetup/Product.wxs)
for new binaries and localization folder
- [ ] [YML for CI
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/ci/templates/build-powertoys-steps.yml)
for new test projects
- [ ] [YML for signed
pipeline](https://github.com/microsoft/PowerToys/blob/main/.pipelines/release.yml)
- [ ] **Documentation updated:** If checked, please file a pull request
on [our docs
repo](https://github.com/MicrosoftDocs/windows-uwp/tree/docs/hub/powertoys)
and link it here: #xxx

<!-- Provide a more detailed description of the PR, other things fixed,
or any additional comments/features here -->
## Detailed Description of the Pull Request / Additional comments

<!-- Describe how you validated the behavior. Add automated tests
wherever possible, but list manual validation steps taken as well -->
## Validation Steps Performed

---------

Co-authored-by: Yu Leng <yuleng@microsoft.com>
2025-11-04 09:27:16 +08:00

118 lines
5.0 KiB
C++

// Copyright (c) Microsoft Corporation
// The Microsoft Corporation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
#pragma once
#include <string>
#include <utility>
#include <windows.h>
#include <propvarutil.h>
namespace PowerRenameLib
{
/// <summary>
/// Helper class for formatting and parsing metadata values
/// Provides static utility functions for converting metadata to human-readable strings
/// and parsing raw metadata values
/// </summary>
class MetadataFormatHelper
{
public:
// Formatting functions - Convert metadata values to display strings
/// <summary>
/// Format aperture value (f-number)
/// </summary>
/// <param name="aperture">Aperture value (e.g., 2.8)</param>
/// <returns>Formatted string (e.g., "f/2.8")</returns>
static std::wstring FormatAperture(double aperture);
/// <summary>
/// Format shutter speed
/// </summary>
/// <param name="speed">Shutter speed in seconds</param>
/// <returns>Formatted string (e.g., "1/100s" or "2.5s")</returns>
static std::wstring FormatShutterSpeed(double speed);
/// <summary>
/// Format ISO value
/// </summary>
/// <param name="iso">ISO speed value</param>
/// <returns>Formatted string (e.g., "ISO 400")</returns>
static std::wstring FormatISO(int64_t iso);
/// <summary>
/// Format flash status
/// </summary>
/// <param name="flashValue">Flash value from EXIF</param>
/// <returns>Formatted string (e.g., "Flash On" or "Flash Off")</returns>
static std::wstring FormatFlash(int64_t flashValue);
/// <summary>
/// Format GPS coordinate
/// </summary>
/// <param name="coord">Coordinate value in decimal degrees</param>
/// <param name="isLatitude">true for latitude, false for longitude</param>
/// <returns>Formatted string (e.g., "40°26.76'N")</returns>
static std::wstring FormatCoordinate(double coord, bool isLatitude);
/// <summary>
/// Format SYSTEMTIME to string
/// </summary>
/// <param name="st">SYSTEMTIME structure</param>
/// <returns>Formatted string (e.g., "2024-03-15 14:30:45")</returns>
static std::wstring FormatSystemTime(const SYSTEMTIME& st);
// Parsing functions - Convert raw metadata to usable values
/// <summary>
/// Parse GPS rational value from PROPVARIANT
/// </summary>
/// <param name="pv">PROPVARIANT containing GPS rational data</param>
/// <returns>Parsed double value</returns>
static double ParseGPSRational(const PROPVARIANT& pv);
/// <summary>
/// Parse single rational value from byte array
/// </summary>
/// <param name="bytes">Byte array containing rational data</param>
/// <param name="offset">Offset in the byte array</param>
/// <returns>Parsed double value (numerator / denominator)</returns>
static double ParseSingleRational(const uint8_t* bytes, size_t offset);
/// <summary>
/// Parse single signed rational value from byte array
/// </summary>
/// <param name="bytes">Byte array containing signed rational data</param>
/// <param name="offset">Offset in the byte array</param>
/// <returns>Parsed double value (signed numerator / signed denominator)</returns>
static double ParseSingleSRational(const uint8_t* bytes, size_t offset);
/// <summary>
/// Parse GPS coordinates from PROPVARIANT values
/// </summary>
/// <param name="latitude">PROPVARIANT containing latitude</param>
/// <param name="longitude">PROPVARIANT containing longitude</param>
/// <param name="latRef">PROPVARIANT containing latitude reference (N/S)</param>
/// <param name="lonRef">PROPVARIANT containing longitude reference (E/W)</param>
/// <returns>Pair of (latitude, longitude) in decimal degrees</returns>
static std::pair<double, double> ParseGPSCoordinates(
const PROPVARIANT& latitude,
const PROPVARIANT& longitude,
const PROPVARIANT& latRef,
const PROPVARIANT& lonRef);
/// <summary>
/// Sanitize a string to make it safe for use in filenames
/// Replaces illegal filename characters (< > : " / \ | ? * and control chars) with underscore
/// Also removes trailing dots and spaces which Windows doesn't allow at end of filename
///
/// IMPORTANT: This should ONLY be called in ExtractPatterns to avoid performance waste.
/// Do NOT call this function when reading raw metadata values.
/// </summary>
/// <param name="str">String to sanitize</param>
/// <returns>Sanitized string safe for use in filename</returns>
static std::wstring SanitizeForFileName(const std::wstring& str);
};
}