nextcloud / photos

📸 Your memories under your control
GNU Affero General Public License v3.0
565 stars 62 forks source link

Intelligently handle Google Camera camera burst subdirectories #298

Open strugee opened 4 years ago

strugee commented 4 years ago

Is your feature request related to a problem? Please describe.

The Google Camera app on my Pixel 3a XL, in certain circumstances, will generate photo "bursts". These are saved in a folder named after the image and with the photos in the burst inside the folder. For example:

% tree IMG_20200418_222652
IMG_20200418_222652
├── 00000PORTRAIT_00000_BURST20200418222652648.jpg
└── 00100lrPORTRAIT_00100_BURST20200418222652648_COVER.jpg

0 directories, 2 files

As you can perhaps guess from the name, this burst was generated because I took a photo in portrait mode. One of them is the unprocessed original, and one of them has the portrait mode effect applied.

I upload these folders as-is to my Nextcloud, but the Photos app doesn't handle them very intelligently: they are treated as regular folders. This makes it annoying to browse folders with these burst subdirectories in them, because they're shown like regular folders.

I'm not sure what other times Google Photos generates these burst subdirectories.

Describe the solution you'd like

Ideally, Photos would recognize that the subdirectory was a burst, and it would display it as one photo. When opened, the interface would make it clear somehow that there are two alternative versions of the photo, and allow the user to switch between which one they're looking at. Note that this is how the Google Photos app on Android works; I assume the web version works the same way.

Describe alternatives you've considered

None thus far.

Additional context

I figured the data that Google Photos uses must be encoded in EXIF or IPTC metadata or something like that, so I did some digging. exiftool(1) dumps the following for the unprocessed photo (note: I filtered out a property called "Hdrp makernote" which was the same for both images and spewed multiple screenfuls of seemingly random characters):

