drewnoakes / metadata-extractor-dotnet

Extracts Exif, IPTC, XMP, ICC and other metadata from image, video and audio files
Other
922 stars 164 forks source link

Rounding error in Shutter Speed value? #352

Open TheHulmaren opened 8 months ago

TheHulmaren commented 8 months ago

Hello, I'm using this library to get EXIF data from images, and encountered a possible rounding error when getting the Shutter Speed tag value.

For example, when the actual shutter speed of the image is 1/30 sec, but somehow in the processed tag description, it says 1/29 sec.

What I'm thinking is that the rounding logic in the method below is a source of the problem.

protected string? GetShutterSpeedDescription(int tagId)
        {
            // I believe this method to now be stable, but am leaving some alternative snippets of
            // code in here, to assist anyone who's looking into this (given that I don't have a public CVS).
            //        float apexValue = _directory.getFloat(ExifSubIFDDirectory.TAG_SHUTTER_SPEED);
            //        int apexPower = (int)Math.pow(2.0, apexValue);
            //        return "1/" + apexPower + " sec";
            // TODO test this method
            // thanks to Mark Edwards for spotting and patching a bug in the calculation of this
            // description (spotted bug using a Canon EOS 300D)
            // thanks also to Gli Blr for spotting this bug
            if (!Directory.TryGetSingle(tagId, out float apexValue))
                return null;

            if (apexValue <= 1)
            {
                var apexPower = (float)(1 / Math.Exp(apexValue * Math.Log(2)));
                var apexPower10 = (long)Math.Round(apexPower * 10.0);
                var fApexPower = apexPower10 / 10.0f;
                return fApexPower + " sec";
            }
            else
            {
                var apexPower = (int)Math.Exp(apexValue * Math.Log(2));
                return "1/" + apexPower + " sec";
            }
        }

For the case when apexValue > 1, I think the code should be like this:

else
            {
                var apexPower = (int)Math.Round(Math.Exp(apexValue * Math.Log(2)));
                return "1/" + apexPower + " sec";
            }

So compared to just naively converting it to int, the value falls to the nearest integer.

I started using this library about 5 hours ago, and new to this area. Therefore I could be wrong about this.

Thank you for reading.

drewnoakes commented 5 months ago

I believe you're right!

Would you like to submit a pull request? Apologies for the delay in responding. This got lost in my notifications.