RhetTbull / osxphotos

Python app to work with pictures and associated metadata from Apple Photos on macOS. Also includes a package to provide programmatic access to the Photos library, pictures, and metadata.
MIT License
2.17k stars 100 forks source link

XMP sidecar exports unnamed faces #1626

Open RhetTbull opened 3 months ago

RhetTbull commented 3 months ago

In working on #1619 I noticed that the --sidecar xmp option exported unnamed face regions. This does not happen in the JSON/exiftool sidecar. I think the behavior should match the JSON sidecars in that unnamed face regions are excluded from the sidecar.

    <rdf:Bag>
     <rdf:li rdf:parseType="Resource">
      <mwg-rs:Area rdf:parseType="Resource">
      <stArea:h>0.066108</stArea:h>
      <stArea:w>0.099186</stArea:w>
      <stArea:x>0.526539</stArea:x>
      <stArea:y>0.279120</stArea:y>
      <stArea:unit>normalized</stArea:unit>
      </mwg-rs:Area>
      <mwg-rs:Name></mwg-rs:Name>
      <mwg-rs:Rotation>0.0</mwg-rs:Rotation>
      <mwg-rs:Type>Face</mwg-rs:Type>
     </rdf:li>
RhetTbull commented 3 months ago

To fix this, add an if block around the region generation. Need to test if the file is still valid even if all faces are unnamed:

<%def name="mwg_face_regions(photo)">
    % if photo.face_info:
    <mwg-rs:Regions rdf:parseType="Resource">
    <mwg-rs:AppliedToDimensions rdf:parseType="Resource">
    <stDim:h>${photo.width if photo.orientation in [5, 6, 7, 8] else photo.height}</stDim:h>
    <stDim:w>${photo.height if photo.orientation in [5, 6, 7, 8] else photo.width}</stDim:w>
    <stDim:unit>pixel</stDim:unit>
    </mwg-rs:AppliedToDimensions>
    <mwg-rs:RegionList>
    <rdf:Bag>
    % for face in photo.face_info:
     % if face.name:
     <rdf:li rdf:parseType="Resource">
      <mwg-rs:Area rdf:parseType="Resource">
      <stArea:h>${'{0:.6f}'.format(face.mwg_rs_area.h)}</stArea:h>
      <stArea:w>${'{0:.6f}'.format(face.mwg_rs_area.w)}</stArea:w>
      <stArea:x>${'{0:.6f}'.format(face.mwg_rs_area.x)}</stArea:x>
      <stArea:y>${'{0:.6f}'.format(face.mwg_rs_area.y)}</stArea:y>
      <stArea:unit>normalized</stArea:unit>
      </mwg-rs:Area>
      <mwg-rs:Name>${face.name}</mwg-rs:Name>
      <mwg-rs:Rotation>${face.roll}</mwg-rs:Rotation>
      <mwg-rs:Type>Face</mwg-rs:Type>
     </rdf:li>
     % endif
    % endfor
    </rdf:Bag>
    </mwg-rs:RegionList>
    </mwg-rs:Regions>
    % endif
</%def>

and

<%def name="mpri_face_regions(photo)">
    % if photo.face_info:
    <MP:RegionInfo rdf:parseType="Resource">
     <MPRI:Regions>
      <rdf:Bag>
      % for face in photo.face_info:
       % if face.name:
       <rdf:li rdf:parseType="Resource">
       <MPReg:PersonDisplayName>${face.name}</MPReg:PersonDisplayName>
       <MPReg:Rectangle>${'{0:.6f}'.format(face.mpri_reg_rect.x)}, ${'{0:.6f}'.format(face.mpri_reg_rect.y)}, ${'{0:.6f}'.format(face.mpri_reg_rect.h)}, ${'{0:.6f}'.format(face.mpri_reg_rect.w)}</MPReg:Rectangle>
       </rdf:li>
       % endif
      % endfor
      </rdf:Bag>
     </MPRI:Regions>
    </MP:RegionInfo>
    % endif
</%def>