ExifTool Version Number         : 11.16
File Name                       : 00000PORTRAIT_00000_BURST20200418222652648.jpg
Directory                       : .
File Permissions                : rw-r--r--
File Type                       : JPEG
File Type Extension             : jpg
MIME Type                       : image/jpeg
Exif Byte Order                 : Little-endian (Intel, II)
Make                            : Google
Camera Model Name               : Pixel 3a XL
Orientation                     : Horizontal (normal)
X Resolution                    : 72
Y Resolution                    : 72
Resolution Unit                 : inches
Software                        : HDR+ 1.0.300173574zp
Modify Date                     : 2020:04:18 22:26:52
Y Cb Cr Positioning             : Centered
Exposure Time                   : 1/15
F Number                        : 1.8
Exposure Program                : Program AE
ISO                             : 5610
Exif Version                    : 0231
Date/Time Original              : 2020:04:18 22:26:52
Create Date                     : 2020:04:18 22:26:52
Offset Time                     : -04:00
Offset Time Original            : -04:00
Offset Time Digitized           : -04:00
Components Configuration        : Y, Cb, Cr, -
Shutter Speed Value             : 1/15
Aperture Value                  : 1.8
Brightness Value                : -5.21
Exposure Compensation           : 0
Max Aperture Value              : 1.8
Subject Distance                : 0.7 m
Metering Mode                   : Center-weighted average
Flash                           : Off, Did not fire
Focal Length                    : 4.4 mm
Warning                         : [minor] Unrecognized MakerNotes
Sub Sec Time                    : 675908
Sub Sec Time Original           : 675908
Sub Sec Time Digitized          : 675908
Flashpix Version                : 0100
Color Space                     : sRGB
Exif Image Width                : 4032
Exif Image Height               : 3024
Interoperability Index          : R98 - DCF basic file (sRGB)
Interoperability Version        : 0100
Sensing Method                  : One-chip color area
Scene Type                      : Directly photographed
Custom Rendered                 : Custom
Exposure Mode                   : Auto
White Balance                   : Auto
Digital Zoom Ratio              : 2
Focal Length In 35mm Format     : 27 mm
Scene Capture Type              : Standard
Contrast                        : Normal
Saturation                      : Normal
Sharpness                       : Normal
Subject Distance Range          : Macro
GPS Version ID                  : 2.2.0.0
GPS Latitude Ref                : North
GPS Longitude Ref               : West
GPS Altitude Ref                : Above Sea Level
GPS Time Stamp                  : 02:26:50
GPS Dilution Of Precision       : 7.743
GPS Processing Method           : fused
GPS Date Stamp                  : 2020:04:19
XMP Toolkit                     : Adobe XMP Core 5.1.0-jc003
Portrait Version                : 0
Burst ID                        : b9b16484-0edd-4836-b95b-9230a77d2139
Camera Burst ID                 : b9b16484-0edd-4836-b95b-9230a77d2139
Has Extended XMP                : F253C6022A3B445A730AAB3A671D9438
Disable Auto Creation           : Animation, Collage
JFIF Version                    : 1.02
Profile CMM Type                : 
Profile Version                 : 4.0.0
Profile Class                   : Display Device Profile
Color Space Data                : RGB
Profile Connection Space        : XYZ
Profile Date Time               : 2016:12:08 09:38:28
Profile File Signature          : acsp
Primary Platform                : Unknown ()
CMM Flags                       : Not Embedded, Independent
Device Manufacturer             : Google
Device Model                    : 
Device Attributes               : Reflective, Glossy, Positive, Color
Rendering Intent                : Perceptual
Connection Space Illuminant     : 0.9642 1 0.82491
Profile Creator                 : Google
Profile ID                      : 75e1a6b13c34376310c8ab660632a28a
Profile Description             : sRGB IEC61966-2.1
Profile Copyright               : Copyright (c) 2016 Google Inc.
Media White Point               : 0.95045 1 1.08905
Media Black Point               : 0 0 0
Red Matrix Column               : 0.43604 0.22249 0.01392
Green Matrix Column             : 0.38512 0.7169 0.09706
Blue Matrix Column              : 0.14305 0.06061 0.71391
Red Tone Reproduction Curve     : (Binary data 32 bytes, use -b option to extract)
Chromatic Adaptation            : 1.04788 0.02292 -0.05019 0.02959 0.99048 -0.01704 -0.00922 0.01508 0.75168
Blue Tone Reproduction Curve    : (Binary data 32 bytes, use -b option to extract)
Green Tone Reproduction Curve   : (Binary data 32 bytes, use -b option to extract)
Image Width                     : 4032
Image Height                    : 3024
Encoding Process                : Baseline DCT, Huffman coding
Bits Per Sample                 : 8
Color Components                : 3
Y Cb Cr Sub Sampling            : YCbCr4:2:0 (2 2)
Aperture                        : 1.8
GPS Altitude                    : 157.3 m Above Sea Level
GPS Date/Time                   : 2020:04:19 02:26:50Z
GPS Latitude                    : 43 deg 7' 42.90" N
GPS Longitude                   : 77 deg 37' 44.47" W
GPS Position                    : 43 deg 7' 42.90" N, 77 deg 37' 44.47" W
Image Size                      : 4032x3024
Megapixels                      : 12.2
Scale Factor To 35 mm Equivalent: 6.1
Shutter Speed                   : 1/15
Create Date                     : 2020:04:18 22:26:52.675908-04:00
Date/Time Original              : 2020:04:18 22:26:52.675908-04:00
Modify Date                     : 2020:04:18 22:26:52.675908-04:00
Circle Of Confusion             : 0.005 mm
Depth Of Field                  : 0.49 m (0.53 - 1.02 m)
Field Of View                   : 67.4 deg
Focal Length                    : 4.4 mm (35 mm equivalent: 27.0 mm)
Hyperfocal Distance             : 2.22 m
Light Value                     : -0.2

