Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Divide by zero error #12

Closed
waffleau opened this issue Oct 1, 2017 · 10 comments
Closed

Divide by zero error #12

waffleau opened this issue Oct 1, 2017 · 10 comments

Comments

@waffleau
Copy link

waffleau commented Oct 1, 2017

Hi @tonytonyjan, you helped me with an issue to do with orientation in this issue. I've opted to try to upgrade to 2.0.0 as my C is a bit too rusty to contribute code directly. :)

Unfortunately I've run into a divide by zero error in 2.0.0. I can extract using the CLI tool. Unfortunately I can't attach one of the images giving me trouble as I don't own them, but I've scrubbed some EXIF data which will hopefully give you something.

To produce, I'm just doing:

Exif::Data.new(IO.read('image.jpeg'))

And the CLI output (I've removed sensitive info):

Image Description   |MY_IMAGE.JPG
Manufacturer        |DJI
Model               |123456
Orientation         |Top-left
X-Resolution        |72
Y-Resolution        |72
Resolution Unit     |Inch
Software            |v01.01.01
Date and Time       |2017:01:01 12:00:00
YCbCr Positioning   |Centered
XP Comment          |Type=N, Mode=P, DE=None
XP Keywords         |v01.01.01;1.1.6;v1.0.0
Compression         |JPEG compression
X-Resolution        |72
Y-Resolution        |72
Resolution Unit     |Inch
Exposure Time       |1/80 sec.
F-Number            |f/4.0
Exposure Program    |Normal program
ISO Speed Ratings   |100
Exif Version        |Exif Version 2.3
Date and Time (Origi|2017:05:22 12:31:11
Date and Time (Digit|2017:05:22 12:31:11
Components Configura|- Cr Cb Y
Compressed Bits per |3.2441677
Shutter Speed       |6.32 EV (1/79 sec.)
Aperture            |4.00 EV (f/4.0)
Exposure Bias       |0.00 EV
Maximum Aperture Val|2.97 EV (f/2.8)
Subject Distance    |0.0 m
Metering Mode       |Average
Light Source        |Cloudy weather
Flash               |No flash function
Focal Length        |8.8 mm
Maker Note          |506 bytes undefined data
FlashPixVersion     |Unknown FlashPix Version
Color Space         |sRGB
Pixel X Dimension   |5472
Pixel Y Dimension   |3648
Exposure Index      |0/0
File Source         |DSC
Scene Type          |Directly photographed
Custom Rendered     |Normal process
Exposure Mode       |Auto exposure
White Balance       |Manual white balance
Digital Zoom Ratio  |0/0
Focal Length in 35mm|24
Scene Capture Type  |Standard
Gain Control        |Normal
Contrast            |Normal
Saturation          |Normal
Sharpness           |Normal
Subject Distance Ran|Unknown
GPS Tag Version     |2.3.0.0
North or South Latit|S
Latitude            |30, 59, 30.5000
East or West Longitu|E
Longitude           |140, 10, 45.5000
Altitude Reference  |Sea level
Altitude            |10
Interoperability Ind|R98
Interoperability Ver|0100

Please let me know if there's anything else I can do to help debug, happy to try branches or whatever else is useful.

@tonytonyjan
Copy link
Owner

How does the error message look like? Would you please paste complete output here?

@waffleau
Copy link
Author

waffleau commented Oct 1, 2017

Unforunately it's not giving me much info, I'm guessing because it's calling out to C. Here's all I get:

Exif::Data.new(IO.read('image.jpeg'))
ZeroDivisionError: divided by 0
	from (irb):35:in `new'
	from (irb):35

@waffleau
Copy link
Author

waffleau commented Oct 1, 2017

I've found a public image that I can reproduce with: https://dtphgwb5vjcez.cloudfront.net/focus/gallery/27/2749/dji-phantom-4-pro-ad33b6ab.jpg

My leading theory right now is that it's related to GPS parsing, as I couldn't get it to fail until I found an image with GPS data in it, but that might be a coincidence.

@tonytonyjan
Copy link
Owner

Seems like the error happens when numerator and denominator are both zero (take ExposureIndex for example). So far I have no idea how to handle this scenario since 0/0 is not a valid rational number.

@tonytonyjan
Copy link
Owner

Maybe we can make it return Float::INFINITY or Float::NAN, any idea?

@waffleau
Copy link
Author

waffleau commented Oct 1, 2017

Ah I see. Float::NAN makes sense, I'd expect the value to be nil in Ruby.

@tonytonyjan
Copy link
Owner

tonytonyjan commented Oct 2, 2017

I surveyed some other libraries:

valid rational 0/0 ℕ/0
exifr Rational Float::NaN Float::INFINITY
python-pillow IFDRational IFDRational with value float('nan') IFDRational with value float('nan')

Currently exif will typecast IFD rational type to Rational, but Rational cannot handle zero denominators. In my option, changing the return type depending on the value is not a good idea. Take python-pillow for example, IFDRational inherits from a standard class Fraction to support zero denominators.

There are several proposals:

  1. Return a float.
  2. Return an instance which inherits from Rational like python-pillow.
  3. Return a tuple, ex. Tuple = Struct.new(:numerator, :denominator)
  4. Return an array, ex. [numerator, denominator]

I need more time to analysis pros and cons for each one.

@waffleau
Copy link
Author

waffleau commented Oct 2, 2017

Fair point. In that case, it seems returning a float makes the most sense as it's the type that a consumer would be expecting. A tuple or an array changes the format, but they prevent any loss of information. I don't know enough about EXIF to know if that information loss is important.

@tonytonyjan
Copy link
Owner

Umm... I just thought for another moment, maybe returning either Rational or Float is the best solution since they are both Numeric. I will commit this change to the next release.

@waffleau
Copy link
Author

waffleau commented Oct 2, 2017

Thanks for your support @tonytonyjan, I really appreciate it. :)

I've got my use case working, so all good on my end now. I have run into one other issue around character encoding that I thought I'd let you know about. It's not really a bug though, so feel free to disregard if it's not something that concerns you.

Basically, some of the fields in the EXIF aren't unicode, so converting to JSON doesn't always work. Work around is pretty simple:

> data = Exif::Data.new(IO.read('image.jpg')).to_h
> data.to_json
Encoding::UndefinedConversionError: "\x9A" from ASCII-8BIT to UTF-8

> data[:exif].delete(:maker_note)
> data.to_json
{ ... }

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants