ruby-vips icon indicating copy to clipboard operation
ruby-vips copied to clipboard

Move structured way to extract a field from image

Open bogdan opened this issue 9 months ago • 4 comments

Reading image metadata is inconvenient because the return format looks like a result of inspect call:

image = Vips::Image.new_from_file('file.png')
image.get "exif-ifd3-GPSTimeStamp"
    # => "13/1 57/1 0/1 (13:57:00.00, Rational, 3 components, 24 bytes)"
image.get "width" # => 3024
image.get "exif-ifd3-UserComment" 
  # => "Hello (world) (Hello (world), ASCII, 14 components, 14 bytes)"

It can be especially difficult to parse as I can not simply ignore what is in parens all the time because they are not always there, or can be part of the output of text fields.

Is it possible to introduce a different method that would return result in a more structured way like?

image.field("exif-ifd3-UserComment") 
# => {type: :string, value: "Hello (world)", encoding: :ASCII, components: 14, bytes: 14}

bogdan avatar Feb 21 '25 18:02 bogdan

Hello @bogdan, you're right, the libvips EXIF metadata system is very old now, and not very good.

There's been some discussion about making something better, but no one's done the work yet, unfortunately. The most recent thread on this was:

https://github.com/libvips/libvips/issues/4002

jcupitt avatar Feb 21 '25 18:02 jcupitt

Is there any way we can work it around at the ruby level?

bogdan avatar Feb 21 '25 19:02 bogdan

libvips puts the raw EXIF data into a binary object called exif-data, so you can always extract that and use any EXIF parse library to read and write values.

$ vipsheader -a ~/pics/k2.jpg | grep exif-data
exif-data: 186 bytes of binary data

Or in ruby:

$ irb
irb(main):001> require "vips"
=> true
irb(main):003> x = Vips::Image.new_from_file "/home/john/pics/k2.jpg"
=> #<Image 1450x2048 uchar, 3 bands, srgb>
irb(main):004> x.get "exif-data"
=> "Exif\x00\x00II*\x00\b\x00\x00\x00\x06\x00\x12\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00\x1A\x01\x05\x00\x01\x00\x00\x00V\x00\x00\x00\e\x01\x05\x00\x01\x00\x00\x00^\x00\x00\x00(\x01\x03\x00\x01\x00\x00\x00\x02\x00\x00\x00\x13\x02\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00i\x87\x04\x00\x01\x00\x00\x00f\x00\x00\x00\x00\x00\x00\x00I\x19\x01\x00\xE8\x03\x00\x00I\x19\x01\x00\xE8\x03\x00\x00\x06\x00\x00\x90\a\x00\x04\x00\x00\x000210\x01\x91\a\x00\x04\x00\x00\x00\x01\x02\x03\x00\x00\xA0\a\x00\x04\x00\x00\x000100\x01\xA0\x03\x00\x01\x00\x00\x00\xFF\xFF\x00\x00\x02\xA0\x04\x00\x01\x00\x00\x00\xAA\x05\x00\x00\x03\xA0\x04\x00\x01\x00\x00\x00\x00\b\x00\x00\x00\x00\x00\x00"

jcupitt avatar Feb 22 '25 11:02 jcupitt

... but of course the right fix is to do this at the libvips level, so all language bindings have a better way to interact with EXIF data.

jcupitt avatar Feb 22 '25 11:02 jcupitt