I diff'd this output with the output of exittool(1) when run on the processed, portrait-mode image and here's what I got (filtering out some boring differences like file modification time as well as a property called "Cameras Camera Depth Map Focal Table" that just spewed a lot of random characters):

2c2
< File Name                       : 00000PORTRAIT_00000_BURST20200418222652648.jpg
---
> File Name                       : 00100lrPORTRAIT_00100_BURST20200418222652648_COVER.jpg
68,70c68
< XMP Toolkit                     : Adobe XMP Core 5.1.0-jc003
< Portrait Version                : 0
< Burst ID                        : b9b16484-0edd-4836-b95b-9230a77d2139
---
> Has Extended XMP                : a447c888ebfb0b4793dd9ae160fec72b
72,73c70,72
< Has Extended XMP                : F253C6022A3B445A730AAB3A671D9438
< Disable Auto Creation           : Animation, Collage
---
> Burst ID                        : b9b16484-0edd-4836-b95b-9230a77d2139
> Burst Primary                   : 1
> Special Type ID                 : com.google.android.apps.camera.gallery.specialtype.SpecialType-PORTRAIT
108c107,135
---
> XMP Toolkit                     : Adobe XMP
> Container Directory Item Mime   : image/jpeg
> Container Directory Item Length : 0
> Container Directory Item Data URI: primary_image
> Profiles Profile Type           : DepthPhoto
> Profiles Profile Camera Indices : 0
> Cameras Camera Trait            : Physical
> Cameras Camera Image Item Semantic: Original
> Cameras Camera Image Item URI   : android/original_image
> Cameras Camera Depth Map Item Semantic: Depth
> Cameras Camera Depth Map Format : RangeInverse
> Cameras Camera Depth Map Units  : Diopters
> Cameras Camera Depth Map Near   : 0.342229
> Cameras Camera Depth Map Far    : 8.000000
> Cameras Camera Depth Map Depth URI: android/depthmap
> Cameras Camera Depth Map Measure Type: OpticalAxis
> Cameras Camera Depth Map Confidence URI: android/confidencemap
> Cameras Camera Imaging Model Focal Length X: 3194.812500
> Cameras Camera Imaging Model Focal Length Y: 3197.943115
> Cameras Camera Imaging Model Image Width: 4032
> Cameras Camera Imaging Model Image Height: 3024
> Cameras Camera Imaging Model Principal Point X: 2023.042603
> Cameras Camera Imaging Model Principal Point Y: 1520.387695
> Cameras Camera Imaging Model Skew: 0.000000
> Cameras Camera Imaging Model Pixel Aspect Ratio: 1.000000
> Cameras Camera Imaging Model Distortion Count: 4
> Cameras Camera Imaging Model Distortion: AACAPwAAAADzKRk+AAAAAJ0D7L4AAAAAOdHiPgAAAAA

It appears that the "Burst ID"/"Camera Burst ID" (not sure how these are different) is a UUID that we can use to tie these photos together, i.e. determine that they were part of the same burst. "Special Type ID" seems to indicate that the photo is a portrait-mode photo. The Google Photos app lets you set which of the two alternative photos in the burst is the "primary" photo, so my guess is that the presence of "Burst Primary: 1" indicates that, but I need to do more testing to be sure.

skjnldsv commented 4 years ago

@strugee thanks for your report! That is a nice idea :)

@jancborchardt what would be the expected ux for this?

jancborchardt commented 4 years ago

Yep, good point.

What we can do is simply show it as 1 picture in the overview, and show the preferred picture of the burst on click, but show both pictures in the slideshow.

To properly show burst mode photos, we could have a bar on the bottom displaying the other photos of that burst. But I'd say first is fixing the current strange display, and then afterwards we can look into how to do it better.

SimonKravis commented 2 years ago

Anyone know what is in the field hrdp_makernote for images from Google Pixel 4a camera? Doesn't look like a Base64 encoded string?

strugee commented 1 year ago

@Bun-Bun this issue is about Nextcloud Photos, the web app, and has nothing to do with uploads.