Exit
  • Global community
    • Language:
      • Deutsch
      • English
      • Español
      • Français
      • Português
  • 日本語コミュニティ
  • 한국 커뮤니티
0

P: [JPEG only] Face data is lost if orientation is changed

Community Beginner ,
May 31, 2019 May 31, 2019

Hi, have been struggling to find an answer to my problem:

If i draw a face region or if a photo has already the data of the face region and i rotate it 90° and i remove the photo from lightroom and re-import, it won't recognize the facetags despite that the information is in the XMP.

 

*As long as the photo is horizontal (that is normal orientation), there is no problem, i can delete the photo from Lightroom and re-import and it wil recognize the face region with the person's name.

 

i have tried to edit xmp metadata in all sorts of ways with exiftool to see if that would fix the problem but havent' had any luck.

 

I would appreciate any help to fix this issue.

Thanks.

Bug Unresolved
TOPICS
macOS , Windows
1.2K
Translate
Report
Community guidelines
Be kind and respectful, give credit to the original source of content, and search for duplicates before posting. Learn more
community guidelines
14 Comments
LEGEND ,
May 31, 2019 May 31, 2019

I observe different behavior in my LR 8.3.1.  Starting with a photo that has a tagged face, when I do Photo > Rotate Left, Metadata > Save Metadata To File, Photo > Remove Photo From Catalog, and then import that photo back into the catalog using Add, the face rectangle and face tag are preserved.

Do Help > System Info. What is the exact version of LR you're running?

Translate
Report
LEGEND ,
May 31, 2019 May 31, 2019

Also, I'm curious -- why do you want to rotate a photo with face tags and re-import it?

Translate
Report
Community Beginner ,
Jun 01, 2019 Jun 01, 2019

i don't want to do that, its just a way to see if light room is detecting the face tags and it isn't...I want to solve this cause if i ever remove my picture from my catalog or import those photos into another pc with lightroom or i rotate the photo would just have to tag them again, that's not right it is supposed to detect the face tags but with photos that have Orientation=90° the tags are not read despite it has the xmp metadata.

Translate
Report
Community Beginner ,
Jun 01, 2019 Jun 01, 2019

I have the same version 😕

Translate
Report
LEGEND ,
Jun 01, 2019 Jun 01, 2019

Let's figure out what's going on in your configuration.  Do this:

1. Select a sample raw photo that's not working.

2. Make sure it has a tagged face.

3. Do Metadata > Save Metadata To File.

4. Right-click the photo and do Show In Finder / Explorer.

5. Make a copy of the photo and the .xmp sidecar and rename before.nef and before.xmp (or whatever raw extension it has).

6. Rotate the photo 90 degrees and repeat steps 3 - 5, renaming the second copy after.nef and after.xmp.

