Cannot update Longitude with SetNewValue()

Started by outdoormagic, March 18, 2022, 11:30:22 AM

Previous topic - Next topic

outdoormagic

Good morning everyone,

I am stumped. I am updating GPS values, rounding them to 6 decimals. The result code from WriteInfo is '1' and I see that the modification date is updated in the Finder. However, when I look at the file, all tags update correctly, except the 'EXIF:GPSLongitude' tag, which has a different value than before (so something changed), but with many decimals. In the following roundn() is a function that rounds to N decimals.

        $refLat = roundn( $refLat, $GPS_DECIMALS );
        $refLon = roundn( $refLon, $GPS_DECIMALS );

        say "BEFORE:";
        say "$refLat, $refLon";
        $exifTool->SetNewValue('XMP:GPSLatitude'    => $refLat, AddValue => 0);
        $exifTool->SetNewValue('XMP:GPSLongitude'   => $refLon, AddValue => 0);
        $exifTool->SetNewValue('EXIF:GPSLatitude'   => abs($refLat), AddValue => 0);
        $exifTool->SetNewValue('EXIF:GPSLongitude'  => abs($refLon), AddValue => 0);

        if ($refLat >= 0){                                                      # set reference tags
            $exifTool->SetNewValue('EXIF:GPSLatitudeRef' => 'N', AddValue => 0);
        }
        else {
            $exifTool->SetNewValue('EXIF:GPSLatitudeRef' => 'S', AddValue => 0);
        }
        if ($refLon >= 0){                                                      # set reference tags
            $exifTool->SetNewValue('EXIF:GPSLongitudeRef' => 'E', AddValue => 0);
        }
        else {
            $exifTool->SetNewValue('EXIF:GPSLongitudeRef' => 'W', AddValue => 0);
        }

I then write to file with:

    my $tmp;
    $tmp = $file.'_tmp';
    my $result = $exifTool->WriteInfo($file, $tmp);                             # write changes to file
    if ( $result == 1 ){                                                        # if successful and changes made
        `rm "$file"`;                                                           # remove original
        `mv "$tmp" "$file"`;                                                    # put updated in place (rename)
    }
    elsif ( $result == 2 ){                                                     # successful, no changes made
        `rm "$tmp"`;                                                            # remove copy and leave original
    }
    elsif ( $result == 0 ){
        say $exifTool->GetValue('Error');
    }

    $exifTool->SetNewValue();                                               # reset SetNewValue


this outputs:

BEFORE:
64.856683, -29.614933


and exits with WriteInfo code 1. Just what I would expect.

Before I run the code, exiftool -a -n -G $FILENAME | grep GPS outputs:

[EXIF]          GPS Version ID                  : 2 2 0 0
[EXIF]          GPS Latitude Ref                : N
[EXIF]          GPS Latitude                    : 64.8566833333333
[EXIF]          GPS Longitude Ref               : W
[EXIF]          GPS Longitude                   : 29.6149333333333
[EXIF]          GPS Altitude Ref                : 0
[EXIF]          GPS Altitude                    : 5299.8
[XMP]           GPS Latitude                    : 64.8566833333333
[XMP]           GPS Longitude                   : -29.6149333333333
[XMP]           GPS Altitude Ref                : 0
[XMP]           GPS Altitude                    : 5299.8
[Composite]     GPS Altitude                    : 5299.8
[Composite]     GPS Latitude                    : 64.8566833333333
[Composite]     GPS Longitude                   : -29.6149333333333
[Composite]     GPS Latitude Ref                : N
[Composite]     GPS Longitude Ref               : W
[Composite]     GPS Position                    : 64.8566833333333 -29.6149333333333


After, it outputs:

[EXIF]          GPS Version ID                  : 2 2 0 0
[EXIF]          GPS Latitude Ref                : N
[EXIF]          GPS Latitude                    : 64.856683
[EXIF]          GPS Longitude Ref               : W
[EXIF]          GPS Longitude                   : 29.6149330001444
[EXIF]          GPS Altitude Ref                : 0
[EXIF]          GPS Altitude                    : 5299.8
[XMP]           GPS Altitude                    : 5299.8
[XMP]           GPS Altitude Ref                : 0
[XMP]           GPS Latitude                    : 64.856683
[XMP]           GPS Longitude                   : -29.614933
[Composite]     GPS Altitude                    : 5299.8
[Composite]     GPS Latitude                    : 64.856683
[Composite]     GPS Longitude                   : -29.6149330001444
[Composite]     GPS Latitude Ref                : N
[Composite]     GPS Longitude Ref               : W
[Composite]     GPS Position                    : 64.856683 -29.6149330001444


Latitude was rounded, but not Longitude, even though Longitude was changed to some new value. What am I missing?

Thank you in advance for any suggestions.

Paul

StarGeek

GPS coordinates are not saved as a simple decimal number (at least in EXIF, it's different for XMP).  They're saved as a set of three fractional numbers, one each for degrees, minutes, and seconds.  If you add -v2 to your command, you'll be able to see what those fractions are.  In this case the result is
  | | 1)  GPSLatitudeRef = N
  | |     - Tag 0x0001 (2 bytes, string[2])
  | | 2)  GPSLatitude = 64 51 24.0588 (64/1 51/1 60147/2500)
  | |     - Tag 0x0002 (24 bytes, rational64u[3])
  | | 3)  GPSLongitudeRef = W
  | |     - Tag 0x0003 (2 bytes, string[2])
  | | 4)  GPSLongitude = 29 36 53.75880052 (29/1 36/1 41233/767)
  | |     - Tag 0x0004 (24 bytes, rational64u[3])


While the Base 2 system (0s and 1s) that computers use works well for integers, it doesn't do as well when it comes to floating point decimals.  Wikipedia has a entry on floating point accuracy problems.  When you add in translating from a decimal number to the fractional numbers to save the values and then translate back again, errors get introduced.  Sort of like translating some text in Google Translate to another language and back again.

I'm sorry if I'm not explaining it well, it's pretty messy to begin with.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

StarGeek

Phil has some comments on the rounding in this post.  I'm pretty sure there's another post somewhere in the forums here with a better explanation, but I can't find it atm.
* Did you read FAQ #3 and use the command listed there?
* Please use the Code button for exiftool code/output.
 
* Please include your OS, Exiftool version, and type of file you're processing (MP4, JPG, etc).

outdoormagic

Quote from: StarGeek on March 18, 2022, 12:21:10 PM
I'm sorry if I'm not explaining it well, it's pretty messy to begin with.

Thank you @StarGeek. It was actually quite clear and very helpful. I appreciate the help.

I was trying to remove decimals to reflect the lower accuracy in practice (devices). Reading Phil's post, he states that
QuoteWhen rationalizing a value, ExifTool attempts to maintain 8 digits of precision, but beyond that there may be rounding errors.
I'm wondering if rounding to 8 decimals doesn't make more sense, as he states that that is the limit ExifTool tries to preserve—even though no device is that accurate.

Another thought would be to build my own ratio instead of rounding. That would ensure a number that doesn't change going forward.

Thanks again, Stargeek. Helpful as always!