Repository navigation
feat: Google Motion Photo support for every adapter - #83
Merged
Merged
Conversation
Read the legacy MicroVideoOffset and Motion Photo 1.0 Container:Directory from the JPEG itself and report the video length as MicroVideoOffset from Reader::read(), so Native, ImageMagick and exiftool behave the same. The scan fallback starts after the primary image's EOI. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is 🚀 New features to boost your workflow:
|
Safe 2.x has no ftell wrapper and Safe 3.x only wraps xml_parser_set_option for PHP 8.4, which broke the PHP 8.2 and 8.3 test jobs. Use the native functions and handle the ftell failure explicitly. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
ildyria
approved these changes
Oct 19, 2026
mlapaglia
added a commit
to mlapaglia/Lychee
that referenced
this pull request
Oct 19, 2026
php-exif 1.5.0 now locates the video of Google Motion Photos for every reader (LycheeOrg/php-exif#83). Bump the dependency, drop Lychee's own reader and its unit tests, and let the backfill command call the php-exif locator. Spec impact: ADR-100-02 supersedes ADR-100-01, Q-100-08 records the decision, and FR-100-01, the services catalogue, test strategy, knowledge map and upload lifecycle now point at php-exif. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Report the video embedded in Google Motion Photos as
MicroVideoOffset(its length in bytes from the end of the file) for every adapter, in both formats:GCamera:MicroVideoOffset(Android 10 and earlier), which only the Exiftool mapper read until now;GCamera:MotionPhotowith aContainer:Directory, Android 11 and later, Ultra HDR files with a gain map included), which no adapter read.Requested on LycheeOrg/Lychee#4900, where this was first written inside Lychee.
How
The new
PHPExif\MotionPhotoclasses read the JPEG itself instead of mapping adapter output. Exiftool's JSON flattensContainer:Directoryinto parallel lists, and they stop lining up when an item has noItem:Length; the primary item of real Pixel files has none. The Native and ImageMagick adapters don't expose the directory at all.JpegXmpReaderwalks the header from SOI to SOS and returns the standard XMP packet, checking every segment length against the file size.MotionPhotoXmpparses it withext-xml, matching namespaces by URI. External entities are not loaded.MotionPhotoLocator::locate(string $path): inttakes the length of theMotionPhotocontainer item, or the legacy offset. A length is only accepted if an MP4ftypbox starts where it points.MotionPhoto="1"but no length is valid, the locator scans for the first plausibleftypbox after the primary image's end-of-image marker. It reads in 64 KiB chunks, so memory use stays constant.Reader::read()calls the locator only when the adapter returned noMicroVideoOffset, and only sets the value when a video is found. Existing Exiftool results are kept. Non-JPEG files are rejected after reading two bytes.The locator can also be used on its own.
Resources/doc/usage.mdhas a short section on both uses.Tests
tests/PHPExif/MotionPhoto/(groupmotionphoto):ftyplook-alike inside image data, boundaries split across chunks, a missing end-of-image marker, and a 20 MB constant-memory check;Readerwith the Native, ImageMagick and Exiftool adapters on two new samples, plus checks that an adapter-provided value is kept and that videos are left alone.tests/files/motion_photo_v1.jpgandmotion_photo_ultrahdr.jpg, about 200 KB each. They aremongolia.jpegwith a motion photo XMP packet, a 1 s H.264 test clip and, for Ultra HDR, a real Pixel gain map.phpstan analyzepasses with no errors.check-code-styleandvalidate-filespass.ExifTest::testAdapterConsistency(a GPS mismatch between ImageMagick and Native ondsc_0003.jpg), also fails onmasterhere.The Exiftool cases only pass in a full run, like the existing
ExiftoolTest. When run alone, theproc_openoverride inExiftoolProcOpenTestmakes the adapter report that it can't open exiftool.🤖 Generated with Claude Code