7. Upload all four files to Dropbox or similar and post the sharing link here. (It likely isn't necessary to upload the second copy of the raw file, but in rare cases the raw file and .xmp sidecar can get inconsistent.)

Translate
Report
Community Beginner ,
Jun 01, 2019 Jun 01, 2019

Hi thank for trying to help me... i just tried with raw file .CR2 and it works! The problems is in the .jpg, so do you still need that i post the raw images or the jpg, or is this a normal behavior with .jpg?

Translate
Report
LEGEND ,
Jun 01, 2019 Jun 01, 2019

I'm able to reproduce the behavior with a JPEG.  It's curious that it happens with a JPEG and not a raw -- I'll investigate further.

Translate
Report
LEGEND ,
Jun 01, 2019 Jun 01, 2019

I think it's a bug with JPEG import. The same region information gets written to the XMP metadata regardless of whether it's a raw or JPEG.

Translate
Report
Community Beginner ,
Jun 02, 2019 Jun 02, 2019

So it is a bug that really sucks, something so basic, i think i will switch to another software. I dont understand why nobody else talks about this online, this is a bad thing for those who take vertical JPEG. Thanks for your time and help!

Translate
Report
Community Beginner ,
Feb 24, 2021 Feb 24, 2021

I was tearing my hair out trying to figure out why what seemed to be random JPGs were losing their face tags when imported into a different catalog...and this is the reason.

 

Confirmed that this is still a bug in Lightroom Classic 10.1.1 under the specific conditions listed above. Adobe, this has been a bug for nearly two years...are you listening?

Translate
Report
New Here ,
Dec 14, 2025 Dec 14, 2025

Well, here we are 6.5 years, later and I can confirm that this bug still exists in LRC 15.0.1. I am going to try to get Adobe to recognize this bug (and maybe fix it). Here's my notes on the bug.

 
The problem is as follows:
If the orientation flag in the metadata is anything except 0, when a jpg photo is imported into Lightroom Classic, any existing face detections are not read in.
 
How to reproduce:
1. Import an unrotated image into Lightroom Classic (LRC).
2. Manually mark a face region and give it a name label.
3. Save the metadata to disk.
4. From the finder / file explorer, change the filename to unrotated.jpg.
5. Import the file unrotated.jpg into LRC. Observe that the face region and label are preserved.
6. Rotate the original image by 90 degrees from within LRC.
7. Save the metadata to disk.
8. From the finder / file explorer, change the filename to rotated.jpg.
9. Import the file rotated.jpg into LRC. Observe that the face region and label are missing.
 
Additional notes:
1. The bug happens for jpg files. It may happen for other types of files, but I have not tested. 
2. The bug happens on the Mac and Windows versions of LRC.
3. The bug happens regardless of whether the file is rotated within LRC or via an external program, such as the finder, provided that the rotation is done by changing the orientation flag in the metadata rather than by destructively rewriting a rotated image.
 
I have been thinking about a workaround in the event that Adobe never fixes the problem. I think it should be possible to make a small script to accomplish this. You can losslessly rotate the jpg file if it has a width and height that are a multiple of the jpg block size (8 or 16 pixels, I have read). If the width or heigh are not proper multiples, a few pixels can be trimmed from the side / bottom (which is not ideal).
1. Rotate the image (losslessly if possible) so that the orientation flag is 0.
2. Apply the same rotation to the region parameters (X, Y, W, and H) to ensure that they stay in the same place in the rotated image. 
3. Copy all the remaining IPTC parameters from the original file to the new file.
 
Translate
Report
New Here ,
Dec 29, 2025 Dec 29, 2025

My son and I made this script to fix the bug. You will need to install the pillow library (pip install pillow)

 

import os
import json
import subprocess
import argparse
import shutil # Added for efficient file copying
from PIL import Image

def run_exiftool(args):
result = subprocess.run(["exiftool"] + args, capture_output=True, text=True)
return result.stdout

def rotate_for_lightroom(input_path, output_path):
# 1. Get structured metadata
metadata_raw = run_exiftool(["-j", "-n", "-struct", "-RegionInfo", "-Orientation", input_path])
metadata_list = json.loads(metadata_raw)
if not metadata_list:
print(f"Could not read file: {input_path}")
return

metadata = metadata_list[0]
orientation = metadata.get("Orientation", 1)

region_info = metadata.get("RegionInfo")
if not region_info:
# No regions defined, so just copy directly
shutil.copy2(input_path, output_path)
print(f"No RegionInfo: {os.path.basename(input_path)} copied directly.")
return

# 2. Process Image with PIL
img = Image.open(input_path)
icc_profile = img.info.get("icc_profile")

if orientation == 1:
# Simple copy if orientation is already Normal (1)
shutil.copy2(input_path, output_path) # copy2 preserves timestamps
print(f"Skipped (Normal): {os.path.basename(input_path)} copied directly.")
return
elif orientation == 6: # 90 CW
final_img = img.rotate(-90, expand=True)
elif orientation == 8: # 270 CW
final_img = img.rotate(-270, expand=True)
elif orientation == 3: # 180
final_img = img.rotate(180, expand=True)
else: # Note: This script does not handle mirrored transforms
final_img = img

new_w, new_h = final_img.size
final_img.save(output_path, "JPEG", quality=98, icc_profile=icc_profile, subsampling=0)

# 3. Transform Coordinates
for region in region_info.get("RegionList", []):
box = region['Area']
x, y, w, h = box['X'], box['Y'], box['W'], box['H']

if orientation == 6: # 90 CW
nx, ny, nw, nh = (1 - y), x, h, w
elif orientation == 8: # 270 CW
nx, ny, nw, nh = y, (1 - x), h, w
elif orientation == 3: # 180
nx, ny, nw, nh = (1 - x), (1 - y), w, h
else:
nx, ny, nw, nh = x, y, w, h

box.update({'X': nx, 'Y': ny, 'W': nw, 'H': nh})

if 'Type' not in region or region['Type'] == 'Unknown':
region['Type'] = 'Face'

# 4. Sync Dimensions
region_info['AppliedToDimensions'] = {'W': new_w, 'H': new_h, 'Unit': 'pixel'}

# 5. Write Metadata
payload = [{"SourceFile": output_path, "RegionInfo": region_info}]
temp_json = f"temp_{os.path.basename(output_path)}.json"
with open(temp_json, "w") as f:
json.dump(payload, f)

run_exiftool([
"-overwrite_original",
"-tagsFromFile", input_path,
"-all:all",
"-unsafe",
"-Orientation=1",
"-struct",
f"-json={temp_json}",
"-n",
output_path
])

os.remove(temp_json)
print(f"Processed (Rotated): {os.path.basename(input_path)}")

def process_directory(input_dir, output_dir):
if not os.path.exists(input_dir):
print(f"Error: Input directory '{input_dir}' does not exist.")
return

if not os.path.exists(output_dir):
os.makedirs(output_dir)

valid_extensions = ('.jpg', '.jpeg', '.JPG', '.JPEG')
files = [f for f in os.listdir(input_dir) if f.endswith(valid_extensions)]

if not files:
print("No valid JPEG images found.")
return

for filename in files:
input_full_path = os.path.join(input_dir, filename)
output_full_path = os.path.join(output_dir, filename)
rotate_for_lightroom(input_full_path, output_full_path)

if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Rotate images and sync Lightroom Face Region metadata.")
parser.add_argument("input", help="Path to source images")
parser.add_argument("output", help="Path to save processed images")
args = parser.parse_args()

process_directory(args.input, args.output)

Translate
Report
New Here ,
Dec 29, 2025 Dec 29, 2025

Please note that I did not check the metadata tags in too much detail as the documentation on their usage is a bit sketchy.

Translate
Report
New Here ,
Dec 29, 2025 Dec 29, 2025
LATEST

Also, the implementation uses lossy rotation. I couldn't find any lossless rotation libraries that are currently maintained, and they don't work properly on images that are not an even multiple of 16 (or sometimes 8) in width or height (and all mine were odd sizes since they came from a scanner).

Translate
Report